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.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -17,6 +17,9 @@ class MachO < ExeFormat
17
17
 
18
18
  MAGICS = [MAGIC, CIGAM, MAGIC64, CIGAM64]
19
19
 
20
+ # "a" != "a" lolz!
21
+ MAGICS.each { |s| s.force_encoding('BINARY') } if MAGIC.respond_to?(:force_encoding)
22
+
20
23
  CPU = {
21
24
  1 => 'VAX', 2 => 'ROMP',
22
25
  4 => 'NS32032', 5 => 'NS32332',
@@ -44,7 +47,7 @@ class MachO < ExeFormat
44
47
  3 => 'MMAX_APC_FPU', 4 => 'MMAX_APC_FPA', 5 => 'MMAX_XPC',
45
48
  },
46
49
  'I386' => { 3 => 'ALL', 4 => '486', 4+128 => '486SX',
47
- 0 => 'INTEL_MODEL_ALL', 10 => 'PENTIUM_4',
50
+ 0 => 'INTEL_MODEL_ALL', 10 => 'PENTIUM_4',
48
51
  5 => 'PENT', 0x16 => 'PENTPRO', 0x36 => 'PENTII_M3', 0x56 => 'PENTII_M5',
49
52
  },
50
53
  'MIPS' => { 0 => 'ALL', 1 => 'R2300', 2 => 'R2600', 3 => 'R2800', 4 => 'R2000a', },
@@ -52,6 +55,7 @@ class MachO < ExeFormat
52
55
  'HPPA' => { 0 => 'ALL', 1 => '7100LC', },
53
56
  'ARM' => { 0 => 'ALL', 1 => 'A500_ARCH', 2 => 'A500', 3 => 'A440',
54
57
  4 => 'M4', 5 => 'A680', 6 => 'ARMV6', 9 => 'ARMV7',
58
+ 11 => 'ARMV7S',
55
59
  },
56
60
  'MC88000' => { 0 => 'ALL', 1 => 'MC88100', 2 => 'MC88110', },
57
61
  :wtf => { 0 => 'MC98000_ALL', 1 => 'MC98601', },
@@ -82,7 +86,7 @@ class MachO < ExeFormat
82
86
  0x10 => 'PREBOUND', 0x20 => 'SPLIT_SEGS', 0x40 => 'LAZY_INIT', 0x80 => 'TWOLEVEL',
83
87
  0x100 => 'FORCE_FLAT', 0x200 => 'NOMULTIDEFS', 0x400 => 'NOFIXPREBINDING', 0x800 => 'PREBINDABLE',
84
88
  0x1000 => 'ALLMODSBOUND', 0x2000 => 'SUBSECTIONS_VIA_SYMBOLS', 0x4000 => 'CANONICAL', 0x8000 => 'WEAK_DEFINES',
85
- 0x10000 => 'BINDS_TO_WEAK', 0x20000 => 'ALLOW_STACK_EXECUTION',
89
+ 0x10000 => 'BINDS_TO_WEAK', 0x20000 => 'ALLOW_STACK_EXECUTION', 0x200000 => 'MH_PIE',
86
90
  }
87
91
 
88
92
  SEG_PROT = { 1 => 'READ', 2 => 'WRITE', 4 => 'EXECUTE' }
@@ -96,12 +100,13 @@ class MachO < ExeFormat
96
100
  0x15 => 'SUB_LIBRARY', 0x16 => 'TWOLEVEL_HINTS', 0x17 => 'PREBIND_CKSUM',
97
101
  0x8000_0018 => 'LOAD_WEAK_DYLIB', 0x19 => 'SEGMENT_64', 0x1a => 'ROUTINES_64',
98
102
  0x1b => 'UUID', 0x8000_001c => 'RPATH', 0x1d => 'CODE_SIGNATURE_PTR', 0x1e => 'CODE_SEGMENT_SPLIT_INFO',
103
+ 0x21 => 'ENCRYPTION_INFO',
99
104
  0x8000_001f => 'REEXPORT_DYLIB',
100
105
  #0x8000_0000 => 'REQ_DYLD',
