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
@@ -1,399 +0,0 @@
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
- # this exemple illustrates the use of the PTrace class to implement a pytstop-like functionnality
8
- # Works on linux/x86
9
- #
10
-
11
- require 'metasm'
12
-
13
- class Rubstop < Metasm::PTrace
14
- EFLAGS = {0 => 'c', 2 => 'p', 4 => 'a', 6 => 'z', 7 => 's', 9 => 'i', 10 => 'd', 11 => 'o'}
15
- # define accessors for registers
16
- %w[eax ebx ecx edx ebp esp edi esi eip orig_eax eflags dr0 dr1 dr2 dr3 dr6 dr7 cs ds es fs gs].each { |reg|
17
- define_method(reg) { peekusr(REGS_I386[reg.upcase]) & 0xffffffff }
18
- define_method(reg+'=') { |v|
19
- @regs_cache[reg] = v
20
- v = [v & 0xffffffff].pack('L').unpack('l').first if v >= 0x8000_0000
21
- pokeusr(REGS_I386[reg.upcase], v)
22
- }
23
- }
24
-
25
- def cont(signal=0)
26
- @ssdontstopbp = nil
27
- singlestep(true) if @wantbp
28
- super(signal)
29
- ::Process.waitpid(@pid)
30
- return if child.exited?
31
- @oldregs.update @regs_cache
32
- readregs
33
- checkbp
34
- end
35
-
36
- def singlestep(justcheck=false)
37
- super()
38
- ::Process.waitpid(@pid)
39
- return if child.exited?
40
- case @wantbp
41
- when ::Integer; bpx @wantbp ; @wantbp = nil
42
- when ::String; self.dr7 |= 1 << (2*@wantbp[2, 1].to_i) ; @wantbp = nil
43
- end
44
- return if justcheck
45
- @oldregs.update @regs_cache
46
- readregs
47
- checkbp
48
- end
49
-
50
- def stepover
51
- i = curinstr.instruction if curinstr
52
- if i and (i.opname == 'call' or (i.prefix and i.prefix[:rep]))
53
- eaddr = @regs_cache['eip'] + curinstr.bin_length
54
- bpx eaddr, true
55
- cont
56
- else
57
- singlestep
58
- end
59
- end
60
-
61
- def stepout
62
- # XXX @regs_cache..
63
- stepover until curinstr.opcode.name == 'ret'
64
- singlestep
65
- end
66
-
67
- def syscall
68
- @ssdontstopbp = nil
69
- singlestep(true) if @wantbp
70
- super()
71
- ::Process.waitpid(@pid)
72
- return if child.exited?
73
- @oldregs.update @regs_cache
74
- readregs
75
- checkbp
76
- end
77
-
78
- def state; :stopped end
79
- def ptrace; self end
80
-
81
- attr_accessor :pgm, :regs_cache, :breakpoints, :singleshot, :wantbp,
82
- :symbols, :symbols_len, :filemap, :has_pax, :oldregs
83
- def initialize(*a)
84
- super(*a)
85
- @pgm = Metasm::ExeFormat.new Metasm::Ia32.new
86
- @pgm.encoded = Metasm::EncodedData.new Metasm::LinuxRemoteString.new(@pid)
87
- @pgm.encoded.data.dbg = self
88
- @regs_cache = {}
89
- @oldregs = {}
90
- readregs
91
- @oldregs.update @regs_cache
92
- @breakpoints = {}
93
- @singleshot = {}
94
- @wantbp = nil
95
- @symbols = {}
96
- @symbols_len = {}
97
- @filemap = {}
98
- @has_pax = false
99
-
100
- stack = self[regs_cache['esp'], 0x1000].to_str.unpack('L*')
101
- stack.shift # argc
102
- stack.shift until stack.empty? or stack.first == 0 # argv
103
- stack.shift
104
- stack.shift until stack.empty? or stack.first == 0 # envp
105
- stack.shift
106
- stack.shift until stack.empty? or stack.shift == 3 # find PHDR ptr in auxv
107
- if phdr = stack.shift
108
- phdr &= 0xffff_f000
109
- loadsyms phdr, phdr.to_s(16)
110
- end
111
- end
112
-
113
- def set_pax(bool)
114
- if bool
115
- @pgm.encoded.data.invalidate
116
- code = @pgm.encoded.data[eip, 4]
117
- if code != "\0\0\0\0" and @pgm.encoded.data[eip+0x6000_0000, 4] == code
118
- @has_pax = 'segmexec'
119
- else
120
- @has_pax = 'pax'
121
- end
122
- else
123
- @has_pax = false
124
- end
125
- end
126
-
127
- def readregs
128
- %w[eax ebx ecx edx esi edi esp ebp eip orig_eax eflags dr0 dr1 dr2 dr3 dr6 dr7 cs ds].each { |r| @regs_cache[r] = send(r) }
129
- @curinstr = nil if @regs_cache['eip'] != @oldregs['eip']
130
- @pgm.encoded.data.invalidate
131
- end
132
-
133
- def curinstr
134
- @curinstr ||= mnemonic_di
135
- end
136
-
137
- def child
138
- $?
139
- end
140
-
141
- def checkbp
142
- ::Process::waitpid(@pid, ::Process::WNOHANG) if not child
143
- return if not child
144
- if not child.stopped?
145
- if child.exited?; log "process exited with status #{child.exitstatus}"
146
- elsif child.signaled?; log "process exited due to signal #{child.termsig} (#{Signal.list.index child.termsig})"
147
- else log "process in unknown status #{child.inspect}"
148
- end
149
- return
150
- elsif child.stopsig != ::Signal.list['TRAP']
151
- log "process stopped due to signal #{child.stopsig} (#{Signal.list.index child.stopsig})"
152
- return # do not check 0xcc at eip-1 ! ( if curinstr.bin_length == 1 )
153
- end
154
- ccaddr = @regs_cache['eip']-1
155
- if @breakpoints[ccaddr] and self[ccaddr] == 0xcc
156
- if @ssdontstopbp != ccaddr
157
- self[ccaddr] = @breakpoints.delete ccaddr
158
- self.eip = ccaddr
159
- @wantbp = ccaddr if not @singleshot.delete ccaddr
160
- @ssdontstopbp = ccaddr
161
- else
162
- @ssdontstopbp = nil
163
- end
164
- elsif @regs_cache['dr6'] & 15 != 0
165
- dr = (0..3).find { |dr_| @regs_cache['dr6'] & (1 << dr_) != 0 }
166
- @wantbp = "dr#{dr}" if not @singleshot.delete @regs_cache['eip']
167
- self.dr6 = 0
168
- self.dr7 = @regs_cache['dr7'] & (0xffff_ffff ^ (3 << (2*dr)))
169
- readregs
170
- end
171
- end
172
-
173
- def bpx(addr, singleshot=false)
174
- @singleshot[addr] = singleshot
175
- return if @breakpoints[addr]
176
- if @has_pax
177
- set_hwbp 'x', addr
178
- else
179
- begin
180
- @breakpoints[addr] = self[addr]
181
- self[addr] = 0xcc
182
- rescue Errno::EIO
183
- log 'i/o error when setting breakpoint, switching to PaX mode'
184
- set_pax true
185
- @breakpoints.delete addr
186
- bpx(addr, singleshot)
187
- end
188
- end
189
- end
190
-
191
- def mnemonic_di(addr = eip)
192
- @pgm.encoded.ptr = addr
193
- di = @pgm.cpu.decode_instruction(@pgm.encoded, addr)
194
- @curinstr = di if addr == @regs_cache['eip']
195
- di
196
- end
197
-
198
- def mnemonic(addr=eip)
199
- mnemonic_di(addr).instruction
200
- end
201
-
202
- def regs_dump
203
- [%w[eax ebx ecx edx orig_eax], %w[ebp esp edi esi eip]].map { |l|
204
- l.map { |reg| "#{reg}=#{'%08x' % @regs_cache[reg]}" }.join(' ')
205
- }.join("\n")
206
- end
207
-
208
- def findfilemap(s)
209
- @filemap.keys.find { |k| @filemap[k][0] <= s and @filemap[k][1] > s } || '???'
210
- end
211
-
212
- def findsymbol(k)
213
- file = findfilemap(k) + '!'
214
- if s = @symbols[k] ? k : @symbols.keys.find { |s_| s_ < k and s_ + @symbols_len[s_].to_i > k }
215
- file + @symbols[s] + (s == k ? '' : "+#{(k-s).to_s(16)}")
216
- else
217
- file + ('%08x' % k)
218
- end
219
- end
220
-
221
- def set_hwbp(type, addr, len=1)
222
- dr = (0..3).find { |dr_| @regs_cache['dr7'] & (1 << (2*dr_)) == 0 and @wantbp != "dr#{dr}" }
223
- if not dr
224
- log 'no debug reg available :('
225
- return false
226
- end
227
- @regs_cache['dr7'] &= 0xffff_ffff ^ (0xf << (16+4*dr))
228
- case type
229
- when 'x'; addr += (@has_pax == 'segmexec' ? 0x6000_0000 : 0)
230
- when 'r'; @regs_cache['dr7'] |= (((len-1)<<2)|3) << (16+4*dr)
231
- when 'w'; @regs_cache['dr7'] |= (((len-1)<<2)|1) << (16+4*dr)
232
- end
233
- send("dr#{dr}=", addr)
234
- self.dr6 = 0
235
- self.dr7 = @regs_cache['dr7'] | (1 << (2*dr))
236
- readregs
237
- true
238
- end
239
-
240
- def clearbreaks
241
- @wantbp = nil if @wantbp == @regs_cache['eip']
242
- @breakpoints.each { |addr, oct| self[addr, 1] = oct }
243
- @breakpoints.clear
244
- if @regs_cache['dr7'] & 0xff != 0
245
- self.dr7 = 0
246
- readregs
247
- end
248
- end
249
-
250
- def loadsyms(baseaddr, name)
251
- @loadedsyms ||= {}
252
- return if @loadedsyms[name] or self[baseaddr, 4] != "\x7fELF"
253
- @loadedsyms[name] = true
254
-
255
- set_status " loading symbols from #{name}..."
256
- e = Metasm::LoadedELF.load self[baseaddr, 0x100_0000]
257
- e.load_address = baseaddr
258
- begin
259
- e.decode
260
- #e = Metasm::ELF.decode_file name rescue return # read from disk
261
- rescue
262
- log "failed to load symbols from #{name}: #$!"
263
- ($!.backtrace - caller).each { |l| log l.chomp }
264
- @filemap[baseaddr.to_s(16)] = [baseaddr, baseaddr+0x1000]
265
- return
266
- end
267
-
268
- if e.tag['SONAME']
269
- name = e.tag['SONAME']
270
- return if name and @loadedsyms[name]
271
- @loadedsyms[name] = true
272
- end
273
-
274
- last_s = e.segments.reverse.find { |s| s.type == 'LOAD' }
275
- vlen = last_s.vaddr + last_s.memsz
276
- vlen -= baseaddr if e.header.type == 'EXEC'
277
- @filemap[name] = [baseaddr, baseaddr + vlen]
278
-
279
- oldsyms = @symbols.length
280
- e.symbols.each { |s|
281
- next if not s.name or s.shndx == 'UNDEF'
282
- sname = s.name
283
- sname = 'weak_'+sname if s.bind == 'WEAK'
284
- sname = 'local_'+sname if s.bind == 'LOCAL'
285
- v = s.value
286
- v = baseaddr + v if v < baseaddr
287
- @symbols[v] = sname
288
- @symbols_len[v] = s.size
289
- }
290
- if e.header.type == 'EXEC'
291
- @symbols[e.header.entry] = 'entrypoint'
292
- end
293
- set_status nil
294
- log "loaded #{@symbols.length-oldsyms} symbols from #{name} at #{'%08x' % baseaddr}"
295
- end
296
-
297
- def loadallsyms
298
- File.read("/proc/#{@pid}/maps").each { |l|
299
- name = l.split[5]
300
- loadsyms l.to_i(16), name if name and name[0] == ?/
301
- }
302
- end
303
-
304
- def loadmap(mapfile)
305
- # file fmt: addr type name eg 'c01001ba t setup_idt'
306
- minaddr = maxaddr = nil
307
- File.read(mapfile).each { |l|
308
- addr, type, name = l.chomp.split
309
- addr = addr.to_i(16)
310
- minaddr = addr if not minaddr or minaddr > addr
311
- maxaddr = addr if not maxaddr or maxaddr < addr
312
- @symbols[addr] = name
313
- }
314
- if minaddr
315
- @filemap[minaddr.to_s(16)] = [minaddr, maxaddr+1]
316
- end
317
- end
318
-
319
- def scansyms
320
- addr = 0
321
- fd = @pgm.encoded.data.readfd
322
- while addr <= 0xffff_f000
323
- addr = 0xc000_0000 if @has_pax and addr == 0x6000_0000
324
- log "scansym: #{'%08x' % addr}" if addr & 0x0fff_ffff == 0
325
- fd.pos = addr
326
- loadsyms(addr, '%08x'%addr) if (fd.read(4) == "\x7fELF" rescue false)
327
- addr += 0x1000
328
- end
329
- end
330
-
331
- def backtrace
332
- s = findsymbol(@regs_cache['eip'])
333
- if block_given?
334
- yield s
335
- else
336
- bt = []
337
- bt << s
338
- end
339
- fp = @regs_cache['ebp']
340
- while fp >= @regs_cache['esp'] and fp <= @regs_cache['esp']+0x10000
341
- s = findsymbol(self[fp+4, 4].unpack('L').first)
342
- if block_given?
343
- yield s
344
- else
345
- bt << s
346
- end
347
- fp = self[fp, 4].unpack('L').first
348
- end
349
- bt
350
- end
351
-
352
- def [](addr, len=nil)
353
- @pgm.encoded.data[addr, len]
354
- end
355
- def []=(addr, len, str=nil)
356
- @pgm.encoded.data[addr, len] = str
357
- end
358
-
359
- attr_accessor :logger
360
- def log(s)
361
- @logger ||= $stdout
362
- @logger.puts s
363
- end
364
-
365
- # set a temporary status info (nil for default value)
366
- def set_status(s)
367
- @logger ||= $stdout
368
- if @logger != $stdout
369
- @logger.statusline = s
370
- else
371
- s ||= ' '*72
372
- @logger.print s + "\r"
373
- @logger.flush
374
- end
375
- end
376
- end
377
-
378
- if $0 == __FILE__
379
- # start debugging
380
- rs = Rubstop.new(ARGV.shift)
381
-
382
- begin
383
- while rs.child.stopped? and rs.child.stopsig == Signal.list['TRAP']
384
- if $VERBOSE
385
- puts "#{'%08x' % rs.eip} #{rs.mnemonic}"
386
- rs.singlestep
387
- else
388
- rs.syscall ; rs.syscall # wait return of syscall
389
- puts "#{rs.orig_eax.to_s.ljust(3)} #{rs.syscallnr.index rs.orig_eax}"
390
- end
391
- end
392
- p rs.child
393
- puts rs.regs_dump
394
- rescue Interrupt
395
- rs.detach rescue nil
396
- puts 'interrupted!'
397
- rescue Errno::ESRCH
398
- end
399
- end