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
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
|
|
7
|
+
require 'metasm/cpu/bpf/opcodes'
|
|
8
|
+
require 'metasm/decode'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class BPF
|
|
12
|
+
def build_bin_lookaside
|
|
13
|
+
opcode_list.inject({}) { |h, op| h.update op.bin => op }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# tries to find the opcode encoded at edata.ptr
|
|
17
|
+
def decode_findopcode(edata)
|
|
18
|
+
return if edata.ptr > edata.data.length-8
|
|
19
|
+
di = DecodedInstruction.new self
|
|
20
|
+
code = edata.data[edata.ptr, 2].unpack('v')[0]
|
|
21
|
+
return di if di.opcode = @bin_lookaside[code]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def decode_instr_op(edata, di)
|
|
25
|
+
op = di.opcode
|
|
26
|
+
di.instruction.opname = op.name
|
|
27
|
+
di.bin_length = 8
|
|
28
|
+
code, jt, jf, k = edata.read(8).unpack('vCCV')
|
|
29
|
+
|
|
30
|
+
op.args.each { |a|
|
|
31
|
+
di.instruction.args << case a
|
|
32
|
+
when :k; Expression[k]
|
|
33
|
+
when :x; Reg.new(:x)
|
|
34
|
+
when :a; Reg.new(:a)
|
|
35
|
+
when :len; Reg.new(:len)
|
|
36
|
+
when :p_k; PktRef.new(nil, Expression[k], op.props[:msz])
|
|
37
|
+
when :p_xk; PktRef.new(Reg.new(:x), Expression[k], op.props[:msz])
|
|
38
|
+
when :m_k; MemRef.new(nil, Expression[4*k], 4)
|
|
39
|
+
when :jt; Expression[jt]
|
|
40
|
+
when :jf; Expression[jf]
|
|
41
|
+
else raise "unhandled arg #{a}"
|
|
42
|
+
end
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# je a, x, 0, 12 -> jne a, x, 12
|
|
46
|
+
# je a, x, 12, 0 -> je a, x, 12
|
|
47
|
+
if op.args[2] == :jt and di.instruction.args[2] == Expression[0]
|
|
48
|
+
di.opcode = op.dup
|
|
49
|
+
di.opcode.props.delete :stopexec
|
|
50
|
+
di.instruction.opname = { 'jg' => 'jle', 'jge' => 'jl', 'je' => 'jne', 'jtest' => 'jntest' }[di.instruction.opname]
|
|
51
|
+
di.instruction.args.delete_at(2)
|
|
52
|
+
elsif op.args[3] == :jf and di.instruction.args[3] == Expression[0]
|
|
53
|
+
di.opcode = op.dup
|
|
54
|
+
di.opcode.props.delete :stopexec
|
|
55
|
+
di.instruction.args.delete_at(3)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
di
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def decode_instr_interpret(di, addr)
|
|
62
|
+
if di.opcode.props[:setip]
|
|
63
|
+
delta = di.instruction.args[-1].reduce + 1
|
|
64
|
+
arg = Expression[addr, :+, 8*delta].reduce
|
|
65
|
+
di.instruction.args[-1] = Expression[arg]
|
|
66
|
+
|
|
67
|
+
if di.instruction.args.length == 4
|
|
68
|
+
delta = di.instruction.args[2].reduce + 1
|
|
69
|
+
arg = Expression[addr, :+, 8*delta].reduce
|
|
70
|
+
di.instruction.args[2] = Expression[arg]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
di
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
|
|
78
|
+
def backtrace_binding
|
|
79
|
+
@backtrace_binding ||= init_backtrace_binding
|
|
80
|
+
end
|
|
81
|
+
def backtrace_binding=(b) @backtrace_binding = b end
|
|
82
|
+
|
|
83
|
+
# populate the @backtrace_binding hash with default values
|
|
84
|
+
def init_backtrace_binding
|
|
85
|
+
@backtrace_binding ||= {}
|
|
86
|
+
|
|
87
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
|
88
|
+
binding = case op
|
|
89
|
+
when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
90
|
+
when 'add'; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } }
|
|
91
|
+
when 'sub'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } }
|
|
92
|
+
when 'mul'; lambda { |di, a0, a1| { a0 => Expression[a0, :*, a1] } }
|
|
93
|
+
when 'div'; lambda { |di, a0, a1| { a0 => Expression[a0, :/, a1] } }
|
|
94
|
+
when 'shl'; lambda { |di, a0, a1| { a0 => Expression[a0, :<<, a1] } }
|
|
95
|
+
when 'shr'; lambda { |di, a0, a1| { a0 => Expression[a0, :>>, a1] } }
|
|
96
|
+
when 'neg'; lambda { |di, a0| { a0 => Expression[:-, a0] } }
|
|
97
|
+
when 'msh'; lambda { |di, a0, a1| { a0 => Expression[[a1, :&, 0xf], :<<, 2] } }
|
|
98
|
+
when 'jmp', 'jg', 'jge', 'je', 'jtest', 'ret'; lambda { |di, *a| { } }
|
|
99
|
+
end
|
|
100
|
+
@backtrace_binding[op] ||= binding if binding
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@backtrace_binding
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def get_backtrace_binding(di)
|
|
107
|
+
a = di.instruction.args.map { |arg|
|
|
108
|
+
case arg
|
|
109
|
+
when PktRef, MemRef, Reg; arg.symbolic(di)
|
|
110
|
+
else arg
|
|
111
|
+
end
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if binding = backtrace_binding[di.opcode.name]
|
|
115
|
+
binding[di, *a]
|
|
116
|
+
else
|
|
117
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
118
|
+
{:incomplete_binding => Expression[1]}
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def get_xrefs_x(dasm, di)
|
|
123
|
+
return [] if not di.opcode.props[:setip]
|
|
124
|
+
|
|
125
|
+
if di.instruction.args.length == 4
|
|
126
|
+
di.instruction.args[-2, 2]
|
|
127
|
+
else
|
|
128
|
+
di.instruction.args[-1, 1]
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# updates an instruction's argument replacing an expression with another (eg label renamed)
|
|
133
|
+
def replace_instr_arg_immediate(i, old, new)
|
|
134
|
+
i.args.map! { |a|
|
|
135
|
+
case a
|
|
136
|
+
when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
|
|
137
|
+
else a
|
|
138
|
+
end
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
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
|
+
|
|
7
|
+
require 'metasm/main'
|
|
8
|
+
|
|
9
|
+
module Metasm
|
|
10
|
+
class BPF < CPU
|
|
11
|
+
class Reg
|
|
12
|
+
attr_accessor :v
|
|
13
|
+
def initialize(v)
|
|
14
|
+
@v = v
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def symbolic(orig=nil) ; @v ; end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class MemRef
|
|
21
|
+
attr_accessor :base, :offset, :msz
|
|
22
|
+
|
|
23
|
+
def memtype
|
|
24
|
+
:mem
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def initialize(base, offset, msz)
|
|
28
|
+
@base = base
|
|
29
|
+
@offset = offset
|
|
30
|
+
@msz = msz
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def symbolic(orig)
|
|
34
|
+
p = Expression[memtype]
|
|
35
|
+
p = Expression[p, :+, @base.symbolic] if base
|
|
36
|
+
p = Expression[p, :+, @offset] if offset
|
|
37
|
+
Indirection[p, @msz, orig]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class PktRef < MemRef
|
|
42
|
+
def memtype
|
|
43
|
+
:pkt
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def initialize(family = :latest)
|
|
48
|
+
super()
|
|
49
|
+
@endianness = :big
|
|
50
|
+
@size = 32
|
|
51
|
+
@family = family
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def init_opcode_list
|
|
55
|
+
send("init_#@family")
|
|
56
|
+
@opcode_list
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
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
|
+
require 'metasm/cpu/bpf/main'
|
|
7
|
+
|
|
8
|
+
module Metasm
|
|
9
|
+
|
|
10
|
+
class BPF
|
|
11
|
+
def addop(name, bin, *args)
|
|
12
|
+
o = Opcode.new name, bin
|
|
13
|
+
args.each { |a|
|
|
14
|
+
o.args << a if @valid_args[a]
|
|
15
|
+
o.props.update a if a.kind_of?(::Hash)
|
|
16
|
+
}
|
|
17
|
+
@opcode_list << o
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def addop_ldx(bin, src)
|
|
21
|
+
addop 'mov', bin | 0x00, :a, src
|
|
22
|
+
addop 'mov', bin | 0x01, :x, src
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def addop_ldsz(bin, src)
|
|
26
|
+
addop 'mov', bin | 0x00, :a, src, :msz => 4
|
|
27
|
+
addop 'mov', bin | 0x08, :a, src, :msz => 2
|
|
28
|
+
addop 'mov', bin | 0x10, :a, src, :msz => 1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def addop_alu(name, bin)
|
|
32
|
+
addop name, bin | 0x04, :a, :k
|
|
33
|
+
addop name, bin | 0x0C, :a, :x
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def addop_j(name, bin)
|
|
37
|
+
addop name, bin | 0x05 | 0x00, :a, :k, :jt, :jf, :setip => true, :stopexec => true
|
|
38
|
+
addop name, bin | 0x05 | 0x08, :a, :x, :jt, :jf, :setip => true, :stopexec => true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def init_bpf
|
|
42
|
+
@opcode_list = []
|
|
43
|
+
[:a, :k, :x, :len, :m_k, :p_k, :p_xk, :jt, :jf].each { |a| @valid_args[a] = true }
|
|
44
|
+
|
|
45
|
+
# LD/ST
|
|
46
|
+
addop_ldx 0x00, :k
|
|
47
|
+
addop_ldsz 0x20, :p_k
|
|
48
|
+
addop_ldsz 0x40, :p_xk
|
|
49
|
+
addop_ldx 0x60, :m_k
|
|
50
|
+
addop_ldx 0x80, :len
|
|
51
|
+
addop 'msh', 0xB1, :x, :p_k, :msz => 1
|
|
52
|
+
addop 'mov', 0x02, :m_k, :a
|
|
53
|
+
addop 'mov', 0x03, :m_k, :x
|
|
54
|
+
|
|
55
|
+
# ALU
|
|
56
|
+
addop_alu 'add', 0x00
|
|
57
|
+
addop_alu 'sub', 0x10
|
|
58
|
+
addop_alu 'mul', 0x20
|
|
59
|
+
addop_alu 'div', 0x30
|
|
60
|
+
addop_alu 'or', 0x40
|
|
61
|
+
addop_alu 'and', 0x50
|
|
62
|
+
addop_alu 'shl', 0x60
|
|
63
|
+
addop_alu 'shr', 0x70
|
|
64
|
+
addop 'neg', 0x84, :a
|
|
65
|
+
|
|
66
|
+
# JMP
|
|
67
|
+
addop 'jmp', 0x05, :k, :setip => true, :stopexec => true
|
|
68
|
+
addop_j 'je', 0x10
|
|
69
|
+
addop_j 'jg', 0x20
|
|
70
|
+
addop_j 'jge', 0x30
|
|
71
|
+
addop_j 'jtest',0x40
|
|
72
|
+
addop 'ret', 0x06, :k, :stopexec => true
|
|
73
|
+
addop 'ret', 0x16, :a, :stopexec => true
|
|
74
|
+
|
|
75
|
+
addop 'mov', 0x07, :x, :a
|
|
76
|
+
addop 'mov', 0x87, :a, :x
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
alias init_latest init_bpf
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
|
|
7
|
+
require 'metasm/cpu/bpf/opcodes'
|
|
8
|
+
require 'metasm/render'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class BPF
|
|
12
|
+
class Reg
|
|
13
|
+
include Renderable
|
|
14
|
+
def render ; [@v.to_s] end
|
|
15
|
+
end
|
|
16
|
+
class MemRef
|
|
17
|
+
include Renderable
|
|
18
|
+
def render
|
|
19
|
+
r = []
|
|
20
|
+
r << memtype
|
|
21
|
+
r << [nil, ' byte ', ' word ', nil, ' dword '][@msz]
|
|
22
|
+
r << '['
|
|
23
|
+
r << @base if @base
|
|
24
|
+
r << '+' if @base and @offset
|
|
25
|
+
r << @offset if @offset
|
|
26
|
+
r << ']'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def render_instruction(i)
|
|
31
|
+
r = []
|
|
32
|
+
r << i.opname
|
|
33
|
+
if not i.args.empty?
|
|
34
|
+
r << ' '
|
|
35
|
+
i.args.each { |a_| r << a_ << ', ' }
|
|
36
|
+
r.pop
|
|
37
|
+
end
|
|
38
|
+
r
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
data/metasm/cpu/cy16.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
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
|
+
|
|
7
|
+
require 'metasm/main'
|
|
8
|
+
require 'metasm/cpu/cy16/decode'
|
|
9
|
+
require 'metasm/cpu/cy16/render'
|
|
@@ -0,0 +1,253 @@
|
|
|
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
|
+
|
|
7
|
+
require 'metasm/cpu/cy16/opcodes'
|
|
8
|
+
require 'metasm/decode'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class CY16
|
|
12
|
+
def build_opcode_bin_mask(op)
|
|
13
|
+
# bit = 0 if can be mutated by an field value, 1 if fixed by opcode
|
|
14
|
+
op.bin_mask = 0
|
|
15
|
+
op.fields.each { |f, off|
|
|
16
|
+
op.bin_mask |= (@fields_mask[f] << off)
|
|
17
|
+
}
|
|
18
|
+
op.bin_mask ^= 0xffff
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_bin_lookaside
|
|
22
|
+
# sets up a hash byte value => list of opcodes that may match
|
|
23
|
+
# opcode.bin_mask is built here
|
|
24
|
+
lookaside = Array.new(256) { [] }
|
|
25
|
+
opcode_list.each { |op|
|
|
26
|
+
build_opcode_bin_mask op
|
|
27
|
+
b = (op.bin >> 8) & 0xff
|
|
28
|
+
msk = (op.bin_mask >> 8) & 0xff
|
|
29
|
+
for i in b..(b | (255^msk))
|
|
30
|
+
lookaside[i] << op if i & msk == b & msk
|
|
31
|
+
end
|
|
32
|
+
}
|
|
33
|
+
lookaside
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def decode_findopcode(edata)
|
|
37
|
+
di = DecodedInstruction.new self
|
|
38
|
+
return if edata.ptr+2 > edata.length
|
|
39
|
+
bin = edata.decode_imm(:u16, @endianness)
|
|
40
|
+
edata.ptr -= 2
|
|
41
|
+
return di if di.opcode = @bin_lookaside[(bin >> 8) & 0xff].find { |op|
|
|
42
|
+
bin & op.bin_mask == op.bin & op.bin_mask
|
|
43
|
+
}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def decode_instr_op_r(val, edata)
|
|
48
|
+
bw = ((val & 0b1000) > 0 ? 1 : 2)
|
|
49
|
+
case val & 0b11_0000
|
|
50
|
+
when 0b00_0000
|
|
51
|
+
Reg.new(val)
|
|
52
|
+
when 0b01_0000
|
|
53
|
+
if val == 0b01_1111
|
|
54
|
+
Expression[edata.decode_imm(:u16, @endianness)]
|
|
55
|
+
else
|
|
56
|
+
Memref.new(Reg.new(8+(val&7)), nil, bw)
|
|
57
|
+
end
|
|
58
|
+
when 0b10_0000
|
|
59
|
+
if val & 7 == 7
|
|
60
|
+
Memref.new(nil, edata.decode_imm(:u16, @endianness), bw)
|
|
61
|
+
else
|
|
62
|
+
Memref.new(Reg.new(8+(val&7)), nil, bw, true)
|
|
63
|
+
end
|
|
64
|
+
when 0b11_0000
|
|
65
|
+
Memref.new(Reg.new(8+(val&7)), edata.decode_imm(:u16, @endianness), bw)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def decode_instr_op(edata, di)
|
|
71
|
+
before_ptr = edata.ptr
|
|
72
|
+
op = di.opcode
|
|
73
|
+
di.instruction.opname = op.name
|
|
74
|
+
bin = edata.decode_imm(:u16, @endianness)
|
|
75
|
+
|
|
76
|
+
field_val = lambda { |f|
|
|
77
|
+
if off = op.fields[f]
|
|
78
|
+
(bin >> off) & @fields_mask[f]
|
|
79
|
+
end
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
op.args.each { |a|
|
|
83
|
+
di.instruction.args << case a
|
|
84
|
+
when :rs, :rd; decode_instr_op_r(field_val[a], edata)
|
|
85
|
+
when :o7; Expression[2*Expression.make_signed(field_val[a], 7)]
|
|
86
|
+
when :x7; Expression[field_val[a]]
|
|
87
|
+
when :u3; Expression[field_val[a]+1]
|
|
88
|
+
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
|
|
89
|
+
end
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
di.instruction.args.reverse!
|
|
93
|
+
|
|
94
|
+
di.bin_length += edata.ptr - before_ptr
|
|
95
|
+
|
|
96
|
+
di
|
|
97
|
+
rescue InvalidRD
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def decode_instr_interpret(di, addr)
|
|
101
|
+
if di.opcode.props[:setip] and di.opcode.args.last == :o7
|
|
102
|
+
delta = di.instruction.args.last.reduce
|
|
103
|
+
arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
|
|
104
|
+
di.instruction.args[-1] = Expression[arg]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
di
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# hash opcode_name => lambda { |dasm, di, *symbolic_args| instr_binding }
|
|
111
|
+
def backtrace_binding
|
|
112
|
+
@backtrace_binding ||= init_backtrace_binding
|
|
113
|
+
end
|
|
114
|
+
def backtrace_binding=(b) @backtrace_binding = b end
|
|
115
|
+
|
|
116
|
+
# populate the @backtrace_binding hash with default values
|
|
117
|
+
def init_backtrace_binding
|
|
118
|
+
@backtrace_binding ||= {}
|
|
119
|
+
|
|
120
|
+
mask = 0xffff
|
|
121
|
+
|
|
122
|
+
opcode_list.map { |ol| ol.basename }.uniq.sort.each { |op|
|
|
123
|
+
binding = case op
|
|
124
|
+
when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] } }
|
|
125
|
+
when 'add', 'adc', 'sub', 'sbc', 'and', 'xor', 'or', 'addi', 'subi'
|
|
126
|
+
lambda { |di, a0, a1|
|
|
127
|
+
e_op = { 'add' => :+, 'adc' => :+, 'sub' => :-, 'sbc' => :-, 'and' => :&,
|
|
128
|
+
'xor' => :^, 'or' => :|, 'addi' => :+, 'subi' => :- }[op]
|
|
129
|
+
ret = Expression[a0, e_op, a1]
|
|
130
|
+
ret = Expression[ret, e_op, :flag_c] if op == 'adc' or op == 'sbb'
|
|
131
|
+
# optimises eax ^ eax => 0
|
|
132
|
+
# avoid hiding memory accesses (to not hide possible fault)
|
|
133
|
+
ret = Expression[ret.reduce] if not a0.kind_of? Indirection
|
|
134
|
+
{ a0 => ret }
|
|
135
|
+
}
|
|
136
|
+
when 'cmp', 'test'; lambda { |di, *a| {} }
|
|
137
|
+
when 'not'; lambda { |di, a0| { a0 => Expression[a0, :^, mask] } }
|
|
138
|
+
when 'call'
|
|
139
|
+
lambda { |di, a0| { :sp => Expression[:sp, :-, 2],
|
|
140
|
+
Indirection[:sp, 2, di.address] => Expression[di.next_addr] }
|
|
141
|
+
}
|
|
142
|
+
when 'ret'; lambda { |di, *a| { :sp => Expression[:sp, :+, 2] } }
|
|
143
|
+
# TODO callCC, retCC ...
|
|
144
|
+
when /^j/; lambda { |di, *a| {} }
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# TODO flags ?
|
|
148
|
+
|
|
149
|
+
@backtrace_binding[op] ||= binding if binding
|
|
150
|
+
}
|
|
151
|
+
@backtrace_binding
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def get_backtrace_binding(di)
|
|
155
|
+
a = di.instruction.args.map { |arg|
|
|
156
|
+
case arg
|
|
157
|
+
when Memref, Reg; arg.symbolic(di)
|
|
158
|
+
else arg
|
|
159
|
+
end
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if binding = backtrace_binding[di.opcode.basename]
|
|
163
|
+
bd = {}
|
|
164
|
+
di.instruction.args.each { |aa| bd[aa.base.symbolic] = Expression[aa.base.symbolic, :+, aa.sz] if aa.kind_of?(Memref) and aa.autoincr }
|
|
165
|
+
bd.update binding[di, *a]
|
|
166
|
+
else
|
|
167
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
|
168
|
+
# assume nothing except the 1st arg is modified
|
|
169
|
+
case a[0]
|
|
170
|
+
when Indirection, Symbol; { a[0] => Expression::Unknown }
|
|
171
|
+
when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
|
|
172
|
+
else {}
|
|
173
|
+
end.update(:incomplete_binding => Expression[1])
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# patch a forward binding from the backtrace binding
|
|
178
|
+
def fix_fwdemu_binding(di, fbd)
|
|
179
|
+
case di.opcode.name
|
|
180
|
+
when 'call'; fbd[Indirection[[:sp, :-, 2], 2]] = fbd.delete(Indirection[:sp, 2])
|
|
181
|
+
end
|
|
182
|
+
fbd
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def get_xrefs_x(dasm, di)
|
|
186
|
+
return [] if not di.opcode.props[:setip]
|
|
187
|
+
|
|
188
|
+
return [Indirection[:sp, 2, di.address]] if di.opcode.name =~ /^r/
|
|
189
|
+
|
|
190
|
+
case tg = di.instruction.args.first
|
|
191
|
+
when Memref; [Expression[tg.symbolic(di)]]
|
|
192
|
+
when Reg; [Expression[tg.symbolic(di)]]
|
|
193
|
+
when Expression, ::Integer; [Expression[tg]]
|
|
194
|
+
else
|
|
195
|
+
puts "unhandled setip at #{di.address} #{di.instruction}" if $DEBUG
|
|
196
|
+
[]
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# checks if expr is a valid return expression matching the :saveip instruction
|
|
201
|
+
def backtrace_is_function_return(expr, di=nil)
|
|
202
|
+
expr = Expression[expr].reduce_rec
|
|
203
|
+
expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp]
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# updates the function backtrace_binding
|
|
207
|
+
# if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand)
|
|
208
|
+
def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
|
|
209
|
+
b = f.backtrace_binding
|
|
210
|
+
|
|
211
|
+
bt_val = lambda { |r|
|
|
212
|
+
next if not retaddrlist
|
|
213
|
+
b[r] = Expression::Unknown
|
|
214
|
+
bt = []
|
|
215
|
+
retaddrlist.each { |retaddr|
|
|
216
|
+
bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true,
|
|
217
|
+
:snapshot_addr => faddr, :origin => retaddr)
|
|
218
|
+
}
|
|
219
|
+
if bt.length != 1
|
|
220
|
+
b[r] = Expression::Unknown
|
|
221
|
+
else
|
|
222
|
+
b[r] = bt.first
|
|
223
|
+
end
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if not wantregs.empty?
|
|
227
|
+
wantregs.each(&bt_val)
|
|
228
|
+
else
|
|
229
|
+
bt_val[:sp]
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
b
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# returns true if the expression is an address on the stack
|
|
236
|
+
def backtrace_is_stack_address(expr)
|
|
237
|
+
Expression[expr].expr_externals.include?(:sp)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# updates an instruction's argument replacing an expression with another (eg label renamed)
|
|
241
|
+
def replace_instr_arg_immediate(i, old, new)
|
|
242
|
+
i.args.map! { |a|
|
|
243
|
+
case a
|
|
244
|
+
when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
|
|
245
|
+
when Memref
|
|
246
|
+
a.offset = (a.offset == old ? new : Expression[a.offset.bind(old => new).reduce]) if a.offset
|
|
247
|
+
a
|
|
248
|
+
else a
|
|
249
|
+
end
|
|
250
|
+
}
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|