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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
data/samples/exeencode.rb
CHANGED
|
@@ -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('-
|
|
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
|
|
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?
|
|
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?
|
|
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}"
|
data/samples/lindebug.rb
CHANGED
|
@@ -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
|
-
|
|
51
|
-
$stdin.ioctl(TCGETS,
|
|
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;
|
|
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.
|
|
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.
|
|
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
|
-
|
|
167
|
+
puts $!, $!.backtrace
|
|
205
168
|
end
|
|
206
|
-
|
|
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.
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
text <<
|
|
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
|
-
|
|
242
|
+
|
|
243
|
+
linelen += w.length+1
|
|
283
244
|
}
|
|
284
|
-
|
|
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.
|
|
295
|
-
addr = @rs.
|
|
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.
|
|
259
|
+
addr = @rs.pc
|
|
298
260
|
end
|
|
299
261
|
@codeptr = addr
|
|
300
262
|
|
|
301
|
-
|
|
302
|
-
|
|
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 <
|
|
305
|
-
self.statusline = " scanning for elf header at #{
|
|
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 #{
|
|
308
|
-
if not @noelfsig[base] and @rs[base,
|
|
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.
|
|
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.
|
|
335
|
-
text <<
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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.
|
|
345
|
-
"*#{di.instruction}".ljust([@console_width-
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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 <<
|
|
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 :
|
|
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 +
|
|
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
|
|
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
|
-
|
|
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
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
update rescue
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
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.
|
|
514
|
-
if @codeptr > @rs.
|
|
515
|
-
@codeptr = @rs.
|
|
516
|
-
elsif @codeptr != @rs.
|
|
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.
|
|
463
|
+
while addr < @rs.pc
|
|
520
464
|
addrs << addr
|
|
521
|
-
o = ((di = @rs.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
555
|
+
@codeptr ||= @rs.pc
|
|
611
556
|
@codeptr -= (1..10).find { |off|
|
|
612
|
-
di = @rs.
|
|
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.
|
|
632
|
-
di = @rs.
|
|
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,
|
|
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.
|
|
591
|
+
@codeptr ||= @rs.pc
|
|
647
592
|
(@win_code_height-1).times {
|
|
648
593
|
@codeptr -= (1..10).find { |off|
|
|
649
|
-
di = @rs.
|
|
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.
|
|
660
|
-
(@win_code_height-1).times { @codeptr += ((o = @rs.
|
|
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
|
|
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
|
-
|
|
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 { |
|
|
638
|
+
@command['quit'] = @command['detach'] = @command['exit'] = lambda { |str|
|
|
695
639
|
@rs.detach
|
|
696
640
|
@running = false
|
|
697
641
|
}
|
|
698
|
-
@command['closeui'] = lambda { |
|
|
699
|
-
@rs.logger = nil
|
|
642
|
+
@command['closeui'] = lambda { |str|
|
|
700
643
|
@running = false
|
|
701
644
|
}
|
|
702
|
-
@command['bpx'] = lambda { |
|
|
703
|
-
|
|
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['
|
|
723
|
-
|
|
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 { |
|
|
726
|
-
@command['d'] = lambda { |
|
|
727
|
-
@command['db'] = lambda { |
|
|
728
|
-
@command['dw'] = lambda { |
|
|
729
|
-
@command['dd'] = lambda { |
|
|
730
|
-
@command['r'] = lambda { |
|
|
731
|
-
r =
|
|
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
|
-
|
|
735
|
-
|
|
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
|
|
744
|
-
|
|
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
|
|
666
|
+
log "#{r} = #{@rs[r]}"
|
|
752
667
|
end
|
|
753
668
|
}
|
|
754
|
-
@command['
|
|
755
|
-
|
|
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['
|
|
794
|
-
@command['
|
|
795
|
-
|
|
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
|
|
882
|
-
|
|
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 { |
|
|
681
|
+
@command['wc'] = lambda { |str|
|
|
888
682
|
@focus = :code
|
|
889
|
-
if
|
|
890
|
-
|
|
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 { |
|
|
896
|
-
@command['?'] = lambda { |
|
|
897
|
-
val =
|
|
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['
|
|
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
|
-
|
|
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
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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
|