ragweed 0.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -0
@@ -0,0 +1,400 @@
1
+ require ::File.join(::File.dirname(__FILE__),'wrap32')
2
+
3
+ # Debugger class for win32
4
+ # You can use this class in 2 ways:
5
+ #
6
+ # (1) You can create instances of Debugger and use them to set and handle
7
+ # breakpoints.
8
+ #
9
+ # (2) If you want to do more advanced event handling, you can subclass from
10
+ # debugger and define your own on_whatever events. If you handle an event
11
+ # that Debugger already handles, call "super", too.
12
+ class Ragweed::Debugger32
13
+ include Ragweed
14
+
15
+ ## This will preserve the last event seen, but as read only
16
+ ## useful if you want to pass around the ragweed object after
17
+ ## an event has occured (post-mortem crash analysis)
18
+ attr_reader :event
19
+
20
+ ## Breakpoint class. Handles the actual setting,
21
+ ## removal and triggers for breakpoints.
22
+ ## no user servicable parts.
23
+ class Breakpoint
24
+
25
+ INT3 = 0xCC
26
+
27
+ attr_accessor :orig, :deferred, :addr
28
+
29
+ def initialize(process, ip, def_status, callable)
30
+ @process = process
31
+ @addr = ip
32
+ @callable = callable
33
+ @deferred = def_status
34
+ @orig = 0
35
+ end
36
+
37
+ def addr; @addr; end
38
+
39
+ def install
40
+ if @addr == 0 or @deferred == true
41
+ return
42
+ end
43
+
44
+ o = @process.read8(@addr)
45
+
46
+ if(orig != INT3)
47
+ @orig = o
48
+ @process.write8(@addr, INT3)
49
+ Ragweed::Wrap32::flush_instruction_cache(@process.handle)
50
+ end
51
+ end
52
+
53
+ def deferred_install(h, base)
54
+ @addr = @process.get_deferred_proc_remote(@addr, h, base)
55
+ self.install
56
+ return @addr
57
+ end
58
+
59
+ def uninstall
60
+ if(@orig != INT3)
61
+ @process.write8(@addr, @orig)
62
+ Ragweed::Wrap32::flush_instruction_cache(@process.handle)
63
+ end
64
+ end
65
+
66
+ def call(*args); @callable.call(*args); end
67
+ end ## End Breakpoint class
68
+
69
+ ## Get a handle to the process so you can mess with it.
70
+ def process; @p; end
71
+
72
+ def self.find_by_regex(rx)
73
+ Ragweed::Wrap32::all_processes do |p|
74
+ if p.szExeFile =~ rx
75
+ return self.new(p.th32ProcessID)
76
+ end
77
+ end
78
+ nil
79
+ end
80
+
81
+ def initialize(p)
82
+ ## grab debug privilege at least once
83
+ @@token ||= Ragweed::Wrap32::ProcessToken.new.grant('seDebugPrivilege')
84
+
85
+ p = Process.new(p) if p.kind_of? Numeric
86
+ @p = p
87
+ @steppers = []
88
+ @handled = Ragweed::Wrap32::ContinueCodes::UNHANDLED
89
+ @attached = false
90
+
91
+ ## breakpoints is a hash with a key being the breakpoint
92
+ ## addr and the value being a Breakpoint class
93
+ @breakpoints = Hash.new
94
+
95
+ ## We want to ignore ntdll!DbgBreakPoint
96
+ @ntdll_dbg_break_point = @p.get_proc_remote('ntdll!DbgBreakPoint')
97
+ end
98
+
99
+ ## single-step the thread (by TID). "callable" is something that honors
100
+ ## .call, like a Proc. In a dubious design decision: the "handle" to the
101
+ ## single stepper is the Proc object itself. See Debugger#on_breakpoint
102
+ ## for an example of how to use this.
103
+ def step(tid, callable)
104
+ if @steppers.empty?
105
+ Ragweed::Wrap32::open_thread(tid) do |h|
106
+ ctx = Ragweed::Wrap32::get_thread_context(h)
107
+ ctx.single_step(true)
108
+ Ragweed::Wrap32::set_thread_context(h, ctx)
109
+ end
110
+ end
111
+ @steppers << callable
112
+ end
113
+
114
+ ## turn off single-stepping for one callable (you can have more than one
115
+ ## at a time). In other words, when you pass a Proc to Debugger#step, save
116
+ ## it somewhere, and later pass it to "unstep" to turn it off.
117
+ def unstep(tid, callable)
118
+ @steppers = @steppers.reject {|x| x == callable}
119
+ if @steppers.empty?
120
+ Ragweed::Wrap32::open_thread(tid) do |h|
121
+ ctx = Ragweed::Wrap32::get_thread_context(h)
122
+ ctx.single_step(false)
123
+ Ragweed::Wrap32::set_thread_context(h, ctx)
124
+ end
125
+ end
126
+ end
127
+
128
+ ## convenience: either from a TID or a BreakpointEvent, get the thread context.
129
+ def context(tid_or_event)
130
+ if not tid_or_event.kind_of? Numeric
131
+ tid = tid_or_event.tid
132
+ else
133
+ tid = tid_or_event
134
+ end
135
+ Ragweed::Wrap32::open_thread(tid) { |h| Ragweed::Wrap32::get_thread_context(h) }
136
+ end
137
+
138
+ ## set a breakpoint given an address, which can also be a string in the form
139
+ ## "module!function", as in, "user32!SendMessageW". Be aware that the symbol
140
+ ## lookup takes place in an injected thread; it's safer to use literal addresses
141
+ ## when possible.
142
+ #
143
+ ## to handle the breakpoint, pass a block to this method, which will be called
144
+ ## when the breakpoint hits.
145
+ #
146
+ ## breakpoints are always re-set after firing. If you don't want them to be
147
+ ## re-set, unset them manually.
148
+ def breakpoint_set(ip, callable=nil, &block)
149
+ if not callable and block_given?
150
+ callable = block
151
+ end
152
+
153
+ def_status = false
154
+
155
+ ## This is usually 'Module!Function' or 'Module!0x1234'
156
+ if @p.is_breakpoint_deferred(ip) == true
157
+ def_status = true
158
+ else
159
+ def_status = false
160
+ ip = @p.get_proc_remote(ip)
161
+ end
162
+
163
+ ## If we cant immediately set the breakpoint
164
+ ## mark it as deferred and wait till later
165
+ ## Sometimes *_proc_remote() will return the
166
+ ## name indicating failure (just in case)
167
+ if ip == 0 or ip == 0xFFFFFFFF or ip.kind_of? String
168
+ def_status = true
169
+ else
170
+ def_status = false
171
+ end
172
+
173
+ ## Dont want duplicate breakpoint objects
174
+ @breakpoints.each_key { |k| if k == ip then return end }
175
+ bp = Breakpoint.new(@p, ip, def_status, callable)
176
+ @breakpoints[ip] = bp
177
+ end
178
+
179
+ ## Clear a breakpoint by ip
180
+ def breakpoint_clear(ip)
181
+ bp = @breakpoints[ip]
182
+
183
+ if bp.nil?
184
+ return nil
185
+ end
186
+
187
+ bp.uninstall
188
+ @breakpoints.delete(ip)
189
+ end
190
+
191
+ ## handle a breakpoint event:
192
+ ## call handlers for the breakpoint, step past and reset it.
193
+ def on_breakpoint(ev)
194
+ ctx = context(ev)
195
+ eip = ev.exception_address
196
+
197
+ if eip == @ntdll_dbg_break_point
198
+ return
199
+ end
200
+
201
+ @breakpoints[eip].uninstall
202
+
203
+ ## Call the block passed to breakpoint_set
204
+ ## which may have been passed through hook()
205
+ @breakpoints[eip].call(ev, ctx)
206
+
207
+ ## single step past the instruction...
208
+ step(ev.tid, (onestep = lambda do |ev, ctx|
209
+ if ev.exception_address != eip
210
+ ## ... then re-install the breakpoint ...
211
+ if not @breakpoints[eip].nil?
212
+ @breakpoints[eip].install
213
+ end
214
+ ## ... and stop single-stepping.
215
+ unstep(ev.tid, onestep)
216
+ end
217
+ end))
218
+
219
+ ## Put execution back where it's supposed to be...
220
+ Ragweed::Wrap32::open_thread(ev.tid) do |h|
221
+ ctx = context(ev)
222
+ ctx.eip = eip ## eip was ev.exception_address
223
+ Ragweed::Wrap32::set_thread_context(h, ctx)
224
+ end
225
+
226
+ ## Tell the target to stop handling this event
227
+ @handled = Ragweed::Wrap32::ContinueCodes::CONTINUE
228
+ end
229
+
230
+ ## FIX: this method should be a bit more descriptive in its naming
231
+ def get_dll_name(ev)
232
+ name = Ragweed::Wrap32::get_mapped_filename(@p.handle, ev.base_of_dll, 256)
233
+ name.gsub!(/[\n]+/,'')
234
+ name.gsub!(/[^\x21-\x7e]/,'')
235
+ i = name.index('0')
236
+ i ||= name.size
237
+ return name[0, i]
238
+ end
239
+
240
+ def on_load_dll(ev)
241
+ dll_name = get_dll_name(ev)
242
+
243
+ @breakpoints.each_pair do |k,bp|
244
+ if !bp.addr.kind_of?String
245
+ next
246
+ end
247
+
248
+ m,f = bp.addr.split('!')
249
+
250
+ if dll_name =~ /#{m}/i
251
+ deferred = bp.deferred
252
+
253
+ if deferred == true
254
+ bp.deferred = false
255
+ end
256
+
257
+ new_addr = bp.deferred_install(ev.file_handle, ev.base_of_dll)
258
+
259
+ if !new_addr.nil?
260
+ @breakpoints[new_addr] = bp.dup
261
+ @breakpoints.delete(k)
262
+ end
263
+ end
264
+ end
265
+ end
266
+
267
+ ## handle a single-step event
268
+ def on_single_step(ev)
269
+ ctx = context(ev)
270
+ Ragweed::Wrap32::open_thread(ev.tid) do |h|
271
+ ## re-enable the trap flag before our handler,
272
+ ## which may choose to disable it.
273
+ ctx.single_step(true)
274
+ Ragweed::Wrap32.set_thread_context(h, ctx)
275
+ end
276
+
277
+ @steppers.each {|s| s.call(ev, ctx)}
278
+
279
+ @handled = Ragweed::Wrap32::ContinueCodes::CONTINUE
280
+ end
281
+
282
+ ## This is sort of insane but most of my programs are just
283
+ ## debug loops, so if you don't do this, they just hang when
284
+ ## the target closes.
285
+ def on_exit_process(ev)
286
+ exit(1)
287
+ end
288
+
289
+ ## TODO: Implement each of these
290
+ def on_create_process(ev) end
291
+ def on_create_thread(ev) end
292
+ def on_exit_thread(ev) end
293
+ def on_output_debug_string(ev) end
294
+ def on_rip(ev) end
295
+ def on_unload_dll(ev) end
296
+ def on_guard_page(ev) end
297
+ def on_alignment(ev) end
298
+ def on_bounds(ev) end
299
+ def on_divide_by_zero(ev) end
300
+ def on_int_overflow(ev) end
301
+ def on_invalid_handle(ev) end
302
+ def on_illegal_instruction(ev) end
303
+ def on_priv_instruction(ev) end
304
+ def on_stack_overflow(ev) end
305
+ def on_heap_corruption(ev) end
306
+ def on_buffer_overrun(ev) end
307
+ def on_invalid_disposition(ev) end
308
+ def on_attach() end
309
+
310
+ ## Read through me to see all the random events
311
+ ## you can hook in a subclass.
312
+ def wait
313
+ self.attach() if not @attached
314
+
315
+ @event = ev = Ragweed::Wrap32::wait_for_debug_event
316
+ return if not ev
317
+ case ev.code
318
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
319
+ try(:on_create_process, ev)
320
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
321
+ try(:on_create_thread, ev)
322
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
323
+ try(:on_exit_process, ev)
324
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
325
+ try(:on_exit_thread, ev)
326
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
327
+ try(:on_load_dll, ev)
328
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
329
+ try(:on_output_debug_string, ev)
330
+ when Ragweed::Wrap32::DebugCodes::RIP
331
+ try(:on_rip, ev)
332
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
333
+ try(:on_unload_dll, ev)
334
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
335
+ case ev.exception_code
336
+ when Ragweed::Wrap32::ExceptionCodes::ACCESS_VIOLATION
337
+ try(:on_access_violation, ev)
338
+ when Ragweed::Wrap32::ExceptionCodes::GUARD_PAGE
339
+ try(:on_guard_page, ev)
340
+ when Ragweed::Wrap32::ExceptionCodes::BREAKPOINT
341
+ try(:on_breakpoint, ev)
342
+ when Ragweed::Wrap32::ExceptionCodes::ALIGNMENT
343
+ try(:on_alignment, ev)
344
+ when Ragweed::Wrap32::ExceptionCodes::SINGLE_STEP
345
+ try(:on_single_step, ev)
346
+ when Ragweed::Wrap32::ExceptionCodes::BOUNDS
347
+ try(:on_bounds, ev)
348
+ when Ragweed::Wrap32::ExceptionCodes::DIVIDE_BY_ZERO
349
+ try(:on_divide_by_zero, ev)
350
+ when Ragweed::Wrap32::ExceptionCodes::INT_OVERFLOW
351
+ try(:on_int_overflow, ev)
352
+ when Ragweed::Wrap32::ExceptionCodes::INVALID_HANDLE
353
+ try(:on_invalid_handle, ev)
354
+ when Ragweed::Wrap32::ExceptionCodes::ILLEGAL_INSTRUCTION
355
+ try(:on_illegal_instruction, ev)
356
+ when Ragweed::Wrap32::ExceptionCodes::PRIV_INSTRUCTION
357
+ try(:on_priv_instruction, ev)
358
+ when Ragweed::Wrap32::ExceptionCodes::STACK_OVERFLOW
359
+ try(:on_stack_overflow, ev)
360
+ when Ragweed::Wrap32::ExceptionCodes::HEAP_CORRUPTION
361
+ try(:on_heap_corruption, ev)
362
+ when Ragweed::Wrap32::ExceptionCodes::BUFFER_OVERRUN
363
+ try(:on_buffer_overrun, ev)
364
+ when Ragweed::Wrap32::ExceptionCodes::INVALID_DISPOSITION
365
+ try(:on_invalid_disposition, ev)
366
+ end
367
+ end
368
+
369
+ Ragweed::Wrap32::continue_debug_event(ev.pid, ev.tid, @handled)
370
+ @handled = Ragweed::Wrap32::ContinueCodes::UNHANDLED
371
+ end
372
+
373
+ ## Debug loop
374
+ def loop
375
+ while true
376
+ wait
377
+ end
378
+ end
379
+
380
+ ## This is called implicitly by Debugger#wait.
381
+ ## Attaches to the child process for debugging
382
+ def attach
383
+ Ragweed::Wrap32::debug_active_process(@p.pid)
384
+ Ragweed::Wrap32::debug_set_process_kill_on_exit
385
+ @attached = true
386
+ try(:on_attach)
387
+ @breakpoints.each_pair do |k, bp|
388
+ bp.install
389
+ end
390
+ end
391
+
392
+ ## Let go of the target.
393
+ def release
394
+ Ragweed::Wrap32::debug_active_process_stop(@p.pid)
395
+ @attached = false
396
+ @breakpoints.each_pair do |k, bp|
397
+ bp.uninstall
398
+ end
399
+ end
400
+ end