101
106
  }
102
107
 
103
108
  THREAD_FLAVOR = {
104
- 'POWERPC' => {
109
+ 'POWERPC' => {
105
110
  1 => 'THREAD_STATE',
106
111
  2 => 'FLOAT_STATE',
107
112
  3 => 'EXCEPTION_STATE',
@@ -126,6 +131,15 @@ class MachO < ExeFormat
126
131
  SYM_SCOPE = { 0 => 'LOCAL', 1 => 'GLOBAL' }
127
132
  SYM_TYPE = { 0 => 'UNDF', 2/2 => 'ABS', 0xa/2 => 'INDR', 0xe/2 => 'SECT', 0x1e/2 => 'TYPE' }
128
133
  SYM_STAB = { }
134
+ IND_SYM_IDX = { 0x4000_0000 => 'INDIRECT_SYMBOL_ABS', 0x8000_0000 => 'INDIRECT_SYMBOL_LOCAL' }
135
+
136
+ GENERIC_RELOC = { 0 => 'VANILLA', 1 => 'PAIR', 2 => 'SECTDIFF', 3 => 'LOCAL_SECTDIFF', 4 => 'PB_LA_PTR' }
137
+
138
+ SEC_TYPE = {
139
+ 0 => 'REGULAR', 1 => 'ZEROFILL', 2 => 'CSTRING_LITERALS', 3 => '4BYTE_LITERALS',
140
+ 4 => '8BYTE_LITERALS', 5 => 'LITERAL_POINTERS', 6 => 'NON_LAZY_SYMBOL_POINTERS',
141
+ 7 => 'LAZY_SYMBOL_POINTERS', 8 => 'SYMBOL_STUBS', 9 => 'MOD_INIT_FUNC_POINTERS'
142
+ }
129
143
 
130
144
  class SerialStruct < Metasm::SerialStruct
131
145
  new_int_field :xword
@@ -180,7 +194,7 @@ class MachO < ExeFormat
180
194
  def decode(m)
181
195
  super(m)
182
196
  ptr = m.encoded.ptr
183
- if @cmd.kind_of? String and self.class.constants.map { |c| c.to_s }.include? @cmd
197
+ if @cmd.kind_of?(String) and self.class.constants.map { |c| c.to_s }.include?(@cmd)
184
198
  @data = self.class.const_get(@cmd).decode(m)
185
199
  end
186
200
  m.encoded.ptr = ptr + @cmdsize - 8
@@ -193,7 +207,7 @@ class MachO < ExeFormat
193
207
  end
194
208
 
195
209
  def encode(m)
196
- ed = super(m)
210
+ ed = super(m)
197
211
  ed << @data.encode(m) if @data
198
212
  ed.align(m.size >> 3)
199
213
  ed.fixup! @cmdsize => ed.length if @cmdsize.kind_of? String
@@ -243,7 +257,10 @@ class MachO < ExeFormat
243
257
  str :name, 16
244
258
  str :segname, 16
245
259
  xwords :addr, :size
246
- words :offset, :align, :reloff, :nreloc, :flags, :res1, :res2
260
+ words :offset, :align, :reloff, :nreloc
261
+ bitfield :word, 0 => :type, 8 => :attributes_sys, 24 => :attributes_usr
262
+ words :res1, :res2
263
+ fld_enum :type, SEC_TYPE
247
264
  attr_accessor :res3 # word 64bit only
248
265
  attr_accessor :segment, :encoded
249
266
 
@@ -258,10 +275,6 @@ class MachO < ExeFormat
258
275
  # addr, offset, etc = @segment.virtaddr + 42
259
276
  super(m)
260
277
  end
261
-
262
- def decode_inner(m)
263
- @encoded = m.encoded[m.addr_to_off(@addr), @size]
264
- end
265
278
  end
266
279
  SECTION_64 = SECTION
267
280
 
@@ -279,7 +292,7 @@ class MachO < ExeFormat
279
292
  words :flavor, :count
280
293
  fld_enum(:flavor) { |m, t| THREAD_FLAVOR[m.header.cputype] || {} }
281
294
  attr_accessor :ctx
282
-
295
+
283
296
  def entrypoint(m)
284
297
  @ctx ||= {}
285
298
  case m.header.cputype
@@ -346,6 +359,7 @@ class MachO < ExeFormat
346
359
  end
347
360
  LOAD_DYLIB = DYLIB
348
361
  ID_DYLIB = DYLIB
362
+ LOAD_WEAK_DYLIB = DYLIB
349
363
 
350
364
  class PREBOUND_DYLIB < STRING
351
365
  word :stroff
@@ -356,6 +370,10 @@ class MachO < ExeFormat
356
370
  LOAD_DYLINKER = STRING
357
371
  ID_DYLINKER = STRING
358
372
 
373
+ class ENCRYPTION_INFO < SerialStruct
374
+ words :cryptoff, :cryptsize, :cryptid
375
+ end
376
+
359
377
  class ROUTINES < SerialStruct
360
378
  xwords :init_addr, :init_module, :res1, :res2, :res3, :res4, :res5, :res6
361
379
  end
@@ -479,6 +497,12 @@ class MachO < ExeFormat
479
497
  end
480
498
  end
481
499
 
500
+ class Relocation < SerialStruct
501
+ word :address
502
+ bitfield :word, 0 => :symbolnum, 24 => :pcrel, 25 => :length, 27 => :extern, 28 => :type
503
+ fld_enum :type, GENERIC_RELOC
504
+ end
505
+
482
506
  def encode_byte(val) Expression[val].encode( :u8, @endianness) end
483
507
  def encode_half(val) Expression[val].encode(:u16, @endianness) end
484
508
  def encode_word(val) Expression[val].encode(:u32, @endianness) end
@@ -487,6 +511,10 @@ class MachO < ExeFormat
487
511
  def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end
488
512
  def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
489
513
  def decode_xword(edata= @encoded) edata.decode_imm((@size == 32 ? :u32 : :u64), @endianness) end
514
+ def sizeof_byte ; 1 ; end
515
+ def sizeof_half ; 2 ; end
516
+ def sizeof_word ; 4 ; end
517
+ def sizeof_xword ; @size == 32 ? 4 : 8 ; end
490
518
 
491
519
 
492
520
  attr_accessor :endianness, :size
@@ -494,6 +522,7 @@ class MachO < ExeFormat
494
522
  attr_accessor :segments
495
523
  attr_accessor :commands
496
524
  attr_accessor :symbols
525
+ attr_accessor :relocs
497
526
 
498
527
  def initialize(cpu=nil)
499
528
  super(cpu)
@@ -523,6 +552,35 @@ class MachO < ExeFormat
523
552
  decode_relocations
524
553
  end
525
554
 
555
+ # return the segment containing address, set seg.encoded.ptr to the correct offset
556
+ def segment_at(addr)
557
+ return if not addr or addr <= 0
558
+ if seg = @segments.find { |seg_| addr >= seg_.virtaddr and addr < seg_.virtaddr + seg_.virtsize }
559
+ seg.encoded.ptr = addr - seg.virtaddr
560
+ seg
561
+ end
562
+ end
563
+
564
+ def addr_to_fileoff(addr)
565
+ s = @segments.find { |s_| s_.virtaddr <= addr and s_.virtaddr + s_.virtsize > addr } if addr
566
+ addr - s.virtaddr + s.fileoff if s
567
+ end
568
+
569
+ def fileoff_to_addr(foff)
570
+ if s = @segments.find { |s_| s_.fileoff <= foff and s_.fileoff + s_.filesize > foff }
571
+ s.virtaddr + module_address + foff - s.fileoff
572
+ end
573
+ end
574
+
575
+ def module_address
576
+ @segments.map { |s_| s_.virtaddr }.min || 0
577
+ end
578
+
579
+ def module_size
580
+ return 0 if not sz = @segments.map { |s_| s_.virtaddr + s_.virtsize }.max
581
+ sz - module_address
582
+ end
583
+
526
584
  def decode_symbols
527
585
  @symbols = []
528
586
  ep_count = 0
@@ -537,30 +595,159 @@ class MachO < ExeFormat
537
595
  when 'THREAD', 'UNIXTHREAD'
538
596
  ep_count += 1
539
597
  ep = cmd.data.entrypoint(self)
540
- next if not seg = @segments.find { |seg_| ep >= seg_.virtaddr and ep < seg_.virtaddr + seg_.virtsize }
541
- seg.encoded.add_export("entrypoint#{"_#{ep_count}" if ep_count >= 2 }", ep - seg.virtaddr)
598
+ next if not seg = segment_at(ep)
599
+ seg.encoded.add_export("entrypoint#{"_#{ep_count}" if ep_count >= 2 }")
542
600
  end
543
601
  }
544
602
  @symbols.each { |s|
545
603
  next if s.value == 0 or not s.name
546
- next if not seg = @segments.find { |seg_| s.value >= seg_.virtaddr and s.value < seg_.virtaddr + seg_.virtsize }
547
- seg.encoded.add_export(s.name, s.value - seg.virtaddr)
604
+ next if not seg = segment_at(s.value)
605
+ seg.encoded.add_export(s.name)
548
606
  }
549
607
  end
550
608
 
551
609
  def decode_relocations
610
+ @relocs = []
611
+ indsymtab = []
612
+ @commands.each { |cmd|
613
+ if cmd.cmd == 'DYSYMTAB'
614
+ @encoded.ptr = cmd.data.extreloff
615
+ cmd.data.nextrel.times { @relocs << Relocation.decode(self) }
616
+ @encoded.ptr = cmd.data.locreloff
617
+ cmd.data.nlocrel.times { @relocs << Relocation.decode(self) }
618
+ @encoded.ptr = cmd.data.indirectsymoff
619
+ cmd.data.nindirectsyms.times { indsymtab << decode_word }
620
+ end
621
+ }
622
+ @segments.each { |seg|
623
+ seg.sections.each { |sec|
624
+ @encoded.ptr = sec.reloff
625
+ sec.nreloc.times { @relocs << Relocation.decode(self) }
626
+
627
+ case sec.type
628
+ when 'NON_LAZY_SYMBOL_POINTERS', 'LAZY_SYMBOL_POINTERS'
629
+ edata = seg.encoded
630
+ off = sec.offset - seg.fileoff
631
+ (sec.size / 4).times { |i|
632
+ sidx = indsymtab[sec.res1+i]
633
+ case IND_SYM_IDX[sidx]
634
+ when 'INDIRECT_SYMBOL_LOCAL' # base reloc: add delta from prefered image base
635
+ edata.ptr = off
636
+ addr = decode_word(edata)
637
+ if s = segment_at(addr)
638
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
639
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[label], :u32, @endianness)
640
+ end
641
+ when 'INDIRECT_SYMBOL_ABS' # nothing
642
+ else
643
+ sym = @symbols[sidx]
644
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[sym.name], :u32, @endianness)
645
+ end
646
+ off += 4
647
+ }
648
+ when 'SYMBOL_STUBS'
649
+ # TODO next unless arch == 386 and sec.attrs & SELF_MODIFYING_CODE and sec.res2 == 5
650
+
651
+ edata = seg.encoded
652
+ edata.data = edata.data.to_str.dup
653
+ off = sec.offset - seg.fileoff + 1
654
+ (sec.size / 5).times { |i|
655
+ sidx = indsymtab[sec.res1+i]
656
+ case IND_SYM_IDX[sidx]
657
+ when 'INDIRECT_SYMBOL_LOCAL' # base reloc: add delta from prefered image base
658
+ edata.ptr = off
659
+ addr = decode_word(edata)
660
+ if s = segment_at(addr)
661
+ label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
662
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[label, :-, Expression[seg.virtaddr, :+, off+4].reduce], :u32, @endianness)
663
+ end
664
+ when 'INDIRECT_SYMBOL_ABS' # nothing
665
+ else
666
+ seg.encoded[off-1] = 0xe9
667
+ sym = @symbols[sidx]
668
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[sym.name, :-, Expression[seg.virtaddr, :+, off+4].reduce], :u32, @endianness)
669
+ end
670
+ off += 5
671
+ }
672
+
673
+ end
674
+ }
675
+ }
676
+ seg = nil
677
+ @relocs.each { |r|
678
+ if r.extern == 1
679
+ sym = @symbols[r.symbolnum]
680
+ seg = @segments.find { |sg| sg.virtaddr <= r.address and sg.virtaddr + sg.virtsize > r.address } unless seg and seg.virtaddr <= r.address and seg.virtaddr + seg.virtsize > r.address
681
+ if not seg
682
+ puts "macho: reloc to unmapped space #{r.inspect} #{sym.inspect}" if $VERBOSE
683
+ next
684
+ end
685
+ seg.encoded.reloc[r.address - seg.virtaddr] = Metasm::Relocation.new(Expression[sym.name], :u32, @endianness)
686
+ end
687
+ }
552
688
  end
