ragweed 0.2.0-java

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.
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