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
@@ -69,11 +69,11 @@ class Shellcode < ExeFormat
|
|
69
69
|
parse(*a) if not a.empty?
|
70
70
|
@encoded << assemble_sequence(@source, @cpu)
|
71
71
|
@source.clear
|
72
|
-
|
72
|
+
self
|
73
73
|
end
|
74
74
|
|
75
75
|
def encode(binding={})
|
76
|
-
@encoded.fixup! binding
|
76
|
+
@encoded.fixup! binding if binding.kind_of? Hash
|
77
77
|
@encoded.fixup @encoded.binding(@base_addr)
|
78
78
|
@encoded.fill @encoded.rawsize
|
79
79
|
self
|
@@ -107,7 +107,11 @@ class Shellcode < ExeFormat
|
|
107
107
|
# returns a virtual subclass of Shellcode whose cpu_from_headers will return cpu
|
108
108
|
def self.withcpu(cpu)
|
109
109
|
c = Class.new(self)
|
110
|
-
c.send(:define_method, :cpu_from_headers) {
|
110
|
+
c.send(:define_method, :cpu_from_headers) {
|
111
|
+
cpu = Metasm.const_get(cpu) if cpu.kind_of?(::String)
|
112
|
+
cpu = cpu.new if cpu.kind_of?(::Class) and cpu.ancestors.include?(CPU)
|
113
|
+
cpu
|
114
|
+
}
|
111
115
|
c
|
112
116
|
end
|
113
117
|
end
|
@@ -0,0 +1,114 @@
|
|
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/exe_format/main'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
# Similar to Shellcode, with distinct sections per memory permission (R / RW / RX)
|
11
|
+
# encoding-side only
|
12
|
+
class Shellcode_RWX < ExeFormat
|
13
|
+
# the array of source elements (Instr/Data etc)
|
14
|
+
attr_accessor :source_r, :source_w, :source_x
|
15
|
+
# base address per section
|
16
|
+
attr_accessor :base_r, :base_w, :base_x
|
17
|
+
# encodeddata
|
18
|
+
attr_accessor :encoded_r, :encoded_w, :encoded_x
|
19
|
+
|
20
|
+
def initialize(cpu=nil)
|
21
|
+
@base_r = @base_w = @base_x = nil
|
22
|
+
@encoded_r = EncodedData.new
|
23
|
+
@encoded_w = EncodedData.new
|
24
|
+
@encoded_x = EncodedData.new
|
25
|
+
|
26
|
+
super(cpu)
|
27
|
+
end
|
28
|
+
|
29
|
+
def parse_init
|
30
|
+
@source_r = []
|
31
|
+
@source_w = []
|
32
|
+
@source_x = []
|
33
|
+
@cursource = @source_x
|
34
|
+
super()
|
35
|
+
end
|
36
|
+
|
37
|
+
# allows definition of the base address
|
38
|
+
def parse_parser_instruction(instr)
|
39
|
+
case instr.raw.downcase
|
40
|
+
when '.base', '.baseaddr', '.base_addr'
|
41
|
+
# ".base_addr <expression>"
|
42
|
+
# expression should #reduce to integer
|
43
|
+
@lexer.skip_space
|
44
|
+
raise instr, 'syntax error' if not base = Expression.parse(@lexer).reduce
|
45
|
+
raise instr, 'syntax error' if tok = @lexer.nexttok and tok.type != :eol
|
46
|
+
if @cursource.equal?(@source_r)
|
47
|
+
@base_r = base
|
48
|
+
elsif @cursource.equal?(@source_w)
|
49
|
+
@base_w = base
|
50
|
+
elsif @cursource.equal?(@source_x)
|
51
|
+
@base_x = base
|
52
|
+
else raise instr, "Where am I ?"
|
53
|
+
end
|
54
|
+
when '.rdata', '.rodata'
|
55
|
+
@cursource = @source_r
|
56
|
+
when '.data', '.bss'
|
57
|
+
@cursource = @source_w
|
58
|
+
when '.text'
|
59
|
+
@cursource = @source_x
|
60
|
+
else super(instr)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# encodes the source found in self.source
|
65
|
+
# appends it to self.encoded
|
66
|
+
# clears self.source
|
67
|
+
# the optional parameter may contain a binding used to fixup! self.encoded
|
68
|
+
# uses self.base_addr if it exists
|
69
|
+
def assemble(*a)
|
70
|
+
parse(*a) if not a.empty?
|
71
|
+
@encoded_r << assemble_sequence(@source_r, @cpu); @source_r.clear
|
72
|
+
@encoded_w << assemble_sequence(@source_w, @cpu); @source_w.clear
|
73
|
+
@encoded_x << assemble_sequence(@source_x, @cpu); @source_x.clear
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def encode(binding={})
|
78
|
+
bd = {}
|
79
|
+
bd.update @encoded_r.binding(@base_r)
|
80
|
+
bd.update @encoded_w.binding(@base_w)
|
81
|
+
bd.update @encoded_x.binding(@base_x)
|
82
|
+
bd.update binding if binding.kind_of?(Hash)
|
83
|
+
@encoded_r.fixup bd
|
84
|
+
@encoded_w.fixup bd
|
85
|
+
@encoded_x.fixup bd
|
86
|
+
self
|
87
|
+
end
|
88
|
+
alias fixup encode
|
89
|
+
|
90
|
+
# resolve inter-section xrefs, raise if unresolved relocations remain
|
91
|
+
# call this when you have assembled+allocated memory for every section
|
92
|
+
def fixup_check(base_r=nil, base_w=nil, base_x=nil, bd={})
|
93
|
+
if base_r.kind_of?(Hash)
|
94
|
+
bd = base_r
|
95
|
+
base_r = nil
|
96
|
+
end
|
97
|
+
@base_r = base_r if base_r
|
98
|
+
@base_w = base_w if base_w
|
99
|
+
@base_x = base_x if base_x
|
100
|
+
fixup bd
|
101
|
+
ed = EncodedData.new << @encoded_r << @encoded_w << @encoded_x
|
102
|
+
raise ["Unresolved relocations:", ed.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not ed.reloc.empty?
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def encode_string(*a)
|
107
|
+
encode(*a)
|
108
|
+
ed = EncodedData.new << @encoded_r << @encoded_w << @encoded_x
|
109
|
+
ed.fixup(ed.binding)
|
110
|
+
raise ["Unresolved relocations:", ed.reloc.map { |o, r| "#{r.target} " + (Backtrace.backtrace_str(r.backtrace) if r.backtrace).to_s }].join("\n") if not ed.reloc.empty?
|
111
|
+
ed.data
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,205 @@
|
|
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/exe_format/main'
|
7
|
+
require 'metasm/encode'
|
8
|
+
require 'metasm/decode'
|
9
|
+
begin
|
10
|
+
require 'zlib'
|
11
|
+
rescue LoadError
|
12
|
+
end
|
13
|
+
|
14
|
+
module Metasm
|
15
|
+
class SWF < ExeFormat
|
16
|
+
attr_accessor :signature, :version, :header, :chunks
|
17
|
+
|
18
|
+
CHUNK_TYPE = {
|
19
|
+
0 => 'End', 1 => 'ShowFrame', 2 => 'DefineShape', 3 => 'FreeCharacter',
|
20
|
+
4 => 'PlaceObject', 5 => 'RemoveObject', 6 => 'DefineBits', 7 => 'DefineButton',
|
21
|
+
8 => 'JPEGTables', 9 => 'SetBackgroundColor', 10 => 'DefineFont', 11 => 'DefineText',
|
22
|
+
12 => 'DoAction', 13 => 'DefineFontInfo', 14 => 'DefineSound', 15 => 'StartSound',
|
23
|
+
16 => 'StopSound', 17 => 'DefineButtonSound', 18 => 'SoundStreamHead', 19 => 'SoundStreamBlock',
|
24
|
+
20 => 'DefineBitsLossless', 21 => 'DefineBitsJPEG2', 22 => 'DefineShape2', 23 => 'DefineButtonCxform',
|
25
|
+
24 => 'Protect', 25 => 'PathsArePostScript', 26 => 'PlaceObject2',
|
26
|
+
28 => 'RemoveObject2', 29 => 'SyncFrame', 31 => 'FreeAll',
|
27
|
+
32 => 'DefineShape3', 33 => 'DefineText2', 34 => 'DefineButton2', 35 => 'DefineBitsJPEG3',
|
28
|
+
36 => 'DefineBitsLossless2', 37 => 'DefineEditText', 38 => 'DefineVideo', 39 => 'DefineSprite',
|
29
|
+
40 => 'NameCharacter', 41 => 'ProductInfo', 42 => 'DefineTextFormat', 43 => 'FrameLabel',
|
30
|
+
44 => 'DefineBehavior', 45 => 'SoundStreamHead2', 46 => 'DefineMorphShape', 47 => 'FrameTag',
|
31
|
+
48 => 'DefineFont2', 49 => 'GenCommand', 50 => 'DefineCommandObj', 51 => 'CharacterSet',
|
32
|
+
52 => 'FontRef', 53 => 'DefineFunction', 54 => 'PlaceFunction', 55 => 'GenTagObject',
|
33
|
+
56 => 'ExportAssets', 57 => 'ImportAssets', 58 => 'EnableDebugger', 59 => 'DoInitAction',
|
34
|
+
60 => 'DefineVideoStream', 61 => 'VideoFrame', 62 => 'DefineFontInfo2', 63 => 'DebugID',
|
35
|
+
64 => 'EnableDebugger2', 65 => 'ScriptLimits', 66 => 'SetTabIndex', 67 => 'DefineShape4',
|
36
|
+
68 => 'DefineMorphShape2', 69 => 'FileAttributes', 70 => 'PlaceObject3', 71 => 'ImportAssets2',
|
37
|
+
72 => 'DoABC', 76 => 'SymbolClass', 82 => 'DoABC2',
|
38
|
+
}
|
39
|
+
|
40
|
+
class SerialStruct < Metasm::SerialStruct
|
41
|
+
new_int_field :u8, :u16, :u32, :f16, :f32
|
42
|
+
end
|
43
|
+
|
44
|
+
class Rectangle < SerialStruct
|
45
|
+
virtual :nbits, :xmin, :xmax, :ymin, :ymax
|
46
|
+
|
47
|
+
def decode(swf)
|
48
|
+
byte = swf.decode_u8
|
49
|
+
bleft = 3
|
50
|
+
@nbits = byte >> bleft
|
51
|
+
@xmin, @xmax, @ymin, @ymax = (0..3).map {
|
52
|
+
nb = @nbits
|
53
|
+
v = 0
|
54
|
+
while nb > bleft
|
55
|
+
nb -= bleft
|
56
|
+
v |= (byte & ((1<<bleft)-1)) << nb
|
57
|
+
|
58
|
+
bleft = 8
|
59
|
+
byte = swf.decode_u8
|
60
|
+
end
|
61
|
+
v |= (byte >> (bleft-nb)) & ((1<<nb)-1)
|
62
|
+
bleft -= nb
|
63
|
+
|
64
|
+
Expression.make_signed(v, @nbits)
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_default_values(swf)
|
69
|
+
@xmin ||= 0
|
70
|
+
@xmax ||= 31
|
71
|
+
@ymin ||= 0
|
72
|
+
@ymax ||= 31
|
73
|
+
@nbits = (0..30).find { |nb|
|
74
|
+
[@xmin, @xmax, @ymin, @ymax].all? { |v|
|
75
|
+
if nb == 0
|
76
|
+
v == 0
|
77
|
+
elsif v >= 0
|
78
|
+
# reserve sign bit
|
79
|
+
(v >> (nb-1)) == 0
|
80
|
+
else
|
81
|
+
(v >> nb) == -1
|
82
|
+
end
|
83
|
+
} } || 31
|
84
|
+
end
|
85
|
+
|
86
|
+
def encode(swf)
|
87
|
+
ed = super(swf)
|
88
|
+
|
89
|
+
byte = @nbits << 3
|
90
|
+
bleft = 3
|
91
|
+
[@xmin, @xmax, @ymin, @ymax].each { |v|
|
92
|
+
nb = @nbits
|
93
|
+
while nb > bleft
|
94
|
+
byte |= (v >> (nb-bleft)) & ((1<<bleft)-1)
|
95
|
+
nb -= bleft
|
96
|
+
|
97
|
+
ed << byte
|
98
|
+
byte = 0
|
99
|
+
bleft = 8
|
100
|
+
end
|
101
|
+
byte |= (v & ((1<<nb)-1)) << (bleft-nb)
|
102
|
+
bleft -= nb
|
103
|
+
}
|
104
|
+
ed << byte if bleft < 8
|
105
|
+
|
106
|
+
ed
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class Header < SerialStruct
|
111
|
+
virtual :view
|
112
|
+
u16 :framerate # XXX bigendian...
|
113
|
+
u16 :framecount
|
114
|
+
|
115
|
+
def bswap_framerate(swf)
|
116
|
+
@framerate = ((@framerate >> 8) & 0xff) | ((@framerate & 0xff) << 8) if swf.endianness == :little
|
117
|
+
end
|
118
|
+
|
119
|
+
def decode(swf)
|
120
|
+
@view = Rectangle.decode(swf)
|
121
|
+
super(swf)
|
122
|
+
bswap_framerate(swf)
|
123
|
+
end
|
124
|
+
|
125
|
+
def encode(swf)
|
126
|
+
ed = @view.encode(swf)
|
127
|
+
bswap_framerate(swf)
|
128
|
+
ed << super(swf)
|
129
|
+
bswap_framerate(swf)
|
130
|
+
ed
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Chunk < SerialStruct
|
135
|
+
bitfield :u16, 0 => :length_, 6 => :tag
|
136
|
+
fld_enum :tag, CHUNK_TYPE
|
137
|
+
attr_accessor :data
|
138
|
+
|
139
|
+
def decode(swf)
|
140
|
+
super(swf)
|
141
|
+
@length = (@length_ == 0x3f ? swf.decode_u32 : @length_)
|
142
|
+
@data = swf.encoded.read(@length)
|
143
|
+
end
|
144
|
+
|
145
|
+
def set_default_values(swf)
|
146
|
+
@length = @data.length
|
147
|
+
@length_ = [@length, 0x3f].min
|
148
|
+
end
|
149
|
+
|
150
|
+
def encode(swf)
|
151
|
+
super(swf) <<
|
152
|
+
(swf.encode_u32(@length) if @length >= 0x3f) <<
|
153
|
+
@data
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def decode_u8( edata=@encoded) edata.decode_imm(:u8, @endianness) end
|
158
|
+
def decode_u16(edata=@encoded) edata.decode_imm(:u16, @endianness) end
|
159
|
+
def decode_u32(edata=@encoded) edata.decode_imm(:u32, @endianness) end
|
160
|
+
def decode_f16(edata=@encoded) edata.decode_imm(:i16, @endianness)/256.0 end
|
161
|
+
def decode_f32(edata=@encoded) edata.decode_imm(:i32, @endianness)/65536.0 end
|
162
|
+
def encode_u8(w) Expression[w].encode(:u8, @endianness) end
|
163
|
+
def encode_u16(w) Expression[w].encode(:u16, @endianness) end
|
164
|
+
def encode_u32(w) Expression[w].encode(:u32, @endianness) end
|
165
|
+
def encode_f16(w) Expression[(w*256).to_i].encode(:u16, @endianness) end
|
166
|
+
def encode_f32(w) Expression[(w*65536).to_i].encode(:u32, @endianness) end
|
167
|
+
def sizeof_u8 ; 1 ; end
|
168
|
+
def sizeof_u16 ; 2 ; end
|
169
|
+
def sizeof_u32 ; 4 ; end
|
170
|
+
def sizeof_f16 ; 2 ; end
|
171
|
+
def sizeof_f32 ; 4 ; end
|
172
|
+
|
173
|
+
attr_accessor :endianness
|
174
|
+
def initialize(cpu = nil)
|
175
|
+
@endianness = :little
|
176
|
+
@header = Header.new
|
177
|
+
@chunks = []
|
178
|
+
super(cpu)
|
179
|
+
end
|
180
|
+
|
181
|
+
def decode_header
|
182
|
+
@signature = @encoded.read(3)
|
183
|
+
@version = decode_u8
|
184
|
+
@data_length = decode_u32
|
185
|
+
case @signature
|
186
|
+
when 'FWS'
|
187
|
+
when 'CWS'
|
188
|
+
# data_length = uncompressed data length
|
189
|
+
data = @encoded.read(@encoded.length-8)
|
190
|
+
data = Zlib::Inflate.inflate(data)
|
191
|
+
@encoded = EncodedData.new(data)
|
192
|
+
else raise InvalidExeFormat, "Bad signature #{@signature.inspect}"
|
193
|
+
end
|
194
|
+
@data_length = [@data_length, @encoded.length].min
|
195
|
+
@header = Header.decode(self)
|
196
|
+
end
|
197
|
+
|
198
|
+
def decode
|
199
|
+
decode_header
|
200
|
+
while @encoded.ptr < @data_length
|
201
|
+
@chunks << Chunk.decode(self)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,402 @@
|
|
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/exe_format/main'
|
8
|
+
require 'metasm/encode'
|
9
|
+
require 'metasm/decode'
|
10
|
+
|
11
|
+
|
12
|
+
module Metasm
|
13
|
+
# WebAssembly
|
14
|
+
# leb integer encoding taken from dex.rb
|
15
|
+
class WasmFile < ExeFormat
|
16
|
+
MAGIC = "\0asm"
|
17
|
+
MAGIC.force_encoding('binary') if MAGIC.respond_to?(:force_encoding)
|
18
|
+
|
19
|
+
SECTION_NAME = { 1 => 'Type', 2 => 'Import', 3 => 'Function', 4 => 'Table',
|
20
|
+
5 => 'Memory', 6 => 'Global', 7 => 'Export', 8 => 'Start',
|
21
|
+
9 => 'Element', 10 => 'Code', 11 => 'Data' }
|
22
|
+
|
23
|
+
TYPE = { -1 => 'i32', -2 => 'i64', -3 => 'f32', -4 => 'f64',
|
24
|
+
-0x10 => 'anyfunc', -0x20 => 'func', -0x40 => 'none' }
|
25
|
+
|
26
|
+
EXTERNAL_KIND = { 0 => 'function', 1 => 'table', 2 => 'memory', 3 => 'global' }
|
27
|
+
|
28
|
+
# begin WTF
|
29
|
+
OPCODE_IMM_COUNT = Hash.new(0)
|
30
|
+
[2, 3, 4, 0xc, 0xd, 0x10].each { |op| OPCODE_IMM_COUNT[op] = 1 }
|
31
|
+
OPCODE_IMM_COUNT[0x11] = 2
|
32
|
+
(0x20..0x24).each { |op| OPCODE_IMM_COUNT[op] = 1 }
|
33
|
+
(0x28..0x3e).each { |op| OPCODE_IMM_COUNT[op] = 2 }
|
34
|
+
(0x3f..0x42).each { |op| OPCODE_IMM_COUNT[op] = 1 }
|
35
|
+
# 0x43 followed by uint32, 0x44 followed by uint64 (float constants)
|
36
|
+
# end WTF
|
37
|
+
|
38
|
+
|
39
|
+
class SerialStruct < Metasm::SerialStruct
|
40
|
+
# TODO move uleb/sleb to new_field for sizeof
|
41
|
+
new_int_field :u4, :uleb, :sleb
|
42
|
+
end
|
43
|
+
|
44
|
+
class Header < SerialStruct
|
45
|
+
mem :sig, 4, MAGIC
|
46
|
+
decode_hook { |exe, hdr| raise InvalidExeFormat, "E: invalid WasmFile signature #{hdr.sig.inspect}" if hdr.sig != MAGIC }
|
47
|
+
u4 :ver, 1
|
48
|
+
end
|
49
|
+
|
50
|
+
class Module < SerialStruct
|
51
|
+
uleb :id
|
52
|
+
fld_enum :id, SECTION_NAME
|
53
|
+
uleb :payload_len
|
54
|
+
attr_accessor :edata, :raw_offset, :name
|
55
|
+
|
56
|
+
def decode(exe)
|
57
|
+
super(exe)
|
58
|
+
@raw_offset = exe.encoded.ptr
|
59
|
+
@edata = exe.encoded[exe.encoded.ptr, @payload_len]
|
60
|
+
exe.encoded.ptr += @payload_len
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_accessor :endianness
|
65
|
+
|
66
|
+
def encode_u4(val) Expression[val].encode(:u32, @endianness) end
|
67
|
+
def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
|
68
|
+
def sizeof_u4 ; 4 ; end
|
69
|
+
def encode_uleb(val, signed=false)
|
70
|
+
v = val
|
71
|
+
out = EncodedData.new
|
72
|
+
while v > 0x7f or v < -0x40 or (signed and v > 0x3f)
|
73
|
+
out << Expression[0x80 | (v&0x7f)].encode(:u8, @endianness)
|
74
|
+
v >>= 7
|
75
|
+
end
|
76
|
+
out << Expression[v & 0x7f].encode(:u8, @endianness)
|
77
|
+
end
|
78
|
+
def decode_uleb(ed = @encoded, signed=false)
|
79
|
+
v = s = 0
|
80
|
+
while s < 10*7
|
81
|
+
b = ed.read(1).unpack('C').first.to_i
|
82
|
+
v |= (b & 0x7f) << s
|
83
|
+
s += 7
|
84
|
+
break if (b&0x80) == 0
|
85
|
+
end
|
86
|
+
v = Expression.make_signed(v, s) if signed
|
87
|
+
v
|
88
|
+
end
|
89
|
+
def encode_sleb(val) encode_uleb(val, true) end
|
90
|
+
def decode_sleb(ed = @encoded) decode_uleb(ed, true) end
|
91
|
+
attr_accessor :header, :modules, :type, :import, :function_signature,
|
92
|
+
:table, :memory, :global, :export, :start_function_index,
|
93
|
+
:element, :function_body, :data, :code_info
|
94
|
+
|
95
|
+
def initialize(endianness=:little)
|
96
|
+
@endianness = endianness
|
97
|
+
@encoded = EncodedData.new
|
98
|
+
super()
|
99
|
+
end
|
100
|
+
|
101
|
+
def decode_type(edata=@encoded)
|
102
|
+
form = decode_sleb(edata)
|
103
|
+
type = TYPE[form] || "unk_type_#{form}"
|
104
|
+
if type == 'func'
|
105
|
+
type = { :params => [], :ret => [] }
|
106
|
+
decode_uleb(edata).times {
|
107
|
+
type[:params] << decode_type(edata)
|
108
|
+
}
|
109
|
+
decode_uleb(edata).times {
|
110
|
+
type[:ret] << decode_type(edata)
|
111
|
+
}
|
112
|
+
end
|
113
|
+
type
|
114
|
+
end
|
115
|
+
|
116
|
+
# return the nth global
|
117
|
+
# use the @global array and the @import array
|
118
|
+
def get_global_nr(nr)
|
119
|
+
glob_imports = @import.to_a.find_all { |i| i[:kind] == 'global' }
|
120
|
+
return glob_imports[nr] if nr < glob_imports.length
|
121
|
+
nr -= glob_imports.length
|
122
|
+
@global[nr]
|
123
|
+
end
|
124
|
+
|
125
|
+
# return the nth function body
|
126
|
+
# use the @function_body array and the @import array
|
127
|
+
def get_function_nr(nr)
|
128
|
+
func_imports = @import.to_a.find_all { |i| i[:kind] == 'function' }
|
129
|
+
return func_imports[nr] if nr < func_imports.length
|
130
|
+
nr -= func_imports.length
|
131
|
+
@function_body[nr]
|
132
|
+
end
|
133
|
+
|
134
|
+
def type_to_s(t)
|
135
|
+
return t unless t.kind_of?(::Hash)
|
136
|
+
(t[:ret].map { |tt| type_to_s(tt) }.join(', ') << ' f(' << t[:params].map { |tt| type_to_s(tt) }.join(', ') << ')').strip
|
137
|
+
end
|
138
|
+
|
139
|
+
def decode_limits(edata=@encoded)
|
140
|
+
flags = decode_uleb(edata)
|
141
|
+
out = { :initial_size => decode_uleb(edata) }
|
142
|
+
out[:maximum] = decode_uleb(edata) if flags & 1
|
143
|
+
out
|
144
|
+
end
|
145
|
+
|
146
|
+
# wtf
|
147
|
+
# read wasm bytecode until reaching the end opcode
|
148
|
+
# return the byte offset
|
149
|
+
def read_code_until_end(m=nil)
|
150
|
+
if m
|
151
|
+
raw_offset = m.raw_offset + m.edata.ptr
|
152
|
+
edata = m.edata
|
153
|
+
else
|
154
|
+
edata = @encoded
|
155
|
+
end
|
156
|
+
|
157
|
+
while op = edata.decode_imm(:u8, @endianness)
|
158
|
+
case op
|
159
|
+
when 0xb
|
160
|
+
# end opcode
|
161
|
+
return raw_offset
|
162
|
+
when 0xe
|
163
|
+
# indirect branch wtf
|
164
|
+
decode_uleb(edata).times { decode_uleb(edata) }
|
165
|
+
decode_uleb(edata)
|
166
|
+
when 0x43
|
167
|
+
edata.read(4)
|
168
|
+
when 0x44
|
169
|
+
edata.read(8)
|
170
|
+
else
|
171
|
+
OPCODE_IMM_COUNT[op].times { decode_uleb(edata) }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
raw_offset
|
175
|
+
end
|
176
|
+
|
177
|
+
def decode_header
|
178
|
+
@header = Header.decode(self)
|
179
|
+
@modules = []
|
180
|
+
end
|
181
|
+
|
182
|
+
def decode
|
183
|
+
decode_header
|
184
|
+
while @encoded.ptr < @encoded.length
|
185
|
+
@modules << Module.decode(self)
|
186
|
+
end
|
187
|
+
@modules.each { |m|
|
188
|
+
@encoded.add_export(new_label("module_#{m.id}"), m.raw_offset)
|
189
|
+
f = "decode_module_#{m.id.to_s.downcase}"
|
190
|
+
send(f, m) if respond_to?(f)
|
191
|
+
}
|
192
|
+
func_imports = @import.to_a.find_all { |i| i[:kind] == 'function' }
|
193
|
+
export.to_a.each { |e|
|
194
|
+
next if e[:kind] != 'function' # TODO resolve init_offset for globals etc?
|
195
|
+
idx = e[:index] - func_imports.length
|
196
|
+
next if not fb = function_body.to_a[idx]
|
197
|
+
@encoded.add_export(new_label(e[:field]), fb[:init_offset], true)
|
198
|
+
}
|
199
|
+
# bytecode start addr => { :local_var => [], :params => [], :ret => [] }
|
200
|
+
# :local_var absent for external code (imported funcs)
|
201
|
+
@code_info = {}
|
202
|
+
import.to_a.each { |i|
|
203
|
+
next unless i[:kind] == 'function'
|
204
|
+
@code_info["#{i[:module]}_#{i[:field]}"] = { :params => i[:type][:params], :ret => i[:type][:ret] }
|
205
|
+
}
|
206
|
+
function_body.to_a.each { |fb|
|
207
|
+
@code_info[fb[:init_offset]] = { :local_var => fb[:local_var], :params => fb[:type][:params], :ret => fb[:type][:ret] }
|
208
|
+
}
|
209
|
+
global_idx = import.to_a.find_all { |i| i[:kind] == 'global' }.length - 1
|
210
|
+
global.to_a.each { |g|
|
211
|
+
@code_info[g[:init_offset]] = { :local_var => [], :params => [], :ret => [g[:type]] }
|
212
|
+
@encoded.add_export new_label("global_#{global_idx += 1}_init"), g[:init_offset]
|
213
|
+
}
|
214
|
+
element.to_a.each { |e|
|
215
|
+
@code_info[e[:init_offset]] = { :local_var => [], :params => [], :ret => ['i32'] }
|
216
|
+
}
|
217
|
+
data.to_a.each { |d|
|
218
|
+
@code_info[d[:init_offset]] = { :local_var => [], :params => [], :ret => ['i32'] }
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
def decode_module_type(m)
|
223
|
+
@type = []
|
224
|
+
decode_uleb(m.edata).times {
|
225
|
+
@type << decode_type(m.edata)
|
226
|
+
}
|
227
|
+
end
|
228
|
+
|
229
|
+
def decode_module_import(m)
|
230
|
+
@import = []
|
231
|
+
decode_uleb(m.edata).times {
|
232
|
+
i = {}
|
233
|
+
i[:module] = m.edata.read(decode_uleb(m.edata))
|
234
|
+
i[:field] = m.edata.read(decode_uleb(m.edata))
|
235
|
+
kind = decode_uleb(m.edata)
|
236
|
+
i[:kind] = EXTERNAL_KIND[kind] || kind
|
237
|
+
case i[:kind]
|
238
|
+
when 'function'
|
239
|
+
i[:type] = @type[decode_uleb(m.edata)] # XXX keep index only, in case @type is not yet known ?
|
240
|
+
when 'table'
|
241
|
+
i[:type] = decode_type(m.edata)
|
242
|
+
i[:limits] = decode_limits(m.edata)
|
243
|
+
when 'memory'
|
244
|
+
i[:limits] = decode_limits(m.edata)
|
245
|
+
when 'global'
|
246
|
+
i[:type] = decode_type(m.edata)
|
247
|
+
i[:mutable] = decode_uleb(m.edata)
|
248
|
+
end
|
249
|
+
@import << i
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
def decode_module_function(m)
|
254
|
+
@function_signature = []
|
255
|
+
idx = 0
|
256
|
+
decode_uleb(m.edata).times {
|
257
|
+
@function_signature << @type[decode_uleb(m.edata)]
|
258
|
+
@function_body[idx][:type] = @function_signature[idx] if function_body
|
259
|
+
idx += 1
|
260
|
+
}
|
261
|
+
end
|
262
|
+
|
263
|
+
def decode_module_table(m)
|
264
|
+
@table = []
|
265
|
+
decode_uleb(m.edata).times {
|
266
|
+
@table << { :type => decode_type(m.edata), :limits => decode_limits(m.edata) }
|
267
|
+
}
|
268
|
+
end
|
269
|
+
|
270
|
+
def decode_module_memory(m)
|
271
|
+
@memory = []
|
272
|
+
decode_uleb(m.edata).times {
|
273
|
+
@memory << { :limits => decode_limits(m.edata) }
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
def decode_module_global(m)
|
278
|
+
@global = []
|
279
|
+
decode_uleb(m.edata).times {
|
280
|
+
@global << { :type => decode_type(m.edata), :mutable => decode_uleb(m.edata), :init_offset => read_code_until_end(m) }
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
def decode_module_export(m)
|
285
|
+
@export = []
|
286
|
+
decode_uleb(m.edata).times {
|
287
|
+
flen = decode_uleb(m.edata)
|
288
|
+
fld = m.edata.read(flen)
|
289
|
+
kind = decode_uleb(m.edata)
|
290
|
+
kind = EXTERNAL_KIND[kind] || kind
|
291
|
+
index = decode_uleb(m.edata)
|
292
|
+
@export << { :field => fld, :kind => kind, :index => index }
|
293
|
+
}
|
294
|
+
end
|
295
|
+
|
296
|
+
def decode_module_start(m)
|
297
|
+
@start_function_index = decode_uleb(m.edata)
|
298
|
+
end
|
299
|
+
|
300
|
+
def decode_module_element(m)
|
301
|
+
@element = []
|
302
|
+
decode_uleb(m.edata).times {
|
303
|
+
seg = { :table_index => decode_uleb(m.edata),
|
304
|
+
:init_offset => read_code_until_end(m),
|
305
|
+
:elems => [] }
|
306
|
+
decode_uleb(m.edata).times {
|
307
|
+
seg[:elems] << decode_uleb(m.edata)
|
308
|
+
}
|
309
|
+
@element << seg
|
310
|
+
@encoded.add_export new_label("element_#{@element.length-1}_init_addr"), @element.last[:init_offset]
|
311
|
+
}
|
312
|
+
end
|
313
|
+
|
314
|
+
def decode_module_code(m)
|
315
|
+
@function_body = []
|
316
|
+
idx = 0
|
317
|
+
decode_uleb(m.edata).times {
|
318
|
+
local_vars = []
|
319
|
+
body_size = decode_uleb(m.edata) # size of local defs + bytecode (in bytes)
|
320
|
+
next_ptr = m.edata.ptr + body_size
|
321
|
+
decode_uleb(m.edata).times { # nr of local vars types
|
322
|
+
n_vars_of_this_type = decode_uleb(m.edata) # nr of local vars of this type
|
323
|
+
type = decode_type(m.edata) # actual type
|
324
|
+
n_vars_of_this_type.times {
|
325
|
+
local_vars << type
|
326
|
+
}
|
327
|
+
}
|
328
|
+
code_offset = m.raw_offset + m.edata.ptr # bytecode comes next
|
329
|
+
m.edata.ptr = next_ptr
|
330
|
+
@function_body << { :local_var => local_vars, :init_offset => code_offset }
|
331
|
+
@function_body.last[:type] = @function_signature[idx] if function_signature
|
332
|
+
@encoded.add_export new_label("function_#{@function_body.length-1}"), @function_body.last[:init_offset]
|
333
|
+
idx += 1
|
334
|
+
}
|
335
|
+
end
|
336
|
+
|
337
|
+
def decode_module_data(m)
|
338
|
+
@data = []
|
339
|
+
decode_uleb(m.edata).times {
|
340
|
+
idx = decode_uleb(m.edata)
|
341
|
+
initoff = read_code_until_end(m)
|
342
|
+
data_len = decode_uleb(m.edata)
|
343
|
+
data_start_ptr = m.raw_offset + m.edata.ptr
|
344
|
+
data = m.edata.read(data_len)
|
345
|
+
data_end_ptr = m.raw_offset + m.edata.ptr
|
346
|
+
|
347
|
+
@data << { :index => idx, :init_offset => initoff, :data => data }
|
348
|
+
@encoded.add_export new_label("data_#{@data.length-1}_init_addr"), initoff
|
349
|
+
@encoded.add_export new_label("data_#{@data.length-1}_start"), data_start_ptr
|
350
|
+
@encoded.add_export new_label("data_#{@data.length-1}_end"), data_end_ptr
|
351
|
+
}
|
352
|
+
end
|
353
|
+
|
354
|
+
def decode_module_0(m)
|
355
|
+
# id == 0 for not well-known modules
|
356
|
+
# the module name is encoded at start of payload (uleb name length + actual name)
|
357
|
+
m.name = m.edata.read(decode_uleb(m.edata))
|
358
|
+
f = "decode_module_0_#{m.name.downcase}"
|
359
|
+
send(f, m) if respond_to?(f)
|
360
|
+
end
|
361
|
+
|
362
|
+
def decode_module_0_name(m)
|
363
|
+
# TODO parse stored names of local variables etc
|
364
|
+
end
|
365
|
+
|
366
|
+
def cpu_from_headers
|
367
|
+
WebAsm.new(self)
|
368
|
+
end
|
369
|
+
|
370
|
+
def init_disassembler
|
371
|
+
dasm = super()
|
372
|
+
function_body.to_a.each { |fb|
|
373
|
+
v = []
|
374
|
+
fb[:local_var].map { |lv| type_to_s(lv) }.each { |lv|
|
375
|
+
v.last && lv == v.last.last ? v.last << lv : v << [lv]
|
376
|
+
}
|
377
|
+
v.map! { |sublist|
|
378
|
+
# i32 ; i32 ; i32 ; i32 ; i32 ; i32 ; i64 -> 5 * i32 ; i64
|
379
|
+
sublist.length > 3 ? "#{sublist.length} * #{sublist.first}" : sublist.join(' ; ')
|
380
|
+
}
|
381
|
+
dasm.add_comment fb[:init_offset], "proto: #{fb[:type] ? type_to_s(fb[:type]) : 'unknown'}"
|
382
|
+
dasm.add_comment fb[:init_offset], "vars: #{v.join(' ; ')}"
|
383
|
+
}
|
384
|
+
global.to_a.each { |g|
|
385
|
+
dasm.add_comment g[:init_offset], "type: #{type_to_s(g[:type])}"
|
386
|
+
}
|
387
|
+
dasm.function[:default] = @cpu.disassembler_default_func
|
388
|
+
dasm
|
389
|
+
end
|
390
|
+
|
391
|
+
def each_section
|
392
|
+
yield @encoded, 0
|
393
|
+
end
|
394
|
+
|
395
|
+
def get_default_entrypoints
|
396
|
+
global.to_a.map { |g| g[:init_offset] } +
|
397
|
+
element.to_a.map { |e| e[:init_offset] } +
|
398
|
+
data.to_a.map { |d| d[:init_offset] } +
|
399
|
+
function_body.to_a.map { |f| f[:init_offset] }
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|