553
689
 
554
690
  def decode_segment(s)
691
+ @encoded.add_export(s.name, s.fileoff)
555
692
  s.encoded = @encoded[s.fileoff, s.filesize]
556
693
  s.encoded.virtsize = s.virtsize
557
- s.sections.each { |ss| ss.encoded = @encoded[ss.offset, ss.size] }
694
+ s.sections.each { |ss|
695
+ ss.encoded = @encoded[ss.offset, ss.size]
696
+ s.encoded.add_export(ss.name, ss.offset - s.fileoff)
697
+ }
558
698
  end
559
699
 
560
700
  def each_section(&b)
561
701
  @segments.each { |s| yield s.encoded, s.virtaddr }
562
702
  end
563
703
 
704
+ def section_info
705
+ ret = []
706
+ @segments.each { |seg|
707
+ ret.concat seg.sections.map { |s| [s.name, s.addr, s.size, s.type] }
708
+ }
709
+ ret
710
+ end
711
+
712
+ def init_disassembler
713
+ d = super()
714
+ case @cpu.shortname
715
+ when 'ia32', 'x64'
716
+ old_cp = d.c_parser
717
+ d.c_parser = nil
718
+ d.parse_c <<EOC
719
+ void *dlsym(int, char *); // has special callback
720
+ // standard noreturn, optimized by gcc
721
+ void __attribute__((noreturn)) exit(int);
722
+ void abort(void) __attribute__((noreturn));
723
+ EOC
724
+ d.function[Expression['_dlsym']] = d.function[Expression['dlsym']] = dls = @cpu.decode_c_function_prototype(d.c_parser, 'dlsym')
725
+ d.function[Expression['_exit']] = d.function[Expression['exit']] = @cpu.decode_c_function_prototype(d.c_parser, 'exit')
726
+ d.function[Expression['abort']] = @cpu.decode_c_function_prototype(d.c_parser, 'abort')
727
+ d.c_parser = old_cp
728
+
729
+ dls.btbind_callback = lambda { |dasm, bind, funcaddr, calladdr, expr, origin, maxdepth|
730
+ sz = @cpu.size/8
731
+ raise 'dlsym call error' if not dasm.decoded[calladdr]
732
+ if @cpu.shortname == 'x64'
733
+ arg2 = :rsi
734
+ else
735
+ arg2 = Indirection.new(Expression[:esp, :+, 2*sz], sz, calladdr)
736
+ end
737
+ fnaddr = dasm.backtrace(arg2, calladdr, :include_start => true, :maxdepth => maxdepth)
738
+ if fnaddr.kind_of?(::Array) and fnaddr.length == 1 and s = dasm.decode_strz(fnaddr.first, 64) and s.length > sz
739
+ bind = bind.merge @cpu.register_symbols[0] => Expression[s]
740
+ end
741
+ bind
742
+ }
743
+
744
+ df = d.function[:default] = @cpu.disassembler_default_func
745
+ df.backtrace_binding[@cpu.register_symbols[4]] = Expression[@cpu.register_symbols[4], :+, @cpu.size/8]
746
+ df.btbind_callback = nil
747
+ end
748
+ d
749
+ end
750
+
564
751
  def get_default_entrypoints
