metasm 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
@@ -0,0 +1,543 @@
|
|
1
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
2
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
3
|
+
#
|
4
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
5
|
+
|
6
|
+
module Metasm
|
7
|
+
module Gui
|
8
|
+
class HexWidget < DrawableWidget
|
9
|
+
# data_size = size of data in bytes (1 => chars, 4 => dwords..)
|
10
|
+
# line_size = nr of bytes shown per line
|
11
|
+
# view_addr = addr of 1st byte to display
|
12
|
+
attr_accessor :dasm, :show_address, :show_data, :show_ascii,
|
13
|
+
:data_size, :line_size, :endianness,
|
14
|
+
#:data_sign, :data_hex,
|
15
|
+
:caret_x_data, :focus_zone,
|
16
|
+
:keep_aligned, :relative_addr, :hl_curbyte,
|
17
|
+
:view_addr, :write_pending
|
18
|
+
|
19
|
+
def initialize_widget(dasm, parent_widget)
|
20
|
+
@dasm = dasm
|
21
|
+
@parent_widget = parent_widget
|
22
|
+
|
23
|
+
# @caret_x = caret position in octets
|
24
|
+
# in hex, round to nearest @data_size and add @caret_x_data (nibbles)
|
25
|
+
@x_data = 7
|
26
|
+
@caret_x_data = 0
|
27
|
+
@oldcaret_x_data = 42
|
28
|
+
@focus_zone = @oldfocus_zone = :hex
|
29
|
+
@addr_min = @dasm.sections.keys.grep(Integer).min rescue nil
|
30
|
+
@addr_max = @dasm.sections.map { |s, e| s + e.length }.max rescue nil
|
31
|
+
@view_addr = @dasm.prog_binding['entrypoint'] || @addr_min || 0
|
32
|
+
@show_address = @show_data = @show_ascii = true
|
33
|
+
@data_size = 1
|
34
|
+
@line_size = 16
|
35
|
+
@num_lines = 2 # height of widget in lines
|
36
|
+
@write_pending = {} # addr -> newvalue (characters)
|
37
|
+
@endianness = @dasm.cpu.endianness
|
38
|
+
@raw_data_cache = {} # addr -> raw @line_size data at addr
|
39
|
+
#@data_sign = false
|
40
|
+
#@data_hex = true
|
41
|
+
@keep_aligned = false # true to keep the topleft octet a multiple of linewidth
|
42
|
+
@relative_addr = nil # show '+42h' in the addr column if not nil
|
43
|
+
@hl_curbyte = true # draw grey bg for current byte
|
44
|
+
|
45
|
+
@default_color_association = { :ascii => :black, :data => :black,
|
46
|
+
:address => :blue, :caret => :black, :background => :white,
|
47
|
+
:write_pending => :darkred, :caret_mirror => :palegrey }
|
48
|
+
end
|
49
|
+
|
50
|
+
def resized(w, h)
|
51
|
+
wc = w/@font_width
|
52
|
+
hc = h/@font_height
|
53
|
+
ca = current_address
|
54
|
+
@num_lines = hc
|
55
|
+
@caret_y = hc-1 if @caret_y >= hc
|
56
|
+
ols = @line_size
|
57
|
+
@line_size = 8
|
58
|
+
@line_size *= 2 while x_ascii+(@show_ascii ? @line_size : 0) < wc # booh..
|
59
|
+
@line_size /= 2
|
60
|
+
if @line_size != ols
|
61
|
+
@view_addr &= -@line_size if @keep_aligned
|
62
|
+
focus_addr ca
|
63
|
+
gui_update
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# converts a screen x coord (in characters) to a [@caret_x, @caret_x_data, @focus_zone]
|
68
|
+
def chroff_to_caretx(x)
|
69
|
+
if x < x_data
|
70
|
+
[0, 0, (@show_data ? :hex : :ascii)]
|
71
|
+
elsif x < x_ascii
|
72
|
+
x -= x_data
|
73
|
+
x -= x/(4*(2*@data_size+1)+1) # remove space after each 4*@data_size
|
74
|
+
x -= x/(2*@data_size+1) # remove space after each @data_size
|
75
|
+
x = 2*@line_size-1 if x >= 2*@line_size # between hex & ascii
|
76
|
+
cx = x/(2*@data_size)*@data_size
|
77
|
+
cxd = x-2*cx
|
78
|
+
[cx, cxd, :hex]
|
79
|
+
elsif x < x_ascii+@line_size
|
80
|
+
x -= x_ascii
|
81
|
+
[x, 0, :ascii]
|
82
|
+
else
|
83
|
+
[@line_size-1, 0, (@show_ascii ? :ascii : :hex)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def click(x, y)
|
88
|
+
@caret_x, @caret_x_data, @focus_zone = chroff_to_caretx((x-1).to_i / @font_width)
|
89
|
+
@caret_y = y.to_i / @font_height
|
90
|
+
update_caret
|
91
|
+
end
|
92
|
+
|
93
|
+
def rightclick(x, y)
|
94
|
+
doubleclick(x, y)
|
95
|
+
end
|
96
|
+
|
97
|
+
def doubleclick(x, y)
|
98
|
+
if x < @x_data * @font_width
|
99
|
+
if @relative_addr
|
100
|
+
@relative_addr = nil
|
101
|
+
else
|
102
|
+
@relative_addr = @view_addr
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@data_size = {1 => 2, 2 => 4, 4 => 8, 8 => 1}[@data_size]
|
106
|
+
end
|
107
|
+
redraw
|
108
|
+
end
|
109
|
+
|
110
|
+
def mouse_wheel(dir, x, y)
|
111
|
+
off = height.to_i/@font_height/4*@line_size
|
112
|
+
case dir
|
113
|
+
when :up; @view_addr -= off
|
114
|
+
when :down; @view_addr += off
|
115
|
+
end
|
116
|
+
gui_update
|
117
|
+
end
|
118
|
+
|
119
|
+
# returns 1 line of data
|
120
|
+
def data_at(addr, len=@line_size)
|
121
|
+
if len == @line_size and l = @raw_data_cache[addr]
|
122
|
+
l
|
123
|
+
elsif s = @dasm.get_section_at(addr)
|
124
|
+
l = s[0].read(len)
|
125
|
+
@raw_data_cache[addr] = l if len == @line_size
|
126
|
+
l
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def paint
|
131
|
+
w_h = height
|
132
|
+
curaddr = @view_addr
|
133
|
+
# current window position
|
134
|
+
x = 1
|
135
|
+
y = 0
|
136
|
+
@num_lines = 0
|
137
|
+
|
138
|
+
# renders a string at current cursor position with a color
|
139
|
+
# must not include newline
|
140
|
+
render = lambda { |str, color|
|
141
|
+
draw_string_color(color, x, y, str)
|
142
|
+
x += str.length * @font_width
|
143
|
+
}
|
144
|
+
|
145
|
+
if @show_address
|
146
|
+
@x_data = [6, Expression[curaddr].to_s.length].max + 1
|
147
|
+
end
|
148
|
+
|
149
|
+
xd = x_data*@font_width + 1
|
150
|
+
xa = x_ascii*@font_width + 1
|
151
|
+
hexfmt = "%0#{@data_size*2}x "
|
152
|
+
wp_win = {} # @write_pending clipped to current window
|
153
|
+
if not @write_pending.empty?
|
154
|
+
if curaddr.kind_of? Integer
|
155
|
+
@write_pending.keys.grep(curaddr...curaddr+(w_h/@font_height+1)*@line_size).each { |k| wp_win[k] = @write_pending[k] }
|
156
|
+
else wp_win = @write_pending.dup
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# draw text until screen is full
|
161
|
+
while y < w_h
|
162
|
+
if @show_address
|
163
|
+
if @relative_addr
|
164
|
+
diff = Expression[curaddr] - @relative_addr
|
165
|
+
if diff.kind_of? Integer
|
166
|
+
addr = "#{'+' if diff >= 0}#{Expression[diff]}".ljust(@x_data-1)
|
167
|
+
else
|
168
|
+
addr = "#{Expression[curaddr]}"
|
169
|
+
end
|
170
|
+
else
|
171
|
+
addr = "#{Expression[curaddr]}"
|
172
|
+
end
|
173
|
+
render[addr.rjust(@x_data-1, '0'), :address]
|
174
|
+
end
|
175
|
+
|
176
|
+
d = data_at(curaddr)
|
177
|
+
if not d and data_at(curaddr+@line_size-1, 1)
|
178
|
+
# data in the current line but not from the beginning
|
179
|
+
d_o = (1...@line_size).find { |o| d = data_at(curaddr+o, @line_size-o) }.to_i
|
180
|
+
else
|
181
|
+
d_o = 0
|
182
|
+
end
|
183
|
+
wp = {}
|
184
|
+
d.length.times { |o|
|
185
|
+
if c = wp_win[curaddr+d_o+o]
|
186
|
+
wp[d_o+o] = true
|
187
|
+
d = d.dup
|
188
|
+
d[o, 1] = c.chr
|
189
|
+
end
|
190
|
+
} if d
|
191
|
+
if @show_data and d
|
192
|
+
x = xd
|
193
|
+
if d_o > 0
|
194
|
+
d_do = [0].pack('C')*(d_o % @data_size) + d
|
195
|
+
i = d_o/@data_size
|
196
|
+
x += (i*(@data_size*2+1) + i/4) * @font_width
|
197
|
+
else
|
198
|
+
d_do = d
|
199
|
+
i = 0
|
200
|
+
end
|
201
|
+
# XXX non-hex display ? (signed int, float..)
|
202
|
+
case @data_size
|
203
|
+
when 1; pak = 'C*'
|
204
|
+
when 2; pak = (@endianness == :little ? 'v*' : 'n*')
|
205
|
+
when 4; pak = (@endianness == :little ? 'V*' : 'N*')
|
206
|
+
when 8; pak = 'Q*' # XXX endianness..
|
207
|
+
end
|
208
|
+
awp = {} ; wp.each_key { |k| awp[k/@data_size] = true }
|
209
|
+
|
210
|
+
if @hl_curbyte and @caret_y == y/@font_height
|
211
|
+
cx = (x_data + x_data_cur(@caret_x, 0))*@font_width + 1
|
212
|
+
draw_rectangle_color(:caret_mirror, cx, y, @data_size*2*@font_width, @font_height)
|
213
|
+
end
|
214
|
+
|
215
|
+
if awp.empty?
|
216
|
+
s = ''
|
217
|
+
d_do.unpack(pak).each { |b|
|
218
|
+
s << (hexfmt % b)
|
219
|
+
s << ' ' if i & 3 == 3
|
220
|
+
i += 1
|
221
|
+
}
|
222
|
+
render[s, :data]
|
223
|
+
else
|
224
|
+
d_do.unpack(pak).each { |b|
|
225
|
+
col = awp[i] ? :write_pending : :data
|
226
|
+
render[hexfmt % b, col]
|
227
|
+
render[' ', :data] if i & 3 == 3
|
228
|
+
i+=1
|
229
|
+
}
|
230
|
+
end
|
231
|
+
end
|
232
|
+
if @show_ascii and d
|
233
|
+
x = xa + d_o*@font_width
|
234
|
+
d = d.gsub(/[^\x20-\x7e]/, '.')
|
235
|
+
if wp.empty?
|
236
|
+
render[d, :ascii]
|
237
|
+
else
|
238
|
+
d.length.times { |o|
|
239
|
+
col = wp[o] ? :write_pending : :ascii
|
240
|
+
render[d[o, 1], col]
|
241
|
+
}
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
curaddr += @line_size
|
246
|
+
@num_lines += 1
|
247
|
+
x = 1
|
248
|
+
y += @font_height
|
249
|
+
end
|
250
|
+
|
251
|
+
# draw caret
|
252
|
+
if @show_data
|
253
|
+
cx = (x_data + x_data_cur)*@font_width+1
|
254
|
+
cy = @caret_y*@font_height
|
255
|
+
col = (focus? && @focus_zone == :hex) ? :caret : :caret_mirror
|
256
|
+
draw_line_color(col, cx, cy, cx, cy+@font_height-1)
|
257
|
+
end
|
258
|
+
|
259
|
+
if @show_ascii
|
260
|
+
cx = (x_ascii + @caret_x)*@font_width+1
|
261
|
+
cy = @caret_y*@font_height
|
262
|
+
col = (focus? && @focus_zone == :ascii) ? :caret : :caret_mirror
|
263
|
+
draw_line_color(col, cx, cy, cx, cy+@font_height-1)
|
264
|
+
end
|
265
|
+
|
266
|
+
@oldcaret_x, @oldcaret_y, @oldcaret_x_data, @oldfocus_zone = @caret_x, @caret_y, @caret_x_data, @focus_zone
|
267
|
+
end
|
268
|
+
|
269
|
+
# char x of start of data zone
|
270
|
+
def x_data
|
271
|
+
@show_address ? @x_data : 0
|
272
|
+
end
|
273
|
+
|
274
|
+
# char x of start of ascii zone
|
275
|
+
def x_ascii
|
276
|
+
x_data + (@show_data ? @line_size*2 + @line_size/@data_size + @line_size/@data_size/4 : 0)
|
277
|
+
end
|
278
|
+
|
279
|
+
# current offset in data zone of caret
|
280
|
+
def x_data_cur(cx = @caret_x, cxd = @caret_x_data)
|
281
|
+
x = (cx/@data_size)*@data_size
|
282
|
+
2*x + x/@data_size + x/@data_size/4 + cxd
|
283
|
+
end
|
284
|
+
|
285
|
+
def keypress(key)
|
286
|
+
case key
|
287
|
+
when :left
|
288
|
+
key_left
|
289
|
+
update_caret
|
290
|
+
when :right
|
291
|
+
key_right
|
292
|
+
update_caret
|
293
|
+
when :up
|
294
|
+
key_up
|
295
|
+
update_caret
|
296
|
+
when :down
|
297
|
+
key_down
|
298
|
+
update_caret
|
299
|
+
when :pgup
|
300
|
+
if not @addr_min or @view_addr > @addr_min
|
301
|
+
@view_addr -= (@num_lines/2)*@line_size
|
302
|
+
gui_update
|
303
|
+
end
|
304
|
+
when :pgdown
|
305
|
+
if not @addr_max or @view_addr < @addr_max
|
306
|
+
@view_addr += (@num_lines/2)*@line_size
|
307
|
+
gui_update
|
308
|
+
end
|
309
|
+
when :home
|
310
|
+
@caret_x = 0
|
311
|
+
update_caret
|
312
|
+
when :end
|
313
|
+
@caret_x = @line_size-1
|
314
|
+
update_caret
|
315
|
+
|
316
|
+
when :backspace
|
317
|
+
key_left
|
318
|
+
if @focus_zone == :hex
|
319
|
+
key_left if @caret_x_data & 1 == 1
|
320
|
+
oo = @caret_x_data/2
|
321
|
+
oo = @data_size - oo - 1 if @endianness == :little
|
322
|
+
@write_pending.delete current_address + oo
|
323
|
+
else
|
324
|
+
@write_pending.delete current_address
|
325
|
+
end
|
326
|
+
redraw
|
327
|
+
when :tab
|
328
|
+
switch_focus_zone
|
329
|
+
update_caret
|
330
|
+
when :enter
|
331
|
+
commit_writes
|
332
|
+
gui_update
|
333
|
+
when :esc
|
334
|
+
if not @write_pending.empty?
|
335
|
+
@write_pending.clear
|
336
|
+
redraw
|
337
|
+
else return false
|
338
|
+
end
|
339
|
+
|
340
|
+
when ?\x20..?\x7e
|
341
|
+
if @focus_zone == :hex
|
342
|
+
if ?a.kind_of?(String) # ruby1.9
|
343
|
+
v = key.ord
|
344
|
+
case key
|
345
|
+
when ?0..?9; v -= ?0.ord
|
346
|
+
when ?a..?f; v -= ?a.ord-10
|
347
|
+
when ?A..?F; v -= ?A.ord-10
|
348
|
+
else return false
|
349
|
+
end
|
350
|
+
else
|
351
|
+
case v = key
|
352
|
+
when ?0..?9; v -= ?0
|
353
|
+
when ?a..?f; v -= ?a-10
|
354
|
+
when ?A..?F; v -= ?A-10
|
355
|
+
else return false
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
oo = @caret_x_data/2
|
360
|
+
oo = @data_size - oo - 1 if @endianness == :little
|
361
|
+
baddr = current_address + oo
|
362
|
+
return false if not d = data_at(baddr, 1)
|
363
|
+
o = 4*((@caret_x_data+1) % 2)
|
364
|
+
@write_pending[baddr] ||= d[0]
|
365
|
+
if ?a.kind_of?(String)
|
366
|
+
@write_pending[baddr] = ((@write_pending[baddr].ord & ~(0xf << o)) | (v << o)).chr
|
367
|
+
else
|
368
|
+
@write_pending[baddr] = (@write_pending[baddr] & ~(0xf << o)) | (v << o)
|
369
|
+
end
|
370
|
+
else
|
371
|
+
@write_pending[current_address] = key
|
372
|
+
end
|
373
|
+
key_right
|
374
|
+
redraw
|
375
|
+
else return false
|
376
|
+
end
|
377
|
+
true
|
378
|
+
end
|
379
|
+
|
380
|
+
def keypress_ctrl(key)
|
381
|
+
case key
|
382
|
+
when ?f
|
383
|
+
if @focus_zone == :hex
|
384
|
+
prompt_search_hex
|
385
|
+
else
|
386
|
+
prompt_search_ascii
|
387
|
+
end
|
388
|
+
else return false
|
389
|
+
end
|
390
|
+
true
|
391
|
+
end
|
392
|
+
|
393
|
+
# pop a dialog, scans the sections for a hex pattern
|
394
|
+
def prompt_search_hex
|
395
|
+
inputbox('hex pattern to search (hex regexp, use .. for wildcard)') { |pat|
|
396
|
+
pat = pat.gsub(' ', '').gsub('..', '.').gsub(/[0-9a-f][0-9a-f]/i) { |o| "\\x#{o}" }
|
397
|
+
pat = Regexp.new(pat, Regexp::MULTILINE, 'n') # 'n' = force ascii-8bit
|
398
|
+
list = [['addr']] + @dasm.pattern_scan(pat).map { |a| [Expression[a]] }
|
399
|
+
listwindow("hex search #{pat}", list) { |i| focus_addr i[0] }
|
400
|
+
}
|
401
|
+
end
|
402
|
+
|
403
|
+
# pop a dialog, scans the sections for a regex
|
404
|
+
def prompt_search_ascii
|
405
|
+
inputbox('data pattern to search (regexp)') { |pat|
|
406
|
+
list = [['addr']] + @dasm.pattern_scan(/#{pat}/).map { |a| [Expression[a]] }
|
407
|
+
listwindow("data search #{pat}", list) { |i| focus_addr i[0] }
|
408
|
+
}
|
409
|
+
end
|
410
|
+
|
411
|
+
def key_left
|
412
|
+
if @focus_zone == :hex
|
413
|
+
if @caret_x_data > 0
|
414
|
+
@caret_x_data -= 1
|
415
|
+
else
|
416
|
+
@caret_x_data = @data_size*2-1
|
417
|
+
@caret_x -= @data_size
|
418
|
+
end
|
419
|
+
else
|
420
|
+
@caret_x -= 1
|
421
|
+
end
|
422
|
+
if @caret_x < 0
|
423
|
+
@caret_x += @line_size
|
424
|
+
key_up
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def key_right
|
429
|
+
if @focus_zone == :hex
|
430
|
+
if @caret_x_data < @data_size*2-1
|
431
|
+
@caret_x_data += 1
|
432
|
+
else
|
433
|
+
@caret_x_data = 0
|
434
|
+
@caret_x += @data_size
|
435
|
+
end
|
436
|
+
else
|
437
|
+
@caret_x += 1
|
438
|
+
end
|
439
|
+
if @caret_x >= @line_size
|
440
|
+
@caret_x = 0
|
441
|
+
key_down
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
def key_up
|
446
|
+
if @caret_y > 0
|
447
|
+
@caret_y -= 1
|
448
|
+
elsif not @addr_min or @view_addr > @addr_min
|
449
|
+
@view_addr -= @line_size
|
450
|
+
redraw
|
451
|
+
else
|
452
|
+
@caret_x = @caret_x_data = 0
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def key_down
|
457
|
+
if @caret_y < @num_lines-2
|
458
|
+
@caret_y += 1
|
459
|
+
elsif not @addr_max or @view_addr < @addr_max
|
460
|
+
@view_addr += @line_size
|
461
|
+
redraw
|
462
|
+
else
|
463
|
+
@caret_x = @line_size-1 # XXX partial final line... (01 23 45 bla )
|
464
|
+
@caret_x_data = @data_size*2-1
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
def switch_focus_zone(n=nil)
|
469
|
+
n ||= { :hex => :ascii, :ascii => :hex }[@focus_zone]
|
470
|
+
@caret_x = @caret_x / @data_size * @data_size if n == :hex
|
471
|
+
@caret_x_data = 0
|
472
|
+
@focus_zone = n
|
473
|
+
end
|
474
|
+
|
475
|
+
def commit_writes
|
476
|
+
a = s = nil
|
477
|
+
@write_pending.each { |k, v|
|
478
|
+
if not s or k < a or k >= a + s.length
|
479
|
+
s, a = @dasm.get_section_at(k)
|
480
|
+
end
|
481
|
+
next if not s
|
482
|
+
s[k-a] = v
|
483
|
+
}
|
484
|
+
@write_pending.clear
|
485
|
+
rescue
|
486
|
+
@parent_widget.messagebox($!, $!.class.to_s)
|
487
|
+
end
|
488
|
+
|
489
|
+
def get_cursor_pos
|
490
|
+
[@view_addr, @caret_x, @caret_y, @caret_x_data, @focus_zone]
|
491
|
+
end
|
492
|
+
|
493
|
+
def set_cursor_pos(p)
|
494
|
+
@view_addr, @caret_x, @caret_y, @caret_x_data, @focus_zone = p
|
495
|
+
redraw
|
496
|
+
update_caret
|
497
|
+
end
|
498
|
+
|
499
|
+
# hint that the caret moved
|
500
|
+
def update_caret
|
501
|
+
return redraw if @hl_curbyte
|
502
|
+
a = []
|
503
|
+
a << [x_data + x_data_cur, @caret_y] << [x_data + x_data_cur(@oldcaret_x, @oldcaret_x_data), @oldcaret_y] if @show_data
|
504
|
+
a << [x_ascii + @caret_x, @caret_y] << [x_ascii + @oldcaret_x, @oldcaret_y] if @show_ascii
|
505
|
+
a.each { |x, y| invalidate_caret(x, y) }
|
506
|
+
@oldcaret_x, @oldcaret_y, @oldcaret_x_data, @oldfocus_zone = @caret_x, @caret_y, @caret_x_data, @focus_zone
|
507
|
+
end
|
508
|
+
|
509
|
+
# focus on addr
|
510
|
+
# returns true on success (address exists)
|
511
|
+
def focus_addr(addr)
|
512
|
+
return if not addr = @parent_widget.normalize(addr)
|
513
|
+
if addr.kind_of? Integer
|
514
|
+
return if @addr_min and (addr < @addr_min or addr > @addr_max)
|
515
|
+
addr &= -@line_size if @keep_aligned
|
516
|
+
@view_addr = addr if addr < @view_addr or addr >= @view_addr+(@num_lines-2)*@line_size
|
517
|
+
elsif s = @dasm.get_section_at(addr)
|
518
|
+
@view_addr = Expression[s[1]]
|
519
|
+
else return
|
520
|
+
end
|
521
|
+
@caret_x = (addr-@view_addr) % @line_size
|
522
|
+
@caret_x_data = 0
|
523
|
+
@caret_y = (addr-@view_addr) / @line_size
|
524
|
+
@focus_zone = :ascii
|
525
|
+
redraw
|
526
|
+
update_caret
|
527
|
+
true
|
528
|
+
end
|
529
|
+
|
530
|
+
# returns the address of the data under the cursor
|
531
|
+
def current_address
|
532
|
+
@view_addr + @caret_y.to_i*@line_size + @caret_x.to_i
|
533
|
+
end
|
534
|
+
|
535
|
+
def gui_update
|
536
|
+
@addr_min = @dasm.sections.keys.grep(Integer).min rescue nil
|
537
|
+
@addr_max = @dasm.sections.map { |s, e| s + e.length }.max rescue nil
|
538
|
+
@raw_data_cache.clear
|
539
|
+
redraw
|
540
|
+
end
|
541
|
+
end
|
542
|
+
end
|
543
|
+
end
|