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
|
@@ -271,7 +271,16 @@ class Expression
|
|
|
271
271
|
def encode(type, endianness, backtrace=nil)
|
|
272
272
|
case val = reduce
|
|
273
273
|
when Integer; EncodedData.new Expression.encode_imm(val, type, endianness, backtrace)
|
|
274
|
-
else
|
|
274
|
+
else
|
|
275
|
+
str = case INT_SIZE[type]
|
|
276
|
+
when 8; "\0"
|
|
277
|
+
when 16; "\0\0"
|
|
278
|
+
when 32; "\0\0\0\0"
|
|
279
|
+
when 64; "\0\0\0\0\0\0\0\0"
|
|
280
|
+
else [0].pack('C')*(INT_SIZE[type]/8)
|
|
281
|
+
end
|
|
282
|
+
str = str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
|
|
283
|
+
EncodedData.new(str, :reloc => {0 => Relocation.new(self, type, endianness, backtrace)})
|
|
275
284
|
end
|
|
276
285
|
end
|
|
277
286
|
|
|
@@ -58,7 +58,7 @@ class AOut < ExeFormat
|
|
|
58
58
|
class Relocation < SerialStruct
|
|
59
59
|
word :address
|
|
60
60
|
bitfield :word, 0 => :symbolnum, 24 => :pcrel, 25 => :length,
|
|
61
|
-
|
|
61
|
+
27 => :extern, 28 => :baserel, 29 => :jmptable, 30 => :relative, 31 => :rtcopy
|
|
62
62
|
fld_enum :length, 0 => 1, 1 => 2, 2 => 4, 3 => 8
|
|
63
63
|
fld_default :length, 4
|
|
64
64
|
end
|
|
@@ -68,7 +68,7 @@ class AOut < ExeFormat
|
|
|
68
68
|
bitfield :byte, 0 => :extern, 1 => :type, 5 => :stab
|
|
69
69
|
byte :other
|
|
70
70
|
half :desc
|
|
71
|
-
|
|
71
|
+
word :value
|
|
72
72
|
attr_accessor :name
|
|
73
73
|
|
|
74
74
|
def decode(aout, strings=nil)
|
|
@@ -93,6 +93,9 @@ class AOut < ExeFormat
|
|
|
93
93
|
def encode_byte(w) Expression[w].encode(:u8 , @endianness) end
|
|
94
94
|
def encode_half(w) Expression[w].encode(:u16, @endianness) end
|
|
95
95
|
def encode_word(w) Expression[w].encode(:u32, @endianness) end
|
|
96
|
+
def sizeof_byte ; 1 ; end
|
|
97
|
+
def sizeof_half ; 2 ; end
|
|
98
|
+
def sizeof_word ; 4 ; end
|
|
96
99
|
|
|
97
100
|
def initialize(cpu = nil)
|
|
98
101
|
@endianness = cpu ? cpu.endianness : :little
|
|
@@ -119,11 +122,11 @@ class AOut < ExeFormat
|
|
|
119
122
|
|
|
120
123
|
@data = EncodedData.new << @encoded.read(@header.data)
|
|
121
124
|
|
|
122
|
-
textrel = @encoded.read @header.trsz
|
|
123
|
-
datarel = @encoded.read @header.drsz
|
|
124
|
-
syms = @encoded.read @header.syms
|
|
125
|
-
strings = @encoded.read
|
|
126
125
|
# TODO
|
|
126
|
+
#textrel = @encoded.read @header.trsz
|
|
127
|
+
#datarel = @encoded.read @header.drsz
|
|
128
|
+
#syms = @encoded.read @header.syms
|
|
129
|
+
#strings = @encoded.read
|
|
127
130
|
end
|
|
128
131
|
|
|
129
132
|
def encode
|
|
@@ -58,6 +58,7 @@ register_signature("\xca\xfe\xba\xbe") { UniversalBinary }
|
|
|
58
58
|
register_signature("dex\n") { DEX }
|
|
59
59
|
register_signature("dey\n") { DEY }
|
|
60
60
|
register_signature("\xfa\x70\x0e\x1f") { FatELF }
|
|
61
|
+
register_signature("\x50\x4b\x03\x04") { ZIP }
|
|
61
62
|
register_signature('Metasm.dasm') { Disassembler }
|
|
62
63
|
|
|
63
64
|
# replacement for AutoExe where #load defaults to a Shellcode of the specified CPU
|
|
@@ -9,6 +9,7 @@ require 'metasm/decode'
|
|
|
9
9
|
|
|
10
10
|
module Metasm
|
|
11
11
|
# BFLT is the binary flat format used by the uClinux
|
|
12
|
+
# from examining a v4 binary, it looks like the header is discarded and the file is mapped from 0x40 to memory address 0 (wrt relocations)
|
|
12
13
|
class Bflt < ExeFormat
|
|
13
14
|
MAGIC = 'bFLT'
|
|
14
15
|
FLAGS = { 1 => 'RAM', 2 => 'GOTPIC', 4 => 'GZIP' }
|
|
@@ -29,13 +30,20 @@ class Bflt < ExeFormat
|
|
|
29
30
|
when MAGIC
|
|
30
31
|
else raise InvalidExeFormat, "Bad bFLT signature #@magic"
|
|
31
32
|
end
|
|
33
|
+
|
|
34
|
+
if @rev >= 0x01000000 and (@rev & 0x00f0ffff) == 0
|
|
35
|
+
puts "Bflt: probable wrong endianness, retrying" if $VERBOSE
|
|
36
|
+
exe.endianness = { :big => :little, :little => :big }[exe.endianness]
|
|
37
|
+
exe.encoded.ptr -= 4*16
|
|
38
|
+
super(exe)
|
|
39
|
+
end
|
|
32
40
|
end
|
|
33
41
|
|
|
34
42
|
def set_default_values(exe)
|
|
35
43
|
@magic ||= MAGIC
|
|
36
44
|
@rev ||= 4
|
|
37
45
|
@entry ||= 0x40
|
|
38
|
-
@data_start ||=
|
|
46
|
+
@data_start ||= 0x40 + exe.text.length if exe.text
|
|
39
47
|
@data_end ||= @data_start + exe.data.data.length if exe.data
|
|
40
48
|
@bss_end ||= @data_start + exe.data.length if exe.data
|
|
41
49
|
@stack_size ||= 0x1000
|
|
@@ -49,7 +57,9 @@ class Bflt < ExeFormat
|
|
|
49
57
|
|
|
50
58
|
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
|
|
51
59
|
def encode_word(w) Expression[w].encode(:u32, @endianness) end
|
|
60
|
+
def sizeof_word ; 4 ; end
|
|
52
61
|
|
|
62
|
+
attr_accessor :endianness
|
|
53
63
|
def initialize(cpu = nil)
|
|
54
64
|
@endianness = cpu ? cpu.endianness : :little
|
|
55
65
|
@header = Header.new
|
|
@@ -61,17 +71,17 @@ class Bflt < ExeFormat
|
|
|
61
71
|
def decode_header
|
|
62
72
|
@encoded.ptr = 0
|
|
63
73
|
@header.decode(self)
|
|
74
|
+
@encoded.add_export(new_label('entrypoint'), @header.entry)
|
|
64
75
|
end
|
|
65
76
|
|
|
66
77
|
def decode
|
|
67
78
|
decode_header
|
|
68
79
|
|
|
69
|
-
@
|
|
70
|
-
@
|
|
71
|
-
@data
|
|
72
|
-
@data.virtsize += (@header.bss_end - @header.data_end)
|
|
80
|
+
@text = @encoded[0x40...@header.data_start]
|
|
81
|
+
@data = @encoded[@header.data_start...@header.data_end]
|
|
82
|
+
@data.virtsize += @header.bss_end - @header.data_end
|
|
73
83
|
|
|
74
|
-
if @header.flags.include?
|
|
84
|
+
if @header.flags.include?('GZIP')
|
|
75
85
|
# TODO gzip
|
|
76
86
|
raise 'bFLT decoder: gzip format not supported'
|
|
77
87
|
end
|
|
@@ -79,7 +89,7 @@ class Bflt < ExeFormat
|
|
|
79
89
|
@reloc = []
|
|
80
90
|
@encoded.ptr = @header.reloc_start
|
|
81
91
|
@header.reloc_count.times { @reloc << decode_word }
|
|
82
|
-
if @header.
|
|
92
|
+
if @header.rev == 2
|
|
83
93
|
@reloc.map! { |r| r & 0x3fff_ffff }
|
|
84
94
|
end
|
|
85
95
|
|
|
@@ -87,32 +97,29 @@ class Bflt < ExeFormat
|
|
|
87
97
|
end
|
|
88
98
|
|
|
89
99
|
def decode_interpret_relocs
|
|
100
|
+
textsz = @header.data_start-0x40
|
|
90
101
|
@reloc.each { |r|
|
|
91
102
|
# where the reloc is
|
|
92
|
-
if r
|
|
103
|
+
if r < textsz
|
|
93
104
|
section = @text
|
|
94
|
-
|
|
95
|
-
elsif r >= @header.data_start and r < @header.data_end
|
|
96
|
-
section = @data
|
|
97
|
-
base = @header.data_start
|
|
105
|
+
off = section.ptr = r
|
|
98
106
|
else
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
section = @data
|
|
108
|
+
off = section.ptr = r-textsz
|
|
101
109
|
end
|
|
102
110
|
|
|
103
111
|
# what it points to
|
|
104
|
-
section.ptr = r-base
|
|
105
112
|
target = decode_word(section)
|
|
106
|
-
if target
|
|
107
|
-
target = label_at(@text, target
|
|
108
|
-
elsif target
|
|
109
|
-
target = label_at(@data, target
|
|
113
|
+
if target < textsz
|
|
114
|
+
target = label_at(@text, target, "xref_#{Expression[target]}")
|
|
115
|
+
elsif target < @header.bss_end-0x40
|
|
116
|
+
target = label_at(@data, target-textsz, "xref_#{Expression[target]}")
|
|
110
117
|
else
|
|
111
|
-
puts "out of bounds reloc target at #{Expression[r]}" if $VERBOSE
|
|
118
|
+
puts "out of bounds reloc target #{Expression[target]} at #{Expression[r]}" if $VERBOSE
|
|
112
119
|
next
|
|
113
120
|
end
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
section.reloc[off] = Relocation.new(Expression[target], :u32, @endianness)
|
|
116
123
|
}
|
|
117
124
|
end
|
|
118
125
|
|
|
@@ -127,8 +134,8 @@ class Bflt < ExeFormat
|
|
|
127
134
|
|
|
128
135
|
@encoded = EncodedData.new
|
|
129
136
|
@encoded << @header.encode(self)
|
|
130
|
-
|
|
131
|
-
binding = @text.binding(
|
|
137
|
+
|
|
138
|
+
binding = @text.binding(0x40).merge(@data.binding(@header.data_start))
|
|
132
139
|
@encoded << @text << @data.data
|
|
133
140
|
@encoded.fixup! binding
|
|
134
141
|
@encoded.reloc.clear
|
|
@@ -143,7 +150,7 @@ class Bflt < ExeFormat
|
|
|
143
150
|
mapaddr = new_label('mapaddr')
|
|
144
151
|
binding = @text.binding(mapaddr).merge(@data.binding(mapaddr))
|
|
145
152
|
[@text, @data].each { |section|
|
|
146
|
-
base =
|
|
153
|
+
base = 0x40 # XXX maybe 0 ?
|
|
147
154
|
base = @header.data_start || base+@text.length if section == @data
|
|
148
155
|
section.reloc.each { |o, r|
|
|
149
156
|
if r.endianness == @endianness and [:u32, :a32, :i32].include? r.type and
|
|
@@ -167,7 +174,16 @@ class Bflt < ExeFormat
|
|
|
167
174
|
case instr.raw.downcase
|
|
168
175
|
when '.text'; @cursource = @textsrc
|
|
169
176
|
when '.data'; @cursource = @datasrc
|
|
170
|
-
|
|
177
|
+
when '.entrypoint'
|
|
178
|
+
# ".entrypoint <somelabel/expression>" or ".entrypoint" (here)
|
|
179
|
+
@lexer.skip_space
|
|
180
|
+
if tok = @lexer.nexttok and tok.type == :string
|
|
181
|
+
raise instr if not entrypoint = Expression.parse(@lexer)
|
|
182
|
+
else
|
|
183
|
+
entrypoint = new_label('entrypoint')
|
|
184
|
+
@cursource << Label.new(entrypoint, instr.backtrace.dup)
|
|
185
|
+
end
|
|
186
|
+
@header.entry = entrypoint
|
|
171
187
|
else super(instr)
|
|
172
188
|
end
|
|
173
189
|
end
|
|
@@ -181,9 +197,23 @@ class Bflt < ExeFormat
|
|
|
181
197
|
self
|
|
182
198
|
end
|
|
183
199
|
|
|
200
|
+
def get_default_entrypoints
|
|
201
|
+
['entrypoint']
|
|
202
|
+
end
|
|
203
|
+
|
|
184
204
|
def each_section
|
|
185
|
-
yield @text,
|
|
186
|
-
yield @data, @header.data_start
|
|
205
|
+
yield @text, 0
|
|
206
|
+
yield @data, @header.data_start - @header.entry
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def section_info
|
|
210
|
+
[['.text', 0, @text.length, 'rx'],
|
|
211
|
+
['.data', @header.data_addr-0x40, @data.data.length, 'rw'],
|
|
212
|
+
['.bss', @header.data_end-0x40, @data.length-@data.data.length, 'rw']]
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def module_symbols
|
|
216
|
+
['entrypoint', @header.entry-0x40]
|
|
187
217
|
end
|
|
188
218
|
end
|
|
189
219
|
end
|
|
@@ -81,7 +81,7 @@ class COFF < ExeFormat
|
|
|
81
81
|
11 => 'UNION_MEMBER', 12 => 'UNION_TAG', 13 => 'TYPEDEF', 14 => 'UNDEF_STATIC',
|
|
82
82
|
15 => 'ENUM_TAG', 16 => 'ENUM_MEMBER', 17 => 'REG_PARAM', 18 => 'BIT_FIELD',
|
|
83
83
|
100 => 'BLOCK', 101 => 'FUNCTION', 102 => 'END_STRUCT',
|
|
84
|
-
|
|
84
|
+
103 => 'FILE', 104 => 'SECTION', 105 => 'WEAK_EXT',
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
DEBUG_TYPE = { 0 => 'UNKNOWN', 1 => 'COFF', 2 => 'CODEVIEW', 3 => 'FPO', 4 => 'MISC',
|
|
@@ -140,7 +140,7 @@ class COFF < ExeFormat
|
|
|
140
140
|
bytes :link_ver_maj, :link_ver_min
|
|
141
141
|
words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code
|
|
142
142
|
# base_of_data does not exist in 64-bit
|
|
143
|
-
new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, 0)
|
|
143
|
+
new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, lambda { |exe, hdr| exe.bitsize != 64 ? 4 : 0 }, 0)
|
|
144
144
|
# NT-specific fields
|
|
145
145
|
xword :image_base
|
|
146
146
|
words :sect_align, :file_align
|
|
@@ -264,7 +264,7 @@ class COFF < ExeFormat
|
|
|
264
264
|
|
|
265
265
|
class TLSDirectory < SerialStruct
|
|
266
266
|
xwords :start_va, :end_va, :index_addr, :callback_p
|
|
267
|
-
|
|
267
|
+
words :zerofill_sz, :characteristics
|
|
268
268
|
|
|
269
269
|
attr_accessor :callbacks
|
|
270
270
|
end
|
|
@@ -413,6 +413,11 @@ class COFF < ExeFormat
|
|
|
413
413
|
end
|
|
414
414
|
|
|
415
415
|
def shortname; 'coff'; end
|
|
416
|
+
|
|
417
|
+
def sizeof_byte ; 1 ; end
|
|
418
|
+
def sizeof_half ; 2 ; end
|
|
419
|
+
def sizeof_word ; 4 ; end
|
|
420
|
+
def sizeof_xword ; @bitsize == 32 ? 4 : 8 ; end
|
|
416
421
|
end
|
|
417
422
|
|
|
418
423
|
# the COFF archive file format
|
|
@@ -448,6 +453,9 @@ class COFFArchive < ExeFormat
|
|
|
448
453
|
def member(name)
|
|
449
454
|
@members.find { |m| m.name == name }
|
|
450
455
|
end
|
|
456
|
+
|
|
457
|
+
def sizeof_half ; 2 ; end
|
|
458
|
+
def sizeof_word ; 4 ; end
|
|
451
459
|
end
|
|
452
460
|
end
|
|
453
461
|
|
|
@@ -17,13 +17,15 @@ class COFF
|
|
|
17
17
|
# decodes a COFF optional header from coff.cursection
|
|
18
18
|
# also decodes directories in coff.directory
|
|
19
19
|
def decode(coff)
|
|
20
|
-
return set_default_values(coff) if coff.header.size_opthdr == 0
|
|
20
|
+
return set_default_values(coff) if coff.header.size_opthdr == 0 and not coff.header.characteristics.include?('EXECUTABLE_IMAGE')
|
|
21
|
+
off = coff.curencoded.ptr
|
|
21
22
|
super(coff)
|
|
23
|
+
nrva = (coff.header.size_opthdr - (coff.curencoded.ptr - off)) / 8
|
|
24
|
+
nrva = @numrva if nrva < 0
|
|
22
25
|
|
|
23
|
-
nrva
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
nrva = DIRECTORIES.length
|
|
26
|
+
if nrva > DIRECTORIES.length or nrva != @numrva
|
|
27
|
+
puts "W: COFF: Weird directories count #{@numrva}" if $VERBOSE
|
|
28
|
+
nrva = DIRECTORIES.length if nrva > DIRECTORIES.length
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
coff.directory = {}
|
|
@@ -171,17 +173,17 @@ class COFF
|
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
class ResourceDirectory
|
|
174
|
-
def decode(coff, edata = coff.curencoded, startptr = edata.ptr)
|
|
176
|
+
def decode(coff, edata = coff.curencoded, startptr = edata.ptr, maxdepth=3)
|
|
175
177
|
super(coff, edata)
|
|
176
178
|
|
|
177
179
|
@entries = []
|
|
178
180
|
|
|
179
181
|
nrnames = @nr_names if $DEBUG
|
|
180
182
|
(@nr_names+@nr_id).times {
|
|
181
|
-
|
|
183
|
+
e = Entry.new
|
|
182
184
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
+
e_id = coff.decode_word(edata)
|
|
186
|
+
e_ptr = coff.decode_word(edata)
|
|
185
187
|
|
|
186
188
|
if not e_id.kind_of? Integer or not e_ptr.kind_of? Integer
|
|
187
189
|
puts 'W: COFF: relocs in the rsrc directory?' if $VERBOSE
|
|
@@ -213,10 +215,12 @@ class COFF
|
|
|
213
215
|
e.subdir_p = e_ptr & 0x7fff_ffff
|
|
214
216
|
if startptr + e.subdir_p >= edata.length
|
|
215
217
|
puts 'W: COFF: invalid resource structure: directory too far' if $VERBOSE
|
|
216
|
-
|
|
218
|
+
elsif maxdepth > 0
|
|
217
219
|
edata.ptr = startptr + e.subdir_p
|
|
218
220
|
e.subdir = ResourceDirectory.new
|
|
219
|
-
e.subdir.decode coff, edata, startptr
|
|
221
|
+
e.subdir.decode coff, edata, startptr, maxdepth-1
|
|
222
|
+
else
|
|
223
|
+
puts 'W: COFF: recursive resource section' if $VERBOSE
|
|
220
224
|
end
|
|
221
225
|
else
|
|
222
226
|
e.dataentry_p = e_ptr
|
|
@@ -244,7 +248,8 @@ class COFF
|
|
|
244
248
|
|
|
245
249
|
decode_tllv = lambda { |ed, state|
|
|
246
250
|
sptr = ed.ptr
|
|
247
|
-
len, vlen
|
|
251
|
+
len, vlen = coff.decode_half(ed), coff.decode_half(ed)
|
|
252
|
+
coff.decode_half(ed) # type
|
|
248
253
|
tagname = ''
|
|
249
254
|
while c = coff.decode_half(ed) and c != 0
|
|
250
255
|
tagname << (c&255)
|
|
@@ -273,7 +278,7 @@ class COFF
|
|
|
273
278
|
when :str
|
|
274
279
|
val = ed.read(vlen*2).unpack('v*')
|
|
275
280
|
val.pop if val[-1] == 0
|
|
276
|
-
val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
|
|
281
|
+
val = val.pack('C*') if val.all? { |c_| c_ > 0 and c_ < 256 }
|
|
277
282
|
vers[tagname] = val
|
|
278
283
|
when :var
|
|
279
284
|
val = ed.read(vlen).unpack('V*')
|
|
@@ -426,8 +431,7 @@ class COFF
|
|
|
426
431
|
def sect_at_rva(rva)
|
|
427
432
|
return if not rva or rva <= 0
|
|
428
433
|
if sections and not @sections.empty?
|
|
429
|
-
|
|
430
|
-
if s = @sections.find { |s_| s_.virtaddr <= rva and s_.virtaddr + valign[s_.virtsize] > rva }
|
|
434
|
+
if s = @sections.find { |s_| s_.virtaddr <= rva and s_.virtaddr + EncodedData.align_size((s_.virtsize == 0 ? s_.rawsize : s_.virtsize), @optheader.sect_align) > rva }
|
|
431
435
|
s.encoded.ptr = rva - s.virtaddr
|
|
432
436
|
@cursection = s
|
|
433
437
|
elsif rva < @sections.map { |s_| s_.virtaddr }.min
|
|
@@ -479,7 +483,7 @@ class COFF
|
|
|
479
483
|
end
|
|
480
484
|
|
|
481
485
|
def each_section
|
|
482
|
-
if @header.size_opthdr == 0
|
|
486
|
+
if @header.size_opthdr == 0 and not @header.characteristics.include?('EXECUTABLE_IMAGE')
|
|
483
487
|
@sections.each { |s|
|
|
484
488
|
next if not s.encoded
|
|
485
489
|
l = new_label(s.name)
|
|
@@ -490,7 +494,9 @@ class COFF
|
|
|
490
494
|
end
|
|
491
495
|
base = @optheader.image_base
|
|
492
496
|
base = 0 if not base.kind_of? Integer
|
|
493
|
-
|
|
497
|
+
sz = @optheader.headers_size
|
|
498
|
+
sz = EncodedData.align_size(@optheader.image_size, 4096) if @sections.empty?
|
|
499
|
+
yield @encoded[0, sz], base
|
|
494
500
|
@sections.each { |s| yield s.encoded, base + s.virtaddr }
|
|
495
501
|
end
|
|
496
502
|
|
|
@@ -566,8 +572,10 @@ class COFF
|
|
|
566
572
|
# decodes a section content (allows simpler LoadedPE override)
|
|
567
573
|
def decode_section_body(s)
|
|
568
574
|
raw = EncodedData.align_size(s.rawsize, @optheader.file_align)
|
|
569
|
-
virt =
|
|
575
|
+
virt = s.virtsize
|
|
570
576
|
virt = raw = s.rawsize if @header.size_opthdr == 0
|
|
577
|
+
virt = raw if virt == 0
|
|
578
|
+
virt = EncodedData.align_size(virt, @optheader.sect_align)
|
|
571
579
|
s.encoded = @encoded[s.rawaddr, [raw, virt].min] || EncodedData.new
|
|
572
580
|
s.encoded.virtsize = virt
|
|
573
581
|
end
|
|
@@ -634,8 +642,13 @@ class COFF
|
|
|
634
642
|
if ct = @directory['certificate_table']
|
|
635
643
|
@certificates = []
|
|
636
644
|
@cursection = self
|
|
645
|
+
if ct[0] > @encoded.length or ct[1] > @encoded.length - ct[0]
|
|
646
|
+
puts "W: COFF: invalid certificate_table #{'0x%X+0x%0X' % ct}" if $VERBOSE
|
|
647
|
+
ct = [ct[0], 1]
|
|
648
|
+
end
|
|
637
649
|
@encoded.ptr = ct[0]
|
|
638
650
|
off_end = ct[0]+ct[1]
|
|
651
|
+
off_end = @encoded.length if off_end > @encoded.length
|
|
639
652
|
while @encoded.ptr < off_end
|
|
640
653
|
certlen = decode_word
|
|
641
654
|
certrev = decode_half
|
|
@@ -704,6 +717,25 @@ class COFF
|
|
|
704
717
|
end
|
|
705
718
|
end
|
|
706
719
|
|
|
720
|
+
def decode_reloc_amd64(r)
|
|
721
|
+
case r.type
|
|
722
|
+
when 'ABSOLUTE'
|
|
723
|
+
when 'HIGHLOW'
|
|
724
|
+
addr = decode_word
|
|
725
|
+
if s = sect_at_va(addr)
|
|
726
|
+
label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
|
|
727
|
+
Metasm::Relocation.new(Expression[label], :u32, @endianness)
|
|
728
|
+
end
|
|
729
|
+
when 'DIR64'
|
|
730
|
+
addr = decode_xword
|
|
731
|
+
if s = sect_at_va(addr)
|
|
732
|
+
label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
|
|
733
|
+
Metasm::Relocation.new(Expression[label], :u64, @endianness)
|
|
734
|
+
end
|
|
735
|
+
else puts "W: COFF: Unsupported amd64 relocation #{r.inspect}" if $VERBOSE
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
|
|
707
739
|
def decode_debug
|
|
708
740
|
if dd = @directory['debug'] and sect_at_rva(dd[0])
|
|
709
741
|
@debug = []
|
|
@@ -719,11 +751,11 @@ class COFF
|
|
|
719
751
|
def decode_tls
|
|
720
752
|
if @directory['tls_table'] and sect_at_rva(@directory['tls_table'][0])
|
|
721
753
|
@tls = TLSDirectory.decode(self)
|
|
722
|
-
|
|
754
|
+
if s = sect_at_va(@tls.callback_p)
|
|
723
755
|
s.encoded.add_export 'tls_callback_table'
|
|
724
756
|
@tls.callbacks.each_with_index { |cb, i|
|
|
725
757
|
@tls.callbacks[i] = curencoded.add_export "tls_callback_#{i}" if sect_at_rva(cb)
|
|
726
|
-
|
|
758
|
+
}
|
|
727
759
|
end
|
|
728
760
|
end
|
|
729
761
|
end
|
|
@@ -815,6 +847,7 @@ class COFFArchive
|
|
|
815
847
|
ar.encoded.ptr += 1 if @size & 1 == 1
|
|
816
848
|
end
|
|
817
849
|
|
|
850
|
+
# TODO XXX are those actually used ?
|
|
818
851
|
def decode_half ; @encoded.decode_imm(:u16, :big) end
|
|
819
852
|
def decode_word ; @encoded.decode_imm(:u32, :big) end
|
|
820
853
|
|