metasm 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|