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,401 @@
1
+ require 'ffi'
2
+
3
+ module Ragweed::Wrap32
4
+ module DebugCodes
5
+ CREATE_PROCESS = 3
6
+ CREATE_THREAD = 2
7
+ EXCEPTION = 1
8
+ EXIT_PROCESS = 5
9
+ EXIT_THREAD = 4
10
+ LOAD_DLL = 6
11
+ OUTPUT_DEBUG_STRING = 8
12
+ RIP = 9
13
+ UNLOAD_DLL = 7
14
+ end
15
+
16
+ module PagePermissions
17
+ PAGE_NOACCESS = 0x1
18
+ PAGE_READONLY = 0x2
19
+ PAGE_READWRITE = 0x4
20
+ PAGE_WRITECOPY = 0x8
21
+ PAGE_EXECUTE = 0x10
22
+ PAGE_EXECUTE_READ = 0x20
23
+ PAGE_EXECUTE_READWRITE = 0x40
24
+ PAGE_EXECUTE_WRITECOPY = 0x80
25
+ end
26
+
27
+ module ExceptionCodes
28
+ ACCESS_VIOLATION = 0xC0000005
29
+ GUARD_PAGE = 0x80000001
30
+ BREAKPOINT = 0x80000003
31
+ ALIGNMENT = 0x80000002
32
+ SINGLE_STEP = 0x80000004
33
+ BOUNDS = 0xC0000008
34
+ DIVIDE_BY_ZERO = 0xC0000094
35
+ INT_OVERFLOW = 0xC0000095
36
+ INVALID_HANDLE = 0xC0000008
37
+ PRIV_INSTRUCTION = 0xC0000096
38
+ ILLEGAL_INSTRUCTION = 0xC000001D
39
+ STACK_OVERFLOW = 0xC00000FD
40
+ HEAP_CORRUPTION = 0xC0000374
41
+ BUFFER_OVERRUN = 0xC0000409
42
+ INVALID_DISPOSITION = 0xC0000026
43
+ end
44
+
45
+ module ExceptionSubTypes
46
+ ACCESS_VIOLATION_TYPE_READ = 0
47
+ ACCESS_VIOLATION_TYPE_WRITE = 1
48
+ ACCESS_VIOLATION_TYPE_DEP = 8
49
+ end
50
+
51
+ module ContinueCodes
52
+ CONTINUE = 0x10002
53
+ BREAK = 0x40010008
54
+ CONTROL_C = 0x40010005
55
+ UNHANDLED = 0x80010001
56
+ TERMINATE_THREAD = 0x40010003
57
+ TERMINATE_PROCESS = 0x40010004
58
+ end
59
+ end
60
+
61
+ class Ragweed::Wrap32::StartupInfo < FFI::Struct
62
+ layout :cb, :ulong,
63
+ :reserved, :pointer,
64
+ :desktop, :pointer,
65
+ :title, :pointer,
66
+ :x, :ulong,
67
+ :y, :ulong,
68
+ :xsize, :ulong,
69
+ :ysize, :ulong,
70
+ :xcountchars, :ulong,
71
+ :ycountchars, :ulong,
72
+ :fillattr, :ulong,
73
+ :flags, :ulong,
74
+ :show_window, :short,
75
+ :breserved, :uint16,
76
+ :preserved, :uint8,
77
+ :std_input, :ulong,
78
+ :std_output, :ulong,
79
+ :std_error, :ulong
80
+ end
81
+
82
+ class Ragweed::Wrap32::ProcessInfo < FFI::Struct
83
+ layout :process_handle, :pointer,
84
+ :thread_handle, :pointer,
85
+ :pid, :ulong,
86
+ :thread_id, :ulong
87
+ end
88
+
89
+ class Ragweed::Wrap32::RipInfo < FFI::Struct
90
+ include Ragweed::FFIStructInclude
91
+ layout :error, :ulong,
92
+ :type, :ulong
93
+ end
94
+
95
+ class Ragweed::Wrap32::OutputDebugStringInfo < FFI::Struct
96
+ include Ragweed::FFIStructInclude
97
+ layout :debug_string_data, :ulong, # pointer
98
+ :unicode, :uint16,
99
+ :debug_string_length, :uint16
100
+ end
101
+
102
+ class Ragweed::Wrap32::UnloadDLLDebugInfo < FFI::Struct
103
+ include Ragweed::FFIStructInclude
104
+ layout :base_of_dll, :ulong
105
+ end
106
+
107
+ class Ragweed::Wrap32::LoadDLLDebugInfo < FFI::Struct
108
+ include Ragweed::FFIStructInclude
109
+ layout :file_handle, :ulong,
110
+ :base_of_dll, :ulong,
111
+ :debug_info_file_offset, :ulong,
112
+ :debug_info_size, :ulong,
113
+ :image_name, :pointer,
114
+ :unicode, :uint16
115
+ end
116
+
117
+ class Ragweed::Wrap32::ExitProcessDebugInfo < FFI::Struct
118
+ include Ragweed::FFIStructInclude
119
+ layout :exit_code, :ulong
120
+ end
121
+
122
+ class Ragweed::Wrap32::ExitThreadDebugInfo < FFI::Struct
123
+ include Ragweed::FFIStructInclude
124
+ layout :exit_code, :ulong
125
+ end
126
+
127
+ class Ragweed::Wrap32::CreateProcessDebugInfo < FFI::Struct
128
+ include Ragweed::FFIStructInclude
129
+ layout :file_handle, :ulong,
130
+ :process_handle, :ulong,
131
+ :thread_handle, :ulong,
132
+ :base_of_image, :pointer,
133
+ :debug_info_file_offset, :ulong,
134
+ :debug_info_size, :ulong,
135
+ :thread_local_base, :pointer,
136
+ :start_address, :pointer,
137
+ :image_name, :pointer,
138
+ :unicode, :uint16
139
+ end
140
+
141
+ class Ragweed::Wrap32::CreateThreadDebugInfo < FFI::Struct
142
+ include Ragweed::FFIStructInclude
143
+ layout :thread_handle, :ulong,
144
+ :thread_local_base, :ulong,
145
+ :start_address, :pointer
146
+ end
147
+
148
+ class Ragweed::Wrap32::ExceptionRecord < FFI::Struct
149
+ include Ragweed::FFIStructInclude
150
+ layout :exception_code, :ulong,
151
+ :exception_flags, :ulong,
152
+ :exception_record, :pointer,
153
+ :exception_address, :ulong,
154
+ :number_of_parameters, :ulong,
155
+ :exception_information, [:uint8, 15] ## EXCEPTION_MAXIMUM_PARAMETERS
156
+ end
157
+
158
+ class Ragweed::Wrap32::ExceptionDebugInfo < FFI::Struct
159
+ include Ragweed::FFIStructInclude
160
+ layout :exception_record, Ragweed::Wrap32::ExceptionRecord,
161
+ :first_chance, :ulong
162
+ end
163
+
164
+ class Ragweed::Wrap32::DebugEventU < FFI::Union
165
+ include Ragweed::FFIStructInclude
166
+ layout :exception_debug_info, Ragweed::Wrap32::ExceptionDebugInfo,
167
+ :create_thread_debug_info, Ragweed::Wrap32::CreateThreadDebugInfo,
168
+ :create_process_debug_info, Ragweed::Wrap32::CreateProcessDebugInfo,
169
+ :exit_thread_debug_info, Ragweed::Wrap32::ExitThreadDebugInfo,
170
+ :exit_process_debug_info, Ragweed::Wrap32::ExitProcessDebugInfo,
171
+ :load_dll_debug_info, Ragweed::Wrap32::LoadDLLDebugInfo,
172
+ :unload_dll_debug_info, Ragweed::Wrap32::UnloadDLLDebugInfo,
173
+ :output_debug_string_info, Ragweed::Wrap32::OutputDebugStringInfo,
174
+ :rip_info, Ragweed::Wrap32::RipInfo
175
+ end
176
+
177
+ class Ragweed::Wrap32::DebugEvent < FFI::Struct
178
+ include Ragweed::FFIStructInclude
179
+
180
+ layout :DebugEventCode, :ulong,
181
+ :ProcessId, :ulong,
182
+ :ThreadId, :ulong,
183
+ :u, Ragweed::Wrap32::DebugEventU
184
+
185
+ # backwards compatability
186
+ def code; self[:DebugEventCode]; end
187
+ def code=(cd); self[:DebugEventCode] = cd; end
188
+ def pid; self[:ProcessId]; end
189
+ def pid=(pd); self[:ProcessId]= pd; end
190
+ def tid; self[:ThreadId]; end
191
+ def tid=(td); self[:ThreadId] = td; end
192
+
193
+ # We have rubified this FFI structure by creating a bunch of proxy
194
+ # methods that are normally only accessible via self.u.x.y which is
195
+ # a lot to type. You can still use that method however these instance
196
+ # variables should allow for considerably clearer code
197
+ if RUBY_VERSION < "1.9"
198
+ def methods regular=true
199
+ ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
200
+ ret += case self[:DebugEventCode]
201
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
202
+ self[:u][:create_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
203
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
204
+ self[:u][:create_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
205
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
206
+ self[:u][:exit_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
207
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
208
+ self[:u][:exit_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
209
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
210
+ self[:u][:load_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
211
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
212
+ self[:u][:output_debug_string_info].members.map{|x| [x.to_s, x.to_s + "="]}
213
+ when Ragweed::Wrap32::DebugCodes::RIP
214
+ self[:u][:rip_info].members.map{|x| [x.to_s, x.to_s + "="]}
215
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
216
+ self[:u][:unload_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
217
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
218
+ self[:u][:exception_debug_info].members.map{|x| [x.to_s, x.to_s + "="]} + self[:u][:exception_debug_info][:exception_record].members.map{|x| [x.to_s, x.to_s + "="]}
219
+ else
220
+ []
221
+ end
222
+ ret.flatten
223
+ end
224
+ else
225
+ def methods regular=true
226
+ ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
227
+ ret += case self[:DebugEventCode]
228
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
229
+ self[:u][:create_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
230
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
231
+ self[:u][:create_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
232
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
233
+ self[:u][:exit_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
234
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
235
+ self[:u][:exit_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
236
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
237
+ self[:u][:load_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
238
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
239
+ self[:u][:output_debug_string_info].members.map{|x| [x, (x.to_s + "=").intern]}
240
+ when Ragweed::Wrap32::DebugCodes::RIP
241
+ self[:u][:rip_info].members.map{|x| [x, (x.to_s + "=").intern]}
242
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
243
+ self[:u][:unload_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
244
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
245
+ self[:u][:exception_debug_info].members.map{|x| [x, (x.to_s + "=").intern]} + self[:u][:exception_debug_info][:exception_record].members.map{|x| [x, (x.to_s + "=").intern]}
246
+ else
247
+ []
248
+ end
249
+ ret.flatten
250
+ end
251
+ end
252
+
253
+ def method_missing meth, *args
254
+ super unless self.respond_to? meth
255
+ if meth.to_s =~ /=$/
256
+ mth = meth.to_s.gsub(/=$/,'').intern
257
+ if self.members.include? mth
258
+ # don't proxy
259
+ self.__send__(:[]=, mth, *args)
260
+ else
261
+ case self[:DebugEventCode]
262
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
263
+ self[:u][:create_process_debug_info].__send__(:[]=, mth, *args)
264
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
265
+ self[:u][:create_thread_debug_info].__send__(:[]=, mth, *args)
266
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
267
+ self[:u][:exit_process_debug_info].__send__(:[]=, mth, *args)
268
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
269
+ self[:u][:exit_thread_debug_info].__send__(:[]=, mth, *args)
270
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
271
+ self[:u][:load_dll_debug_info].__send__(:[]=, mth, *args)
272
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
273
+ self[:u][:output_debug_string_info].__send__(:[]=, mth, *args)
274
+ when Ragweed::Wrap32::DebugCodes::RIP
275
+ self[:u][:rip_info].__send__(:[]=, mth, *args)
276
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
277
+ self[:u][:unload_dll_debug_info].__send__(:[]=, mth, *args)
278
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
279
+ case mth
280
+ when :exception_record, :first_chance
281
+ self[:u][:exception_debug_info].__send__(:[]=, mth, *args)
282
+ else # it's in the exception_record -- gross, I know but...
283
+ self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
284
+ end
285
+ end
286
+ end
287
+ else
288
+ if self.members.include? meth
289
+ # don't proxy
290
+ self.__send__(:[], meth, *args)
291
+ else
292
+ case self[:DebugEventCode]
293
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
294
+ self[:u][:create_process_debug_info].__send__(:[], meth, *args)
295
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
296
+ self[:u][:create_thread_debug_info].__send__(:[], meth, *args)
297
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
298
+ self[:u][:exit_process_debug_info].__send__(:[], meth, *args)
299
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
300
+ self[:u][:exit_thread_debug_info].__send__(:[], meth, *args)
301
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
302
+ self[:u][:load_dll_debug_info].__send__(:[], meth, *args)
303
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
304
+ self[:u][:output_debug_string_info].__send__(:[], meth, *args)
305
+ when Ragweed::Wrap32::DebugCodes::RIP
306
+ self[:u][:rip_info].__send__(:[], meth, *args)
307
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
308
+ self[:u][:unload_dll_debug_info].__send__(:[], meth, *args)
309
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
310
+ case meth
311
+ when :exception_record, :first_chance
312
+ self[:u][:exception_debug_info].__send__(:[], meth, *args)
313
+ else # it's in the exception_record -- gross, I know but...
314
+ self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ def respond_to? meth, include_priv=false
322
+ # mth = meth.to_s.gsub(/=$/,'')
323
+ !((self.methods & [meth, meth.to_s]).empty?) || super
324
+ end
325
+
326
+ def inspect_code(c)
327
+ Ragweed::Wrap32::DebugCodes.to_key_hash[c].to_s || c.to_i
328
+ end
329
+
330
+ def inspect_exception_code(c)
331
+ Ragweed::Wrap32::ExceptionCodes.to_key_hash[c].to_s || c.to_i.to_s(16)
332
+ end
333
+
334
+ def inspect_parameters(p)
335
+ "[ " + p.map {|x| x.to_i.to_s}.join(", ") + " ]"
336
+ end
337
+
338
+ def inspect
339
+ body = lambda do
340
+ self.members.each_with_index do |m,i|
341
+ "#{self.values[i].to_s.hexify} #{self.values[i].to_s.hexify}"
342
+ end.join(", ")
343
+ end
344
+ "#<DebugEvent #{body.call}>"
345
+ end
346
+ end
347
+
348
+ ## Wrap the Win32 debugging specific APIs
349
+ module Ragweed::Wrap32
350
+ module Win
351
+ extend FFI::Library
352
+
353
+ ffi_lib 'kernel32'
354
+ ffi_convention :stdcall
355
+
356
+ attach_function 'WaitForDebugEvent', [ :pointer, :ulong ], :ulong
357
+ attach_function 'ContinueDebugEvent', [ :ulong, :ulong, :ulong ], :ulong
358
+ attach_function 'DebugActiveProcess', [ :ulong ], :ulong
359
+ attach_function 'DebugSetProcessKillOnExit', [ :ulong ], :ulong
360
+ attach_function 'DebugActiveProcessStop', [ :ulong ], :ulong
361
+ attach_function 'FlushInstructionCache', [ :ulong, :ulong, :ulong ], :ulong
362
+ end
363
+
364
+ class << self
365
+ def wait_for_debug_event(ms=1000)
366
+ # buf = FFI::MemoryPointer.new(Ragweed::Wrap32::DebugEvent, 1)
367
+ buf = FFI::MemoryPointer.from_string("\x00" * 1024)
368
+ r = Win.WaitForDebugEvent(buf, ms)
369
+ raise WinX.new(:wait_for_debug_event) if r == 0 and get_last_error != 121
370
+ return Ragweed::Wrap32::DebugEvent.new(buf) if r != 0
371
+ return nil
372
+ end
373
+
374
+ def continue_debug_event(pid, tid, code)
375
+ r = Win.ContinueDebugEvent(pid, tid, code)
376
+ raise WinX.new(:continue_debug_event) if r == 0
377
+ return r
378
+ end
379
+
380
+ def debug_active_process(pid)
381
+ r = Win.DebugActiveProcess(pid)
382
+ raise WinX.new(:debug_active_process) if r == 0
383
+ return r
384
+ end
385
+
386
+ def debug_set_process_kill_on_exit(val=0)
387
+ r = Win.DebugSetProcessKillOnExit(val)
388
+ raise WinX.new(:debug_set_process_kill_on_exit) if r == 0
389
+ return r
390
+ end
391
+
392
+ def debug_active_process_stop(pid)
393
+ # don't care about failure
394
+ Win.DebugActiveProcessStop(pid)
395
+ end
396
+
397
+ def flush_instruction_cache(h, v1=0, v2=0)
398
+ Win.FlushInstructionCache(h, v1, v2)
399
+ end
400
+ end
401
+ end
@@ -0,0 +1,49 @@
1
+ module Ragweed
2
+ class Device
3
+ def initialize(path, options={})
4
+ @path = path
5
+ @options = options
6
+ @h = Ragweed::Wrap32::create_file(@path, :flags => Ragweed::Wrap32::FileAttributes::OVERLAPPED|Ragweed::Wrap32::FileAttributes::NORMAL)
7
+ end
8
+
9
+ def ioctl(code, inbuf, outbuf)
10
+ overlap(lambda do |o|
11
+ Ragweed::Wrap32::device_io_control(@h, code, inbuf, outbuf, o)
12
+ end) do |ret, count|
13
+ outbuf[0..count]
14
+ end
15
+ end
16
+
17
+ def read(sz)
18
+ overlap(lambda do |o|
19
+ Ragweed::Wrap32::read_file(@h, sz, o)
20
+ end) do |ret, count|
21
+ ret[0..count]
22
+ end
23
+ end
24
+
25
+ def write(buf)
26
+ overlap(lambda do |o|
27
+ Ragweed::Wrap32::write_file(@h, buf, o)
28
+ end) do |ret, count|
29
+ count
30
+ end
31
+ end
32
+
33
+ def release
34
+ Ragweed::Wrap32::close_handle(@h)
35
+ @h = nil
36
+ end
37
+
38
+ private
39
+
40
+ def overlap(proc)
41
+ o = Ragweed::Wrap32::Overlapped.get
42
+ ret = proc.call(o)
43
+ count = o.wait(@h)
44
+ r = yield ret, count
45
+ o.release
46
+ ret = r if r
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,50 @@
1
+ class Ragweed::Event
2
+ # Quick wrapper around Win32 events. Events are simple thread sync
3
+ # objects that are cross-process. They are like semaphores that you
4
+ # can select() on.
5
+
6
+ # You can just do WinEvent.new to get a new anonymous handle, and
7
+ # then call .handle on it to find out what the handle was. Communicate
8
+ # your pid and the handle value, somehow, to a remote process. That
9
+ # process can get the same event by passing a WinProcess and the
10
+ # handle here.
11
+ #
12
+ # So, in Process1 (assume pid 668, and handle 300):
13
+ #
14
+ # e = WinEvent.new
15
+ # puts #{ get_current_process_id }: #{ e.handle }"
16
+ #
17
+ # And in Process2:
18
+ #
19
+ # e = WinEvent.new(WinProcess.new(668), 300)
20
+ #
21
+ # Now both processes share an event.
22
+ def initialize(p=nil, h=nil)
23
+ @p = p
24
+ @h = (@p.dup_handle(h) if h) || create_event
25
+ end
26
+
27
+ # Don't return until the event is signalled. Note that you
28
+ # can't break this with timeouts or CTR-C.
29
+ def wait
30
+ Ragweed::Wrap32::wait_for_single_object @h
31
+ end
32
+
33
+ # Signal the event; anyone waiting on it is now released.
34
+ def signal
35
+ Ragweed::Wrap32::set_event(@h)
36
+ end
37
+
38
+ # Force the event back to unsignalled state.
39
+ def reset
40
+ Ragweed::Wrap32::reset_event(@h)
41
+ end
42
+
43
+ # A wait loop.
44
+ def on(&block)
45
+ while 1
46
+ wait
47
+ break if not yield
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ class Ragweed::Debugger32
2
+ # Hook function calls
3
+ # nargs is the number of arguments taken by function at ip
4
+ # callable/block is called with ev, ctx, dir (:enter or :leave), and args Array (see examples/hook_notepad.rb)
5
+ # default handler prints arguments
6
+ def hook(ip, nargs, callable=nil, &block)
7
+
8
+ callable ||= block || lambda do |ev,ctx,dir,args|
9
+ #puts args.map{|a| "%08x" % a}.join(',')
10
+ end
11
+
12
+ breakpoint_set(ip) do |ev,ctx|
13
+ esp = process.read32(ctx.esp)
14
+ nargs = nargs.to_i
15
+
16
+ if nargs >= 1
17
+ args = (1..nargs).map {|i| process.read32(ctx.esp + 4*i)}
18
+ end
19
+
20
+ ## set exit bpoint
21
+ ## We cant always set a leave bp due to
22
+ ## calling conventions but we can avoid
23
+ ## a crash by setting a breakpoint on
24
+ ## the wrong address. So we attempt to
25
+ ## get an idea of where the instruction
26
+ ## is mapped.
27
+ eip = ctx.eip
28
+ if esp != 0 #and esp > (eip & 0xf0000000)
29
+ breakpoint_set(esp) do |ev,ctx|
30
+ callable.call(ev, ctx, :leave, args)
31
+ breakpoint_clear(esp)
32
+ end.install
33
+ end
34
+
35
+ ## Call the block sent to hook()
36
+ callable.call(ev, ctx, :enter, args)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,46 @@
1
+ class Ragweed::Wrap32::Overlapped
2
+ attr_accessor :internal
3
+ attr_accessor :internal_high
4
+ attr_accessor :offset
5
+ attr_accessor :offset_high
6
+ attr_accessor :event
7
+ attr_accessor :target
8
+
9
+ def self.get
10
+ h = Ragweed::Wrap32::create_event(nil, false, true)
11
+ r = self.new
12
+ r.event = h
13
+ return r
14
+ end
15
+
16
+ def initialize(str=nil)
17
+ @buf = "\x00" * 20
18
+ @internal, @internal_high, @offset, @offset_high, @event = [0,0,0,0,0]
19
+ init(str) if str
20
+ end
21
+
22
+ def to_s
23
+ buf = [@internal, @internal_high, @offset, @offset_high, @event].pack("LLLLL")
24
+ @buf.replace(buf)
25
+ end
26
+
27
+ def release
28
+ Ragweed::Wrap32::close_handle(@event)
29
+ end
30
+
31
+ def wait(h)
32
+ return if not @event
33
+ Ragweed::Wrap32::wait_for_single_object(@event)
34
+ Ragweed::Wrap32::get_overlapped_result(h, self)
35
+ end
36
+
37
+ private
38
+
39
+ def init(str)
40
+ @internal,
41
+ @internal_high,
42
+ @offset,
43
+ @offset_high,
44
+ @event = str.unpack("LLLLL")
45
+ end
46
+ end