metasm 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|