metasm 1.0.0 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +3 -0
- data/.gitignore +3 -0
- data/.hgtags +3 -0
- data/Gemfile +3 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +3 -1
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +23 -0
- data/{lib/metasm.rb → metasm.rb} +15 -3
- data/{lib/metasm → metasm}/compile_c.rb +15 -9
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +404 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/metasm/cpu/arm.rb +14 -0
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +15 -18
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +3 -6
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +285 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/mips/compile_c.rb → metasm/cpu/bpf.rb} +4 -2
- data/metasm/cpu/bpf/decode.rb +110 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +30 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/cy16.rb} +2 -4
- data/metasm/cpu/cy16/decode.rb +247 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +30 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +34 -34
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +71 -4
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +21 -12
- data/{lib/metasm/mips.rb → metasm/cpu/ebpf.rb} +3 -4
- data/metasm/cpu/ebpf/debug.rb +61 -0
- data/metasm/cpu/ebpf/decode.rb +142 -0
- data/metasm/cpu/ebpf/main.rb +58 -0
- data/metasm/cpu/ebpf/opcodes.rb +97 -0
- data/metasm/cpu/ebpf/render.rb +36 -0
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +23 -9
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +44 -6
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +342 -128
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +75 -53
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +66 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +55 -17
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +32 -5
- data/metasm/cpu/mcs51.rb +8 -0
- data/metasm/cpu/mcs51/decode.rb +99 -0
- data/metasm/cpu/mcs51/main.rb +87 -0
- data/metasm/cpu/mcs51/opcodes.rb +120 -0
- data/metasm/cpu/mips.rb +14 -0
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +59 -38
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +13 -6
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +87 -18
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +243 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/metasm/cpu/openrisc.rb +11 -0
- data/metasm/cpu/openrisc/debug.rb +106 -0
- data/metasm/cpu/openrisc/decode.rb +182 -0
- data/metasm/cpu/openrisc/decompile.rb +350 -0
- data/metasm/cpu/openrisc/main.rb +70 -0
- data/metasm/cpu/openrisc/opcodes.rb +109 -0
- data/metasm/cpu/openrisc/render.rb +37 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/metasm/cpu/ppc.rb +11 -0
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -37
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +23 -18
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -6
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +116 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +50 -23
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +38 -27
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/st20.rb +9 -0
- data/metasm/cpu/st20/decode.rb +173 -0
- data/metasm/cpu/st20/decompile.rb +283 -0
- data/metasm/cpu/st20/main.rb +37 -0
- data/metasm/cpu/st20/opcodes.rb +140 -0
- data/{lib/metasm/arm.rb → metasm/cpu/webasm.rb} +4 -5
- data/metasm/cpu/webasm/debug.rb +31 -0
- data/metasm/cpu/webasm/decode.rb +321 -0
- data/metasm/cpu/webasm/decompile.rb +386 -0
- data/metasm/cpu/webasm/encode.rb +104 -0
- data/metasm/cpu/webasm/main.rb +81 -0
- data/metasm/cpu/webasm/opcodes.rb +214 -0
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +40 -25
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +58 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +59 -28
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +18 -6
- data/metasm/cpu/x86_64/opcodes.rb +138 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +12 -4
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +286 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +48 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +201 -407
- data/{lib/metasm → metasm}/decode.rb +104 -24
- data/{lib/metasm → metasm}/decompile.rb +804 -478
- data/{lib/metasm → metasm}/disassemble.rb +385 -170
- data/{lib/metasm → metasm}/disassemble_api.rb +684 -105
- data/{lib/metasm → metasm}/dynldr.rb +231 -138
- data/{lib/metasm → metasm}/encode.rb +20 -5
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +3 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +35 -7
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +70 -23
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +24 -22
- data/{lib/metasm → metasm}/exe_format/dex.rb +26 -8
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +108 -58
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +202 -36
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +126 -32
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +218 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +28 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +2 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +96 -11
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/metasm/exe_format/wasm.rb +402 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +177 -114
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1754 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +16 -12
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +360 -77
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +109 -34
- data/{lib/metasm → metasm}/gui/gtk.rb +174 -44
- data/{lib/metasm → metasm}/gui/qt.rb +14 -4
- data/{lib/metasm → metasm}/gui/win32.rb +180 -43
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +421 -286
- data/metasm/os/emulator.rb +175 -0
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +335 -0
- data/{lib/metasm → metasm}/os/windows.rb +151 -58
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +49 -36
- data/{lib/metasm → metasm}/parse_c.rb +405 -246
- data/{lib/metasm → metasm}/preprocessor.rb +71 -41
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +4 -3
- data/misc/lint.rb +58 -0
- data/misc/objdiff.rb +4 -1
- data/misc/objscan.rb +1 -1
- data/misc/openrisc-parser.rb +79 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +29 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +48 -7
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +35 -27
- data/samples/elfencode.rb +15 -0
- data/samples/emubios.rb +251 -0
- data/samples/emudbg.rb +127 -0
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +186 -391
- data/samples/metasm-shell.rb +68 -57
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +57 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +80 -26
- data/tests/mcs51.rb +27 -0
- data/tests/mips.rb +10 -3
- data/tests/preprocessor.rb +18 -0
- data/tests/x86_64.rb +66 -18
- metadata +465 -219
- metadata.gz.sig +2 -0
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -872
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
@@ -4,7 +4,7 @@
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
5
5
|
|
6
6
|
|
7
|
-
require 'metasm/ia32/opcodes'
|
7
|
+
require 'metasm/cpu/ia32/opcodes'
|
8
8
|
|
9
9
|
module Metasm
|
10
10
|
class Ia32
|
@@ -18,7 +18,7 @@ class Ia32
|
|
18
18
|
@dbg_register_flags ||= :eflags
|
19
19
|
end
|
20
20
|
|
21
|
-
def dbg_register_list
|
21
|
+
def dbg_register_list
|
22
22
|
@dbg_register_list ||= [:eax, :ebx, :ecx, :edx, :esi, :edi, :ebp, :esp, :eip]
|
23
23
|
end
|
24
24
|
|
@@ -46,10 +46,10 @@ class Ia32
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def dbg_enable_singlestep(dbg)
|
49
|
-
dbg_set_flag(dbg, :t)
|
49
|
+
dbg_set_flag(dbg, :t) if dbg_get_flag(dbg, :t) == 0
|
50
50
|
end
|
51
51
|
def dbg_disable_singlestep(dbg)
|
52
|
-
dbg_unset_flag(dbg, :t)
|
52
|
+
dbg_unset_flag(dbg, :t) if dbg_get_flag(dbg, :t) != 0
|
53
53
|
end
|
54
54
|
|
55
55
|
def dbg_enable_bp(dbg, bp)
|
@@ -66,9 +66,11 @@ class Ia32
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
DBG_BPX = "\xcc"
|
70
|
+
DBG_BPX.force_encoding('BINARY') if DBG_BPX.respond_to?(:force_encoding)
|
69
71
|
def dbg_enable_bpx(dbg, bp)
|
70
72
|
bp.internal[:previous] ||= dbg.memory[bp.address, 1]
|
71
|
-
dbg.memory[bp.address, 1] =
|
73
|
+
dbg.memory[bp.address, 1] = DBG_BPX
|
72
74
|
end
|
73
75
|
|
74
76
|
def dbg_disable_bpx(dbg, bp)
|
@@ -113,7 +115,7 @@ class Ia32
|
|
113
115
|
if dbg[:dr6] == 0 and dbg[:dr7] == 0
|
114
116
|
dbg[:dr7] = 0x10000 # some OS (eg Windows) only return dr6 if dr7 != 0
|
115
117
|
end
|
116
|
-
dbg[:dr6] = 0
|
118
|
+
dbg[:dr6] = 0 if dbg[:dr6] & 0x400f != 0
|
117
119
|
end
|
118
120
|
|
119
121
|
def dbg_evt_bpx(dbg, b)
|
@@ -189,5 +191,41 @@ class Ia32
|
|
189
191
|
def dbg_func_arg_set(dbg, argnr, arg)
|
190
192
|
dbg.memory_write_int(Expression[:esp, :+, 4*(argnr+1)], arg)
|
191
193
|
end
|
194
|
+
|
195
|
+
def dbg_resolve_pc(di, fbd, pc_reg, dbg_ctx)
|
196
|
+
a = di.instruction.args.map { |aa| symbolic(aa) }
|
197
|
+
|
198
|
+
cond = case di.opcode.name
|
199
|
+
when 'jz', 'je'; dbg_ctx.get_flag(:z)
|
200
|
+
when 'jnz', 'jne'; !dbg_ctx.get_flag(:z)
|
201
|
+
when 'jo'; dbg_ctx.get_flag(:o)
|
202
|
+
when 'jno'; !dbg_ctx.get_flag(:o)
|
203
|
+
when 'js'; dbg_ctx.get_flag(:s)
|
204
|
+
when 'jns'; !dbg_ctx.get_flag(:s)
|
205
|
+
when 'jc', 'jb', 'jnae'; dbg_ctx.get_flag(:c)
|
206
|
+
when 'jnc', 'jnb', 'jae'; !dbg_ctx.get_flag(:c)
|
207
|
+
when 'jbe', 'jna'; dbg_ctx.get_flag(:c) or dbg_ctx.get_flag(:z)
|
208
|
+
when 'jnbe', 'ja'; !dbg_ctx.get_flag(:c) and !dbg_ctx.get_flag(:z)
|
209
|
+
when 'jl', 'jnge'; dbg_ctx.get_flag(:s) != dbg_ctx.get_flag(:o)
|
210
|
+
when 'jnl', 'jge'; dbg_ctx.get_flag(:s) == dbg_ctx.get_flag(:o)
|
211
|
+
when 'jle', 'jng'; dbg_ctx.get_flag(:z) or dbg_ctx.get_flag(:s) != dbg_ctx.get_flag(:o)
|
212
|
+
when 'jnle', 'jg'; !dbg_ctx.get_flag(:z) and dbg_ctx.get_flag(:s) == dbg_ctx.get_flag(:o)
|
213
|
+
when 'jp', 'jpe'; dbg_ctx.get_flag(:p)
|
214
|
+
when 'jnp', 'jpo'; !dbg_ctx.get_flag(:p)
|
215
|
+
when 'loop'; dbg_ctx[dbg_register_list[2]] != 0
|
216
|
+
when 'loopz', 'loope'; dbg_ctx[dbg_register_list[2]] != 0 and dbg_ctx.get_flag(:z)
|
217
|
+
when 'loopnz', 'loopne'; dbg_ctx[dbg_register_list[2]] != 0 and !dbg_ctx.get_flag(:z)
|
218
|
+
when 'jcxz', 'jecxz', 'jrcxz'
|
219
|
+
mask = {?c => 0xffff, ?e => 0xffff_ffff, ?r => -1}[di.opcode.name[1]]
|
220
|
+
dbg_ctx[dbg_register_list[2]] & mask == 0
|
221
|
+
else return super(di, fbd, pc_reg, dbg_ctx)
|
222
|
+
end
|
223
|
+
|
224
|
+
if cond
|
225
|
+
fbd[pc_reg] = a.last
|
226
|
+
else
|
227
|
+
fbd[pc_reg] = di.next_addr
|
228
|
+
end
|
229
|
+
end
|
192
230
|
end
|
193
231
|
end
|
@@ -4,13 +4,13 @@
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
5
5
|
|
6
6
|
|
7
|
-
require 'metasm/ia32/opcodes'
|
7
|
+
require 'metasm/cpu/ia32/opcodes'
|
8
8
|
require 'metasm/decode'
|
9
9
|
|
10
10
|
module Metasm
|
11
11
|
class Ia32
|
12
12
|
class ModRM
|
13
|
-
def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg)
|
13
|
+
def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg, h = {})
|
14
14
|
m = (byte >> 6) & 3
|
15
15
|
rm = byte & 7
|
16
16
|
|
@@ -28,7 +28,11 @@ class Ia32
|
|
28
28
|
b = Reg.new(a, adsz)
|
29
29
|
else
|
30
30
|
s = 1
|
31
|
-
|
31
|
+
if h[:mrmvex]
|
32
|
+
i = SimdReg.new(a, h[:mrmvex])
|
33
|
+
else
|
34
|
+
i = Reg.new(a, adsz)
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
38
|
when :sib
|
@@ -37,7 +41,11 @@ class Ia32
|
|
37
41
|
ii = ((sib >> 3) & 7)
|
38
42
|
if ii != 4
|
39
43
|
s = 1 << ((sib >> 6) & 3)
|
40
|
-
|
44
|
+
if h[:mrmvex]
|
45
|
+
i = SimdReg.new(ii, h[:mrmvex])
|
46
|
+
else
|
47
|
+
i = Reg.new(ii, adsz)
|
48
|
+
end
|
41
49
|
end
|
42
50
|
|
43
51
|
bb = sib & 7
|
@@ -52,11 +60,12 @@ class Ia32
|
|
52
60
|
end
|
53
61
|
}
|
54
62
|
|
55
|
-
if imm and imm.reduce.kind_of?
|
63
|
+
if imm and ir = imm.reduce and ir.kind_of?(Integer) and ir < 0 and (ir < -0x10_0000 or (!b and !i))
|
56
64
|
# probably a base address -> unsigned
|
57
65
|
imm = Expression[imm.reduce & ((1 << (adsz || 32)) - 1)]
|
58
66
|
end
|
59
67
|
|
68
|
+
opsz = h[:argsz] if h[:argsz]
|
60
69
|
new adsz, opsz, s, i, b, imm, seg
|
61
70
|
end
|
62
71
|
end
|
@@ -90,8 +99,7 @@ class Ia32
|
|
90
99
|
msk = op.bin_mask[0]
|
91
100
|
|
92
101
|
for i in b..(b | (255^msk))
|
93
|
-
|
94
|
-
lookaside[i] << op
|
102
|
+
lookaside[i] << op if i & msk == b & msk
|
95
103
|
end
|
96
104
|
}
|
97
105
|
lookaside
|
@@ -117,8 +125,6 @@ class Ia32
|
|
117
125
|
v = byte & 7
|
118
126
|
end
|
119
127
|
instr.prefix[:seg] = SegReg.new(v)
|
120
|
-
|
121
|
-
instr.prefix[:jmphint] = ((byte & 0x10) == 0x10)
|
122
128
|
else
|
123
129
|
return false
|
124
130
|
end
|
@@ -133,11 +139,10 @@ class Ia32
|
|
133
139
|
while edata.ptr < edata.data.length
|
134
140
|
pfx = di.instruction.prefix || {}
|
135
141
|
byte = edata.data[edata.ptr]
|
136
|
-
byte = byte.unpack('C').first if byte.kind_of?
|
142
|
+
byte = byte.unpack('C').first if byte.kind_of?(::String)
|
137
143
|
return di if di.opcode = @bin_lookaside[byte].find { |op|
|
138
144
|
# fetch the relevant bytes from edata
|
139
145
|
bseq = edata.data[edata.ptr, op.bin.length].unpack('C*')
|
140
|
-
di.opcode = op if op.props[:opsz] # needed by opsz(di)
|
141
146
|
|
142
147
|
# check against full opcode mask
|
143
148
|
op.bin.zip(bseq, op.bin_mask).all? { |b1, b2, m| b2 and ((b1 & m) == (b2 & m)) } and
|
@@ -147,12 +152,17 @@ class Ia32
|
|
147
152
|
(fld = op.fields[:seg2A] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg2A] == 1) or
|
148
153
|
(fld = op.fields[:seg3A] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg3A] < 4) or
|
149
154
|
(fld = op.fields[:seg3A] || op.fields[:seg3] and (bseq[fld[0]] >> fld[1]) & @fields_mask[:seg3] > 5) or
|
150
|
-
(fld = op.fields[:
|
151
|
-
(
|
155
|
+
(op.props[:modrmA] and fld = op.fields[:modrm] and (bseq[fld[0]] >> fld[1]) & 0xC0 == 0xC0) or
|
156
|
+
(op.props[:modrmR] and fld = op.fields[:modrm] and (bseq[fld[0]] >> fld[1]) & 0xC0 != 0xC0) or
|
157
|
+
(fld = op.fields[:vex_vvvv] and @size != 64 and (bseq[fld[0]] >> fld[1]) & @fields_mask[:vex_vvvv] < 8) or
|
158
|
+
(sz = op.props[:opsz] and opsz(di, op) != sz) or
|
159
|
+
(sz = op.props[:adsz] and adsz(di, op) != sz) or
|
152
160
|
(ndpfx = op.props[:needpfx] and not pfx[:list].to_a.include? ndpfx) or
|
161
|
+
(pfx[:adsz] and op.props[:adsz] and op.props[:adsz] == @size) or
|
153
162
|
# return non-ambiguous opcode (eg push.i16 in 32bit mode) / sync with addop_post in opcode.rb
|
154
|
-
(pfx[:opsz] and (op.args == [:i] or op.args == [:farptr] or op.name
|
155
|
-
(pfx[:adsz] and op.props[:adsz] and op.props[:
|
163
|
+
(pfx[:opsz] and not op.props[:opsz] and (op.args == [:i] or op.args == [:farptr] or op.name == 'ret')) or
|
164
|
+
(pfx[:adsz] and not op.props[:adsz] and (op.props[:strop] or op.props[:stropz] or op.args.include?(:mrm_imm) or op.args.include?(:modrm) or op.name =~ /loop|xlat/)) or
|
165
|
+
(op.name == 'nop' and op.bin[0] == 0x90 and di.instruction.prefix and di.instruction.prefix[:rex_b])
|
156
166
|
)
|
157
167
|
}
|
158
168
|
|
@@ -174,19 +184,21 @@ class Ia32
|
|
174
184
|
when 0xF2, 0xF3; pfx.delete :rep
|
175
185
|
end
|
176
186
|
|
187
|
+
if op.props[:setip] and not op.props[:stopexec] and pfx[:seg]
|
188
|
+
case pfx.delete(:seg).val
|
189
|
+
when 1; pfx[:jmphint] = 'hintnojmp'
|
190
|
+
when 3; pfx[:jmphint] = 'hintjmp'
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
177
194
|
field_val = lambda { |f|
|
178
195
|
if fld = op.fields[f]
|
179
196
|
(bseq[fld[0]] >> fld[1]) & @fields_mask[f]
|
180
197
|
end
|
181
198
|
}
|
182
199
|
|
183
|
-
opsz = opsz(di)
|
184
|
-
|
185
|
-
if pfx[:adsz]
|
186
|
-
adsz = 48 - @size
|
187
|
-
else
|
188
|
-
adsz = @size
|
189
|
-
end
|
200
|
+
opsz = op.props[:argsz] || opsz(di)
|
201
|
+
adsz = (pfx[:adsz] ? 48 - @size : @size)
|
190
202
|
|
191
203
|
mmxsz = ((op.props[:xmmx] && pfx[:opsz]) ? 128 : 64)
|
192
204
|
op.args.each { |a|
|
@@ -194,19 +206,28 @@ class Ia32
|
|
194
206
|
when :reg; Reg.new field_val[a], opsz
|
195
207
|
when :eeec; CtrlReg.new field_val[a]
|
196
208
|
when :eeed; DbgReg.new field_val[a]
|
209
|
+
when :eeet; TstReg.new field_val[a]
|
197
210
|
when :seg2, :seg2A, :seg3, :seg3A; SegReg.new field_val[a]
|
198
211
|
when :regfp; FpReg.new field_val[a]
|
199
212
|
when :regmmx; SimdReg.new field_val[a], mmxsz
|
200
213
|
when :regxmm; SimdReg.new field_val[a], 128
|
214
|
+
when :regymm; SimdReg.new field_val[a], 256
|
201
215
|
|
202
216
|
when :farptr; Farptr.decode edata, @endianness, opsz
|
203
217
|
when :i8, :u8, :u16; Expression[edata.decode_imm(a, @endianness)]
|
204
218
|
when :i; Expression[edata.decode_imm("#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym, @endianness)]
|
205
219
|
|
206
|
-
when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx
|
207
|
-
when :modrm
|
208
|
-
when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx
|
209
|
-
when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx[:
|
220
|
+
when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx.delete(:seg)
|
221
|
+
when :modrm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, opsz, pfx.delete(:seg)
|
222
|
+
when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz]
|
223
|
+
when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]
|
224
|
+
when :modrmymm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 256, pfx.delete(:seg), SimdReg, :argsz => op.props[:argsz], :mrmvex => op.props[:mrmvex]
|
225
|
+
|
226
|
+
when :vexvreg; Reg.new((field_val[:vex_vvvv] ^ 0xf), opsz)
|
227
|
+
when :vexvxmm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 128)
|
228
|
+
when :vexvymm; SimdReg.new((field_val[:vex_vvvv] ^ 0xf), 256)
|
229
|
+
when :i4xmm; SimdReg.new((edata.decode_imm(:u8, @endianness) >> 4) & 7, 128)
|
230
|
+
when :i4ymm; SimdReg.new((edata.decode_imm(:u8, @endianness) >> 4) & 7, 256)
|
210
231
|
|
211
232
|
when :imm_val1; Expression[1]
|
212
233
|
when :imm_val3; Expression[3]
|
@@ -220,6 +241,8 @@ class Ia32
|
|
220
241
|
|
221
242
|
di.bin_length += edata.ptr - before_ptr
|
222
243
|
|
244
|
+
return false if edata.ptr > edata.length
|
245
|
+
|
223
246
|
if op.name == 'movsx' or op.name == 'movzx'
|
224
247
|
if di.opcode.props[:argsz] == 8
|
225
248
|
di.instruction.args[1].sz = 8
|
@@ -231,9 +254,10 @@ class Ia32
|
|
231
254
|
else
|
232
255
|
di.instruction.args[0].sz = @size
|
233
256
|
end
|
257
|
+
elsif op.name == 'crc32'
|
258
|
+
di.instruction.args[0].sz = 32
|
234
259
|
end
|
235
260
|
|
236
|
-
pfx.delete :seg
|
237
261
|
case pfx.delete(:rep)
|
238
262
|
when :nz
|
239
263
|
if di.opcode.props[:strop]
|
@@ -256,7 +280,7 @@ class Ia32
|
|
256
280
|
# adds the eip delta to the offset +off+ of the instruction (may be an Expression) + its bin_length
|
257
281
|
# do not call twice on the same di !
|
258
282
|
def decode_instr_interpret(di, addr)
|
259
|
-
if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.instruction.opname
|
283
|
+
if di.opcode.props[:setip] and di.instruction.args.last.kind_of? Expression and di.instruction.opname !~ /^i?ret/
|
260
284
|
delta = di.instruction.args.last.reduce
|
261
285
|
arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
|
262
286
|
di.instruction.args[-1] = Expression[arg]
|
@@ -299,17 +323,16 @@ class Ia32
|
|
299
323
|
end
|
300
324
|
end
|
301
325
|
|
302
|
-
|
303
|
-
|
304
|
-
@
|
326
|
+
def opsz(di, op=nil)
|
327
|
+
if di and di.instruction.prefix and di.instruction.prefix[:opsz] and (op || di.opcode).props[:needpfx] != 0x66; 48-@size
|
328
|
+
else @size
|
329
|
+
end
|
305
330
|
end
|
306
|
-
def backtrace_binding=(b) @backtrace_binding = b end
|
307
331
|
|
308
|
-
def
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
ret
|
332
|
+
def adsz(di, op=nil)
|
333
|
+
if di and di.instruction.prefix and di.instruction.prefix[:adsz] and (op || di.opcode).props[:needpfx] != 0x67; 48-@size
|
334
|
+
else @size
|
335
|
+
end
|
313
336
|
end
|
314
337
|
|
315
338
|
# populate the @backtrace_binding hash with default values
|
@@ -317,15 +340,37 @@ class Ia32
|
|
317
340
|
@backtrace_binding ||= {}
|
318
341
|
|
319
342
|
eax, ecx, edx, ebx, esp, ebp, esi, edi = register_symbols
|
343
|
+
ebx = ebx
|
320
344
|
|
321
345
|
mask = lambda { |di| (1 << opsz(di))-1 } # 32bits => 0xffff_ffff
|
322
346
|
sign = lambda { |v, di| Expression[[[v, :&, mask[di]], :>>, opsz(di)-1], :'!=', 0] }
|
323
347
|
|
324
348
|
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
325
349
|
binding = case op
|
326
|
-
when 'mov', '
|
350
|
+
when 'mov', 'movzx', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
351
|
+
when 'movsx', 'movsxd'
|
352
|
+
lambda { |di, a0, a1|
|
353
|
+
sz1 = di.instruction.args[1].sz
|
354
|
+
sign1 = Expression[[a1, :>>, sz1-1], :&, 1]
|
355
|
+
{ a0 => Expression[[a1, :|, [sign1, :*, (-1 << sz1)]], :&, mask[di]] }
|
356
|
+
}
|
327
357
|
when 'lea'; lambda { |di, a0, a1| { a0 => a1.target } }
|
328
|
-
when 'xchg'; lambda { |di, a0, a1|
|
358
|
+
when 'xchg'; lambda { |di, a0, a1|
|
359
|
+
# specialcase xchg al, ah (conflict on eax not handled in get_backtrace_binding)
|
360
|
+
if a0.kind_of?(Expression) and a1.kind_of?(Expression) and
|
361
|
+
a0.op == :& and a0.rexpr == 255 and
|
362
|
+
a1.op == :& and a1.rexpr == 255 and
|
363
|
+
((a0.lexpr.kind_of?(Expression) and a0.lexpr.lexpr == a1.lexpr and a0.lexpr.op == :>> and a0.lexpr.rexpr == 8) or
|
364
|
+
(a1.lexpr.kind_of?(Expression) and a1.lexpr.lexpr == a0.lexpr and a1.lexpr.op == :>> and a1.lexpr.rexpr == 8))
|
365
|
+
tgreg = a0.lexpr.kind_of?(Expression) ? a1.lexpr : a0.lexpr
|
366
|
+
invmask = (@size == 64 ? 0xffff_ffff_ffff_0000 : 0xffff_0000)
|
367
|
+
{ tgreg => Expression[[tgreg, :&, invmask], :|,
|
368
|
+
[[[tgreg, :>>, 8], :&, 0x00ff], :|,
|
369
|
+
[[tgreg, :<<, 8], :&, 0xff00]]] }
|
370
|
+
else
|
371
|
+
{ a0 => Expression[a1], a1 => Expression[a0] }
|
372
|
+
end
|
373
|
+
}
|
329
374
|
when 'add', 'sub', 'or', 'xor', 'and', 'pxor', 'adc', 'sbb'
|
330
375
|
lambda { |di, a0, a1|
|
331
376
|
e_op = { 'add' => :+, 'sub' => :-, 'or' => :|, 'and' => :&, 'xor' => :^, 'pxor' => :^, 'adc' => :+, 'sbb' => :- }[op]
|
@@ -345,13 +390,28 @@ class Ia32
|
|
345
390
|
lambda { |di, a0, a1|
|
346
391
|
e_op = (op[2] == ?r ? :>> : :<<)
|
347
392
|
inv_op = {:<< => :>>, :>> => :<< }[e_op]
|
348
|
-
|
349
|
-
|
393
|
+
operandsize = di.instruction.args[0].sz
|
394
|
+
operandmask = (1 << operandsize) - 1
|
395
|
+
sz = [a1, :%, operandsize]
|
396
|
+
isz = [[operandsize, :-, a1], :%, operandsize]
|
350
397
|
# ror a, b => (a >> b) | (a << (32-b))
|
351
|
-
{ a0 => Expression[[[a0, e_op, sz], :|, [a0, inv_op, isz]], :&,
|
398
|
+
{ a0 => Expression[[[[a0, :&, operandmask], e_op, sz], :|, [[a0, :&, operandmask], inv_op, isz]], :&, operandmask] }
|
352
399
|
}
|
353
|
-
when '
|
400
|
+
when 'shl', 'sal'; lambda { |di, a0, a1| { a0 => Expression[a0, (op[-1] == ?r ? :>> : :<<), [a1, :%, [opsz(di), 32].max]] } }
|
401
|
+
when 'sar'; lambda { |di, a0, a1|
|
402
|
+
sz = [opsz(di), 32].max
|
403
|
+
a1 = [a1, :%, sz]
|
404
|
+
{ a0 => Expression[[a0, :>>, a1], :|,
|
405
|
+
[[[mask[di], :*, sign[a0, di]], :<<, [sz, :-, a1]], :&, mask[di]]] } }
|
354
406
|
when 'shr'; lambda { |di, a0, a1| { a0 => Expression[[a0, :&, mask[di]], :>>, [a1, :%, opsz(di)]] } }
|
407
|
+
when 'shrd'
|
408
|
+
lambda { |di, a0, a1, a2|
|
409
|
+
{ a0 => Expression[[a0, :>>, [a2, :%, opsz(di)]], :|, [a1, :<<, [[opsz(di), :-, a2], :%, opsz(di)]]] }
|
410
|
+
}
|
411
|
+
when 'shld'
|
412
|
+
lambda { |di, a0, a1, a2|
|
413
|
+
{ a0 => Expression[[a0, :<<, [a2, :%, opsz(di)]], :|, [a1, :>>, [[opsz(di), :-, a2], :%, opsz(di)]]] }
|
414
|
+
}
|
355
415
|
when 'cwd', 'cdq', 'cqo'; lambda { |di| { Expression[edx, :&, mask[di]] => Expression[mask[di], :*, sign[eax, di]] } }
|
356
416
|
when 'cbw', 'cwde', 'cdqe'; lambda { |di|
|
357
417
|
o2 = opsz(di)/2 ; m2 = (1 << o2) - 1
|
@@ -362,7 +422,7 @@ class Ia32
|
|
362
422
|
when 'pop'
|
363
423
|
lambda { |di, a0| { esp => Expression[esp, :+, opsz(di)/8],
|
364
424
|
a0 => Indirection[esp, opsz(di)/8, di.address] } }
|
365
|
-
when 'pushfd'
|
425
|
+
when 'pushfd', 'pushf', 'pushfq'
|
366
426
|
# TODO Unknown per bit
|
367
427
|
lambda { |di|
|
368
428
|
efl = Expression[0x202]
|
@@ -372,12 +432,12 @@ class Ia32
|
|
372
432
|
bts[7, :eflag_s]
|
373
433
|
bts[11, :eflag_o]
|
374
434
|
{ esp => Expression[esp, :-, opsz(di)/8], Indirection[esp, opsz(di)/8, di.address] => efl }
|
375
|
-
|
376
|
-
when 'popfd'
|
435
|
+
}
|
436
|
+
when 'popfd', 'popf', 'popfq'
|
377
437
|
lambda { |di| bt = lambda { |pos| Expression[[Indirection[esp, opsz(di)/8, di.address], :>>, pos], :&, 1] }
|
378
438
|
{ esp => Expression[esp, :+, opsz(di)/8], :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7], :eflag_o => bt[11] } }
|
379
439
|
when 'sahf'
|
380
|
-
lambda { |di| bt = lambda { |pos| Expression[[eax, :>>, pos], :&, 1] }
|
440
|
+
lambda { |di| bt = lambda { |pos| Expression[[eax, :>>, 8+pos], :&, 1] }
|
381
441
|
{ :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7] } }
|
382
442
|
when 'lahf'
|
383
443
|
lambda { |di|
|
@@ -386,7 +446,7 @@ class Ia32
|
|
386
446
|
bts[0, :eflag_c] #bts[2, :eflag_p] #bts[4, :eflag_a]
|
387
447
|
bts[6, :eflag_z]
|
388
448
|
bts[7, :eflag_s]
|
389
|
-
{ eax => efl }
|
449
|
+
{ Expression[[eax, :>>, 8], :&, 0xff] => efl }
|
390
450
|
}
|
391
451
|
when 'pushad'
|
392
452
|
lambda { |di|
|
@@ -411,9 +471,25 @@ class Ia32
|
|
411
471
|
ret
|
412
472
|
}
|
413
473
|
when 'call'
|
414
|
-
lambda { |di, a0|
|
415
|
-
|
474
|
+
lambda { |di, a0|
|
475
|
+
sz = opsz(di)/8
|
476
|
+
if a0.kind_of? Farptr
|
477
|
+
{ esp => Expression[esp, :-, 2*sz],
|
478
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr],
|
479
|
+
Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown }
|
480
|
+
else
|
481
|
+
{ esp => Expression[esp, :-, sz],
|
482
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr] }
|
483
|
+
end
|
484
|
+
}
|
485
|
+
when 'callf'
|
486
|
+
lambda { |di, a0|
|
487
|
+
sz = opsz(di)/8
|
488
|
+
{ esp => Expression[esp, :-, 2*sz],
|
489
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr],
|
490
|
+
Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown } }
|
416
491
|
when 'ret'; lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/8, :+, a[0] || 0]] } }
|
492
|
+
when 'retf';lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/4, :+, a[0] || 0]] } }
|
417
493
|
when 'loop', 'loopz', 'loopnz'; lambda { |di, a0| { ecx => Expression[ecx, :-, 1] } }
|
418
494
|
when 'enter'
|
419
495
|
lambda { |di, a0, a1|
|
@@ -426,7 +502,7 @@ class Ia32
|
|
426
502
|
(1..depth).each { |i|
|
427
503
|
b[Indirection[[esp, :+, a0.reduce+i*sz], sz, di.address]] =
|
428
504
|
b[Indirection[[ebp, :-, i*sz], sz, di.address]] =
|
429
|
-
|
505
|
+
Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
|
430
506
|
}
|
431
507
|
b
|
432
508
|
}
|
@@ -434,22 +510,47 @@ class Ia32
|
|
434
510
|
when 'aaa'; lambda { |di| { eax => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
435
511
|
when 'imul'
|
436
512
|
lambda { |di, *a|
|
437
|
-
|
438
|
-
|
513
|
+
if not a[1]
|
514
|
+
# 1 operand from: store result in edx:eax
|
515
|
+
bd = {}
|
516
|
+
m = mask[di]
|
517
|
+
s = opsz(di)
|
518
|
+
e = Expression[Expression.make_signed(Expression[a[0], :&, m], s), :*, Expression.make_signed(Expression[eax, :&, m], s)]
|
519
|
+
if s == 8
|
520
|
+
bd[Expression[eax, :&, 0xffff]] = e
|
521
|
+
else
|
522
|
+
bd[Expression[eax, :&, m]] = Expression[e, :&, m]
|
523
|
+
bd[Expression[edx, :&, m]] = Expression[[e, :>>, opsz(di)], :&, m]
|
524
|
+
end
|
525
|
+
# XXX eflags?
|
526
|
+
next bd
|
527
|
+
end
|
439
528
|
|
440
529
|
if a[2]; e = Expression[a[1], :*, a[2]]
|
441
530
|
else e = Expression[[a[0], :*, a[1]], :&, (1 << (di.instruction.args.first.sz || opsz(di))) - 1]
|
442
531
|
end
|
443
532
|
{ a[0] => e }
|
444
533
|
}
|
445
|
-
when 'mul'
|
534
|
+
when 'mul'
|
535
|
+
lambda { |di, *a|
|
536
|
+
m = mask[di]
|
537
|
+
e = Expression[a, :*, [eax, :&, m]]
|
538
|
+
if opsz(di) == 8
|
539
|
+
{ Expression[eax, :&, 0xffff] => e }
|
540
|
+
else
|
541
|
+
{ Expression[eax, :&, m] => Expression[e, :&, m],
|
542
|
+
Expression[edx, :&, m] => Expression[[e, :>>, opsz(di)], :&, m] }
|
543
|
+
end
|
544
|
+
}
|
545
|
+
when 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
446
546
|
when 'rdtsc'; lambda { |di| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
447
|
-
when /^(stos|movs|lods|scas|cmps)[
|
448
|
-
lambda { |di|
|
449
|
-
|
547
|
+
when /^(stos|movs|lods|scas|cmps)[bwdq]$/
|
548
|
+
lambda { |di, *a|
|
549
|
+
next {:incomplete_binding => 1} if di.opcode.args.include?(:regxmm) # XXX movsd xmm0, xmm1...
|
550
|
+
op =~ /^(stos|movs|lods|scas|cmps)([bwdq])$/
|
450
551
|
e_op = $1
|
451
|
-
sz = { 'b' => 1, 'w' => 2, 'd' => 4 }[$2]
|
452
|
-
eax_ = Reg.new(0, 8*sz).symbolic
|
552
|
+
sz = { 'b' => 1, 'w' => 2, 'd' => 4, 'q' => 8 }[$2]
|
553
|
+
eax_ = self.class::Reg.new(0, 8*sz).symbolic
|
453
554
|
dir = :+
|
454
555
|
if di.block and (di.block.list.find { |ddi| ddi.opcode.name == 'std' } rescue nil)
|
455
556
|
dir = :-
|
@@ -476,7 +577,7 @@ class Ia32
|
|
476
577
|
end
|
477
578
|
when 'scas'
|
478
579
|
case pfx[:rep]
|
479
|
-
when nil; { edi => Expression[edi, dir, sz] }
|
580
|
+
when nil; { edi => Expression[edi, dir, sz], :eflag_z => Expression[pedi, :==, Expression[eax, :&, (1 << (sz*8))-1]] }
|
480
581
|
else { edi => Expression::Unknown, ecx => Expression::Unknown }
|
481
582
|
end
|
482
583
|
when 'cmps'
|
@@ -505,7 +606,7 @@ class Ia32
|
|
505
606
|
ret
|
506
607
|
}
|
507
608
|
when 'fstenv', 'fnstenv'
|
508
|
-
|
609
|
+
lambda { |di, a0|
|
509
610
|
# stores the address of the last non-control fpu instr run
|
510
611
|
lastfpuinstr = di.block.list[0...di.block.list.index(di)].reverse.find { |pdi|
|
511
612
|
case pdi.opcode.name
|
@@ -534,7 +635,8 @@ class Ia32
|
|
534
635
|
a0 => Expression[a0, :^, [1, :<<, [a1, :%, opsz(di)]]] } }
|
535
636
|
when 'bswap'
|
536
637
|
lambda { |di, a0|
|
537
|
-
|
638
|
+
case opsz(di)
|
639
|
+
when 64
|
538
640
|
{ a0 => Expression[
|
539
641
|
[[[[a0, :&, 0xff000000_00000000], :>>, 56], :|,
|
540
642
|
[[a0, :&, 0x00ff0000_00000000], :>>, 40]], :|,
|
@@ -544,14 +646,35 @@ class Ia32
|
|
544
646
|
[[a0, :&, 0x00000000_00ff0000], :<<, 24]], :|,
|
545
647
|
[[[a0, :&, 0x00000000_0000ff00], :<<, 40], :|,
|
546
648
|
[[a0, :&, 0x00000000_000000ff], :<<, 56]]]] }
|
547
|
-
|
649
|
+
when 32
|
548
650
|
{ a0 => Expression[
|
549
651
|
[[[a0, :&, 0xff000000], :>>, 24], :|,
|
550
652
|
[[a0, :&, 0x00ff0000], :>>, 8]], :|,
|
551
653
|
[[[a0, :&, 0x0000ff00], :<<, 8], :|,
|
552
654
|
[[a0, :&, 0x000000ff], :<<, 24]]] }
|
655
|
+
when 16
|
656
|
+
# bswap ax => mov ax, 0
|
657
|
+
{ a0 => 0 }
|
553
658
|
end
|
554
659
|
}
|
660
|
+
when 'movdqa', 'movdqu', 'movaps', 'movups'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
661
|
+
when 'cmpxchg'; lambda { |di, a0, a1| # eax == a0 ? a0 <= a1, zf <= 1 : eax <= a0, zf <= 0
|
662
|
+
eax_ = self.class::Reg.new(0, opsz(di)).symbolic
|
663
|
+
cmp = Expression[eax_, :==, a0]
|
664
|
+
{ :eflag_z => cmp,
|
665
|
+
eax_ => Expression[[cmp, :*, eax_], :|, [[1, :-, cmp], :*, a0]],
|
666
|
+
a0 => Expression[[cmp, :*, a1], :|, [[1, :-, cmp], :*, a0]] } }
|
667
|
+
when 'cmpxchg8b', 'cmpxchg16b'; lambda { |di, a0| # edx:eax == mem ? mem <= ecx:ebx, zf <= 1 : edx:eax <= mem, zf <= 0
|
668
|
+
sz = (di.opcode.name =~ /8b/ ? 32 : 64)
|
669
|
+
eax_ = self.class::Reg.new(0, sz).symbolic
|
670
|
+
ecx_ = self.class::Reg.new(1, sz).symbolic
|
671
|
+
edx_ = self.class::Reg.new(2, sz).symbolic
|
672
|
+
ebx_ = self.class::Reg.new(3, sz).symbolic
|
673
|
+
cmp = Expression[[[edx_, :<<, sz], :|, eax_], :==, a0]
|
674
|
+
{ :eflag_z => cmp,
|
675
|
+
eax_ => Expression[[cmp, :*, eax_], :|, [[1, :-, cmp], :*, [a0, :&, (1 << sz) - 1]]],
|
676
|
+
edx_ => Expression[[cmp, :*, edx_], :|, [[1, :-, cmp], :*, [a0, :>>, sz]]],
|
677
|
+
a0 => Expression[[cmp, :*, [[ecx_, :<<, sz], :|, ebx_]], :|, [[1, :-, cmp], :*, a0]] } }
|
555
678
|
when 'nop', 'pause', 'wait', 'cmp', 'test'; lambda { |di, *a| {} }
|
556
679
|
end
|
557
680
|
|
@@ -579,7 +702,7 @@ class Ia32
|
|
579
702
|
end
|
580
703
|
ret
|
581
704
|
}
|
582
|
-
when 'inc', 'dec', 'neg', 'shl', 'shr', 'sar', 'ror', 'rol', 'rcr', 'rcl', 'shld', 'shrd'
|
705
|
+
when 'inc', 'dec', 'neg', 'shl', 'shr', 'sal', 'sar', 'ror', 'rol', 'rcr', 'rcl', 'shld', 'shrd'
|
583
706
|
lambda { |di, a0, *a|
|
584
707
|
ret = (binding ? binding[di, a0, *a] : {})
|
585
708
|
res = ret[a0] || Expression::Unknown
|
@@ -588,6 +711,8 @@ class Ia32
|
|
588
711
|
case op
|
589
712
|
when 'neg'; ret[:eflag_c] = Expression[[res, :&, mask[di]], :'!=', 0]
|
590
713
|
when 'inc', 'dec' # don't touch carry flag
|
714
|
+
when 'shr', 'sar', 'shrd'; ret[:eflag_c] = Expression[[a0, :>>, [a[0], :-, 1]], :&, 1] # XXX shr 0 => no touch flag
|
715
|
+
when 'shl', 'sal', 'shld'; ret[:eflag_c] = Expression[[a0, :>>, [di.instruction.args[0].sz, :-, a[0]]], :&, 1]
|
591
716
|
else ret[:eflag_c] = Expression::Unknown # :incomplete_binding ?
|
592
717
|
end
|
593
718
|
ret[:eflag_o] = case op
|
@@ -601,7 +726,11 @@ class Ia32
|
|
601
726
|
when 'imul', 'mul', 'idiv', 'div', /^(scas|cmps)[bwdq]$/
|
602
727
|
lambda { |di, *a|
|
603
728
|
ret = (binding ? binding[di, *a] : {})
|
604
|
-
ret[:eflag_z]
|
729
|
+
ret[:eflag_z] ||= Expression::Unknown
|
730
|
+
ret[:eflag_s] ||= Expression::Unknown
|
731
|
+
ret[:eflag_c] ||= Expression::Unknown
|
732
|
+
ret[:eflag_o] ||= Expression::Unknown
|
733
|
+
# :incomplete_binding ?
|
605
734
|
ret
|
606
735
|
}
|
607
736
|
end
|
@@ -611,8 +740,8 @@ class Ia32
|
|
611
740
|
@backtrace_binding
|
612
741
|
end
|
613
742
|
|
614
|
-
# returns the condition (bool Expression) under which a
|
615
|
-
# returns nil if not a
|
743
|
+
# returns the condition (bool Expression) under which a conditional jump is taken
|
744
|
+
# returns nil if not a conditional jump
|
616
745
|
# backtrace for the condition must include the jump itself (eg loop -> ecx--)
|
617
746
|
def get_jump_condition(di)
|
618
747
|
ecx = register_symbols[1]
|
@@ -627,12 +756,7 @@ class Ia32
|
|
627
756
|
end
|
628
757
|
|
629
758
|
def get_backtrace_binding(di)
|
630
|
-
a = di.instruction.args.map { |arg|
|
631
|
-
case arg
|
632
|
-
when ModRM, Reg, SimdReg; arg.symbolic(di)
|
633
|
-
else arg
|
634
|
-
end
|
635
|
-
}
|
759
|
+
a = di.instruction.args.map { |arg| symbolic(arg, di) }
|
636
760
|
|
637
761
|
if binding = backtrace_binding[di.opcode.basename]
|
638
762
|
bd = binding[di, *a]
|
@@ -674,6 +798,40 @@ class Ia32
|
|
674
798
|
end
|
675
799
|
end
|
676
800
|
|
801
|
+
# patch a forward binding from the backtrace binding
|
802
|
+
# fixes fwdemu for push/pop/call/ret
|
803
|
+
def fix_fwdemu_binding(di, fbd)
|
804
|
+
if di.instruction.args.grep(ModRM).find { |m| m.seg and m.symbolic(di).target.lexpr =~ /^segment_base_/ }
|
805
|
+
fbd = fbd.dup
|
806
|
+
fbd[:incomplete_binding] = Expression[1]
|
807
|
+
end
|
808
|
+
|
809
|
+
case di.opcode.name
|
810
|
+
when /^push/, 'call'
|
811
|
+
ori = fbd
|
812
|
+
fbd = {}
|
813
|
+
sz = opsz(di)/8
|
814
|
+
esp = register_symbols[4]
|
815
|
+
if ori[esp] and ori[Indirection[esp, sz]]
|
816
|
+
ori.each { |k, v|
|
817
|
+
if k.kind_of?(Indirection)
|
818
|
+
fbd[k.bind(esp => ori[esp]).reduce_rec] = v
|
819
|
+
else
|
820
|
+
fbd[k] = v
|
821
|
+
end
|
822
|
+
}
|
823
|
+
else
|
824
|
+
fbd = ori.dup
|
825
|
+
fbd[:incomplete_binding] = Expression[1] # TODO
|
826
|
+
end
|
827
|
+
when /^pop/, 'ret' # nothing to do
|
828
|
+
when /^(push|pop|call|ret|enter|leave|stos|movs|lods|scas|cmps)/
|
829
|
+
fbd = fbd.dup
|
830
|
+
fbd[:incomplete_binding] = Expression[1] # TODO
|
831
|
+
end
|
832
|
+
fbd
|
833
|
+
end
|
834
|
+
|
677
835
|
def get_xrefs_x(dasm, di)
|
678
836
|
return [] if not di.opcode.props[:setip]
|
679
837
|
|
@@ -681,9 +839,8 @@ class Ia32
|
|
681
839
|
case di.opcode.basename
|
682
840
|
when 'ret'; return [Indirection[register_symbols[4], sz/8, di.address]]
|
683
841
|
when 'jmp', 'call'
|
684
|
-
|
685
|
-
|
686
|
-
return get_xrefs_x_jmptable(dasm, di, a, sz)
|
842
|
+
if dasm and not di.instruction.args.first.kind_of?(Expression) and switch_table = get_xrefs_x_jmptable(dasm, di)
|
843
|
+
return switch_table
|
687
844
|
end
|
688
845
|
end
|
689
846
|
|
@@ -695,57 +852,57 @@ class Ia32
|
|
695
852
|
when Expression, ::Integer; [Expression[tg]]
|
696
853
|
when Farptr; tg.seg.reduce < 0x30 ? [tg.addr] : [Expression[[tg.seg, :*, 0x10], :+, tg.addr]]
|
697
854
|
else
|
698
|
-
puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
|
855
|
+
puts "unhandled setip at #{Expression[di.address]} #{di.instruction}" if $DEBUG
|
699
856
|
[]
|
700
857
|
end
|
701
858
|
end
|
702
859
|
|
703
|
-
#
|
704
|
-
#
|
705
|
-
def get_xrefs_x_jmptable(dasm, di
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
860
|
+
# indirect call, try to match a switch table pattern (eg jmp [base+4*idx])
|
861
|
+
# return a list of target addresses if found, nil otherwise
|
862
|
+
def get_xrefs_x_jmptable(dasm, di)
|
863
|
+
puts "search jmptable for #{Expression[di.address]} #{di.instruction}" if $DEBUG
|
864
|
+
arg0 = di.instruction.args.first.symbolic(di)
|
865
|
+
|
866
|
+
bt_log = []
|
867
|
+
dasm.backtrace(arg0, di.address, :maxdepth => 3, :log => bt_log)
|
868
|
+
|
869
|
+
expr = nil
|
870
|
+
index = nil
|
871
|
+
index_max = nil
|
872
|
+
|
873
|
+
bt_log.each { |btl|
|
874
|
+
next if btl[0] != :up
|
875
|
+
last = dasm.di_at(btl[4])
|
876
|
+
break if not last or last.block.to_normal.length > 2
|
877
|
+
next if last.block.to_normal.length != 2
|
878
|
+
# search cmp eax, 42 ; ja too_big ; jmp [base+4*eax]
|
879
|
+
# XXX 256 cases switch => no cmp...
|
880
|
+
prelast = last.block.list.reverse.find { |pl| pl.opcode.name == 'cmp' }
|
881
|
+
break unless prelast and cmp_value = prelast.instruction.args.last and cmp_value.kind_of?(Expression) and cmp_value.reduce.kind_of?(::Integer)
|
882
|
+
cmp_value = cmp_value.reduce % (1 << prelast.instruction.args.first.sz) # cmp al, -12h ; jnbe => -12h is unsigned 0eeh
|
883
|
+
index = prelast.instruction.args.first.symbolic(prelast)
|
884
|
+
index = index.externals.first if index.kind_of?(Expression) # cmp bl, 13 => ebx
|
885
|
+
expr = Expression[btl[1], :&, ((1 << @size) - 1)] # XXX without the mask, additions may overflow (this breaks elsewhere too, need Expr32)
|
886
|
+
(expr.externals.grep(Symbol) - [index]).uniq.each { |r|
|
887
|
+
rv = dasm.backtrace(r, prelast.address, :maxdepth => 3)
|
888
|
+
expr = expr.bind(r => rv[0]) if rv.length == 1
|
723
889
|
}
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
puts "unrecognized jmp table pattern, using wild guess for #{di}" if $VERBOSE
|
730
|
-
di.add_comment 'wildguess'
|
731
|
-
if s = dasm.get_section_at(mrm.imm - 3*sz/8)
|
732
|
-
v = -3
|
733
|
-
else
|
734
|
-
s = dasm.get_section_at(mrm.imm)
|
735
|
-
v = 0
|
736
|
-
end
|
737
|
-
loop do
|
738
|
-
ptr = dasm.normalize s[0].decode_imm("u#{sz}".to_sym, @endianness)
|
739
|
-
diff = Expression[ptr, :-, di.address].reduce
|
740
|
-
if (diff.kind_of? ::Integer and diff.abs < 4096) or (di.opcode.basename == 'call' and ptr != 0 and dasm.get_section_at(ptr))
|
741
|
-
dasm.add_xref(s[1]+s[0].ptr-sz/8, Xref.new(:r, di.address, sz/8))
|
742
|
-
ret << Indirection[[mrm.imm, :+, v*sz/8], sz/8, di.address]
|
743
|
-
elsif v > 0
|
744
|
-
break
|
890
|
+
cmp_value = prelast.instruction.args.last.reduce % (1 << prelast.instruction.args.first.sz)
|
891
|
+
case last.opcode.name
|
892
|
+
when 'jae', 'jb', 'jnae', 'jnb'; index_max = cmp_value-1
|
893
|
+
when 'ja', 'jbe', 'jna', 'jnbe'; index_max = cmp_value
|
894
|
+
else; expr = nil
|
745
895
|
end
|
746
|
-
|
896
|
+
break
|
897
|
+
}
|
898
|
+
|
899
|
+
if expr and expr.externals.grep(Symbol).uniq == [index]
|
900
|
+
# yay !
|
901
|
+
# include the symbolic dest for backtrace stuff
|
902
|
+
puts "found jmptable for #{Expression[di.address]} #{di.instruction} (#{index_max+1} entries)" if $VERBOSE
|
903
|
+
# TODO add labels / tables / xrefs etc
|
904
|
+
[Expression[arg0]] + (0..index_max).map { |i| expr.bind(index => i) }
|
747
905
|
end
|
748
|
-
ret
|
749
906
|
end
|
750
907
|
|
751
908
|
# checks if expr is a valid return expression matching the :saveip instruction
|
@@ -1087,11 +1244,15 @@ class Ia32
|
|
1087
1244
|
# the binding will not include memory access from subfunctions
|
1088
1245
|
# entry should be an entrypoint of the disassembler if finish is nil
|
1089
1246
|
# the code sequence must have only one end, with no to_normal
|
1090
|
-
|
1247
|
+
# options:
|
1248
|
+
# :include_flags => include EFLAGS in the returned binding
|
1249
|
+
def code_binding(dasm, entry, finish=nil, nargs={})
|
1250
|
+
include_flags = nargs.delete :include_flags
|
1251
|
+
|
1091
1252
|
entry = dasm.normalize(entry)
|
1092
1253
|
finish = dasm.normalize(finish) if finish
|
1093
1254
|
lastdi = nil
|
1094
|
-
|
1255
|
+
bd = {}
|
1095
1256
|
bt = lambda { |from, expr, inc_start|
|
1096
1257
|
ret = dasm.backtrace(Expression[expr], from, :snapshot_addr => entry, :include_start => inc_start)
|
1097
1258
|
ret.length == 1 ? ret.first : Expression::Unknown
|
@@ -1116,7 +1277,7 @@ class Ia32
|
|
1116
1277
|
get_xrefs_w(dasm, di).each { |waddr, len|
|
1117
1278
|
# we want the ptr expressed with reg values at entry
|
1118
1279
|
ptr = bt[a, waddr, false]
|
1119
|
-
|
1280
|
+
bd[Indirection[ptr, len, a]] = bt[a, Indirection[waddr, len, a], true]
|
1120
1281
|
}
|
1121
1282
|
false
|
1122
1283
|
end
|
@@ -1139,13 +1300,13 @@ class Ia32
|
|
1139
1300
|
if lastdi.opcode.props[:setip]
|
1140
1301
|
e = get_xrefs_x(dasm, lastdi)
|
1141
1302
|
raise 'bad code_binding ending' if e.to_a.length != 1 or not lastdi.opcode.props[:stopexec]
|
1142
|
-
|
1303
|
+
bd[:ip] = bt[lastdi.address, e.first, false]
|
1143
1304
|
elsif not lastdi.opcode.props[:stopexec]
|
1144
|
-
|
1305
|
+
bd[:ip] = lastdi.next_addr
|
1145
1306
|
end
|
1146
1307
|
end
|
1147
1308
|
end
|
1148
|
-
|
1309
|
+
bd.delete_if { |k, v| Expression[k] == Expression[v] }
|
1149
1310
|
|
1150
1311
|
# add register binding
|
1151
1312
|
raise "no code_binding end" if not lastdi and not finish
|
@@ -1158,10 +1319,63 @@ class Ia32
|
|
1158
1319
|
mask = 0xffff_ffff # dont use 1<<@size, because 16bit code may use e.g. edi (through opszoverride)
|
1159
1320
|
mask = 0xffff_ffff_ffff_ffff if @size == 64
|
1160
1321
|
val = Expression[val, :&, mask].reduce
|
1161
|
-
|
1322
|
+
bd[reg] = Expression[val]
|
1162
1323
|
}
|
1163
1324
|
|
1164
|
-
binding
|
1325
|
+
# add EFLAGS binding
|
1326
|
+
if include_flags
|
1327
|
+
[:eflag_z, :eflag_s, :eflag_c, :eflag_o].each { |eflag|
|
1328
|
+
val =
|
1329
|
+
if lastdi; bt[lastdi.address, eflag, true]
|
1330
|
+
else bt[finish, eflag, false]
|
1331
|
+
end
|
1332
|
+
next if val == Expression[eflag]
|
1333
|
+
bd[eflag] = Expression[val.reduce]
|
1334
|
+
}
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
bd
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
# trace the stack pointer register across a function, rename occurences of esp+XX to esp+var_XX
|
1341
|
+
def name_local_vars(dasm, funcaddr)
|
1342
|
+
esp = register_symbols[4]
|
1343
|
+
func = dasm.function[funcaddr]
|
1344
|
+
subs = []
|
1345
|
+
dasm.trace_function_register(funcaddr, esp => 0) { |di, r, off, trace|
|
1346
|
+
next if r.to_s =~ /flag/
|
1347
|
+
if di.opcode.name == 'call' and tf = di.block.to_normal.find { |t| dasm.function[t] and dasm.function[t].localvars }
|
1348
|
+
subs << [trace[esp], dasm.function[tf].localvars]
|
1349
|
+
end
|
1350
|
+
di.instruction.args.grep(ModRM).each { |mrm|
|
1351
|
+
b = mrm.b || (mrm.i if mrm.s == 1)
|
1352
|
+
# its a modrm => b is read, so ignore r/off (not yet applied), use trace only
|
1353
|
+
stackoff = trace[b.symbolic] if b
|
1354
|
+
next if not stackoff
|
1355
|
+
imm = mrm.imm || Expression[0]
|
1356
|
+
frameoff = imm + stackoff
|
1357
|
+
if frameoff.kind_of?(::Integer)
|
1358
|
+
# XXX register args ? non-ABI standard register args ? (eg optimized x64)
|
1359
|
+
str = 'var_%X' % (-frameoff)
|
1360
|
+
str = 'arg_%X' % (frameoff-@size/8) if frameoff > 0
|
1361
|
+
str = func.get_localvar_stackoff(frameoff, di, str) if func
|
1362
|
+
imm = imm.expr if imm.kind_of?(ExpressionString)
|
1363
|
+
mrm.imm = ExpressionString.new(imm, str, :stackvar)
|
1364
|
+
end
|
1365
|
+
}
|
1366
|
+
off = off.reduce if off.kind_of?(Expression)
|
1367
|
+
next unless off.kind_of?(Integer)
|
1368
|
+
off
|
1369
|
+
}
|
1370
|
+
# if subfunctions are called at a fixed stack offset, rename var_3c -> subarg_0
|
1371
|
+
if func and func.localvars and not subs.empty? and subs.all? { |sb| sb[0] == subs.first[0] }
|
1372
|
+
func.localvars.each { |varoff, varname|
|
1373
|
+
subargnames = subs.map { |o, sb| sb[varoff-o+@size/8] }.compact
|
1374
|
+
if subargnames.uniq.length == 1
|
1375
|
+
varname.replace 'sub'+subargnames[0]
|
1376
|
+
end
|
1377
|
+
}
|
1378
|
+
end
|
1165
1379
|
end
|
1166
1380
|
end
|
1167
1381
|
end
|