metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,228 @@
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
+ #
8
+ # This sample defines an ApiHook class, that you can subclass to easily hook functions
9
+ # in a debugged process. Your custom function will get called whenever an API function is,
10
+ # giving you access to the arguments, you can also take control just before control returns
11
+ # to the caller.
12
+ # See the example in the end for more details.
13
+ # As a standalone application, it hooks WriteFile in the 'notepad' process, and make it
14
+ # skip the first two bytes of the buffer.
15
+ #
16
+
17
+ require 'metasm'
18
+
19
+ class ApiHook
20
+ # rewrite this function to list the hooks you want
21
+ # return an array of hashes
22
+ def setup
23
+ #[{ :function => 'WriteFile', :abi => :stdcall }, # standard function hook
24
+ # { :module => 'Foo.dll', :rva => 0x2433, # arbitrary code hook
25
+ # :abi => :fastcall, :hookname => 'myhook' }] # hooks named pre_myhook/post_myhook
26
+ end
27
+
28
+ # initialized from a Debugger or a process description that will be debugged
29
+ # sets the hooks up, then run_forever
30
+ def initialize(dbg)
31
+ if not dbg.kind_of? Metasm::Debugger
32
+ process = Metasm::OS.current.find_process(dbg)
33
+ raise 'no such process' if not process
34
+ dbg = process.debugger
35
+ end
36
+ dbg.loadallsyms
37
+ @dbg = dbg
38
+ setup.each { |h| setup_hook(h) }
39
+ init_prerun if respond_to?(:init_prerun) # allow subclass to do stuff before main loop
40
+ @dbg.run_forever
41
+ end
42
+
43
+ # setup one function hook
44
+ def setup_hook(h)
45
+ pre = "pre_#{h[:hookname] || h[:function]}"
46
+ post = "post_#{h[:hookname] || h[:function]}"
47
+
48
+ @nargs = h[:nargs] || method(pre).arity if respond_to?(pre)
49
+
50
+ if target = h[:address]
51
+ elsif target = h[:rva]
52
+ modbase = @dbg.modulemap[h[:module]]
53
+ raise "cant find module #{h[:module]} in #{@dbg.modulemap.join(', ')}" if not modbase
54
+ target += modbase[0]
55
+ else
56
+ target = h[:function]
57
+ end
58
+
59
+ @dbg.bpx(target) {
60
+ catch(:finish) {
61
+ @cur_abi = h[:abi]
62
+ @ret_longlong = h[:ret_longlong]
63
+ if respond_to? pre
64
+ args = read_arglist
65
+ send pre, *args
66
+ end
67
+ if respond_to? post
68
+ @dbg.bpx(@dbg.func_retaddr, true) {
69
+ retval = read_ret
70
+ send post, retval, args
71
+ }
72
+ end
73
+ }
74
+ }
75
+ end
76
+
77
+ # retrieve the arglist at func entry, from @nargs & @cur_abi
78
+ def read_arglist
79
+ nr = @nargs
80
+ args = []
81
+
82
+ if (@cur_abi == :fastcall or @cur_abi == :thiscall) and nr > 0
83
+ args << @dbg.get_reg_value(:ecx)
84
+ nr -= 1
85
+ end
86
+
87
+ if @cur_abi == :fastcall and nr > 0
88
+ args << @dbg.get_reg_value(:edx)
89
+ nr -= 1
90
+ end
91
+
92
+ nr.times { |i| args << @dbg.func_arg(i) }
93
+
94
+ args
95
+ end
96
+
97
+ # retrieve the function returned value
98
+ def read_ret
99
+ ret = @dbg.func_retval
100
+ if @ret_longlong
101
+ ret = (ret & 0xffffffff) | (@dbg[:edx] << 32)
102
+ end
103
+ ret
104
+ end
105
+
106
+ # patch the value of an argument
107
+ # only valid in pre_hook
108
+ # nr starts at 0
109
+ def patch_arg(nr, value)
110
+ case @cur_abi
111
+ when :fastcall
112
+ case nr
113
+ when 0
114
+ @dbg.set_reg_value(:ecx, value)
115
+ return
116
+ when 1
117
+ @dbg.set_reg_value(:edx, value)
118
+ return
119
+ else
120
+ nr -= 2
121
+ end
122
+ when :thiscall
123
+ case nr
124
+ when 0
125
+ @dbg.set_reg_value(:ecx, value)
126
+ return
127
+ else
128
+ nr -= 1
129
+ end
130
+ end
131
+
132
+ @dbg.func_arg_set(nr, value)
133
+ end
134
+
135
+ # patch the function return value
136
+ # only valid post_hook
137
+ def patch_ret(val)
138
+ if @ret_longlong
139
+ @dbg.set_reg_value(:edx, (val >> 32) & 0xffffffff)
140
+ val &= 0xffffffff
141
+ end
142
+ @dbg.func_retval_set(val)
143
+ end
144
+
145
+ # skip the function call
146
+ # only valid in pre_hook
147
+ def finish(retval)
148
+ patch_ret(retval)
149
+ @dbg.ip = @dbg.func_retaddr
150
+ case @cur_abi
151
+ when :fastcall
152
+ @dbg[:esp] += 4*(@nargs-2) if @nargs > 2
153
+ when :thiscall
154
+ @dbg[:esp] += 4*(@nargs-1) if @nargs > 1
155
+ when :stdcall
156
+ @dbg[:esp] += 4*@nargs
157
+ end
158
+ @dbg.sp += @dbg.cpu.size/8
159
+ throw :finish
160
+ end
161
+ end
162
+
163
+
164
+
165
+ if __FILE__ == $0
166
+
167
+ # this is the class you have to define to hook
168
+ #
169
+ # setup() defines the list of hooks as an array of hashes
170
+ # for exported functions, simply use :function => function name
171
+ # for arbitrary hook, :module => 'module.dll', :rva => 0x1234, :hookname => 'myhook' (call pre_myhook/post_myhook)
172
+ # :abi can be :stdcall (windows standard export), :fastcall or :thiscall, leave empty for cdecl
173
+ # if pre_<function> is defined, it is called whenever the function is entered, via a bpx (int3)
174
+ # if post_<function> is defined, it is called whenever the function exists, with a bpx on the return address setup at func entry
175
+ # the pre_hook receives all arguments to the original function
176
+ # change them with patch_arg(argnr, newval)
177
+ # read memory with @dbg.memory_read_int(ptr), or @dbg.memory[ptr, length]
178
+ # skip the function call with finish(fake_retval) (!) needs a correct :abi & param count !
179
+ # the post_hook receives the function return value
180
+ # change it with patch_ret(newval)
181
+ class MyHook < ApiHook
182
+ def setup
183
+ [{ :function => 'WriteFile', :abi => :stdcall }]
184
+ end
185
+
186
+ def init_prerun
187
+ puts "hooks ready, save a file in notepad"
188
+ end
189
+
190
+ def pre_WriteFile(handle, pbuf, size, pwritten, overlap)
191
+ # we can skip the function call with this
192
+ #finish(28)
193
+
194
+ # spy on the api / trace calls
195
+ bufdata = @dbg.memory[pbuf, size]
196
+ puts "writing #{bufdata.inspect}"
197
+
198
+ # but we can also mess with the args
199
+ # ex: skip first 2 bytes of the buffer
200
+ patch_arg(1, pbuf+2)
201
+ patch_arg(2, size-2)
202
+ end
203
+
204
+ def post_WriteFile(retval, arglistcopy)
205
+ # we can patch the API return value with this
206
+ #patch_retval(42)
207
+
208
+ # finish messing with the args: fake the nrofbyteswritten
209
+ handle, pbuf, size, pwritten, overlap = arglistcopy
210
+ written = @dbg.memory_read_int(pwritten)
211
+ if written == size
212
+ # if written everything, patch the value so that the program dont detect our intervention
213
+ @dbg.memory_write_int(pwritten, written+2)
214
+ end
215
+
216
+ puts "write retval: #{retval}, written: #{written} bytes"
217
+ end
218
+ end
219
+
220
+ # name says it all
221
+ Metasm::WinOS.get_debug_privilege
222
+
223
+ # run our Hook engine on a running 'notepad' instance
224
+ MyHook.new('notepad')
225
+
226
+ # the script ends when notepad exits
227
+
228
+ end
@@ -0,0 +1,143 @@
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
+ # a preleminary attempt to use MS dbghelp.dll to retrieve PE symbols
7
+
8
+ require 'metasm'
9
+
10
+ dll = 'C:\\Program Files\\Debugging Tools For Windows (x86)\\dbghelp.dll'
11
+
12
+ Metasm::DynLdr.new_api_c <<EOS, dll
13
+ #define SYMOPT_CASE_INSENSITIVE 0x00000001
14
+ #define SYMOPT_UNDNAME 0x00000002
15
+ #define SYMOPT_DEFERRED_LOADS 0x00000004
16
+ #define SYMOPT_NO_CPP 0x00000008
17
+ #define SYMOPT_LOAD_LINES 0x00000010
18
+ #define SYMOPT_OMAP_FIND_NEAREST 0x00000020
19
+ #define SYMOPT_LOAD_ANYTHING 0x00000040
20
+ #define SYMOPT_IGNORE_CVREC 0x00000080
21
+ #define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
22
+ #define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
23
+ #define SYMOPT_EXACT_SYMBOLS 0x00000400
24
+ #define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
25
+ #define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
26
+ #define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
27
+ #define SYMOPT_PUBLICS_ONLY 0x00004000
28
+ #define SYMOPT_NO_PUBLICS 0x00008000
29
+ #define SYMOPT_AUTO_PUBLICS 0x00010000
30
+ #define SYMOPT_NO_IMAGE_SEARCH 0x00020000
31
+ #define SYMOPT_SECURE 0x00040000
32
+ #define SYMOPT_NO_PROMPTS 0x00080000
33
+ #define SYMOPT_DEBUG 0x80000000
34
+
35
+ typedef int BOOL;
36
+ typedef char CHAR;
37
+ typedef unsigned long DWORD;
38
+ typedef unsigned __int64 DWORD64;
39
+ typedef void *HANDLE;
40
+ typedef unsigned __int64 *PDWORD64;
41
+ typedef void *PVOID;
42
+ typedef unsigned long ULONG;
43
+ typedef unsigned __int64 ULONG64;
44
+ typedef const CHAR *PCSTR;
45
+ typedef CHAR *PSTR;
46
+
47
+ struct _SYMBOL_INFO {
48
+ ULONG SizeOfStruct;
49
+ ULONG TypeIndex;
50
+ ULONG64 Reserved[2];
51
+ ULONG info;
52
+ ULONG Size;
53
+ ULONG64 ModBase;
54
+ ULONG Flags;
55
+ ULONG64 Value;
56
+ ULONG64 Address;
57
+ ULONG Register;
58
+ ULONG Scope;
59
+ ULONG Tag;
60
+ ULONG NameLen;
61
+ ULONG MaxNameLen;
62
+ CHAR Name[1];
63
+ };
64
+ typedef struct _SYMBOL_INFO *PSYMBOL_INFO;
65
+
66
+ typedef __stdcall BOOL (*PSYM_ENUMERATESYMBOLS_CALLBACK)(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext);
67
+
68
+ __stdcall DWORD SymGetOptions(void);
69
+ __stdcall DWORD SymSetOptions(DWORD SymOptions __attribute__((in)));
70
+ __stdcall BOOL SymInitialize(HANDLE hProcess __attribute__((in)), PSTR UserSearchPath __attribute__((in)), BOOL fInvadeProcess __attribute__((in)));
71
+ __stdcall DWORD64 SymLoadModule64(HANDLE hProcess __attribute__((in)), HANDLE hFile __attribute__((in)), PSTR ImageName __attribute__((in)), PSTR ModuleName __attribute__((in)), DWORD64 BaseOfDll __attribute__((in)), DWORD SizeOfDll __attribute__((in)));
72
+ __stdcall BOOL SymSetSearchPath(HANDLE hProcess __attribute__((in)), PSTR SearchPathA __attribute__((in)));
73
+ __stdcall BOOL SymFromAddr(HANDLE hProcess __attribute__((in)), DWORD64 Address __attribute__((in)), PDWORD64 Displacement __attribute__((out)), PSYMBOL_INFO Symbol __attribute__((in)) __attribute__((out)));
74
+ __stdcall BOOL SymEnumSymbols(HANDLE hProcess __attribute__((in)), ULONG64 BaseOfDll __attribute__((in)), PCSTR Mask __attribute__((in)), PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback __attribute__((in)), PVOID UserContext __attribute__((in)));
75
+ EOS
76
+
77
+ #SYMOPT = 4|0x80000 # defered_load no_prompt
78
+ #Metasm::WinAPI.new_api dll, 'SymInitialize', 'III I'
79
+ #Metasm::WinAPI.new_api dll, 'SymGetOptions', 'I'
80
+ #Metasm::WinAPI.new_api dll, 'SymSetOptions', 'I I'
81
+ #Metasm::WinAPI.new_api dll, 'SymSetSearchPath', 'IP I'
82
+ #Metasm::WinAPI.new_api dll, 'SymLoadModule64', 'IIPIIII I' # ???ull?
83
+ #Metasm::WinAPI.new_api dll, 'SymFromAddr', 'IIIPP I' # handle ull_addr poffset psym
84
+
85
+ class Tracer < Metasm::WinDbgAPI
86
+ def initialize(*a)
87
+ super(*a)
88
+ loop
89
+ puts 'finished'
90
+ end
91
+
92
+ def handler_newprocess(pid, tid, info)
93
+ puts "newprocess: init symsrv"
94
+
95
+ h = @hprocess[pid]
96
+ dl = Metasm::DynLdr
97
+ dl.syminitialize(h, 0, 0)
98
+ dl.symsetoptions(dl.symgetoptions|dl::SYMOPT_DEFERRED_LOADS|dl::SYMOPT_NO_PROMPTS)
99
+ sympath = ENV['_NT_SYMBOL_PATH'] || 'srv**symbols*http://msdl.microsoft.com/download/symbols'
100
+ dl.symsetsearchpath(h, sympath.dup) # dup cause ENV is frozen and make WinAPI raises
101
+
102
+ Metasm::WinAPI::DBG_CONTINUE
103
+ end
104
+
105
+ def handler_loaddll(pid, tid, info)
106
+ pe = Metasm::LoadedPE.load(@mem[pid][info.imagebase, 0x1000000])
107
+ pe.decode_header
108
+ pe.decode_exports
109
+ return if not pe.export
110
+ libname = pe.export.libname
111
+ puts "loaddll: #{libname} @#{'%x' % info.imagebase}"
112
+ h = @hprocess[pid]
113
+ dl = Metasm::DynLdr
114
+ dl.symloadmodule64(h, 0, libname, 0, info.imagebase, pe.optheader.image_size)
115
+ symstruct = [0x58].pack('L') + 0.chr*4*19 + [512].pack('L') # sizeofstruct, ..., nameszmax
116
+ text = pe.sections.find { |s| s.name == '.text' }
117
+ # XXX should SymEnumSymbols, but win32api callbacks sucks
118
+ text.rawsize.times { |o|
119
+ sym = symstruct + 0.chr*512 # name concat'ed after the struct
120
+ off = 0.chr*8
121
+ if dl.symfromaddr(h, info.imagebase+text.virtaddr+o, off, sym) and off.unpack('L').first == 0
122
+ symnamelen = sym[19*4, 4].unpack('L').first
123
+ puts ' %x %s' % [text.virtaddr+o, sym[0x54, symnamelen]]
124
+ end
125
+ puts ' %x/%x' % [o, text.rawsize] if $VERBOSE and o & 0xffff == 0
126
+ }
127
+ puts
128
+ end
129
+ end
130
+
131
+ if $0 == __FILE__
132
+ Metasm::WinOS.get_debug_privilege
133
+ if ARGV.empty?
134
+ # display list of running processes if no target found
135
+ puts Metasm::WinOS.list_processes.sort_by { |pr_| pr_.pid }
136
+ abort 'target needed'
137
+ end
138
+ pid = ARGV.shift.dup
139
+ if pr = Metasm::WinOS.find_process(pid)
140
+ pid = pr.pid
141
+ end
142
+ Tracer.new pid
143
+ end
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+ # This file is part of Metasm, the Ruby assembly manipulation suite
3
+ # Copyright (C) 2006-2009 Yoann GUILLOT
4
+ #
5
+ # Licence is LGPL, see LICENCE in the top-level directory
6
+
7
+
8
+ #
9
+ # this script disassembles an executable (elf/pe) using the GTK front-end
10
+ # use live:bla to open a running process whose filename contains 'bla'
11
+ #
12
+ # key binding (non exhaustive):
13
+ # Enter to follow a label (the current hilighted word)
14
+ # Esc to return to the previous position
15
+ # Space to switch between listing and graph views
16
+ # Tab to decompile (on already disassembled code)
17
+ # 'c' to start disassembling from the cursor position
18
+ # 'g' to go to a specific address (label/042h)
19
+ # 'l' to list known labels
20
+ # 'f' to list known functions
21
+ # 'x' to list xrefs to current address
22
+ # 'n' to rename a label (current word or current address)
23
+ # ctrl+'r' to run arbitrary ruby code in the context of the Gui objet (access to 'dasm', 'curaddr')
24
+ # ctrl+mousewheel to zoom in graph view ; also doubleclick on the background ('fit to window'/'reset zoom')
25
+ #
26
+
27
+ require 'metasm'
28
+ require 'optparse'
29
+
30
+ $VERBOSE = true
31
+
32
+ # parse arguments
33
+ opts = { :sc_cpu => 'Ia32' }
34
+ OptionParser.new { |opt|
35
+ opt.banner = 'Usage: disassemble-gtk.rb [options] <executable> [<entrypoints>]'
36
+ opt.on('--no-data-trace', 'do not backtrace memory read/write accesses') { opts[:nodatatrace] = true }
37
+ opt.on('--debug-backtrace', 'enable backtrace-related debug messages (very verbose)') { opts[:debugbacktrace] = true }
38
+ opt.on('-P <plugin>', '--plugin <plugin>', 'load a metasm disassembler/debugger plugin') { |h| (opts[:plugin] ||= []) << h }
39
+ opt.on('-e <code>', '--eval <code>', 'eval a ruby code') { |h| (opts[:hookstr] ||= []) << h }
40
+ opt.on('--map <mapfile>', 'load a map file (addr <-> name association)') { |f| opts[:map] = f }
41
+ opt.on('--fast', 'dasm cli args with disassemble_fast_deep') { opts[:fast] = true }
42
+ opt.on('--decompile') { opts[:decompile] = true }
43
+ opt.on('--gui <gtk|win32|qt>') { |g| require 'metasm/gui/' + g }
44
+ opt.on('--cpu <cpu>', 'the CPU class to use for a shellcode (Ia32, X64, ...)') { |c| opts[:sc_cpu] = c }
45
+ opt.on('--exe <exe_fmt>', 'the executable file format to use (PE, ELF, ...)') { |c| opts[:exe_fmt] = c }
46
+ opt.on('--rebase <addr>', 'rebase the loaded file to <addr>') { |a| opts[:rebase] = Integer(a) }
47
+ opt.on('-c <header>', '--c-header <header>', 'read C function prototypes (for external library functions)') { |h| opts[:cheader] = h }
48
+ opt.on('-a', '--autoload', 'loads all relevant files with same filename (.h, .map..)') { opts[:autoload] = true }
49
+ opt.on('-v', '--verbose') { $VERBOSE = true } # default
50
+ opt.on('-q', '--no-verbose') { $VERBOSE = false }
51
+ opt.on('-d', '--debug') { $DEBUG = $VERBOSE = true }
52
+ }.parse!(ARGV)
53
+
54
+ case exename = ARGV.shift
55
+ when /^live:(.*)/
56
+ t = $1
57
+ t = t.to_i if $1 =~ /^[0-9]+$/
58
+ os = Metasm::OS.current
59
+ raise 'no such target' if not target = os.find_process(t) || os.create_process(t)
60
+ p target if $VERBOSE
61
+ w = Metasm::Gui::DbgWindow.new(target.debugger, "#{target.pid}:#{target.modules[0].path rescue nil} - metasm debugger")
62
+ dbg = w.dbg_widget.dbg
63
+ when /^(tcp:|udp:)?..+:/
64
+ dbg = Metasm::GdbRemoteDebugger.new(exename, opts[:sc_cpu])
65
+ w = Metasm::Gui::DbgWindow.new(dbg, "remote - metasm debugger")
66
+ else
67
+ w = Metasm::Gui::DasmWindow.new("#{exename + ' - ' if exename}metasm disassembler")
68
+ if exename
69
+ exe = w.loadfile(exename, opts[:sc_cpu], opts[:exe_fmt])
70
+ exe.disassembler.rebase(opts[:rebase]) if opts[:rebase]
71
+ if opts[:autoload]
72
+ basename = exename.sub(/\.\w\w?\w?$/, '')
73
+ opts[:map] ||= basename + '.map' if File.exist?(basename + '.map')
74
+ opts[:cheader] ||= basename + '.h' if File.exist?(basename + '.h')
75
+ (opts[:plugin] ||= []) << (basename + '.rb') if File.exist?(basename + '.rb')
76
+ end
77
+ end
78
+ end
79
+
80
+ ep = ARGV.map { |arg| (?0..?9).include?(arg[0]) ? Integer(arg) : arg }
81
+
82
+ if exe
83
+ dasm = exe.init_disassembler
84
+
85
+ dasm.load_map opts[:map] if opts[:map]
86
+ dasm.parse_c_file opts[:cheader] if opts[:cheader]
87
+ dasm.backtrace_maxblocks_data = -1 if opts[:nodatatrace]
88
+ dasm.debug_backtrace = true if opts[:debugbacktrace]
89
+ dasm.disassemble_fast_deep(*ep) if opts[:fast]
90
+ dasm.callback_finished = lambda { w.dasm_widget.focus_addr w.dasm_widget.curaddr, :decompile ; dasm.decompiler.finalize } if opts[:decompile]
91
+ elsif dbg
92
+ dbg.load_map opts[:map] if opts[:map]
93
+ opts[:plugin].to_a.each { |p| dbg.load_plugin(p) }
94
+ end
95
+ if dasm
96
+ w.display(dasm, ep)
97
+ opts[:plugin].to_a.each { |p| dasm.load_plugin(p) }
98
+ end
99
+
100
+ opts[:hookstr].to_a.each { |f| eval f }
101
+
102
+ Metasm::Gui.main