metasm 1.0.0 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +3 -0
- data/.gitignore +3 -0
- data/.hgtags +3 -0
- data/Gemfile +3 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +3 -1
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +23 -0
- data/{lib/metasm.rb → metasm.rb} +15 -3
- data/{lib/metasm → metasm}/compile_c.rb +15 -9
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +404 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/metasm/cpu/arm.rb +14 -0
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +15 -18
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +3 -6
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +285 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/mips/compile_c.rb → metasm/cpu/bpf.rb} +4 -2
- data/metasm/cpu/bpf/decode.rb +110 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +30 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/cy16.rb} +2 -4
- data/metasm/cpu/cy16/decode.rb +247 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +30 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +34 -34
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +71 -4
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +21 -12
- data/{lib/metasm/mips.rb → metasm/cpu/ebpf.rb} +3 -4
- data/metasm/cpu/ebpf/debug.rb +61 -0
- data/metasm/cpu/ebpf/decode.rb +142 -0
- data/metasm/cpu/ebpf/main.rb +58 -0
- data/metasm/cpu/ebpf/opcodes.rb +97 -0
- data/metasm/cpu/ebpf/render.rb +36 -0
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +23 -9
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +44 -6
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +342 -128
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +75 -53
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +66 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +55 -17
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +32 -5
- data/metasm/cpu/mcs51.rb +8 -0
- data/metasm/cpu/mcs51/decode.rb +99 -0
- data/metasm/cpu/mcs51/main.rb +87 -0
- data/metasm/cpu/mcs51/opcodes.rb +120 -0
- data/metasm/cpu/mips.rb +14 -0
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +59 -38
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +13 -6
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +87 -18
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +243 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/metasm/cpu/openrisc.rb +11 -0
- data/metasm/cpu/openrisc/debug.rb +106 -0
- data/metasm/cpu/openrisc/decode.rb +182 -0
- data/metasm/cpu/openrisc/decompile.rb +350 -0
- data/metasm/cpu/openrisc/main.rb +70 -0
- data/metasm/cpu/openrisc/opcodes.rb +109 -0
- data/metasm/cpu/openrisc/render.rb +37 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/metasm/cpu/ppc.rb +11 -0
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -37
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +23 -18
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -6
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +116 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +50 -23
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +38 -27
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/st20.rb +9 -0
- data/metasm/cpu/st20/decode.rb +173 -0
- data/metasm/cpu/st20/decompile.rb +283 -0
- data/metasm/cpu/st20/main.rb +37 -0
- data/metasm/cpu/st20/opcodes.rb +140 -0
- data/{lib/metasm/arm.rb → metasm/cpu/webasm.rb} +4 -5
- data/metasm/cpu/webasm/debug.rb +31 -0
- data/metasm/cpu/webasm/decode.rb +321 -0
- data/metasm/cpu/webasm/decompile.rb +386 -0
- data/metasm/cpu/webasm/encode.rb +104 -0
- data/metasm/cpu/webasm/main.rb +81 -0
- data/metasm/cpu/webasm/opcodes.rb +214 -0
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +40 -25
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +58 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +59 -28
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +18 -6
- data/metasm/cpu/x86_64/opcodes.rb +138 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +12 -4
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +286 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +48 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +201 -407
- data/{lib/metasm → metasm}/decode.rb +104 -24
- data/{lib/metasm → metasm}/decompile.rb +804 -478
- data/{lib/metasm → metasm}/disassemble.rb +385 -170
- data/{lib/metasm → metasm}/disassemble_api.rb +684 -105
- data/{lib/metasm → metasm}/dynldr.rb +231 -138
- data/{lib/metasm → metasm}/encode.rb +20 -5
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +3 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +35 -7
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +70 -23
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +24 -22
- data/{lib/metasm → metasm}/exe_format/dex.rb +26 -8
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +108 -58
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +202 -36
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +126 -32
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +218 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +28 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +2 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +96 -11
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/metasm/exe_format/wasm.rb +402 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +177 -114
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1754 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +16 -12
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +360 -77
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +109 -34
- data/{lib/metasm → metasm}/gui/gtk.rb +174 -44
- data/{lib/metasm → metasm}/gui/qt.rb +14 -4
- data/{lib/metasm → metasm}/gui/win32.rb +180 -43
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +421 -286
- data/metasm/os/emulator.rb +175 -0
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +335 -0
- data/{lib/metasm → metasm}/os/windows.rb +151 -58
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +49 -36
- data/{lib/metasm → metasm}/parse_c.rb +405 -246
- data/{lib/metasm → metasm}/preprocessor.rb +71 -41
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +4 -3
- data/misc/lint.rb +58 -0
- data/misc/objdiff.rb +4 -1
- data/misc/objscan.rb +1 -1
- data/misc/openrisc-parser.rb +79 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +29 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +48 -7
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +35 -27
- data/samples/elfencode.rb +15 -0
- data/samples/emubios.rb +251 -0
- data/samples/emudbg.rb +127 -0
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +186 -391
- data/samples/metasm-shell.rb +68 -57
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +57 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +80 -26
- data/tests/mcs51.rb +27 -0
- data/tests/mips.rb +10 -3
- data/tests/preprocessor.rb +18 -0
- data/tests/x86_64.rb +66 -18
- metadata +465 -219
- metadata.gz.sig +2 -0
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -872
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
@@ -0,0 +1,386 @@
|
|
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/webasm/main'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class WebAsm
|
11
|
+
def wasm_type_to_type(t)
|
12
|
+
case t
|
13
|
+
when 'i32'; C::BaseType.new(:int)
|
14
|
+
when 'i64'; C::BaseType.new(:longlong)
|
15
|
+
when 'f32'; C::BaseType.new(:float)
|
16
|
+
when 'f64'; C::BaseType.new(:double)
|
17
|
+
when 'anyfunc'; C::Function.new(C::BaseType.new(:void))
|
18
|
+
when Hash
|
19
|
+
ret = t[:ret].first ? wasm_type_to_type(t[:ret].first) : C::BaseType.new(:void)
|
20
|
+
args = t[:params].map { |p| C::Variable.new(nil, wasm_type_to_type(p)) }
|
21
|
+
C::Function.new(ret, args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def decompile_init(dcmp)
|
26
|
+
mem = dcmp.c_parser.toplevel.symbol['mem'] = C::Variable.new('mem', C::Pointer.new(C::BaseType.new(:char)))
|
27
|
+
mem.storage = :static
|
28
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(mem)
|
29
|
+
|
30
|
+
global_idx = 0
|
31
|
+
@wasm_file.import.to_a.each { |i|
|
32
|
+
case i[:kind]
|
33
|
+
when 'global'
|
34
|
+
global_idx += 1
|
35
|
+
var = C::Variable.new
|
36
|
+
var.name = '%s_%s' % [i[:module], i[:field]]
|
37
|
+
var.type = C::Array.new(wasm_type_to_type(i[:type]), 1)
|
38
|
+
var.storage = :extern
|
39
|
+
dcmp.c_parser.toplevel.symbol[var.name] = var
|
40
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(var)
|
41
|
+
when 'function'
|
42
|
+
var = C::Variable.new
|
43
|
+
var.name = '%s_%s' % [i[:module], i[:field]]
|
44
|
+
var.type = wasm_type_to_type(i[:type])
|
45
|
+
var.storage = :extern
|
46
|
+
dcmp.c_parser.toplevel.symbol[var.name] = var
|
47
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(var)
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
@wasm_file.global.to_a.each_with_index { |g, idx|
|
52
|
+
g_name = 'global_%d' % global_idx
|
53
|
+
global_idx += 1
|
54
|
+
var = C::Variable.new
|
55
|
+
var.name = g_name
|
56
|
+
var.type = C::Array.new(wasm_type_to_type(g[:type]), 1)
|
57
|
+
var.storage = :static
|
58
|
+
dcmp.c_parser.toplevel.symbol[var.name] = var
|
59
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(var)
|
60
|
+
|
61
|
+
# decompile initializers
|
62
|
+
g_init_name = g_name + '_init'
|
63
|
+
dcmp.dasm.disassemble(g_init_name)
|
64
|
+
dcmp.decompile_func(g_init_name)
|
65
|
+
if init = dcmp.c_parser.toplevel.symbol[g_init_name] and init.initializer.kind_of?(C::Block) and
|
66
|
+
init.initializer.statements.first.kind_of?(C::Return)
|
67
|
+
dcmp.c_parser.toplevel.symbol[g_name].initializer = [ init.initializer.statements.first.value ]
|
68
|
+
dcmp.c_parser.toplevel.symbol.delete(g_init_name)
|
69
|
+
dcmp.c_parser.toplevel.statements.delete_if { |st| st.kind_of?(C::Declaration) and st.var.name == g_init_name }
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
@wasm_file.table.to_a.each_with_index { |t, idx|
|
74
|
+
break if idx > 0
|
75
|
+
t_name = 'indirect_calltable'
|
76
|
+
var = C::Variable.new
|
77
|
+
var.name = t_name
|
78
|
+
sz = t[:limits][:initial_size]
|
79
|
+
var.type = C::Array.new(C::Pointer.new(wasm_type_to_type(t[:type])), sz)
|
80
|
+
var.storage = :static
|
81
|
+
dcmp.c_parser.toplevel.symbol[var.name] = var
|
82
|
+
dcmp.c_parser.toplevel.statements << C::Declaration.new(var)
|
83
|
+
var.initializer = [C::CExpression[0]] * sz
|
84
|
+
|
85
|
+
# initializer
|
86
|
+
@wasm_file.element.to_a.each_with_index { |e, eidx|
|
87
|
+
next if e[:table_index] != idx
|
88
|
+
# address of the code that evals the index at which to place the elements inside the table
|
89
|
+
e_init_name = "element_#{eidx}_init_addr"
|
90
|
+
dcmp.dasm.disassemble(e_init_name)
|
91
|
+
dcmp.decompile_func(e_init_name)
|
92
|
+
if init = dcmp.c_parser.toplevel.symbol[e_init_name] and init.initializer.kind_of?(C::Block) and
|
93
|
+
init.initializer.statements.first.kind_of?(C::Return)
|
94
|
+
eoff = init.initializer.statements.first.value.reduce(dcmp.c_parser)
|
95
|
+
dcmp.c_parser.toplevel.symbol.delete(e_init_name)
|
96
|
+
dcmp.c_parser.toplevel.statements.delete_if { |st| st.kind_of?(C::Declaration) and st.var.name == e_init_name }
|
97
|
+
e[:elems].each_with_index { |ev, vidx|
|
98
|
+
# table 0 is the only table in a wasm file and contains a list of function indexes used with the call_indirect asm instruction
|
99
|
+
# e_init_name gives the index at which we should put e[:elems], and we convert the func indexes into C names
|
100
|
+
vidx += eoff
|
101
|
+
if vidx >= sz or vidx < 0
|
102
|
+
puts "W: initializing indirect_calltable, would put #{ev} beyond end of table (#{vidx} > #{sz})"
|
103
|
+
next
|
104
|
+
end
|
105
|
+
if not tg_func = @wasm_file.get_function_nr(ev)
|
106
|
+
puts "W: initializing indirect_calltable, bad func index #{ev}"
|
107
|
+
next
|
108
|
+
end
|
109
|
+
funcname = dcmp.dasm.get_label_at(tg_func[:init_offset]) || "func_at_#{'%x' % tg_func[:init_offset]}"
|
110
|
+
# XXX should decompile funcname now ?
|
111
|
+
var.initializer[vidx] = C::CExpression[:&, C::Variable.new(funcname)]
|
112
|
+
}
|
113
|
+
end
|
114
|
+
}
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def abi_funcall
|
119
|
+
@abi_funcall ||= { :changed => [] }
|
120
|
+
end
|
121
|
+
|
122
|
+
def decompile_makestackvars(dasm, funcstart, blocks)
|
123
|
+
@decomp_mkstackvars_terminals = [:frameptr, :local_base, :mem]
|
124
|
+
oldbd = {}
|
125
|
+
oldbd[funcstart] = dasm.address_binding[funcstart]
|
126
|
+
dasm.address_binding[funcstart] = { :opstack => Expression[:frameptr] }
|
127
|
+
blocks.each { |block|
|
128
|
+
oldbd[block.address] = dasm.address_binding[block.address]
|
129
|
+
stkoff = dasm.backtrace(:opstack, block.address, :snapshot_addr => funcstart)
|
130
|
+
dasm.address_binding[block.address] = { :opstack => Expression[:frameptr, :+, stkoff[0]-:frameptr] }
|
131
|
+
yield block
|
132
|
+
# store frameptr offset at each 'end' 'return' or 'else' instruction
|
133
|
+
if di = block.list.last and %w[end return else].include?(di.opcode.name)
|
134
|
+
stkoff = dasm.backtrace(:opstack, di.address, :snapshot_addr => funcstart)
|
135
|
+
if stkoff.length == 1 and (stkoff[0] - :frameptr).kind_of?(::Integer)
|
136
|
+
di.misc[:dcmp_stackoff] = stkoff[0] - :frameptr
|
137
|
+
end
|
138
|
+
end
|
139
|
+
}
|
140
|
+
oldbd.each { |a, b| b ? dasm.address_binding[a] = b : dasm.address_binding.delete(a) }
|
141
|
+
end
|
142
|
+
|
143
|
+
def decompile_func_finddeps_di(dcmp, func, di, a, w)
|
144
|
+
end
|
145
|
+
|
146
|
+
def decompile_func_finddeps(dcmp, blocks, func)
|
147
|
+
{}
|
148
|
+
end
|
149
|
+
|
150
|
+
def decompile_blocks(dcmp, myblocks, deps, func, nextaddr = nil)
|
151
|
+
func_entry = myblocks.first[0]
|
152
|
+
if w_func = @wasm_file.function_body.find { |fb| fb[:init_offset] == func_entry }
|
153
|
+
elsif g = @wasm_file.global.find { |gg| gg[:init_offset] == func_entry }
|
154
|
+
w_func = { :local_var => [], :type => { :params => [], :ret => [g[:type]] } }
|
155
|
+
elsif (@wasm_file.element.to_a + @wasm_file.data.to_a).find { |gg| gg[:init_offset] == func_entry }
|
156
|
+
w_func = { :local_var => [], :type => { :params => [], :ret => ['i32'] } }
|
157
|
+
end
|
158
|
+
scope = func.initializer
|
159
|
+
func.type.args.each { |a| scope.symbol[a.name] = a }
|
160
|
+
stmts = scope.statements
|
161
|
+
|
162
|
+
local = []
|
163
|
+
w_func[:type][:params].each { |t|
|
164
|
+
local << C::Variable.new("arg_#{local.length}", wasm_type_to_type(t))
|
165
|
+
scope.symbol[local.last.name] = local.last
|
166
|
+
func.type.args << local.last
|
167
|
+
}
|
168
|
+
w_func[:local_var].each { |t|
|
169
|
+
local << C::Variable.new("var_#{local.length}", wasm_type_to_type(t))
|
170
|
+
scope.symbol[local.last.name] = local.last
|
171
|
+
local.last.initializer = C::CExpression[0]
|
172
|
+
stmts << C::Declaration.new(local.last)
|
173
|
+
}
|
174
|
+
|
175
|
+
opstack = {}
|
176
|
+
|
177
|
+
# *(_int32*)(local_base+16) => 16
|
178
|
+
ce_ptr_offset = lambda { |ee, base|
|
179
|
+
if ee.kind_of?(C::CExpression) and ee.op == :* and not ee.lexpr and ee.rexpr.kind_of?(C::CExpression) and
|
180
|
+
not ee.rexpr.op and ee.rexpr.rexpr.kind_of?(C::CExpression)
|
181
|
+
if not ee.rexpr.rexpr.op and ee.rexpr.rexpr.rexpr.kind_of?(C::Variable) and ee.rexpr.rexpr.rexpr.name == base
|
182
|
+
0
|
183
|
+
elsif ee.rexpr.rexpr.lexpr.kind_of?(C::Variable) and ee.rexpr.rexpr.lexpr.name == base and
|
184
|
+
ee.rexpr.rexpr.rexpr.kind_of?(C::CExpression) and not ee.rexpr.rexpr.rexpr.op and ee.rexpr.rexpr.rexpr.rexpr.kind_of?(::Integer)
|
185
|
+
if ee.rexpr.rexpr.op == :+
|
186
|
+
ee.rexpr.rexpr.rexpr.rexpr
|
187
|
+
elsif ee.rexpr.rexpr.op == :-
|
188
|
+
-ee.rexpr.rexpr.rexpr.rexpr
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
}
|
193
|
+
opstack_idx = -1
|
194
|
+
ce_local_offset = lambda { |ee| ce_ptr_offset[ee, 'local_base'] }
|
195
|
+
ce_opstack_offset = lambda { |ee| ce_ptr_offset[ee, 'frameptr'] }
|
196
|
+
|
197
|
+
di_addr = nil
|
198
|
+
|
199
|
+
# Expr => CExpr
|
200
|
+
ce = lambda { |*e|
|
201
|
+
c_expr = dcmp.decompile_cexpr(Expression[Expression[*e].reduce], scope)
|
202
|
+
dcmp.walk_ce(c_expr, true) { |ee|
|
203
|
+
if ee.rexpr.kind_of?(::Array)
|
204
|
+
# funcall arglist
|
205
|
+
ee.rexpr.map! { |eee|
|
206
|
+
if loff = ce_local_offset[eee]
|
207
|
+
C::CExpression[local[loff/8]]
|
208
|
+
elsif soff = ce_opstack_offset[eee]
|
209
|
+
C::CExpression[opstack[-soff/8]]
|
210
|
+
else
|
211
|
+
eee
|
212
|
+
end
|
213
|
+
}
|
214
|
+
end
|
215
|
+
if loff = ce_local_offset[ee.lexpr]
|
216
|
+
ee.lexpr = local[loff/8]
|
217
|
+
end
|
218
|
+
if loff = ce_local_offset[ee.rexpr]
|
219
|
+
ee.rexpr = local[loff/8]
|
220
|
+
ee.rexpr = C::CExpression[ee.rexpr] if not ee.op and ee.type.pointer?
|
221
|
+
end
|
222
|
+
if soff = ce_opstack_offset[ee.rexpr]
|
223
|
+
# must do soff.rexpr before lexpr in case of reaffectation !
|
224
|
+
ee.rexpr = opstack[-soff/8]
|
225
|
+
ee.rexpr = C::CExpression[ee.rexpr] if not ee.op and ee.type.pointer?
|
226
|
+
end
|
227
|
+
if soff = ce_opstack_offset[ee.lexpr]
|
228
|
+
if ee.op == :'='
|
229
|
+
# affectation: create a new variable
|
230
|
+
varname = "loc_#{opstack_idx += 1}"
|
231
|
+
ne = C::Variable.new(varname, wasm_type_to_type("i#{8*dcmp.sizeof(ee.lexpr)}"))
|
232
|
+
scope.symbol[varname] = ne
|
233
|
+
stmts << C::Declaration.new(ne)
|
234
|
+
opstack[-soff/8] = ne
|
235
|
+
end
|
236
|
+
ee.lexpr = opstack[-soff/8]
|
237
|
+
end
|
238
|
+
}
|
239
|
+
ret = if loff = ce_local_offset[c_expr]
|
240
|
+
C::CExpression[local[loff/8]]
|
241
|
+
elsif soff = ce_opstack_offset[c_expr]
|
242
|
+
C::CExpression[opstack[-soff/8]]
|
243
|
+
else
|
244
|
+
c_expr
|
245
|
+
end
|
246
|
+
dcmp.walk_ce(ret) { |ee| ee.with_misc :di_addr => di_addr if di_addr }
|
247
|
+
ret
|
248
|
+
}
|
249
|
+
|
250
|
+
|
251
|
+
blocks_toclean = myblocks.dup
|
252
|
+
until myblocks.empty?
|
253
|
+
b, to = myblocks.shift
|
254
|
+
if l = dcmp.dasm.get_label_at(b)
|
255
|
+
stmts << C::Label.new(l)
|
256
|
+
end
|
257
|
+
|
258
|
+
# go !
|
259
|
+
di_list = dcmp.dasm.decoded[b].block.list.dup
|
260
|
+
di_list.each { |di|
|
261
|
+
di_addr = di.address
|
262
|
+
if di.opcode.name == 'if' or di.opcode.name == 'br_if'
|
263
|
+
n = dcmp.backtrace_target(get_xrefs_x(dcmp.dasm, di).first, di.address)
|
264
|
+
bd = get_fwdemu_binding(di)
|
265
|
+
if di.opcode.name == 'if'
|
266
|
+
cc = ce[:!, bd[:flag]]
|
267
|
+
else
|
268
|
+
cc = ce[bd[:flag]]
|
269
|
+
end
|
270
|
+
stmts << C::If.new(C::CExpression[cc], C::Goto.new(n).with_misc(:di_addr => di.address)).with_misc(:di_addr => di.address)
|
271
|
+
to.delete dcmp.dasm.normalize(n)
|
272
|
+
elsif (di.opcode.name == 'end' or di.opcode.name == 'return') and di.opcode.props[:stopexec]
|
273
|
+
fsig = w_func[:type]
|
274
|
+
rettype = wasm_type_to_type(fsig[:ret].first) if fsig[:ret] and fsig[:ret].first
|
275
|
+
if not fsig[:ret].empty?
|
276
|
+
off = di.misc[:dcmp_stackoff] || -8
|
277
|
+
ret = C::CExpression[ce[Indirection[[:frameptr, :+, off], dcmp.sizeof(rettype)]]]
|
278
|
+
end
|
279
|
+
stmts << C::Return.new(ret).with_misc(:di_addr => di.address)
|
280
|
+
elsif (di.opcode.name == 'end' or di.opcode.name == 'else') and di.misc[:dcmp_stackoff] and di.misc[:end_of]
|
281
|
+
# end of block returning a value: store the value in a real variable instead of the autogenerated local
|
282
|
+
# so that if { } else {} both update the same var
|
283
|
+
start = di.misc[:end_of]
|
284
|
+
start_rettype = start.instruction.args.first.to_s
|
285
|
+
if start_rettype != 'none'
|
286
|
+
retsz = dcmp.sizeof(wasm_type_to_type(start_rettype))
|
287
|
+
off = di.misc[:dcmp_stackoff]
|
288
|
+
if not start.misc[:dcmp_retval] or not scope.symbol[start.misc[:dcmp_retval]]
|
289
|
+
stmts << C::CExpression[ce[Indirection[[:frameptr, :+, off], retsz], :'=', Indirection[[:frameptr, :+, off], retsz]]]
|
290
|
+
start.misc[:dcmp_retval] = stmts.last.lexpr.name
|
291
|
+
else
|
292
|
+
stmts << C::CExpression[ce[scope.symbol[start.misc[:dcmp_retval]], :'=', Indirection[[:frameptr, :+, off], retsz]]]
|
293
|
+
end
|
294
|
+
end
|
295
|
+
elsif di.opcode.name == 'call'
|
296
|
+
tg = di.misc[:x].first
|
297
|
+
raise "no call target for #{di}" if not tg
|
298
|
+
tg = dcmp.dasm.auto_label_at(tg, 'sub') if dcmp.dasm.get_section_at(tg)
|
299
|
+
f = dcmp.c_parser.toplevel.symbol[tg]
|
300
|
+
raise "no global function #{tg} for #{di}" if not f
|
301
|
+
|
302
|
+
args = []
|
303
|
+
bd = get_fwdemu_binding(di)
|
304
|
+
i = 0
|
305
|
+
while bd_arg = bd["param_#{i}"]
|
306
|
+
args << ce[bd_arg]
|
307
|
+
i += 1
|
308
|
+
end
|
309
|
+
e = C::CExpression[f, :funcall, args].with_misc(:di_addr => di.address)
|
310
|
+
if bd_ret = bd.index(Expression["ret_0"])
|
311
|
+
e = ce[bd_ret, :'=', e]
|
312
|
+
end
|
313
|
+
stmts << e
|
314
|
+
elsif di.opcode.name == 'call_indirect'
|
315
|
+
args = []
|
316
|
+
bd = get_fwdemu_binding(di)
|
317
|
+
wt = @wasm_file.type[di.instruction.args.first.reduce]
|
318
|
+
fptr = C::CExpression[[dcmp.c_parser.toplevel.symbol['indirect_calltable'], :[], ce[bd['func_idx']]], wasm_type_to_type(wt)]
|
319
|
+
i = 0
|
320
|
+
while bd_arg = bd["param_#{i}"]
|
321
|
+
args << ce[bd_arg]
|
322
|
+
i += 1
|
323
|
+
end
|
324
|
+
e = C::CExpression[fptr, :funcall, args].with_misc(:di_addr => di.address)
|
325
|
+
if bd_ret = bd.index(Expression["ret_0"])
|
326
|
+
e = ce[bd_ret, :'=', e]
|
327
|
+
end
|
328
|
+
stmts << e
|
329
|
+
else
|
330
|
+
bd = get_fwdemu_binding(di)
|
331
|
+
if di.backtrace_binding[:incomplete_binding]
|
332
|
+
stmts << C::Asm.new(di.instruction.to_s, nil, nil, nil, nil, nil).with_misc(:di_addr => di.address)
|
333
|
+
else
|
334
|
+
bd.each { |k, v|
|
335
|
+
next if k == :opstack
|
336
|
+
e = ce[k, :'=', v]
|
337
|
+
stmts << e if not e.kind_of?(C::Variable) # [:eflag_s, :=, :unknown].reduce
|
338
|
+
}
|
339
|
+
end
|
340
|
+
end
|
341
|
+
di_addr = nil
|
342
|
+
}
|
343
|
+
|
344
|
+
case to.length
|
345
|
+
when 0
|
346
|
+
if not myblocks.empty? and not stmts.last.kind_of?(C::Return)
|
347
|
+
puts " block #{Expression[b]} has no to and don't end in ret"
|
348
|
+
end
|
349
|
+
when 1
|
350
|
+
if (myblocks.empty? ? nextaddr != to[0] : myblocks.first.first != to[0])
|
351
|
+
stmts << C::Goto.new(dcmp.dasm.auto_label_at(to[0], 'unknown_goto'))
|
352
|
+
end
|
353
|
+
else
|
354
|
+
puts " block #{Expression[b]} with multiple to"
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# cleanup di.bt_binding (we set :frameptr etc in those, this may confuse the dasm)
|
359
|
+
blocks_toclean.each { |b_, to_|
|
360
|
+
dcmp.dasm.decoded[b_].block.list.each { |di|
|
361
|
+
di.backtrace_binding = nil
|
362
|
+
}
|
363
|
+
}
|
364
|
+
end
|
365
|
+
|
366
|
+
def decompile_check_abi(dcmp, entry, func)
|
367
|
+
scope = func.initializer
|
368
|
+
@wasm_file.function_body.to_a.each { |fb|
|
369
|
+
next if fb[:init_offset] != entry
|
370
|
+
w_type = wasm_type_to_type(fb[:type])
|
371
|
+
func.type.type = w_type.type
|
372
|
+
if func.type.args.length > w_type.args.length
|
373
|
+
# detected an argument that is actually a local variable, move into func scope
|
374
|
+
while a = func.type.args.delete_at(w_type.args.length)
|
375
|
+
if a.has_attribute('unused')
|
376
|
+
scope.symbol.delete a.name
|
377
|
+
else
|
378
|
+
a.initializer = C::CExpression[0]
|
379
|
+
scope.statements[0, 0] = [C::Declaration.new(a)]
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
}
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
@@ -0,0 +1,104 @@
|
|
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/webasm/opcodes'
|
8
|
+
require 'metasm/parse'
|
9
|
+
|
10
|
+
module Metasm
|
11
|
+
class WebAsm
|
12
|
+
def parse_argument(lexer)
|
13
|
+
lexer = AsmPreprocessor.new(lexer) if lexer.kind_of? String
|
14
|
+
lexer.skip_space
|
15
|
+
return if not tok = lexer.readtok
|
16
|
+
|
17
|
+
if tok.type == :punct and tok.raw == '['
|
18
|
+
# Memref or BrTable
|
19
|
+
ary = []
|
20
|
+
loop do
|
21
|
+
# XXX empty array for BrTable ?
|
22
|
+
ary << parse_argument(lexer)
|
23
|
+
raise tok, 'bad ptr' if not ary.last.kind_of?(Expression)
|
24
|
+
lexer.skip_space
|
25
|
+
tok2 = lexer.readtok
|
26
|
+
if tok2 and tok2.type == :punct and tok2.raw == ']'
|
27
|
+
break
|
28
|
+
elsif not tok2 or tok2.type != :punct or tok2.raw != ','
|
29
|
+
raise tok, "unexpected #{tok2 ? 'eof' : tok2.raw}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
lexer.skip_space
|
33
|
+
tok2 = lexer.readtok
|
34
|
+
if tok2 and tok2.type == :string and tok2.raw == 'or'
|
35
|
+
# BrTable
|
36
|
+
df = parse_argument(lexer)
|
37
|
+
BrTable.new(ary, df)
|
38
|
+
else
|
39
|
+
raise tok, 'bad Memref/BrTable' if ary.length != 1
|
40
|
+
lexer.unreadtok(tok2) if tok2
|
41
|
+
Memref.new(ary[0])
|
42
|
+
end
|
43
|
+
elsif WasmFile::TYPE.index(tok.raw)
|
44
|
+
BlockSignature.new(WasmFile::TYPE.index(tok.raw))
|
45
|
+
else
|
46
|
+
lexer.unreadtok tok
|
47
|
+
expr = Expression.parse(lexer)
|
48
|
+
lexer.skip_space
|
49
|
+
expr
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_arg_valid?(o, spec, arg)
|
54
|
+
spec and arg
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_instruction_mnemonic(lexer)
|
58
|
+
return if not tok = lexer.readtok
|
59
|
+
tok = tok.dup
|
60
|
+
while ntok = lexer.nexttok and ntok.type == :punct and (ntok.raw == '.' or ntok.raw == '/')
|
61
|
+
tok.raw << lexer.readtok.raw
|
62
|
+
ntok = lexer.readtok
|
63
|
+
raise tok, 'invalid opcode name' if not ntok or ntok.type != :string
|
64
|
+
tok.raw << ntok.raw
|
65
|
+
end
|
66
|
+
|
67
|
+
raise tok, 'invalid opcode' if not opcode_list_byname[tok.raw]
|
68
|
+
tok
|
69
|
+
end
|
70
|
+
|
71
|
+
def encode_uleb(val, signed=false)
|
72
|
+
# TODO labels ?
|
73
|
+
v = Expression[val].reduce
|
74
|
+
raise "need numeric value for #{val}" if not v.kind_of?(::Integer)
|
75
|
+
out = EncodedData.new
|
76
|
+
while v > 0x7f or v < -0x40 or (signed and v > 0x3f)
|
77
|
+
out << Expression[0x80 | (v&0x7f)].encode(:u8, @endianness)
|
78
|
+
v >>= 7
|
79
|
+
end
|
80
|
+
out << Expression[v & 0x7f].encode(:u8, @endianness)
|
81
|
+
end
|
82
|
+
|
83
|
+
def encode_instr_op(program, i, op)
|
84
|
+
ed = EncodedData.new([op.bin].pack('C*'))
|
85
|
+
op.args.zip(i.args).each { |oa, ia|
|
86
|
+
case oa
|
87
|
+
when :f32; ed << ia.encode(:u32, @endianness)
|
88
|
+
when :f64; ed << ia.encode(:u64, @endianness)
|
89
|
+
when :memoff; ed << encode_uleb(ia.off)
|
90
|
+
when :uleb; ed << encode_uleb(ia)
|
91
|
+
when :sleb; ed << encode_uleb(ia, true)
|
92
|
+
when :blocksig
|
93
|
+
ia = ia.id if ia.kind_of?(BlockSignature)
|
94
|
+
ed << encode_uleb(ia, true)
|
95
|
+
when :br_table
|
96
|
+
ed << encode_uleb(ia.ary.length)
|
97
|
+
ia.ary.each { |a| ed << encode_uleb(a) }
|
98
|
+
ed << encode_uleb(ia.default)
|
99
|
+
end
|
100
|
+
}
|
101
|
+
ed
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|