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
@@ -26,7 +26,8 @@ $opts = {
26
26
 
27
27
  OptionParser.new { |opt|
28
28
  opt.on('-o file', 'output filename') { |f| $opts[:outfilename] = f }
29
- opt.on('-f') { $opts[:overwrite_outfile] = true }
29
+ opt.on('-i', 'dont overwrite existing outfile') { $opts[:nooverwrite_outfile] = true }
30
+ opt.on('-f', 'overwrite existing outfile (default)') { $opts.delete :nooverwrite_outfile } # without this, optparse autocomplete to --fno-pic and break older scripts...
30
31
  opt.on('--c', 'parse source as a C file') { $opts[:srctype] = 'c' }
31
32
  opt.on('--asm', 'parse asm as an ASM file') { $opts[:srctype] = 'asm' }
32
33
  opt.on('--stdin', 'parse source on stdin') { ARGV << '-' }
@@ -44,7 +45,7 @@ OptionParser.new { |opt|
44
45
  opt.on('--le', 'set cpu in little-endian mode') { $opts[:cpu].endianness = :little }
45
46
  opt.on('--be', 'set cpu in big-endian mode') { $opts[:cpu].endianness = :big }
46
47
  opt.on('--fno-pic', 'generate position-dependant code') { $opts[:cpu].generate_PIC = false }
47
- opt.on('--shared', 'generate shared library') { $opts[:exetype] = :lib }
48
+ opt.on('--shared', '--lib', '--dll', 'generate shared library') { $opts[:exetype] = :lib }
48
49
  opt.on('--ruby-module-hack', 'use the dynldr module hack to use any ruby lib available for ruby symbols') { $opts[:dldrhack] = true }
49
50
  }.parse!
50
51
 
@@ -62,7 +63,7 @@ else
62
63
  src << DATA.read # the text after __END__ in this file
63
64
  end
64
65
 
65
- if $opts[:outfilename] and not $opts[:overwrite_outfile] and File.exist?($opts[:outfilename])
66
+ if $opts[:outfilename] and $opts[:nooverwrite_outfile] and File.exist?($opts[:outfilename])
66
67
  abort "Error: target file exists !"
67
68
  end
68
69
 
@@ -93,7 +94,7 @@ if $opts[:to_string]
93
94
  end
94
95
 
95
96
  if of = $opts[:outfilename]
96
- abort "Error: target file #{of.inspect} exists !" if File.exists? of and not $opts[:overwrite_outfile]
97
+ abort "Error: target file #{of.inspect} exists !" if File.exists?(of) and $opts[:nooverwrite_outfile]
97
98
  File.open(of, 'w') { |fd| fd.puts str }
98
99
  puts "saved to file #{of.inspect}"
99
100
  else
@@ -101,7 +102,7 @@ if $opts[:to_string]
101
102
  end
102
103
  else
103
104
  of = $opts[:outfilename] ||= 'a.out'
104
- abort "Error: target file #{of.inspect} exists !" if File.exists? of and not $opts[:overwrite_outfile]
105
+ abort "Error: target file #{of.inspect} exists !" if File.exists?(of) and $opts[:nooverwrite_outfile]
105
106
  Metasm::DynLdr.compile_binary_module_hack(exe) if $opts[:dldrhack]
106
107
  exe.encode_file(of, $opts[:exetype])
107
108
  puts "saved to file #{of.inspect}"
@@ -41,7 +41,7 @@ if opts[:vspath] ||= ARGV.shift
41
41
  end
42
42
 
43
43
  funcnames = opts[:exe].map { |e|
44
- pe = PE.decode_file_header(e)
44
+ pe = PE.decode_file_header(e) rescue next
45
45
  pe.decode_imports
46
46
  if not pe.imports
47
47
  puts "#{e} has no imports"
@@ -47,14 +47,15 @@ module Ansi
47
47
  $stdin.ioctl(TIOCGWINSZ, s) >= 0 ? s.unpack('SS') : [80, 25]
48
48
  end
49
49
  def self.set_term_canon(bool)
50
- tty = ''.ljust(256)
51
- $stdin.ioctl(TCGETS, tty)
50
+ ttys = ''.ljust(256)
51
+ $stdin.ioctl(TCGETS, ttys)
52
+ tty = ttys.unpack('C*')
52
53
  if bool
53
54
  tty[12] &= ~(ECHO|CANON)
54
55
  else
55
56
  tty[12] |= ECHO|CANON
56
57
  end
57
- $stdin.ioctl(TCSETS, tty)
58
+ $stdin.ioctl(TCSETS, tty.pack('C*'))
58
59
  end
59
60
 
60
61
  ESC_SEQ = {'A' => :up, 'B' => :down, 'C' => :right, 'D' => :left,
@@ -85,49 +86,11 @@ module Ansi
85
86
  end
86
87
  end
87
88
 
88
- class Indirect < Metasm::ExpressionType
89
- attr_accessor :ptr, :sz
90
- UNPACK_STR = {1 => 'C', 2 => 'S', 4 => 'L'}
91
- def initialize(ptr, sz) @ptr, @sz = ptr, sz end
92
- def bind(bd)
93
- raw = bd['tracer_memory'][@ptr.bind(bd).reduce, @sz]
94
- Metasm::Expression[raw.unpack(UNPACK_STR[@sz]).first]
95
- end
96
- def externals ; @ptr.externals end
97
- end
98
-
99
- class ExprParser < Metasm::Expression
100
- def self.parse_intfloat(lex, tok)
101
- case tok.raw
102
- when 'byte', 'word', 'dword'
103
- nil while ntok = lex.readtok and ntok.type == :space
104
- nil while ntok = lex.readtok and ntok.type == :space if ntok and ntok.raw == 'ptr'
105
- if ntok and ntok.raw == '['
106
- tok.value = Indirect.new(parse(lex), {'byte' => 1, 'word' => 2, 'dword' => 4}[tok.raw])
107
- nil while ntok = lex.readtok and ntok.type == :space
108
- nil while ntok = lex.readtok and ntok.type == :space if ntok and ntok.raw == ']'
109
- lex.unreadtok ntok
110
- end
111
- else super(lex, tok)
112
- end
113
- end
114
- def self.parse_value(lex)
115
- nil while tok = lex.readtok and tok.type == :space
116
- lex.unreadtok tok
117
- if tok and tok.type == :punct and tok.raw == '['
118
- tt = tok.dup
119
- tt.type = :string
120
- tt.raw = 'dword'
121
- lex.unreadtok tt
122
- end
123
- super(lex)
124
- end
125
- end
126
-
127
89
  class LinDebug
128
- attr_accessor :win_data_height, :win_code_height, :win_prpt_height
90
+ attr_accessor :win_reg_height, :win_data_height, :win_code_height, :win_prpt_height
129
91
  def init_screen
130
92
  Ansi.set_term_canon(true)
93
+ @win_reg_height = 2
131
94
  @win_data_height = 20
132
95
  @win_code_height = 20
133
96
  resize
@@ -139,7 +102,7 @@ class LinDebug
139
102
  $stdout.flush
140
103
  end
141
104
 
142
- def win_data_start; 2 end
105
+ def win_data_start; @win_reg_height end
143
106
  def win_code_start; win_data_start+win_data_height end
144
107
  def win_prpt_start; win_code_start+win_code_height end
145
108
 
@@ -164,9 +127,8 @@ class LinDebug
164
127
  attr_accessor :dataptr, :codeptr, :rs, :promptlog, :command
165
128
  def initialize(rs)
166
129
  @rs = rs
167
- @rs.logger = self
130
+ @rs.set_log_proc { |l| add_log l }
168
131
  @datafmt = 'db'
169
- @watch = nil
170
132
 
171
133
  @prompthistlen = 20
172
134
  @prompthistory = []
@@ -176,6 +138,7 @@ class LinDebug
176
138
  @promptpos = 0
177
139
  @log_off = 0
178
140
  @console_width = 80
141
+ @oldregs = {}
179
142
 
180
143
  @running = false
181
144
  @focus = :prompt
@@ -185,7 +148,7 @@ class LinDebug
185
148
  end
186
149
 
187
150
  def init_rs
188
- @codeptr = @dataptr = @rs.regs_cache['eip'] # avoid initial faults
151
+ @codeptr = @dataptr = @rs.pc # avoid initial faults
189
152
  end
190
153
 
191
154
  def main_loop
@@ -201,9 +164,9 @@ class LinDebug
201
164
  $stdout.print Ansi.set_cursor_pos(@console_height, 1)
202
165
  end
203
166
  rescue
204
- $stdout.puts $!, $!.backtrace
167
+ puts $!, $!.backtrace
205
168
  end
206
- $stdout.puts @promptlog.last
169
+ puts @promptlog.last
207
170
  end
208
171
 
209
172
  # optimize string to display to stdout
@@ -218,7 +181,7 @@ class LinDebug
218
181
  def display_screen(screenlines, cursx, cursy)
219
182
 
220
183
  @oldscreenbuf ||= []
221
- lines = screenlines.to_a
184
+ lines = screenlines.lines
222
185
  oldlines = @oldscreenbuf
223
186
  @oldscreenbuf = lines
224
187
  screenlines = lines.zip(oldlines).map { |l, ol| l == ol ? "\n" : l }.join
@@ -247,41 +210,40 @@ class LinDebug
247
210
  end
248
211
 
249
212
  def _updateregs
250
- text = ''
251
- text << ' '
252
- x = 1
253
- %w[eax ebx ecx edx eip].each { |r|
254
- text << Color[:changed] if @rs.regs_cache[r] != @rs.oldregs[r]
255
- text << r << ?=
256
- text << ('%08X' % @rs.regs_cache[r])
257
- text << Color[:normal] if @rs.regs_cache[r] != @rs.oldregs[r]
258
- text << ' '
259
- x += r.length + 11
260
- }
261
- text << (' '*([@console_width-x, 0].max)) << "\n" << ' '
262
- x = 1
263
- %w[esi edi ebp esp].each { |r|
264
- text << Color[:changed] if @rs.regs_cache[r] != @rs.oldregs[r]
265
- text << r << ?=
266
- text << ('%08X' % @rs.regs_cache[r])
267
- text << Color[:normal] if @rs.regs_cache[r] != @rs.oldregs[r]
268
- text << ' '
269
- x += r.length + 11
213
+ pvrsz = 0
214
+ words = @rs.register_list.map { |r|
215
+ rs = r.to_s.rjust(pvrsz)
216
+ pvrsz = rs.length
217
+ rv = @rs[r]
218
+ ["#{rs}=%0#{@rs.register_size[r]/4}X " % rv,
219
+ (@oldregs[r] != rv)]
220
+ } + @rs.flag_list.map { |fl|
221
+ fv = @rs.get_flag(fl)
222
+ [fv ? fl.to_s.upcase : fl.to_s.downcase,
223
+ (@oldregs[fl] != fv)]
270
224
  }
271
- Rubstop::EFLAGS.sort.each { |off, flag|
272
- val = @rs.regs_cache['eflags'] & (1<<off)
273
- flag = flag.upcase if val != 0
274
- if val != @rs.oldregs['eflags'] & (1 << off)
275
- text << Color[:changed]
276
- text << flag
277
- text << Color[:normal]
278
- else
279
- text << flag
225
+
226
+ text = ' '
227
+ linelen = 1 # line length w/o ansi colors
228
+
229
+ owr = @win_reg_height
230
+ @win_reg_height = 1
231
+ words.each { |w, changed|
232
+ if linelen + w.length >= @console_width - 1
233
+ text << (' '*([@console_width-linelen, 0].max)) << "\n "
234
+ linelen = 1
235
+ @win_reg_height += 1
280
236
  end
237
+
238
+ text << Color[:changed] if changed
239
+ text << w
240
+ text << Color[:normal] if changed
281
241
  text << ' '
282
- x += 2
242
+
243
+ linelen += w.length+1
283
244
  }
284
- text << (' '*([@console_width-x, 0].max)) << "\n"
245
+ resize if owr != @win_reg_height
246
+ text << (' '*([@console_width-linelen, 0].max)) << "\n"
285
247
  end
286
248
 
287
249
  def updatecode
@@ -291,21 +253,23 @@ class LinDebug
291
253
  def _updatecode
292
254
  if @codeptr
293
255
  addr = @codeptr
294
- elsif @rs.oldregs['eip'] and @rs.oldregs['eip'] < @rs.regs_cache['eip'] and @rs.oldregs['eip'] + 8 >= @rs.regs_cache['eip']
295
- addr = @rs.oldregs['eip']
256
+ elsif @oldregs[@rs.register_pc] and @oldregs[@rs.register_pc] < @rs.pc and @oldregs[@rs.register_pc] + 8 >= @rs.pc
257
+ addr = @oldregs[@rs.register_pc]
296
258
  else
297
- addr = @rs.regs_cache['eip']
259
+ addr = @rs.pc
298
260
  end
299
261
  @codeptr = addr
300
262
 
301
- if @rs.findfilemap(addr) == '???'
302
- base = addr & 0xffff_f000
263
+ addrsz = @rs.register_size[@rs.register_pc]
264
+ addrfmt = "%0#{addrsz/4}X"
265
+ if not @rs.addr2module(addr) and @rs.shortname !~ /remote/
266
+ base = addr & ((1 << addrsz) - 0x1000)
303
267
  @noelfsig ||= {} # cache elfmagic notfound
304
- if not @noelfsig[base] and base < 0xc000_0000
305
- self.statusline = " scanning for elf header at #{'%08X' % base}"
268
+ if not @noelfsig[base] and base < ((1 << addrsz) - 0x1_0000)
269
+ self.statusline = " scanning for elf header at #{addrfmt % base}"
306
270
  128.times {
307
- @statusline = " scanning for elf header at #{'%08X' % base}"
308
- if not @noelfsig[base] and @rs[base, 4] == Metasm::ELF::MAGIC
271
+ @statusline = " scanning for elf header at #{addrfmt % base}"
272
+ if not @noelfsig[base] and @rs[base, Metasm::ELF::MAGIC.length] == Metasm::ELF::MAGIC
309
273
  @rs.loadsyms(base, base.to_s(16))
310
274
  break
311
275
  else
@@ -320,36 +284,43 @@ class LinDebug
320
284
 
321
285
  text = ''
322
286
  text << Color[:border]
323
- title = @rs.findsymbol(addr)
287
+ title = @rs.addrname(addr)
324
288
  pre = [@console_width-100, 6].max
325
289
  post = @console_width - (pre + title.length + 2)
326
290
  text << Ansi.hline(pre) << ' ' << title << ' ' << Ansi.hline(post) << Color[:normal] << "\n"
327
291
 
292
+ seg = ''
293
+ seg = ('%04X' % @rs['cs']) << ':' if @rs.cpu.shortname =~ /ia32|x64/
294
+
328
295
  cnt = @win_code_height
329
296
  while (cnt -= 1) > 0
330
297
  if @rs.symbols[addr]
331
298
  text << (' ' << @rs.symbols[addr] << ?:) << Ansi::ClearLineAfter << "\n"
332
299
  break if (cnt -= 1) <= 0
333
300
  end
334
- text << Color[:hilight] if addr == @rs.regs_cache['eip']
335
- text << ('%04X' % @rs.regs_cache['cs']) << ':'
336
- text << ('%08X' % addr)
337
- di = @rs.mnemonic_di(addr)
338
- di = nil if di and addr < @rs.regs_cache['eip'] and addr+di.bin_length > @rs.regs_cache['eip']
301
+ text << Color[:hilight] if addr == @rs.pc
302
+ text << seg
303
+ if @rs.shortname =~ /remote/ and @rs.realmode
304
+ text << (addrfmt % (addr - 16*@rs['cs']))
305
+ else
306
+ text << (addrfmt % addr)
307
+ end
308
+ di = @rs.di_at(addr)
309
+ di = nil if di and addr < @rs.pc and addr+di.bin_length > @rs.pc
339
310
  len = (di ? di.bin_length : 1)
340
311
  text << ' '
341
- text << @rs[addr, [len, 10].min].unpack('C*').map { |c| '%02X' % c }.join.ljust(22)
312
+ text << @rs.memory[addr, [len, 10].min].to_s.unpack('C*').map { |c| '%02X' % c }.join.ljust(22)
342
313
  if di
343
314
  text <<
344
- if addr == @rs.regs_cache['eip']
345
- "*#{di.instruction}".ljust([@console_width-37, 0].max)
315
+ if addr == @rs.pc
316
+ "*#{di.instruction}".ljust([@console_width-(addrsz/4+seg.length+24), 0].max)
346
317
  else
347
318
  " #{di.instruction}" << Ansi::ClearLineAfter
348
319
  end
349
320
  else
350
321
  text << ' <unk>' << Ansi::ClearLineAfter
351
322
  end
352
- text << Color[:normal] if addr == @rs.regs_cache['eip']
323
+ text << Color[:normal] if addr == @rs.pc
353
324
  addr += len
354
325
  text << "\n"
355
326
  end
@@ -361,27 +332,33 @@ class LinDebug
361
332
  end
362
333
 
363
334
  def _updatedata
364
- @dataptr &= 0xffff_ffff
335
+ addrsz = @rs.register_size[@rs.register_pc]
336
+ addrfmt = "%0#{addrsz/4}X"
337
+
338
+ @dataptr &= ((1 << addrsz) - 1)
365
339
  addr = @dataptr
366
340
 
367
341
  text = ''
368
342
  text << Color[:border]
369
- title = @rs.findsymbol(addr)
343
+ title = @rs.addrname(addr)
370
344
  pre = [@console_width-100, 6].max
371
345
  post = [@console_width - (pre + title.length + 2), 0].max
372
346
  text << Ansi.hline(pre) << ' ' << title << ' ' << Ansi.hline(post) << Color[:normal] << "\n"
373
347
 
348
+ seg = ''
349
+ seg = ('%04X' % @rs['ds']) << ':' if @rs.cpu.shortname =~ /^ia32/
350
+
374
351
  cnt = @win_data_height
375
352
  while (cnt -= 1) > 0
376
- raw = @rs[addr, 16].to_s
377
- text << ('%04X' % @rs.regs_cache['ds']) << ':' << ('%08X' % addr) << ' '
353
+ raw = @rs.memory[addr, 16].to_s
354
+ text << seg << (addrfmt % addr) << ' '
378
355
  case @datafmt
379
356
  when 'db'; text << raw[0,8].unpack('C*').map { |c| '%02x ' % c }.join << ' ' <<
380
357
  raw[8,8].to_s.unpack('C*').map { |c| '%02x ' % c }.join
381
358
  when 'dw'; text << raw.unpack('S*').map { |c| '%04x ' % c }.join
382
359
  when 'dd'; text << raw.unpack('L*').map { |c| '%08x ' % c }.join
383
360
  end
384
- text << ' ' << raw.unpack('C*').map { |c| (0x20..0x7e).include?(c) ? c : ?. }.pack('C*')
361
+ text << ' ' << raw.unpack('C*').map { |c| (0x20..0x7e).include?(c) ? c : 0x2e }.pack('C*')
385
362
  text << Ansi::ClearLineAfter << "\n"
386
363
  addr += 16
387
364
  end
@@ -420,17 +397,17 @@ class LinDebug
420
397
  @console_height, @console_width = Ansi.get_terminal_size
421
398
  @win_data_height = 1 if @win_data_height < 1
422
399
  @win_code_height = 1 if @win_code_height < 1
423
- if @win_data_height + @win_code_height + 5 > @console_height
400
+ if @win_data_height + @win_code_height + @win_reg_height + 3 > @console_height
424
401
  @win_data_height = @console_height/2 - 4
425
402
  @win_code_height = @console_height/2 - 4
426
403
  end
427
- @win_prpt_height = @console_height-(@win_data_height+@win_code_height+2) - 1
404
+ @win_prpt_height = @console_height-(@win_data_height+@win_code_height+@win_reg_height) - 1
428
405
  @oldscreenbuf = []
429
406
  update
430
407
  end
431
408
 
432
409
  def log(*strs)
433
- strs.each { |str|
410
+ strs.each { |str|
434
411
  raise str.inspect if not str.kind_of? ::String
435
412
  str = str.chomp
436
413
  if str.length > @console_width
@@ -440,85 +417,52 @@ class LinDebug
440
417
  end
441
418
  @promptlog << str
442
419
  @promptlog.shift if @promptlog.length > @promptloglen
443
- }
420
+ }
444
421
  end
445
422
 
446
- def puts(*s)
447
- s.each { |s_| log s_.to_s }
448
- super(*s) if not @running
449
- update rescue super(*s)
450
- end
451
-
452
- def mem_binding(expr)
453
- b = @rs.regs_cache.dup
454
- ext = expr.externals
455
- (ext - @rs.regs_cache.keys).each { |ex|
456
- if not s = @rs.symbols.index(ex)
457
- near = @rs.symbols.values.grep(/#{ex}/i)
458
- if near.length > 1
459
- log "#{ex.inspect} is ambiguous: #{near.inspect}"
460
- return {}
461
- elsif near.empty?
462
- log "unknown value #{ex.inspect}"
463
- return {}
464
- else
465
- log "using #{near.first.inspect} for #{ex.inspect}"
466
- s = @rs.symbols.index(near.first)
467
- end
468
- end
469
- b[ex] = s
470
- }
471
- b['tracer_memory'] = @rs
472
- b
423
+ def add_log(l)
424
+ log l
425
+ puts l if not @running
426
+ update rescue puts l
473
427
  end
474
428
 
475
429
  def exec_prompt
476
430
  @log_off = 0
477
431
  log ':'+@promptbuf
478
432
  return if @promptbuf == ''
479
- lex = Metasm::Preprocessor.new.feed @promptbuf
433
+ str = @promptbuf
480
434
  @prompthistory << @promptbuf
481
435
  @prompthistory.shift if @prompthistory.length > @prompthistlen
482
436
  @promptbuf = ''
483
437
  @promptpos = @promptbuf.length
484
- argint = lambda {
485
- begin
486
- raise if not e = ExprParser.parse(lex)
487
- rescue
488
- log 'syntax error'
489
- return
490
- end
491
- e = e.bind(mem_binding(e)).reduce
492
- if e.kind_of? Integer; e
493
- else log "could not resolve #{e.inspect}" ; nil
494
- end
495
- }
496
438
 
497
- cmd = lex.readtok
498
- cmd = cmd.raw if cmd
499
- nil while ntok = lex.readtok and ntok.type == :space
500
- lex.unreadtok ntok
439
+ cmd, str = str.split(/\s+/, 2)
501
440
  if @command.has_key? cmd
502
- @command[cmd].call(lex, argint)
441
+ @command[cmd].call(str.to_s)
503
442
  else
504
443
  if cmd and (poss = @command.keys.find_all { |c| c[0, cmd.length] == cmd }).length == 1
505
- @command[poss.first].call(lex, argint)
444
+ @command[poss.first].call(str.to_s)
506
445
  else
507
446
  log 'unknown command'
508
447
  end
509
448
  end
510
449
  end
511
450
 
451
+ def preupdate
452
+ @rs.register_list.each { |r| @oldregs[r] = @rs[r] }
453
+ @rs.flag_list.each { |fl| @oldregs[fl] = @rs.get_flag(fl) }
454
+ end
455
+
512
456
  def updatecodeptr
513
- @codeptr ||= @rs.regs_cache['eip']
514
- if @codeptr > @rs.regs_cache['eip'] or @codeptr < @rs.regs_cache['eip'] - 6*@win_code_height
515
- @codeptr = @rs.regs_cache['eip']
516
- elsif @codeptr != @rs.regs_cache['eip']
457
+ @codeptr ||= @rs.pc
458
+ if @codeptr > @rs.pc or @codeptr < @rs.pc - 6*@win_code_height
459
+ @codeptr = @rs.pc
460
+ elsif @codeptr != @rs.pc
517
461
  addr = @codeptr
518
462
  addrs = []
519
- while addr < @rs.regs_cache['eip']
463
+ while addr < @rs.pc
520
464
  addrs << addr
521
- o = ((di = @rs.mnemonic_di(addr)) ? di.bin_length : 0)
465
+ o = ((di = @rs.di_at(addr)) ? di.bin_length : 0)
522
466
  addr += ((o == 0) ? 1 : o)
523
467
  end
524
468
  if addrs.length > @win_code_height-4
@@ -529,36 +473,40 @@ class LinDebug
529
473
  end
530
474
 
531
475
  def updatedataptr
532
- @dataptr = @watch.bind(mem_binding(@watch)).reduce if @watch
533
476
  end
534
477
 
535
478
  def singlestep
536
479
  self.statusline = ' target singlestepping...'
537
- @rs.singlestep
480
+ preupdate
481
+ @rs.singlestep_wait
538
482
  updatecodeptr
539
483
  @statusline = nil
540
484
  end
541
485
  def stepover
542
486
  self.statusline = ' target running...'
543
- @rs.stepover
487
+ preupdate
488
+ @rs.stepover_wait
544
489
  updatecodeptr
545
490
  @statusline = nil
546
491
  end
547
492
  def cont(*a)
548
493
  self.statusline = ' target running...'
549
- @rs.cont(*a)
494
+ preupdate
495
+ @rs.continue_wait(*a)
550
496
  updatecodeptr
551
497
  @statusline = nil
552
498
  end
553
499
  def stepout
554
500
  self.statusline = ' target running...'
555
- @rs.stepout
501
+ preupdate
502
+ @rs.stepout_wait
556
503
  updatecodeptr
557
504
  @statusline = nil
558
505
  end
559
506
  def syscall
560
507
  self.statusline = ' target running to next syscall...'
561
- @rs.syscall
508
+ preupdate
509
+ @rs.syscall_wait
562
510
  updatecodeptr
563
511
  @statusline = nil
564
512
  end
@@ -578,17 +526,14 @@ class LinDebug
578
526
  end
579
527
  break if handle_keypress(Ansi.getkey)
580
528
  end
581
- @rs.checkbp
582
529
  end
583
530
 
584
531
  def handle_keypress(k)
585
532
  case k
586
- when 4; log 'exiting'; return true # eof
587
- when ?\e; focus = :prompt
533
+ when ?\4; log 'exiting'; return true # eof
534
+ when ?\e; @focus = :prompt
588
535
  when :f5; cont
589
- when :f6
590
- syscall
591
- log @rs.syscallnr.index(@rs.regs_cache['orig_eax']) || @rs.regs_cache['orig_eax'].to_s
536
+ when :f6; syscall
592
537
  when :f10; stepover
593
538
  when :f11; singlestep
594
539
  when :f12; stepout
@@ -607,9 +552,9 @@ class LinDebug
607
552
  when :data
608
553
  @dataptr -= 16
609
554
  when :code
610
- @codeptr ||= @rs.regs_cache['eip']
555
+ @codeptr ||= @rs.pc
611
556
  @codeptr -= (1..10).find { |off|
612
- di = @rs.mnemonic_di(@codeptr-off)
557
+ di = @rs.di_at(@codeptr-off)
613
558
  di.bin_length == off if di
614
559
  } || 10
615
560
  end
@@ -628,25 +573,25 @@ class LinDebug
628
573
  when :data
629
574
  @dataptr += 16
630
575
  when :code
631
- @codeptr ||= @rs.regs_cache['eip']
632
- di = @rs.mnemonic_di(@codeptr)
576
+ @codeptr ||= @rs.pc
577
+ di = @rs.di_at(@codeptr)
633
578
  @codeptr += (di ? (di.bin_length || 1) : 1)
634
579
  end
635
580
  when :left; @promptpos -= 1 if @promptpos > 0
636
581
  when :right; @promptpos += 1 if @promptpos < @promptbuf.length
637
582
  when :home; @promptpos = 0
638
583
  when :end; @promptpos = @promptbuf.length
639
- when :backspace, 0x7f; @promptbuf[@promptpos-=1, 1] = '' if @promptpos > 0
584
+ when :backspace, ?\x7f; @promptbuf[@promptpos-=1, 1] = '' if @promptpos > 0
640
585
  when :suppr; @promptbuf[@promptpos, 1] = '' if @promptpos < @promptbuf.length
641
586
  when :pgup
642
587
  case @focus
643
588
  when :prompt; @log_off += @win_prpt_height-3
644
589
  when :data; @dataptr -= 16*(@win_data_height-1)
645
590
  when :code
646
- @codeptr ||= @rs.regs_cache['eip']
591
+ @codeptr ||= @rs.pc
647
592
  (@win_code_height-1).times {
648
593
  @codeptr -= (1..10).find { |off|
649
- di = @rs.mnemonic_di(@codeptr-off)
594
+ di = @rs.di_at(@codeptr-off)
650
595
  di.bin_length == off if di
651
596
  } || 10
652
597
  }
@@ -656,8 +601,8 @@ class LinDebug
656
601
  when :prompt; @log_off -= @win_prpt_height-3
657
602
  when :data; @dataptr += 16*(@win_data_height-1)
658
603
  when :code
659
- @codeptr ||= @rs.regs_cache['eip']
660
- (@win_code_height-1).times { @codeptr += ((o = @rs.mnemonic_di(@codeptr)) ? [o.bin_length, 1].max : 1) }
604
+ @codeptr ||= @rs.pc
605
+ (@win_code_height-1).times { @codeptr += ((o = @rs.di_at(@codeptr)) ? [o.bin_length, 1].max : 1) }
661
606
  end
662
607
  when ?\t
663
608
  if not @promptbuf[0, @promptpos].include? ' '
@@ -676,7 +621,7 @@ class LinDebug
676
621
  rescue Exception
677
622
  log "error: #$!", *$!.backtrace
678
623
  end
679
- when 0x20..0x7e
624
+ when ?\ ..?~
680
625
  @promptbuf[@promptpos, 0] = k.chr
681
626
  @promptpos += 1
682
627
  else log "unknown key pressed #{k.inspect}"
@@ -685,240 +630,89 @@ class LinDebug
685
630
  end
686
631
 
687
632
  def load_commands
688
- ntok = nil
689
- @command['kill'] = lambda { |lex, int|
633
+ @command['kill'] = lambda { |str|
690
634
  @rs.kill
691
635
  @running = false
692
636
  log 'killed'
693
637
  }
694
- @command['quit'] = @command['detach'] = @command['exit'] = lambda { |lex, int|
638
+ @command['quit'] = @command['detach'] = @command['exit'] = lambda { |str|
695
639
  @rs.detach
696
640
  @running = false
697
641
  }
698
- @command['closeui'] = lambda { |lex, int|
699
- @rs.logger = nil
642
+ @command['closeui'] = lambda { |str|
700
643
  @running = false
701
644
  }
702
- @command['bpx'] = lambda { |lex, int|
703
- addr = int[]
704
- @rs.bpx addr
705
- }
706
- @command['bphw'] = lambda { |lex, int|
707
- type = lex.readtok.raw
708
- addr = int[]
709
- @rs.set_hwbp type, addr
710
- }
711
- @command['bl'] = lambda { |lex, int|
712
- log "bpx at #{@rs.findsymbol(@rs.wantbp)}" if @rs.wantbp.kind_of? ::Integer
713
- @rs.breakpoints.sort.each { |addr, oct|
714
- log "bpx at #{@rs.findsymbol(addr)}"
715
- }
716
- (0..3).each { |dr|
717
- if @rs.regs_cache['dr7'] & (1 << (2*dr)) != 0
718
- log "bphw #{{0=>'x', 1=>'w', 2=>'?', 3=>'r'}[(@rs.regs_cache['dr7'] >> (16+4*dr)) & 3]} at #{@rs.findsymbol(@rs.regs_cache["dr#{dr}"])}"
719
- end
720
- }
645
+ @command['bpx'] = lambda { |str|
646
+ @rs.bpx @rs.resolve(str)
721
647
  }
722
- @command['bc'] = lambda { |lex, int|
723
- @rs.clearbreaks
648
+ @command['bphw'] = @command['hwbp'] = lambda { |str|
649
+ type, str = str.split(/\s+/, 2)
650
+ @rs.hwbp @rs.resolve(str.to_s), type
724
651
  }
725
- @command['bt'] = lambda { |lex, int| @rs.backtrace { |t| puts t } }
726
- @command['d'] = lambda { |lex, int| @dataptr = int[] || return }
727
- @command['db'] = lambda { |lex, int| @datafmt = 'db' ; @dataptr = int[] || return }
728
- @command['dw'] = lambda { |lex, int| @datafmt = 'dw' ; @dataptr = int[] || return }
729
- @command['dd'] = lambda { |lex, int| @datafmt = 'dd' ; @dataptr = int[] || return }
730
- @command['r'] = lambda { |lex, int|
731
- r = lex.readtok.raw
732
- nil while ntok = lex.readtok and ntok.type == :space
652
+ @command['bt'] = lambda { |str| @rs.stacktrace { |a,t| add_log "#{'%x' % a} #{t}" } }
653
+ @command['d'] = lambda { |str| @dataptr = @rs.resolve(str) if str.length > 0 }
654
+ @command['db'] = lambda { |str| @datafmt = 'db' ; @dataptr = @rs.resolve(str) if str.length > 0 }
655
+ @command['dw'] = lambda { |str| @datafmt = 'dw' ; @dataptr = @rs.resolve(str) if str.length > 0 }
656
+ @command['dd'] = lambda { |str| @datafmt = 'dd' ; @dataptr = @rs.resolve(str) if str.length > 0 }
657
+ @command['r'] = lambda { |str|
658
+ r, str = str.split(/\s+/, 2)
733
659
  if r == 'fl'
734
- flag = ntok.raw
735
- if i = Rubstop::EFLAGS.index(flag)
736
- @rs.eflags ^= 1 << i
737
- @rs.readregs
738
- else
739
- log "bad flag #{flag}"
740
- end
741
- elsif not @rs.regs_cache[r]
660
+ @rs.toggle_flag(str.to_sym)
661
+ elsif not @rs[r]
742
662
  log "bad reg #{r}"
743
- elsif ntok
744
- lex.unreadtok ntok
745
- newval = int[]
746
- if newval and newval.kind_of? ::Integer
747
- @rs.send r+'=', newval
748
- @rs.readregs
749
- end
663
+ elsif str and str.length > 0
664
+ @rs[r] = @rs.resolve(str)
750
665
  else
751
- log "#{r} = #{@rs.regs_cache[r]}"
666
+ log "#{r} = #{@rs[r]}"
752
667
  end
753
668
  }
754
- @command['run'] = @command['cont'] = lambda { |lex, int|
755
- if tok = lex.readtok
756
- lex.unreadtok tok
757
- cont int[]
758
- else cont
759
- end
760
- }
761
- @command['syscall'] = lambda { |lex, int| syscall }
762
- @command['singlestep'] = lambda { |lex, int| singlestep }
763
- @command['stepover'] = lambda { |lex, int| stepover }
764
- @command['stepout'] = lambda { |lex, int| stepout }
765
- @command['g'] = lambda { |lex, int|
766
- target = int[]
767
- @rs.singlestep if @rs.regs_cache['eip'] == target
768
- @rs.bpx target, true
769
- cont
770
- }
771
- @command['u'] = lambda { |lex, int| @codeptr = int[] || break }
772
- @command['has_pax'] = lambda { |lex, int|
773
- if tok = lex.readtok
774
- lex.unreadtok tok
775
- if (int[] == 0)
776
- @rs.set_pax false
777
- else
778
- @rs.set_pax true
779
- end
780
- else @rs.set_pax !@rs.has_pax
781
- end
782
- log "has_pax now #{@rs.has_pax}"
783
- }
784
- @command['loadsyms'] = lambda { |lex, int|
785
- mapfile = ''
786
- mapfile << ntok.raw while ntok = lex.readtok
787
- if mapfile != ''
788
- @rs.loadmap mapfile
789
- else
790
- @rs.loadallsyms
791
- end
669
+ @command['g'] = lambda { |str|
670
+ @rs.go @rs.resolve(str)
792
671
  }
793
- @command['scansyms'] = lambda { |lex, int| @rs.scansyms }
794
- @command['sym'] = lambda { |lex, int|
795
- sym = ''
796
- sym << ntok.raw while ntok = lex.readtok
797
- s = []
798
- @rs.symbols.each { |k, v|
799
- s << k if v =~ /#{sym}/
800
- }
801
- if s.empty?
802
- log "unknown symbol #{sym}"
803
- else
804
- s.sort.each { |s_| log "#{'%08x' % s_} #{@rs.symbols_len[s_].to_s.ljust 6} #{@rs.findsymbol(s_)}" }
805
- end
806
- }
807
- @command['delsym'] = lambda { |lex, int|
808
- addr = int[]
809
- log "deleted #{@rs.symbols.delete addr}"
810
- @rs.symbols_len.delete addr
811
- }
812
- @command['addsym'] = lambda { |lex, int|
813
- name = lex.readtok.raw
814
- addr = int[]
815
- if t = lex.readtok
816
- lex.unreadtok t
817
- @rs.symbols_len[addr] = int[]
818
- else
819
- @rs.symbols_len[addr] = 1
820
- end
821
- @rs.symbols[addr] = name
822
- }
823
- @command['help'] = lambda { |lex, int|
824
- log 'commands: (addr/values are things like dword ptr [ebp+(4*byte [eax])] ), type <tab> to see all commands'
825
- log ' bpx <addr>'
826
- log ' bphw [r|w|x] <addr>: debug register breakpoint'
827
- log ' bl: list breakpoints'
828
- log ' bc: clear breakpoints'
829
- log ' cont [<signr>]: continue the target sending a signal'
830
- log ' d/db/dw/dd [<addr>]: change data type/address'
831
- log ' g <addr>: set a bp at <addr> and run'
832
- log ' has_pax [0|1]: set has_pax flag'
833
- log ' loadsyms: load symbol information from mapped files (from /proc and disk)'
834
- log ' ma <addr> <ascii>: write memory'
835
- log ' mx <addr> <hex>: write memory'
836
- log ' maps: list maps'
837
- log ' r <reg> [<value>]: show/change register'
838
- log ' r fl <flag>: toggle eflags bit'
839
- log ' scansyms: scan memory for ELF headers'
840
- log ' sym <symbol regex>: show symbol information'
841
- log ' addsym <name> <addr> [<size>]'
842
- log ' delsym <addr>'
843
- log ' u <addr>: disassemble addr'
844
- log ' reload: reload lindebug source'
845
- log ' ruby <ruby code>: instance_evals ruby code in current instance'
846
- log ' closeui: detach from the underlying RubStop'
847
- log 'keys:'
848
- log ' F5: continue'
849
- log ' F6: syscall'
850
- log ' F10: step over'
851
- log ' F11: single step'
852
- log ' F12: step out (til next ret)'
853
- log ' pgup/pgdown: move command history'
854
- }
855
- @command['reload'] = lambda { |lex, int| load $0 ; load_commands }
856
- @command['ruby'] = lambda { |lex, int|
857
- str = ''
858
- str << ntok.raw while ntok = lex.readtok
859
- instance_eval str
860
- }
861
- @command['maps'] = lambda { |lex, int|
862
- @rs.filemap.sort_by { |f, (b, e)| b }.each { |f, (b, e)|
863
- log "#{f.ljust 20} #{'%08x' % b} - #{'%08x' % e}"
864
- }
865
- }
866
- @command['ma'] = lambda { |lex, int|
867
- addr = int[]
868
- str = ''
869
- str << ntok.raw while ntok = lex.readtok
870
- @rs[addr, str.length] = str
871
- }
872
- @command['mx'] = lambda { |lex, int|
873
- addr = int[]
874
- data = [lex.readtok.raw].pack('H*')
875
- @rs[addr, data.length] = data
876
- }
877
- @command['resize'] = lambda { |lex, int| resize }
878
- @command['watch'] = lambda { |lex, int| @watch = ExprParser.parse(lex) ; updatedataptr }
879
- @command['wd'] = lambda { |lex, int|
672
+ @command['u'] = lambda { |str| @codeptr = @rs.resolve(str) }
673
+ @command['ruby'] = lambda { |str| instance_eval str }
674
+ @command['wd'] = lambda { |str|
880
675
  @focus = :data
881
- if tok = lex.readtok
882
- lex.unreadtok tok
883
- @win_data_height = int[] || return
676
+ if str.length > 0
677
+ @win_data_height = @rs.resolve(str)
884
678
  resize
885
679
  end
886
680
  }
887
- @command['wc'] = lambda { |lex, int|
681
+ @command['wc'] = lambda { |str|
888
682
  @focus = :code
889
- if tok = lex.readtok
890
- lex.unreadtok tok
891
- @win_code_height = int[] || return
683
+ if str.length > 0
684
+ @win_code_height = @rs.resolve(str)
892
685
  resize
893
686
  end
894
687
  }
895
- @command['wp'] = lambda { |lex, int| @focus = :prompt }
896
- @command['?'] = lambda { |lex, int|
897
- val = int[]
688
+ @command['wp'] = lambda { |str| @focus = :prompt }
689
+ @command['?'] = lambda { |str|
690
+ val = @rs.resolve(str)
898
691
  log "#{val} 0x#{val.to_s(16)} #{[val].pack('L').inspect}"
899
692
  }
900
- @command['.'] = lambda { |lex, int| @codeptr = nil }
693
+ @command['syscall'] = lambda { |str|
694
+ @rs.syscall_wait(str)
695
+ }
901
696
  end
902
697
  end
903
698
 
904
699
 
905
700
  if $0 == __FILE__
906
701
  require 'optparse'
907
- filemap = nil
702
+ opts = { :sc_cpu => 'Ia32' }
908
703
  OptionParser.new { |opt|
909
- opt.on('-m map', '--map filemap') { |f| filemap = f }
704
+ opt.on('-m map', '--map filemap') { |f| opts[:filemap] = f }
705
+ opt.on('--cpu cpu') { |c| opts[:sc_cpu] = c }
910
706
  }.parse!(ARGV)
911
707
 
912
- if not defined? Rubstop
913
- if ARGV.first =~ /:/
914
- stub = 'gdbclient'
915
- else
916
- stub = 'rubstop'
917
- end
918
- require File.join(File.dirname(__FILE__), stub)
708
+ case ARGV.first
709
+ when /^(tcp:|udp:)?..+:/, /^ser:/
710
+ opts[:sc_cpu] = eval(opts[:sc_cpu]) if opts[:sc_cpu] =~ /[.(\s:]/
711
+ opts[:sc_cpu] = opts[:sc_cpu].new if opts[:sc_cpu].kind_of?(::Class)
712
+ rs = Metasm::GdbRemoteDebugger.new(ARGV.first, opts[:sc_cpu])
713
+ else
714
+ rs = Metasm::LinDebugger.new(ARGV.join(' '))
919
715
  end
920
-
921
- rs = Rubstop.new(ARGV.join(' '))
922
- rs.loadmap(filemap) if filemap
716
+ rs.load_map(opts[:filemap]) if opts[:filemap]
923
717
  LinDebug.new(rs).main_loop
924
718
  end