565
752
  @commands.find_all { |cmd| cmd.cmd == 'THREAD' or cmd.cmd == 'UNIXTHREAD' }.map { |cmd| cmd.data.entrypoint(self) }
566
753
  end
@@ -795,6 +982,7 @@ class UniversalBinary < ExeFormat
795
982
 
796
983
  def encode_word(val) Expression[val].encode(:u32, @endianness) end
797
984
  def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
985
+ def sizeof_word ; 4 ; end
798
986
 
799
987
  attr_accessor :endianness, :encoded, :header, :archive
800
988
  def initialize
@@ -16,7 +16,7 @@ class ExeFormat
16
16
  # creates a new instance, populates self.encoded with the supplied string
17
17
  def self.load(str, *a, &b)
18
18
  e = new(*a, &b)
19
- if str.kind_of? EncodedData; e.encoded = str
19
+ if str.kind_of?(EncodedData); e.encoded = str
20
20
  else e.encoded << str
21
21
  end
22
22
  e
@@ -63,6 +63,30 @@ class ExeFormat
63
63
  e
64
64
  end
65
65
 
66
+ def load(str)
67
+ if str.kind_of?(EncodedData); @encoded = str
68
+ else @encoded << str
69
+ end
70
+ self
71
+ end
72
+
73
+ def load_file(path)
74
+ @filename ||= path
75
+ load(VirtualFile.read(path))
76
+ end
77
+
78
+ def decode_file(path)
79
+ load_file(path)
80
+ decode
81
+ self
82
+ end
83
+
84
+ def decode_file_header(path)
85
+ load_file(path)
86
+ decode_header
87
+ self
88
+ end
89
+
66
90
  # creates a new object using the specified cpu, parses the asm source, and assemble
