metasm 1.0.1 → 1.0.2

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