tduehr-ragweed 0.1.7 → 0.1.7.1
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.
- data/History.txt +5 -0
- data/Rakefile +4 -2
- data/examples/tux-example.rb +1 -1
- data/lib/ragweed/debugger32.rb +40 -40
- data/lib/ragweed/debuggerosx.rb +10 -2
- data/lib/ragweed/debuggertux.rb +33 -33
- data/lib/ragweed/rasm/bblock.rb +68 -0
- data/lib/ragweed/rasm/isa.rb +38 -5
- data/lib/ragweed/rasm.rb +1 -1
- data/lib/ragweed/sbuf.rb +1 -1
- data/lib/ragweed/trampoline.rb +5 -5
- data/lib/ragweed/utils.rb +83 -41
- data/lib/ragweed/wrap32/debugging.rb +12 -12
- data/lib/ragweed/wrap32/device.rb +6 -6
- data/lib/ragweed/wrap32/event.rb +3 -3
- data/lib/ragweed/wrap32/process.rb +20 -20
- data/lib/ragweed/wrap32/process_token.rb +5 -5
- data/lib/ragweed/wrap32/thread_context.rb +9 -9
- data/lib/ragweed/wrap32/wrap32.rb +4 -4
- data/lib/ragweed/wrap32.rb +1 -1
- data/lib/ragweed/wraposx/kernelerrorx.rb +1 -1
- data/lib/ragweed/wraposx/thread_info.rb +1 -1
- data/lib/ragweed/wraposx/wraposx.rb +63 -0
- data/lib/ragweed/wraposx.rb +1 -1
- data/lib/ragweed/wraptux.rb +1 -1
- data/lib/ragweed.rb +1 -1
- data/ragweed.gemspec +34 -0
- metadata +13 -10
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -23,10 +23,12 @@ PROJ.ignore_file = '.gitignore'
|
|
23
23
|
PROJ.authors = 'tduehr, tqbf, struct'
|
24
24
|
PROJ.email = 'td@matasano.com'
|
25
25
|
PROJ.description = 'General debugging tool written in Ruby for OSX/Win32/Linux'
|
26
|
+
PROJ.summary = 'Scriptable debugger'
|
27
|
+
PROJ.exclude << %w(old$)
|
26
28
|
PROJ.url = 'http://github.com/tduehr/ragweed/tree/master'
|
27
29
|
PROJ.version = Ragweed::VERSION
|
28
|
-
|
29
|
-
|
30
|
+
PROJ.rdoc.opts << "--inline-source"
|
31
|
+
PROJ.rdoc.opts << "--line-numbers"
|
30
32
|
PROJ.spec.opts << '--color'
|
31
33
|
|
32
34
|
# EOF
|
data/examples/tux-example.rb
CHANGED
data/lib/ragweed/debugger32.rb
CHANGED
@@ -35,14 +35,14 @@ class Ragweed::Debugger32
|
|
35
35
|
@orig = process.read8(@addr)
|
36
36
|
if(@orig != INT3)
|
37
37
|
process.write8(@addr, INT3)
|
38
|
-
Wrap32::flush_instruction_cache(@bp.process.handle)
|
38
|
+
Ragweed::Wrap32::flush_instruction_cache(@bp.process.handle)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
def uninstall
|
43
43
|
if(@orig != INT3)
|
44
44
|
process.write8(@addr, @orig)
|
45
|
-
Wrap32::flush_instruction_cache(@bp.process.handle)
|
45
|
+
Ragweed::Wrap32::flush_instruction_cache(@bp.process.handle)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -57,7 +57,7 @@ class Ragweed::Debugger32
|
|
57
57
|
# on the image name of the process.
|
58
58
|
# d = Debugger.find_by_regex /notepad/i
|
59
59
|
def self.find_by_regex(rx)
|
60
|
-
Wrap32::all_processes do |p|
|
60
|
+
Ragweed::Wrap32::all_processes do |p|
|
61
61
|
if p.szExeFile =~ rx
|
62
62
|
return self.new(p.th32ProcessID)
|
63
63
|
end
|
@@ -69,12 +69,12 @@ class Ragweed::Debugger32
|
|
69
69
|
# pass this either a PID or a Process object.
|
70
70
|
def initialize(p)
|
71
71
|
# grab debug privilege at least once.
|
72
|
-
@@token ||= Wrap32::ProcessToken.new.grant("seDebugPrivilege")
|
72
|
+
@@token ||= Ragweed::Wrap32::ProcessToken.new.grant("seDebugPrivilege")
|
73
73
|
|
74
74
|
p = Process.new(p) if p.kind_of? Numeric
|
75
75
|
@p = p
|
76
76
|
@steppers = []
|
77
|
-
@handled = Wrap32::ContinueCodes::UNHANDLED
|
77
|
+
@handled = Ragweed::Wrap32::ContinueCodes::UNHANDLED
|
78
78
|
@first = true
|
79
79
|
@attached = false
|
80
80
|
|
@@ -107,8 +107,8 @@ class Ragweed::Debugger32
|
|
107
107
|
# for an example of how to use this.
|
108
108
|
def step(tid, callable)
|
109
109
|
if @steppers.empty?
|
110
|
-
Wrap32::open_thread(tid) do |h|
|
111
|
-
ctx = Wrap32::ThreadContext.get(h)
|
110
|
+
Ragweed::Wrap32::open_thread(tid) do |h|
|
111
|
+
ctx = Ragweed::Wrap32::ThreadContext.get(h)
|
112
112
|
ctx.single_step(true)
|
113
113
|
ctx.set(h)
|
114
114
|
end
|
@@ -122,8 +122,8 @@ class Ragweed::Debugger32
|
|
122
122
|
def unstep(tid, callable)
|
123
123
|
@steppers = @steppers.reject {|x| x == callable}
|
124
124
|
if @steppers.empty?
|
125
|
-
Wrap32::open_thread(tid) do |h|
|
126
|
-
ctx = Wrap32::ThreadContext.get(h)
|
125
|
+
Ragweed::Wrap32::open_thread(tid) do |h|
|
126
|
+
ctx = Ragweed::Wrap32::ThreadContext.get(h)
|
127
127
|
ctx.single_step(false)
|
128
128
|
ctx.set(h)
|
129
129
|
end
|
@@ -137,7 +137,7 @@ class Ragweed::Debugger32
|
|
137
137
|
else
|
138
138
|
tid = tid_or_event
|
139
139
|
end
|
140
|
-
Wrap32::open_thread(tid) {|h| Wrap32::ThreadContext.get(h)}
|
140
|
+
Ragweed::Wrap32::open_thread(tid) {|h| Ragweed::Wrap32::ThreadContext.get(h)}
|
141
141
|
end
|
142
142
|
|
143
143
|
# set a breakpoint given an address, which can also be a string in the form
|
@@ -218,7 +218,7 @@ class Ragweed::Debugger32
|
|
218
218
|
end))
|
219
219
|
|
220
220
|
# put execution back where it's supposed to be...
|
221
|
-
Wrap32::open_thread(ev.tid) do |h|
|
221
|
+
Ragweed::Wrap32::open_thread(ev.tid) do |h|
|
222
222
|
ctx = context(ev)
|
223
223
|
ctx.eip = eip # eip was ev.exception_address
|
224
224
|
ctx.set(h)
|
@@ -226,13 +226,13 @@ class Ragweed::Debugger32
|
|
226
226
|
end
|
227
227
|
|
228
228
|
# tell the target to stop handling this event
|
229
|
-
@handled = Wrap32::ContinueCodes::CONTINUE
|
229
|
+
@handled = Ragweed::Wrap32::ContinueCodes::CONTINUE
|
230
230
|
end
|
231
231
|
|
232
232
|
# handle a single-step event
|
233
233
|
def on_single_step(ev)
|
234
234
|
ctx = context(ev)
|
235
|
-
Wrap32::open_thread(ev.tid) do |h|
|
235
|
+
Ragweed::Wrap32::open_thread(ev.tid) do |h|
|
236
236
|
# re-enable the trap flag before our handler, which may
|
237
237
|
# choose to disable it.
|
238
238
|
ctx.single_step(true)
|
@@ -241,7 +241,7 @@ class Ragweed::Debugger32
|
|
241
241
|
|
242
242
|
@steppers.each {|s| s.call(ev, ctx)}
|
243
243
|
|
244
|
-
@handled = Wrap32::ContinueCodes::CONTINUE
|
244
|
+
@handled = Ragweed::Wrap32::ContinueCodes::CONTINUE
|
245
245
|
end
|
246
246
|
|
247
247
|
# this is sort of insane but most of my programs are just
|
@@ -259,54 +259,54 @@ class Ragweed::Debugger32
|
|
259
259
|
def wait
|
260
260
|
self.attach() if not @attached
|
261
261
|
|
262
|
-
ev = Wrap32::wait_for_debug_event
|
262
|
+
ev = Ragweed::Wrap32::wait_for_debug_event
|
263
263
|
return if not ev
|
264
264
|
case ev.code
|
265
|
-
when Wrap32::DebugCodes::CREATE_PROCESS
|
265
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
266
266
|
try(:on_create_process, ev)
|
267
|
-
when Wrap32::DebugCodes::CREATE_THREAD
|
267
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
268
268
|
try(:on_create_thread, ev)
|
269
|
-
when Wrap32::DebugCodes::EXIT_PROCESS
|
269
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
270
270
|
try(:on_exit_process, ev)
|
271
|
-
when Wrap32::DebugCodes::EXIT_THREAD
|
271
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
272
272
|
try(:on_exit_thread, ev)
|
273
|
-
when Wrap32::DebugCodes::LOAD_DLL
|
273
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
274
274
|
try(:on_load_dll, ev)
|
275
|
-
when Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
275
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
276
276
|
try(:on_output_debug_string, ev)
|
277
|
-
when Wrap32::DebugCodes::RIP
|
277
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
278
278
|
try(:on_rip, ev)
|
279
|
-
when Wrap32::DebugCodes::UNLOAD_DLL
|
279
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
280
280
|
try(:on_unload_dll, ev)
|
281
|
-
when Wrap32::DebugCodes::EXCEPTION
|
281
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
282
282
|
case ev.exception_code
|
283
|
-
when Wrap32::ExceptionCodes::ACCESS_VIOLATION
|
283
|
+
when Ragweed::Wrap32::ExceptionCodes::ACCESS_VIOLATION
|
284
284
|
try(:on_access_violation, ev)
|
285
|
-
when Wrap32::ExceptionCodes::BREAKPOINT
|
285
|
+
when Ragweed::Wrap32::ExceptionCodes::BREAKPOINT
|
286
286
|
try(:on_breakpoint, ev)
|
287
|
-
when Wrap32::ExceptionCodes::ALIGNMENT
|
287
|
+
when Ragweed::Wrap32::ExceptionCodes::ALIGNMENT
|
288
288
|
try(:on_alignment, ev)
|
289
|
-
when Wrap32::ExceptionCodes::SINGLE_STEP
|
289
|
+
when Ragweed::Wrap32::ExceptionCodes::SINGLE_STEP
|
290
290
|
try(:on_single_step, ev)
|
291
|
-
when Wrap32::ExceptionCodes::BOUNDS
|
291
|
+
when Ragweed::Wrap32::ExceptionCodes::BOUNDS
|
292
292
|
try(:on_bounds, ev)
|
293
|
-
when Wrap32::ExceptionCodes::DIVIDE_BY_ZERO
|
293
|
+
when Ragweed::Wrap32::ExceptionCodes::DIVIDE_BY_ZERO
|
294
294
|
try(:on_divide_by_zero, ev)
|
295
|
-
when Wrap32::ExceptionCodes::INT_OVERFLOW
|
295
|
+
when Ragweed::Wrap32::ExceptionCodes::INT_OVERFLOW
|
296
296
|
try(:on_int_overflow, ev)
|
297
|
-
when Wrap32::ExceptionCodes::INVALID_HANDLE
|
297
|
+
when Ragweed::Wrap32::ExceptionCodes::INVALID_HANDLE
|
298
298
|
try(:on_invalid_handle, ev)
|
299
|
-
when Wrap32::ExceptionCodes::PRIV_INSTRUCTION
|
299
|
+
when Ragweed::Wrap32::ExceptionCodes::PRIV_INSTRUCTION
|
300
300
|
try(:on_priv_instruction, ev)
|
301
|
-
when Wrap32::ExceptionCodes::STACK_OVERFLOW
|
301
|
+
when Ragweed::Wrap32::ExceptionCodes::STACK_OVERFLOW
|
302
302
|
try(:on_stack_overflow, ev)
|
303
|
-
when Wrap32::ExceptionCodes::INVALID_DISPOSITION
|
303
|
+
when Ragweed::Wrap32::ExceptionCodes::INVALID_DISPOSITION
|
304
304
|
try(:on_invalid_disposition, ev)
|
305
305
|
end
|
306
306
|
end
|
307
307
|
|
308
|
-
Wrap32::continue_debug_event(ev.pid, ev.tid, @handled)
|
309
|
-
@handled = Wrap32::ContinueCodes::UNHANDLED
|
308
|
+
Ragweed::Wrap32::continue_debug_event(ev.pid, ev.tid, @handled)
|
309
|
+
@handled = Ragweed::Wrap32::ContinueCodes::UNHANDLED
|
310
310
|
end
|
311
311
|
|
312
312
|
# debug loop.
|
@@ -319,8 +319,8 @@ class Ragweed::Debugger32
|
|
319
319
|
# this is called implicitly by Debugger#wait.
|
320
320
|
# Attaches to the child process for debugging
|
321
321
|
def attach
|
322
|
-
Wrap32::debug_active_process(@p.pid)
|
323
|
-
Wrap32::debug_set_process_kill_on_exit
|
322
|
+
Ragweed::Wrap32::debug_active_process(@p.pid)
|
323
|
+
Ragweed::Wrap32::debug_set_process_kill_on_exit
|
324
324
|
@attached = true
|
325
325
|
@breakpoints.each do |k, v|
|
326
326
|
v.install
|
@@ -329,7 +329,7 @@ class Ragweed::Debugger32
|
|
329
329
|
|
330
330
|
# let go of the target.
|
331
331
|
def release
|
332
|
-
Wrap32::debug_active_process_stop(@p.pid)
|
332
|
+
Ragweed::Wrap32::debug_active_process_stop(@p.pid)
|
333
333
|
@attached = false
|
334
334
|
@breakpoints.each do |k, v|
|
335
335
|
v.uninstall
|
data/lib/ragweed/debuggerosx.rb
CHANGED
@@ -346,6 +346,16 @@ class Ragweed::Debuggerosx
|
|
346
346
|
Ragweed::Wraposx::task_threads(@task)
|
347
347
|
end
|
348
348
|
|
349
|
+
# decrement our tasks suspend count
|
350
|
+
def resume_task
|
351
|
+
Ragweed::Wraposx::task_resume(@task)
|
352
|
+
end
|
353
|
+
|
354
|
+
# increment our tasks suspend count
|
355
|
+
def suspend_task
|
356
|
+
Ragweed::Wraposx::task_suspend(@task)
|
357
|
+
end
|
358
|
+
|
349
359
|
# returns a Ragweed::Wraposx::ThreadContext object containing the register states
|
350
360
|
# thread: thread to get the register state of
|
351
361
|
def get_registers(thread=nil)
|
@@ -396,10 +406,8 @@ class Ragweed::Debuggerosx
|
|
396
406
|
|
397
407
|
# Extended and Top info flavors are included in case Apple re implements them
|
398
408
|
when :extended
|
399
|
-
warn "VM Region Extended Info not implemented by Apple. Returning RegionBasicInfo"
|
400
409
|
return Ragweed::Wraposx::RegionExtendedInfo.get(@task, addr)
|
401
410
|
when :top
|
402
|
-
warn "VM Region Top Info not implemented be Apple. Returning RegionBasicInfo"
|
403
411
|
return Ragweed::Wraposx::RegionTopInfo.get(@task, addr)
|
404
412
|
else
|
405
413
|
warn "Unknown flavor requested. Returning RegionBasicInfo."
|
data/lib/ragweed/debuggertux.rb
CHANGED
@@ -13,7 +13,7 @@ module Ragweed; end
|
|
13
13
|
## debugger and define your own on_whatever events. If you handle an event
|
14
14
|
## that Debuggertux already handles, call "super", too.
|
15
15
|
class Ragweed::Debuggertux
|
16
|
-
include Ragweed
|
16
|
+
# include Ragweed
|
17
17
|
|
18
18
|
attr_reader :pid
|
19
19
|
attr_reader :status
|
@@ -99,16 +99,16 @@ class Ragweed::Debuggertux
|
|
99
99
|
|
100
100
|
## This is crude!
|
101
101
|
def self.find_by_regex(rx)
|
102
|
-
|
103
|
-
a.delete_if do |x| x == '.' end
|
104
|
-
a.delete_if do |x| x == '..' end
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
102
|
+
a = Dir.entries("/proc/")
|
103
|
+
a.delete_if do |x| x == '.'; end
|
104
|
+
a.delete_if do |x| x == '..'; end
|
105
|
+
a.delete_if do |x| x =~ /[a-z]/; end
|
106
|
+
a.each do |x|
|
107
|
+
f = File.read("/proc/#{x}/cmdline")
|
108
|
+
if f =~ rx
|
109
|
+
return x
|
110
|
+
end
|
111
|
+
end
|
112
112
|
end
|
113
113
|
|
114
114
|
def install_bps
|
@@ -128,24 +128,24 @@ class Ragweed::Debuggertux
|
|
128
128
|
## Attach calls install_bps so dont forget to call breakpoint_set
|
129
129
|
## BEFORE attach or explicitly call install_bps
|
130
130
|
def attach(opts=@opts)
|
131
|
-
Wraptux::ptrace(Ragweed::Wraptux::Ptrace::ATTACH, @pid, 0, 0)
|
131
|
+
Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::ATTACH, @pid, 0, 0)
|
132
132
|
@attached = true
|
133
133
|
self.install_bps if (opts[:install] and not @installed)
|
134
134
|
end
|
135
135
|
|
136
136
|
def continue
|
137
137
|
on_continue
|
138
|
-
Wraptux::ptrace(Ragweed::Wraptux::Ptrace::CONTINUE, @pid, 0, 0)
|
138
|
+
Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::CONTINUE, @pid, 0, 0)
|
139
139
|
end
|
140
140
|
|
141
141
|
def detach
|
142
142
|
on_detach
|
143
|
-
Wraptux::ptrace(Ragweed::Wraptux::Ptrace::DETACH, @pid, 0, 0)
|
143
|
+
Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::DETACH, @pid, 0, 0)
|
144
144
|
end
|
145
145
|
|
146
146
|
def stepp
|
147
147
|
on_stepp
|
148
|
-
ret = Wraptux::ptrace(Ragweed::Wraptux::Ptrace::STEP, @pid, 1, 0)
|
148
|
+
ret = Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::STEP, @pid, 1, 0)
|
149
149
|
end
|
150
150
|
|
151
151
|
## Adds a breakpoint to be installed
|
@@ -205,7 +205,7 @@ class Ragweed::Debuggertux
|
|
205
205
|
## originally stored with it. If its a different signal,
|
206
206
|
## then process it accordingly and move on
|
207
207
|
def wait(opts = 0)
|
208
|
-
r = Wraptux::waitpid(@pid,opts)
|
208
|
+
r = Ragweed::Wraptux::waitpid(@pid,opts)
|
209
209
|
status = r[1]
|
210
210
|
wstatus = status & 0x7f
|
211
211
|
signal = status >> 8
|
@@ -218,13 +218,13 @@ class Ragweed::Debuggertux
|
|
218
218
|
when wstatus != 0x7f ##WIFSIGNALED
|
219
219
|
@exited = false
|
220
220
|
self.on_signal
|
221
|
-
when signal == Wraptux::Signal::SIGINT
|
221
|
+
when signal == Ragweed::Wraptux::Signal::SIGINT
|
222
222
|
self.continue
|
223
|
-
when signal == Wraptux::Signal::SIGSEGV
|
223
|
+
when signal == Ragweed::Wraptux::Signal::SIGSEGV
|
224
224
|
self.on_segv
|
225
|
-
when signal == Wraptux::Signal::SIGILL
|
225
|
+
when signal == Ragweed::Wraptux::Signal::SIGILL
|
226
226
|
self.on_illegalinst
|
227
|
-
when signal == Wraptux::Signal::SIGTRAP
|
227
|
+
when signal == Ragweed::Wraptux::Signal::SIGTRAP
|
228
228
|
## Check if EIP matches a breakpoint we have set
|
229
229
|
r = self.get_registers
|
230
230
|
eip = r[:eip]
|
@@ -236,9 +236,9 @@ class Ragweed::Debuggertux
|
|
236
236
|
puts "We got a SIGTRAP but not at our breakpoint... continuing"
|
237
237
|
end
|
238
238
|
self.continue
|
239
|
-
when signal == Wraptux::Signal::SIGCONT
|
239
|
+
when signal == Ragweed::Wraptux::Signal::SIGCONT
|
240
240
|
self.continue
|
241
|
-
when signal == Wraptux::Signal::SIGSTOP
|
241
|
+
when signal == Ragweed::Wraptux::Signal::SIGSTOP
|
242
242
|
self.continue
|
243
243
|
else
|
244
244
|
raise "Add more signal handlers (##{signal})"
|
@@ -249,23 +249,23 @@ class Ragweed::Debuggertux
|
|
249
249
|
## Return an array of thread PIDs
|
250
250
|
def self.threads(pid)
|
251
251
|
a = Dir.entries("/proc/#{pid}/task/")
|
252
|
-
a.delete_if
|
253
|
-
a.delete_if
|
252
|
+
a.delete_if { |x| x == '.' }
|
253
|
+
a.delete_if { |x| x == '..' }
|
254
254
|
end
|
255
255
|
|
256
256
|
## Gets the registers for the given process
|
257
257
|
def get_registers
|
258
|
-
size = Wraptux::SIZEOFLONG * 17
|
258
|
+
size = Ragweed::Wraptux::SIZEOFLONG * 17
|
259
259
|
regs = Array.new(size)
|
260
260
|
regs = regs.to_ptr
|
261
261
|
regs.struct!('LLLLLLLLLLLLLLLLL', :ebx,:ecx,:edx,:esi,:edi,:ebp,:eax,:xds,:xes,:xfs,:xgs,:orig_eax,:eip,:xcs,:eflags,:esp,:xss)
|
262
|
-
Wraptux::ptrace(Ragweed::Wraptux::Ptrace::GETREGS, @pid, 0, regs.to_i)
|
262
|
+
Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::GETREGS, @pid, 0, regs.to_i)
|
263
263
|
return regs
|
264
264
|
end
|
265
265
|
|
266
266
|
## Sets registers for the given process
|
267
267
|
def set_registers(r)
|
268
|
-
Wraptux::ptrace(Ragweed::Wraptux::Ptrace::SETREGS, @pid, 0, r.to_i)
|
268
|
+
Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::SETREGS, @pid, 0, r.to_i)
|
269
269
|
end
|
270
270
|
|
271
271
|
## Here we need to do something about the bp
|
@@ -284,14 +284,14 @@ class Ragweed::Debuggertux
|
|
284
284
|
set_registers(r)
|
285
285
|
stepp
|
286
286
|
## ptrace peektext returns -1 upon reinstallation of bp without calling
|
287
|
-
|
288
|
-
Wraptux::waitpid(@pid, 0)
|
287
|
+
## waitpid() if that occurs the breakpoint cannot be reinstalled
|
288
|
+
Ragweed::Wraptux::waitpid(@pid, 0)
|
289
289
|
@breakpoints[eip].first.install
|
290
290
|
end
|
291
291
|
end
|
292
292
|
|
293
293
|
def print_regs
|
294
|
-
|
294
|
+
regs = self.get_registers
|
295
295
|
puts "eip %08x" % regs[:eip]
|
296
296
|
puts "edi %08x" % regs[:esi]
|
297
297
|
puts "edi %08x" % regs[:edi]
|
@@ -332,15 +332,15 @@ class Ragweed::Debuggertux
|
|
332
332
|
end
|
333
333
|
|
334
334
|
def on_stepp
|
335
|
-
|
335
|
+
#puts "single stepping"
|
336
336
|
end
|
337
337
|
|
338
338
|
def on_segv
|
339
|
-
|
339
|
+
print_regs
|
340
340
|
exit
|
341
341
|
end
|
342
342
|
|
343
343
|
def default_opts(opts)
|
344
|
-
|
344
|
+
@opts = @opts.merge(opts)
|
345
345
|
end
|
346
346
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Ragweed; end
|
2
|
+
module Ragweed::Rasm
|
3
|
+
# Ruby inline assembler.
|
4
|
+
class Bblock
|
5
|
+
# Don't call this directly; use Bblock#make
|
6
|
+
def initialize
|
7
|
+
@insns = Ragweed::Rasm::Subprogram.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# Wrap the methods of Rasm::Subprogram we care about:
|
11
|
+
|
12
|
+
# Assemble the instructions, which also calculates appropriate
|
13
|
+
# jump labels.
|
14
|
+
def assemble; @insns.assemble; end
|
15
|
+
|
16
|
+
# Disassemble the block (after it's been assembled) into
|
17
|
+
# Frasm objects.
|
18
|
+
def disassemble; @insns.disassemble; end
|
19
|
+
|
20
|
+
# Generate a human-readable assembly listing.
|
21
|
+
def listing; @insns.dump_disassembly; end
|
22
|
+
|
23
|
+
# Append more instructions to a previously created block;
|
24
|
+
# see Bblock#make
|
25
|
+
def add(&block)
|
26
|
+
instance_eval(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Takes a block argument, containing (mostly) assembly
|
30
|
+
# instructions, as interpreted by Rasm. For example:
|
31
|
+
#
|
32
|
+
# Bblock.make {
|
33
|
+
# push ebp
|
34
|
+
# mov ebp, esp
|
35
|
+
# push ebx
|
36
|
+
# xor ebx, ebx
|
37
|
+
# addl esp, 4
|
38
|
+
# pop ebp
|
39
|
+
# ret
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# Each of those instructions is in fact the name of a class
|
43
|
+
# in Rasm, lowercased; Bblock has a method_missing that catches
|
44
|
+
# and instantiates them.
|
45
|
+
#
|
46
|
+
# Your block can contain arbitrary Ruby, but remember that it
|
47
|
+
# runs in the scope of an anonymous class and so cannot directly
|
48
|
+
# reference instance variables.
|
49
|
+
def self.make(&block)
|
50
|
+
c = Bblock.new
|
51
|
+
c.instance_eval(&block)
|
52
|
+
c
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(meth, *args)
|
56
|
+
k = Ragweed::Rasm.const_get(meth.to_s.capitalize)
|
57
|
+
|
58
|
+
# If it's a class, it's an assembly opcode; otherwise,
|
59
|
+
# it's a register or operand.
|
60
|
+
if k.class == Class
|
61
|
+
@insns << (k = k.new(*args))
|
62
|
+
else
|
63
|
+
k
|
64
|
+
end
|
65
|
+
k
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/ragweed/rasm/isa.rb
CHANGED
@@ -174,7 +174,7 @@ module Ragweed::Rasm
|
|
174
174
|
# labels. Produces raw instruction stream.
|
175
175
|
def assemble
|
176
176
|
patches = {}
|
177
|
-
buf = Sbuf.new
|
177
|
+
buf = Ragweed::Sbuf.new
|
178
178
|
|
179
179
|
each do |i|
|
180
180
|
if i.kind_of? Instruction
|
@@ -248,7 +248,7 @@ module Ragweed::Rasm
|
|
248
248
|
def coerce(v)
|
249
249
|
if v
|
250
250
|
v = v.derive
|
251
|
-
v = v.to_i if v.kind_of? Ptr
|
251
|
+
v = v.to_i if v.kind_of? Ragweed::Ptr
|
252
252
|
if v.kind_of? Array
|
253
253
|
v = v[0].clone
|
254
254
|
v.indir = true
|
@@ -263,7 +263,7 @@ module Ragweed::Rasm
|
|
263
263
|
|
264
264
|
# Never called directly (see subclasses below)
|
265
265
|
def initialize(x=nil, y=nil)
|
266
|
-
@buf = Sbuf.new
|
266
|
+
@buf = Ragweed::Sbuf.new
|
267
267
|
self.src = y
|
268
268
|
self.dst = x
|
269
269
|
@loc = nil
|
@@ -472,6 +472,27 @@ module Ragweed::Rasm
|
|
472
472
|
super
|
473
473
|
end
|
474
474
|
end
|
475
|
+
|
476
|
+
## ------------------------------------------------------------------------
|
477
|
+
|
478
|
+
# Push the registers onto the stack
|
479
|
+
# not valid for 64bit mode
|
480
|
+
class Pushad < Instruction
|
481
|
+
def to_s
|
482
|
+
add(0x60)
|
483
|
+
super
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
## ------------------------------------------------------------------------
|
488
|
+
|
489
|
+
# Pop the registers off the stack
|
490
|
+
class Popad < Instruction
|
491
|
+
def to_s
|
492
|
+
add(0x61)
|
493
|
+
super
|
494
|
+
end
|
495
|
+
end
|
475
496
|
|
476
497
|
## ------------------------------------------------------------------------
|
477
498
|
|
@@ -599,6 +620,7 @@ module Ragweed::Rasm
|
|
599
620
|
@x = Ebp.clone
|
600
621
|
end
|
601
622
|
end
|
623
|
+
Subl = Sub
|
602
624
|
|
603
625
|
## ------------------------------------------------------------------------
|
604
626
|
|
@@ -1019,10 +1041,11 @@ module Ragweed::Rasm
|
|
1019
1041
|
class Pushf < Instruction
|
1020
1042
|
# 9c pushfd
|
1021
1043
|
|
1022
|
-
def initialize; end
|
1044
|
+
# def initialize; end
|
1023
1045
|
def to_s
|
1024
1046
|
raise(TooMan, "too many arguments") if @src or @dst
|
1025
1047
|
add(0x9c)
|
1048
|
+
super
|
1026
1049
|
end
|
1027
1050
|
end
|
1028
1051
|
|
@@ -1031,15 +1054,25 @@ module Ragweed::Rasm
|
|
1031
1054
|
class Popf < Instruction
|
1032
1055
|
# 9d popfd
|
1033
1056
|
|
1034
|
-
def initialize; end
|
1057
|
+
# def initialize; end
|
1035
1058
|
def to_s
|
1036
1059
|
raise(TooMan, "too many arguments") if @src or @dst
|
1037
1060
|
add(0x9d)
|
1061
|
+
super
|
1038
1062
|
end
|
1039
1063
|
end
|
1040
1064
|
|
1041
1065
|
## ------------------------------------------------------------------------
|
1042
1066
|
|
1067
|
+
class Iret < Instruction
|
1068
|
+
def to_s
|
1069
|
+
add(0xcf)
|
1070
|
+
super
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
## ------------------------------------------------------------------------
|
1075
|
+
|
1043
1076
|
# INT 3, mostly, but will do INT X
|
1044
1077
|
class Int < Instruction
|
1045
1078
|
## cc int 3
|
data/lib/ragweed/rasm.rb
CHANGED
data/lib/ragweed/sbuf.rb
CHANGED
@@ -138,7 +138,7 @@ class Ragweed::Sbuf
|
|
138
138
|
def eof?; @position >= length; end
|
139
139
|
def clear!; @content = "" and reset; end
|
140
140
|
def remainder(n = position); @content[n..-1] || ""; end
|
141
|
-
def remainder_as_buffer(t=Sbuf); t.new(:content => remainder); end
|
141
|
+
def remainder_as_buffer(t=Ragweed::Sbuf); t.new(:content => remainder); end
|
142
142
|
|
143
143
|
def self.szl64; 8; end
|
144
144
|
def self.szb64; 8; end
|
data/lib/ragweed/trampoline.rb
CHANGED
@@ -57,9 +57,9 @@ class Ragweed::Trampoline
|
|
57
57
|
s = @shim.assemble
|
58
58
|
base.write(s)
|
59
59
|
|
60
|
-
th = Wrap32::create_remote_thread(@p.handle, base, argm)
|
61
|
-
Wrap32::wait_for_single_object(th) if @wait
|
62
|
-
Wrap32::close_handle(th)
|
60
|
+
th = Ragweed::Wrap32::create_remote_thread(@p.handle, base, argm)
|
61
|
+
Ragweed::Wrap32::wait_for_single_object(th) if @wait
|
62
|
+
Ragweed::Wrap32::close_handle(th)
|
63
63
|
ret = @p.read32(cur)
|
64
64
|
if ret == 0xDEADBEEF
|
65
65
|
ret = nil
|
@@ -91,12 +91,12 @@ class Trevil
|
|
91
91
|
"WaitForSingleObject"].
|
92
92
|
map {|x| @p.get_proc("kernel32!#{x}").to_i}.
|
93
93
|
pack("LLLLL")
|
94
|
-
state = [Wrap32::get_current_process_id, @ev1.handle, @ev2.handle].
|
94
|
+
state = [Ragweed::Wrap32::get_current_process_id, @ev1.handle, @ev2.handle].
|
95
95
|
pack("LLL")
|
96
96
|
|
97
97
|
data.write(swch + state)
|
98
98
|
base.write(event_pair_stub(:debug => false).assemble)
|
99
|
-
Wrap32::create_remote_thread(@p.handle, base, data)
|
99
|
+
Ragweed::Wrap32::create_remote_thread(@p.handle, base, data)
|
100
100
|
@ev1.wait
|
101
101
|
@ev2
|
102
102
|
end
|