67
91
  def self.assemble(cpu, source, file='<unk>', lineno=1)
68
92
  source, cpu = cpu, source if source.kind_of? CPU
@@ -175,9 +199,8 @@ class ExeFormat
175
199
  end
176
200
 
177
201
  # saves the result of +encode_string+ in the specified file
178
- # fails if the file already exists
202
+ # overwrites existing files
179
203
  def encode_file(path, *a)
180
- #raise Errno::EEXIST, path if File.exist? path # race, but cannot use O_EXCL, as O_BINARY is not defined in ruby
181
204
  encode_string(*a)
182
205
  File.open(path, 'wb') { |fd| fd.write(@encoded.data) }
183
206
  end
@@ -51,6 +51,7 @@ class MZ < ExeFormat
51
51
  def encode_word(val) Expression[val].encode(:u16, @endianness) end
52
52
  # decodes a 16bits word from self.encoded
53
53
  def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end
54
+ def sizeof_word ; 2 ; end
54
55
 
55
56
 
56
57
  attr_accessor :endianness, :header, :source
@@ -30,7 +30,7 @@ class NDS < ExeFormat
30
30
  mem :secareadisable, 8
31
31
  words :endoff, :headersz
32
32
  mem :reserved4, 56
33
- mem :ninlogo, 156
33
+ mem :ninlogo, 156
34
34
  half :logoCRC, 0xcf56
35
35
  half :headerCRC
36
36
  end
@@ -70,14 +70,17 @@ class NDS < ExeFormat
70
70
  def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end
71
71
  def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end
72
72
  def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
73
+ def sizeof_byte ; 1 ; end
74
+ def sizeof_half ; 2 ; end
75
+ def sizeof_word ; 4 ; end
73
76
 
74
77
 
75
78
  attr_accessor :header, :icon, :arm9, :arm7
76
79
  attr_accessor :files, :fat
77
80
 
78
- def initialize(endianness=:little)
79
- @endianness = endianness
80
- @encoded = EncodedData.new
81
+ def initialize(cpu=nil)
82
+ @endianness = (cpu ? cpu.endianness : :little)
83
+ super(cpu)
81
84
  end
82
85
 
83
86
  # decodes the header from the current offset in self.encoded