metasm 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -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 +2 -0
- 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 +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- 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 +289 -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/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- 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 +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -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/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- 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 +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -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 +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- 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/{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 +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- 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 +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -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 +26 -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 +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- 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 +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- 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 -873
- 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
data/metasm/cpu/ia32.rb
ADDED
@@ -0,0 +1,17 @@
|
|
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
|
+
# fix autorequire warning
|
7
|
+
class Metasm::Ia32 < Metasm::CPU
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'metasm/main'
|
11
|
+
require 'metasm/cpu/ia32/parse'
|
12
|
+
require 'metasm/cpu/ia32/encode'
|
13
|
+
require 'metasm/cpu/ia32/decode'
|
14
|
+
require 'metasm/cpu/ia32/render'
|
15
|
+
require 'metasm/cpu/ia32/compile_c'
|
16
|
+
require 'metasm/cpu/ia32/decompile'
|
17
|
+
require 'metasm/cpu/ia32/debug'
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Licence is LGPL, see LICENCE in the top-level directory
|
5
5
|
|
6
6
|
|
7
|
-
require 'metasm/ia32/parse'
|
7
|
+
require 'metasm/cpu/ia32/parse'
|
8
8
|
require 'metasm/compile_c'
|
9
9
|
|
10
10
|
module Metasm
|
@@ -527,7 +527,7 @@ class CCompiler < C::Compiler
|
|
527
527
|
if expr.rexpr.type.specifier == :unsigned and r.sz == 64
|
528
528
|
label = new_label('unsign_float')
|
529
529
|
if m.sz == 64 and @cpusz < 64
|
530
|
-
|
530
|
+
m = get_composite_parts(m)[1]
|
531
531
|
end
|
532
532
|
m2 = m
|
533
533
|
m2 = make_volatile(m, expr.rexpr.type) if m.kind_of? ModRM
|
@@ -637,7 +637,7 @@ class CCompiler < C::Compiler
|
|
637
637
|
# both sides are already cast to the same type by the precompiler
|
638
638
|
# XXX expr.type.pointer?
|
639
639
|
if expr.type.integral? and expr.type.name == :ptr and expr.lexpr.type.kind_of? C::BaseType and
|
640
|
-
|
640
|
+
typesize[expr.lexpr.type.name] == typesize[:ptr]
|
641
641
|
expr.lexpr.type.name = :ptr
|
642
642
|
end
|
643
643
|
l = c_cexpr_inner(expr.lexpr)
|
@@ -711,6 +711,7 @@ class CCompiler < C::Compiler
|
|
711
711
|
end
|
712
712
|
when :-
|
713
713
|
r = c_cexpr_inner(expr.rexpr)
|
714
|
+
r = resolve_address r if r.kind_of? Address
|
714
715
|
if r.kind_of? Expression
|
715
716
|
unuse l, r
|
716
717
|
l = Address.new(l.modrm.dup)
|
@@ -1077,6 +1078,7 @@ class CCompiler < C::Compiler
|
|
1077
1078
|
when 'add', 'sub', 'and', 'or', 'xor'
|
1078
1079
|
r = make_volatile(r, type) if l.kind_of? ModRM and r.kind_of? ModRM
|
1079
1080
|
unuse r
|
1081
|
+
r = Reg.new(r.val, l.sz) if r.kind_of?(Reg) and l.kind_of?(ModRM) and l.sz and l.sz != r.sz # add byte ptr [eax], bl
|
1080
1082
|
instr op, l, r
|
1081
1083
|
when 'shr', 'sar', 'shl'
|
1082
1084
|
if r.kind_of? Expression
|
@@ -1509,10 +1511,6 @@ class CCompiler < C::Compiler
|
|
1509
1511
|
#File.open('m-dbg-precomp.c', 'w') { |fd| fd.puts @parser }
|
1510
1512
|
#File.open('m-dbg-src.asm', 'w') { |fd| fd.puts @source }
|
1511
1513
|
end
|
1512
|
-
|
1513
|
-
def check_reserved_name(var)
|
1514
|
-
Reg.s_to_i[var.name] or super(var)
|
1515
|
-
end
|
1516
1514
|
end
|
1517
1515
|
|
1518
1516
|
def new_ccompiler(parser, exe=ExeFormat.new)
|
@@ -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)
|
@@ -113,7 +113,7 @@ class Ia32
|
|
113
113
|
if dbg[:dr6] == 0 and dbg[:dr7] == 0
|
114
114
|
dbg[:dr7] = 0x10000 # some OS (eg Windows) only return dr6 if dr7 != 0
|
115
115
|
end
|
116
|
-
dbg[:dr6] = 0
|
116
|
+
dbg[:dr6] = 0 if dbg[:dr6] & 0x400f != 0
|
117
117
|
end
|
118
118
|
|
119
119
|
def dbg_evt_bpx(dbg, b)
|
@@ -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|
|
@@ -199,15 +211,23 @@ class Ia32
|
|
199
211
|
when :regfp; FpReg.new field_val[a]
|
200
212
|
when :regmmx; SimdReg.new field_val[a], mmxsz
|
201
213
|
when :regxmm; SimdReg.new field_val[a], 128
|
214
|
+
when :regymm; SimdReg.new field_val[a], 256
|
202
215
|
|
203
216
|
when :farptr; Farptr.decode edata, @endianness, opsz
|
204
217
|
when :i8, :u8, :u16; Expression[edata.decode_imm(a, @endianness)]
|
205
218
|
when :i; Expression[edata.decode_imm("#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym, @endianness)]
|
206
219
|
|
207
|
-
when :mrm_imm; ModRM.decode edata, (adsz == 16 ? 6 : 5), @endianness, adsz, opsz, pfx
|
208
|
-
when :modrm
|
209
|
-
when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx
|
210
|
-
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)
|
211
231
|
|
212
232
|
when :imm_val1; Expression[1]
|
213
233
|
when :imm_val3; Expression[3]
|
@@ -221,6 +241,8 @@ class Ia32
|
|
221
241
|
|
222
242
|
di.bin_length += edata.ptr - before_ptr
|
223
243
|
|
244
|
+
return false if edata.ptr > edata.length
|
245
|
+
|
224
246
|
if op.name == 'movsx' or op.name == 'movzx'
|
225
247
|
if di.opcode.props[:argsz] == 8
|
226
248
|
di.instruction.args[1].sz = 8
|
@@ -232,9 +254,10 @@ class Ia32
|
|
232
254
|
else
|
233
255
|
di.instruction.args[0].sz = @size
|
234
256
|
end
|
257
|
+
elsif op.name == 'crc32'
|
258
|
+
di.instruction.args[0].sz = 32
|
235
259
|
end
|
236
260
|
|
237
|
-
pfx.delete :seg
|
238
261
|
case pfx.delete(:rep)
|
239
262
|
when :nz
|
240
263
|
if di.opcode.props[:strop]
|
@@ -257,7 +280,7 @@ class Ia32
|
|
257
280
|
# adds the eip delta to the offset +off+ of the instruction (may be an Expression) + its bin_length
|
258
281
|
# do not call twice on the same di !
|
259
282
|
def decode_instr_interpret(di, addr)
|
260
|
-
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/
|
261
284
|
delta = di.instruction.args.last.reduce
|
262
285
|
arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
|
263
286
|
di.instruction.args[-1] = Expression[arg]
|
@@ -306,11 +329,16 @@ class Ia32
|
|
306
329
|
end
|
307
330
|
def backtrace_binding=(b) @backtrace_binding = b end
|
308
331
|
|
309
|
-
def opsz(di)
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
332
|
+
def opsz(di, op=nil)
|
333
|
+
if di and di.instruction.prefix and di.instruction.prefix[:opsz] and (op || di.opcode).props[:needpfx] != 0x66; 48-@size
|
334
|
+
else @size
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def adsz(di, op=nil)
|
339
|
+
if di and di.instruction.prefix and di.instruction.prefix[:adsz] and (op || di.opcode).props[:needpfx] != 0x67; 48-@size
|
340
|
+
else @size
|
341
|
+
end
|
314
342
|
end
|
315
343
|
|
316
344
|
# populate the @backtrace_binding hash with default values
|
@@ -318,15 +346,37 @@ class Ia32
|
|
318
346
|
@backtrace_binding ||= {}
|
319
347
|
|
320
348
|
eax, ecx, edx, ebx, esp, ebp, esi, edi = register_symbols
|
349
|
+
ebx = ebx
|
321
350
|
|
322
351
|
mask = lambda { |di| (1 << opsz(di))-1 } # 32bits => 0xffff_ffff
|
323
352
|
sign = lambda { |v, di| Expression[[[v, :&, mask[di]], :>>, opsz(di)-1], :'!=', 0] }
|
324
353
|
|
325
354
|
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
326
355
|
binding = case op
|
327
|
-
when 'mov', '
|
356
|
+
when 'mov', 'movzx', 'movd', 'movq'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
357
|
+
when 'movsx', 'movsxd'
|
358
|
+
lambda { |di, a0, a1|
|
359
|
+
sz1 = di.instruction.args[1].sz
|
360
|
+
sign1 = Expression[[a1, :>>, sz1-1], :&, 1]
|
361
|
+
{ a0 => Expression[[a1, :|, [sign1, :*, (-1 << sz1)]], :&, mask[di]] }
|
362
|
+
}
|
328
363
|
when 'lea'; lambda { |di, a0, a1| { a0 => a1.target } }
|
329
|
-
when 'xchg'; lambda { |di, a0, a1|
|
364
|
+
when 'xchg'; lambda { |di, a0, a1|
|
365
|
+
# specialcase xchg al, ah (conflict on eax not handled in get_backtrace_binding)
|
366
|
+
if a0.kind_of?(Expression) and a1.kind_of?(Expression) and
|
367
|
+
a0.op == :& and a0.rexpr == 255 and
|
368
|
+
a1.op == :& and a1.rexpr == 255 and
|
369
|
+
((a0.lexpr.kind_of?(Expression) and a0.lexpr.lexpr == a1.lexpr and a0.lexpr.op == :>> and a0.lexpr.rexpr == 8) or
|
370
|
+
(a1.lexpr.kind_of?(Expression) and a1.lexpr.lexpr == a0.lexpr and a1.lexpr.op == :>> and a1.lexpr.rexpr == 8))
|
371
|
+
tgreg = a0.lexpr.kind_of?(Expression) ? a1.lexpr : a0.lexpr
|
372
|
+
invmask = (@size == 64 ? 0xffff_ffff_ffff_0000 : 0xffff_0000)
|
373
|
+
{ tgreg => Expression[[tgreg, :&, invmask], :|,
|
374
|
+
[[[tgreg, :>>, 8], :&, 0x00ff], :|,
|
375
|
+
[[tgreg, :<<, 8], :&, 0xff00]]] }
|
376
|
+
else
|
377
|
+
{ a0 => Expression[a1], a1 => Expression[a0] }
|
378
|
+
end
|
379
|
+
}
|
330
380
|
when 'add', 'sub', 'or', 'xor', 'and', 'pxor', 'adc', 'sbb'
|
331
381
|
lambda { |di, a0, a1|
|
332
382
|
e_op = { 'add' => :+, 'sub' => :-, 'or' => :|, 'and' => :&, 'xor' => :^, 'pxor' => :^, 'adc' => :+, 'sbb' => :- }[op]
|
@@ -346,13 +396,23 @@ class Ia32
|
|
346
396
|
lambda { |di, a0, a1|
|
347
397
|
e_op = (op[2] == ?r ? :>> : :<<)
|
348
398
|
inv_op = {:<< => :>>, :>> => :<< }[e_op]
|
349
|
-
|
350
|
-
|
399
|
+
operandsize = di.instruction.args[0].sz
|
400
|
+
operandmask = (1 << operandsize) - 1
|
401
|
+
sz = [a1, :%, operandsize]
|
402
|
+
isz = [[operandsize, :-, a1], :%, operandsize]
|
351
403
|
# ror a, b => (a >> b) | (a << (32-b))
|
352
|
-
{ a0 => Expression[[[a0, e_op, sz], :|, [a0, inv_op, isz]], :&,
|
404
|
+
{ a0 => Expression[[[[a0, :&, operandmask], e_op, sz], :|, [[a0, :&, operandmask], inv_op, isz]], :&, operandmask] }
|
353
405
|
}
|
354
406
|
when 'sar', 'shl', 'sal'; lambda { |di, a0, a1| { a0 => Expression[a0, (op[-1] == ?r ? :>> : :<<), [a1, :%, [opsz(di), 32].max]] } }
|
355
407
|
when 'shr'; lambda { |di, a0, a1| { a0 => Expression[[a0, :&, mask[di]], :>>, [a1, :%, opsz(di)]] } }
|
408
|
+
when 'shrd'
|
409
|
+
lambda { |di, a0, a1, a2|
|
410
|
+
{ a0 => Expression[[a0, :>>, [a2, :%, opsz(di)]], :|, [a1, :<<, [[opsz(di), :-, a2], :%, opsz(di)]]] }
|
411
|
+
}
|
412
|
+
when 'shld'
|
413
|
+
lambda { |di, a0, a1, a2|
|
414
|
+
{ a0 => Expression[[a0, :<<, [a2, :%, opsz(di)]], :|, [a1, :>>, [[opsz(di), :-, a2], :%, opsz(di)]]] }
|
415
|
+
}
|
356
416
|
when 'cwd', 'cdq', 'cqo'; lambda { |di| { Expression[edx, :&, mask[di]] => Expression[mask[di], :*, sign[eax, di]] } }
|
357
417
|
when 'cbw', 'cwde', 'cdqe'; lambda { |di|
|
358
418
|
o2 = opsz(di)/2 ; m2 = (1 << o2) - 1
|
@@ -363,7 +423,7 @@ class Ia32
|
|
363
423
|
when 'pop'
|
364
424
|
lambda { |di, a0| { esp => Expression[esp, :+, opsz(di)/8],
|
365
425
|
a0 => Indirection[esp, opsz(di)/8, di.address] } }
|
366
|
-
when 'pushfd'
|
426
|
+
when 'pushfd', 'pushf'
|
367
427
|
# TODO Unknown per bit
|
368
428
|
lambda { |di|
|
369
429
|
efl = Expression[0x202]
|
@@ -373,8 +433,8 @@ class Ia32
|
|
373
433
|
bts[7, :eflag_s]
|
374
434
|
bts[11, :eflag_o]
|
375
435
|
{ esp => Expression[esp, :-, opsz(di)/8], Indirection[esp, opsz(di)/8, di.address] => efl }
|
376
|
-
|
377
|
-
when 'popfd'
|
436
|
+
}
|
437
|
+
when 'popfd', 'popf'
|
378
438
|
lambda { |di| bt = lambda { |pos| Expression[[Indirection[esp, opsz(di)/8, di.address], :>>, pos], :&, 1] }
|
379
439
|
{ esp => Expression[esp, :+, opsz(di)/8], :eflag_c => bt[0], :eflag_z => bt[6], :eflag_s => bt[7], :eflag_o => bt[11] } }
|
380
440
|
when 'sahf'
|
@@ -412,9 +472,25 @@ class Ia32
|
|
412
472
|
ret
|
413
473
|
}
|
414
474
|
when 'call'
|
415
|
-
lambda { |di, a0|
|
416
|
-
|
475
|
+
lambda { |di, a0|
|
476
|
+
sz = opsz(di)/8
|
477
|
+
if a0.kind_of? Farptr
|
478
|
+
{ esp => Expression[esp, :-, 2*sz],
|
479
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr],
|
480
|
+
Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown }
|
481
|
+
else
|
482
|
+
{ esp => Expression[esp, :-, sz],
|
483
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr] }
|
484
|
+
end
|
485
|
+
}
|
486
|
+
when 'callf'
|
487
|
+
lambda { |di, a0|
|
488
|
+
sz = opsz(di)/8
|
489
|
+
{ esp => Expression[esp, :-, 2*sz],
|
490
|
+
Indirection[esp, sz, di.address] => Expression[di.next_addr],
|
491
|
+
Indirection[[esp, :+, sz], sz, di.address] => Expression::Unknown } }
|
417
492
|
when 'ret'; lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/8, :+, a[0] || 0]] } }
|
493
|
+
when 'retf';lambda { |di, *a| { esp => Expression[esp, :+, [opsz(di)/4, :+, a[0] || 0]] } }
|
418
494
|
when 'loop', 'loopz', 'loopnz'; lambda { |di, a0| { ecx => Expression[ecx, :-, 1] } }
|
419
495
|
when 'enter'
|
420
496
|
lambda { |di, a0, a1|
|
@@ -427,7 +503,7 @@ class Ia32
|
|
427
503
|
(1..depth).each { |i|
|
428
504
|
b[Indirection[[esp, :+, a0.reduce+i*sz], sz, di.address]] =
|
429
505
|
b[Indirection[[ebp, :-, i*sz], sz, di.address]] =
|
430
|
-
|
506
|
+
Expression::Unknown # TODO Indirection[[ebp, :-, i*sz], sz, di.address]
|
431
507
|
}
|
432
508
|
b
|
433
509
|
}
|
@@ -435,21 +511,46 @@ class Ia32
|
|
435
511
|
when 'aaa'; lambda { |di| { eax => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
436
512
|
when 'imul'
|
437
513
|
lambda { |di, *a|
|
438
|
-
|
439
|
-
|
514
|
+
if not a[1]
|
515
|
+
# 1 operand from: store result in edx:eax
|
516
|
+
bd = {}
|
517
|
+
m = mask[di]
|
518
|
+
s = opsz(di)
|
519
|
+
e = Expression[Expression.make_signed(Expression[a[0], :&, m], s), :*, Expression.make_signed(Expression[eax, :&, m], s)]
|
520
|
+
if s == 8
|
521
|
+
bd[Expression[eax, :&, 0xffff]] = e
|
522
|
+
else
|
523
|
+
bd[Expression[eax, :&, m]] = Expression[e, :&, m]
|
524
|
+
bd[Expression[edx, :&, m]] = Expression[[e, :>>, opsz(di)], :&, m]
|
525
|
+
end
|
526
|
+
# XXX eflags?
|
527
|
+
next bd
|
528
|
+
end
|
440
529
|
|
441
530
|
if a[2]; e = Expression[a[1], :*, a[2]]
|
442
531
|
else e = Expression[[a[0], :*, a[1]], :&, (1 << (di.instruction.args.first.sz || opsz(di))) - 1]
|
443
532
|
end
|
444
533
|
{ a[0] => e }
|
445
534
|
}
|
446
|
-
when 'mul'
|
535
|
+
when 'mul'
|
536
|
+
lambda { |di, *a|
|
537
|
+
m = mask[di]
|
538
|
+
e = Expression[a, :*, [eax, :&, m]]
|
539
|
+
if opsz(di) == 8
|
540
|
+
{ Expression[eax, :&, 0xffff] => e }
|
541
|
+
else
|
542
|
+
{ Expression[eax, :&, m] => Expression[e, :&, m],
|
543
|
+
Expression[edx, :&, m] => Expression[[e, :>>, opsz(di)], :&, m] }
|
544
|
+
end
|
545
|
+
}
|
546
|
+
when 'div', 'idiv'; lambda { |di, *a| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
447
547
|
when 'rdtsc'; lambda { |di| { eax => Expression::Unknown, edx => Expression::Unknown, :incomplete_binding => Expression[1] } }
|
448
|
-
when /^(stos|movs|lods|scas|cmps)[
|
449
|
-
lambda { |di|
|
450
|
-
|
548
|
+
when /^(stos|movs|lods|scas|cmps)[bwdq]$/
|
549
|
+
lambda { |di, *a|
|
550
|
+
next {:incomplete_binding => 1} if di.opcode.args.include?(:regxmm) # XXX movsd xmm0, xmm1...
|
551
|
+
op =~ /^(stos|movs|lods|scas|cmps)([bwdq])$/
|
451
552
|
e_op = $1
|
452
|
-
sz = { 'b' => 1, 'w' => 2, 'd' => 4 }[$2]
|
553
|
+
sz = { 'b' => 1, 'w' => 2, 'd' => 4, 'q' => 8 }[$2]
|
453
554
|
eax_ = Reg.new(0, 8*sz).symbolic
|
454
555
|
dir = :+
|
455
556
|
if di.block and (di.block.list.find { |ddi| ddi.opcode.name == 'std' } rescue nil)
|
@@ -477,7 +578,7 @@ class Ia32
|
|
477
578
|
end
|
478
579
|
when 'scas'
|
479
580
|
case pfx[:rep]
|
480
|
-
when nil; { edi => Expression[edi, dir, sz] }
|
581
|
+
when nil; { edi => Expression[edi, dir, sz], :eflag_z => Expression[pedi, :==, Expression[eax, :&, (1 << (sz*8))-1]] }
|
481
582
|
else { edi => Expression::Unknown, ecx => Expression::Unknown }
|
482
583
|
end
|
483
584
|
when 'cmps'
|
@@ -506,7 +607,7 @@ class Ia32
|
|
506
607
|
ret
|
507
608
|
}
|
508
609
|
when 'fstenv', 'fnstenv'
|
509
|
-
|
610
|
+
lambda { |di, a0|
|
510
611
|
# stores the address of the last non-control fpu instr run
|
511
612
|
lastfpuinstr = di.block.list[0...di.block.list.index(di)].reverse.find { |pdi|
|
512
613
|
case pdi.opcode.name
|
@@ -535,7 +636,8 @@ class Ia32
|
|
535
636
|
a0 => Expression[a0, :^, [1, :<<, [a1, :%, opsz(di)]]] } }
|
536
637
|
when 'bswap'
|
537
638
|
lambda { |di, a0|
|
538
|
-
|
639
|
+
case opsz(di)
|
640
|
+
when 64
|
539
641
|
{ a0 => Expression[
|
540
642
|
[[[[a0, :&, 0xff000000_00000000], :>>, 56], :|,
|
541
643
|
[[a0, :&, 0x00ff0000_00000000], :>>, 40]], :|,
|
@@ -545,12 +647,15 @@ class Ia32
|
|
545
647
|
[[a0, :&, 0x00000000_00ff0000], :<<, 24]], :|,
|
546
648
|
[[[a0, :&, 0x00000000_0000ff00], :<<, 40], :|,
|
547
649
|
[[a0, :&, 0x00000000_000000ff], :<<, 56]]]] }
|
548
|
-
|
650
|
+
when 32
|
549
651
|
{ a0 => Expression[
|
550
652
|
[[[a0, :&, 0xff000000], :>>, 24], :|,
|
551
653
|
[[a0, :&, 0x00ff0000], :>>, 8]], :|,
|
552
654
|
[[[a0, :&, 0x0000ff00], :<<, 8], :|,
|
553
655
|
[[a0, :&, 0x000000ff], :<<, 24]]] }
|
656
|
+
when 16
|
657
|
+
# bswap ax => mov ax, 0
|
658
|
+
{ a0 => 0 }
|
554
659
|
end
|
555
660
|
}
|
556
661
|
when 'nop', 'pause', 'wait', 'cmp', 'test'; lambda { |di, *a| {} }
|
@@ -602,7 +707,11 @@ class Ia32
|
|
602
707
|
when 'imul', 'mul', 'idiv', 'div', /^(scas|cmps)[bwdq]$/
|
603
708
|
lambda { |di, *a|
|
604
709
|
ret = (binding ? binding[di, *a] : {})
|
605
|
-
ret[:eflag_z]
|
710
|
+
ret[:eflag_z] ||= Expression::Unknown
|
711
|
+
ret[:eflag_s] ||= Expression::Unknown
|
712
|
+
ret[:eflag_c] ||= Expression::Unknown
|
713
|
+
ret[:eflag_o] ||= Expression::Unknown
|
714
|
+
# :incomplete_binding ?
|
606
715
|
ret
|
607
716
|
}
|
608
717
|
end
|
@@ -675,6 +784,30 @@ class Ia32
|
|
675
784
|
end
|
676
785
|
end
|
677
786
|
|
787
|
+
# patch a forward binding from the backtrace binding
|
788
|
+
# fixes fwdemu for push/pop/call/ret
|
789
|
+
def fix_fwdemu_binding(di, fbd)
|
790
|
+
if di.instruction.args.grep(ModRM).find { |m| m.seg and m.symbolic(di).target.lexpr =~ /^segment_base_/ }
|
791
|
+
fbd = fbd.dup
|
792
|
+
fbd[:incomplete_binding] = Expression[1]
|
793
|
+
end
|
794
|
+
|
795
|
+
case di.opcode.name
|
796
|
+
when 'push', 'call'
|
797
|
+
fbd = fbd.dup
|
798
|
+
sz = opsz(di)/8
|
799
|
+
esp = register_symbols[4]
|
800
|
+
if i = fbd.delete(Indirection[esp, sz])
|
801
|
+
fbd[Indirection[[esp, :-, sz], sz]] = i
|
802
|
+
end
|
803
|
+
when 'pop', 'ret' # nothing to do
|
804
|
+
when /^(push|pop|call|ret|enter|leave|stos|movs|lods|scas|cmps)/
|
805
|
+
fbd = fbd.dup
|
806
|
+
fbd[:incomplete_binding] = Expression[1] # TODO
|
807
|
+
end
|
808
|
+
fbd
|
809
|
+
end
|
810
|
+
|
678
811
|
def get_xrefs_x(dasm, di)
|
679
812
|
return [] if not di.opcode.props[:setip]
|
680
813
|
|
@@ -683,8 +816,8 @@ class Ia32
|
|
683
816
|
when 'ret'; return [Indirection[register_symbols[4], sz/8, di.address]]
|
684
817
|
when 'jmp', 'call'
|
685
818
|
a = di.instruction.args.first
|
686
|
-
if dasm and a.kind_of?(ModRM) and a.imm and a.s == sz/8 and not a.b and dasm.get_section_at(a.imm)
|
687
|
-
return get_xrefs_x_jmptable(dasm, di, a,
|
819
|
+
if dasm and a.kind_of?(ModRM) and a.imm and (a.s == sz/8 or a.s == 4) and not a.b and dasm.get_section_at(a.imm)
|
820
|
+
return get_xrefs_x_jmptable(dasm, di, a, a.s*8)
|
688
821
|
end
|
689
822
|
end
|
690
823
|
|
@@ -724,6 +857,19 @@ class Ia32
|
|
724
857
|
}
|
725
858
|
l = dasm.auto_label_at(mrm.imm, 'jmp_table', 'xref')
|
726
859
|
replace_instr_arg_immediate(di.instruction, mrm.imm, Expression[l])
|
860
|
+
# add 'case 1' comments
|
861
|
+
cases = {}
|
862
|
+
ret.each_with_index { |ind, idx|
|
863
|
+
idx -= 1 # ret[0] = symbolic
|
864
|
+
next if idx < 0
|
865
|
+
a = dasm.backtrace(ind, di.address)
|
866
|
+
if a.length == 1 and a[0].kind_of?(Expression) and addr = a[0].reduce and addr.kind_of?(::Integer)
|
867
|
+
(cases[addr] ||= []) << idx
|
868
|
+
end
|
869
|
+
}
|
870
|
+
cases.each { |addr, list|
|
871
|
+
dasm.add_comment(addr, "case #{list.join(', ')}:")
|
872
|
+
}
|
727
873
|
return ret
|
728
874
|
end
|
729
875
|
|
@@ -735,7 +881,7 @@ class Ia32
|
|
735
881
|
s = dasm.get_section_at(mrm.imm)
|
736
882
|
v = 0
|
737
883
|
end
|
738
|
-
|
884
|
+
while s[0].ptr < s[0].length
|
739
885
|
ptr = dasm.normalize s[0].decode_imm("u#{sz}".to_sym, @endianness)
|
740
886
|
diff = Expression[ptr, :-, di.address].reduce
|
741
887
|
if (diff.kind_of? ::Integer and diff.abs < 4096) or (di.opcode.basename == 'call' and ptr != 0 and dasm.get_section_at(ptr))
|
@@ -1164,5 +1310,46 @@ class Ia32
|
|
1164
1310
|
|
1165
1311
|
binding
|
1166
1312
|
end
|
1313
|
+
|
1314
|
+
# trace the stack pointer register across a function, rename occurences of esp+XX to esp+var_XX
|
1315
|
+
def name_local_vars(dasm, funcaddr)
|
1316
|
+
esp = register_symbols[4]
|
1317
|
+
func = dasm.function[funcaddr]
|
1318
|
+
subs = []
|
1319
|
+
dasm.trace_function_register(funcaddr, esp => 0) { |di, r, off, trace|
|
1320
|
+
next if r.to_s =~ /flag/
|
1321
|
+
if di.opcode.name == 'call' and tf = di.block.to_normal.find { |t| dasm.function[t] and dasm.function[t].localvars }
|
1322
|
+
subs << [trace[esp], dasm.function[tf].localvars]
|
1323
|
+
end
|
1324
|
+
di.instruction.args.grep(ModRM).each { |mrm|
|
1325
|
+
b = mrm.b || (mrm.i if mrm.s == 1)
|
1326
|
+
# its a modrm => b is read, so ignore r/off (not yet applied), use trace only
|
1327
|
+
stackoff = trace[b.symbolic] if b
|
1328
|
+
next if not stackoff
|
1329
|
+
imm = mrm.imm || Expression[0]
|
1330
|
+
frameoff = imm + stackoff
|
1331
|
+
if frameoff.kind_of?(::Integer)
|
1332
|
+
# XXX register args ? non-ABI standard register args ? (eg optimized x64)
|
1333
|
+
str = 'var_%X' % (-frameoff)
|
1334
|
+
str = 'arg_%X' % (frameoff-@size/8) if frameoff > 0
|
1335
|
+
str = func.get_localvar_stackoff(frameoff, di, str) if func
|
1336
|
+
imm = imm.expr if imm.kind_of?(ExpressionString)
|
1337
|
+
mrm.imm = ExpressionString.new(imm, str, :stackvar)
|
1338
|
+
end
|
1339
|
+
}
|
1340
|
+
off = off.reduce if off.kind_of?(Expression)
|
1341
|
+
next unless off.kind_of?(Integer)
|
1342
|
+
off
|
1343
|
+
}
|
1344
|
+
# if subfunctions are called at a fixed stack offset, rename var_3c -> subarg_0
|
1345
|
+
if func and func.localvars and not subs.empty? and subs.all? { |sb| sb[0] == subs.first[0] }
|
1346
|
+
func.localvars.each { |varoff, varname|
|
1347
|
+
subargnames = subs.map { |o, sb| sb[varoff-o+@size/8] }.compact
|
1348
|
+
if subargnames.uniq.length == 1
|
1349
|
+
varname.replace 'sub'+subargnames[0]
|
1350
|
+
end
|
1351
|
+
}
|
1352
|
+
end
|
1353
|
+
end
|
1167
1354
|
end
|
1168
1355
|
end
|