tduehr-ragweed 0.1.5

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 (62) hide show
  1. data/History.txt +15 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +30 -0
  5. data/examples/hittracertux.rb +48 -0
  6. data/examples/hittracerx.rb +63 -0
  7. data/examples/hook_notepad.rb +9 -0
  8. data/examples/snicker.rb +183 -0
  9. data/examples/tux-example.rb +23 -0
  10. data/lib/ragweed/arena.rb +55 -0
  11. data/lib/ragweed/blocks.rb +128 -0
  12. data/lib/ragweed/debugger32.rb +338 -0
  13. data/lib/ragweed/debuggerosx.rb +419 -0
  14. data/lib/ragweed/debuggertux.rb +347 -0
  15. data/lib/ragweed/detour.rb +223 -0
  16. data/lib/ragweed/ptr.rb +48 -0
  17. data/lib/ragweed/rasm/isa.rb +1046 -0
  18. data/lib/ragweed/rasm/util.rb +26 -0
  19. data/lib/ragweed/rasm.rb +53 -0
  20. data/lib/ragweed/sbuf.rb +197 -0
  21. data/lib/ragweed/trampoline.rb +103 -0
  22. data/lib/ragweed/utils.rb +87 -0
  23. data/lib/ragweed/wrap32/debugging.rb +163 -0
  24. data/lib/ragweed/wrap32/device.rb +49 -0
  25. data/lib/ragweed/wrap32/event.rb +50 -0
  26. data/lib/ragweed/wrap32/hooks.rb +23 -0
  27. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  28. data/lib/ragweed/wrap32/process.rb +506 -0
  29. data/lib/ragweed/wrap32/process_token.rb +59 -0
  30. data/lib/ragweed/wrap32/thread_context.rb +208 -0
  31. data/lib/ragweed/wrap32/winx.rb +16 -0
  32. data/lib/ragweed/wrap32/wrap32.rb +526 -0
  33. data/lib/ragweed/wrap32.rb +53 -0
  34. data/lib/ragweed/wraposx/constants.rb +101 -0
  35. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  36. data/lib/ragweed/wraposx/region_info.rb +244 -0
  37. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  38. data/lib/ragweed/wraposx/thread_info.rb +213 -0
  39. data/lib/ragweed/wraposx/wraposx.rb +376 -0
  40. data/lib/ragweed/wraposx.rb +53 -0
  41. data/lib/ragweed/wraptux/constants.rb +68 -0
  42. data/lib/ragweed/wraptux/threads.rb +3 -0
  43. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  44. data/lib/ragweed/wraptux.rb +53 -0
  45. data/lib/ragweed.rb +84 -0
  46. data/spec/ragweed_spec.rb +7 -0
  47. data/spec/spec_helper.rb +16 -0
  48. data/tasks/ann.rake +80 -0
  49. data/tasks/bones.rake +20 -0
  50. data/tasks/gem.rake +201 -0
  51. data/tasks/git.rake +40 -0
  52. data/tasks/notes.rake +27 -0
  53. data/tasks/post_load.rake +34 -0
  54. data/tasks/rdoc.rake +51 -0
  55. data/tasks/rubyforge.rake +55 -0
  56. data/tasks/setup.rb +292 -0
  57. data/tasks/spec.rake +54 -0
  58. data/tasks/svn.rake +47 -0
  59. data/tasks/test.rake +40 -0
  60. data/tasks/zentest.rake +36 -0
  61. data/test/test_ragweed.rb +0 -0
  62. metadata +127 -0
@@ -0,0 +1,526 @@
1
+ %w[ostruct Win32API pp].each {|x| require x}
2
+
3
+ module Ragweed;end
4
+ module Ragweed::Wrap32
5
+ NULL = 0x0
6
+
7
+ module PagePerms
8
+ EXECUTE = 0x10
9
+ EXECUTE_READ = 0x20
10
+ EXECUTE_READWRITE = 0x40
11
+ EXECUTE_WRITECOPY = 0x80
12
+ NOACCESS = 0x1
13
+ READONLY = 0x2
14
+ READWRITE = 0x4
15
+ WRITECOPY = 0x8
16
+
17
+ WRITEABLE = [EXECUTE_READWRITE,
18
+ EXECUTE_WRITECOPY,
19
+ READWRITE,
20
+ WRITECOPY]
21
+ end
22
+
23
+ module FileSharing
24
+ NONE = 0
25
+ DELETE = 4
26
+ READ = 1
27
+ WRITE = 2
28
+ end
29
+
30
+ module FileDisposition
31
+ CREATE_ALWAYS = 2
32
+ CREATE_NEW = 1
33
+ OPEN_ALWAYS = 4
34
+ OPEN_EXISTING = 3
35
+ TRUNCATE_EXISTING = 5
36
+ end
37
+
38
+ module FileAttributes
39
+ ARCHIVE = 0x20
40
+ ENCRYPTED = 0x4000
41
+ HIDDEN = 0x2
42
+ NORMAL = 0x80
43
+ OFFLINE = 0x1000
44
+ READONLY = 1
45
+ SYSTEM = 4
46
+ TEMPORARY = 0x100
47
+ BACKUP = 0x02000000
48
+ DELETE_ON_CLOSE = 0x04000000
49
+ NO_BUFFERING = 0x20000000
50
+ NO_RECALL = 0x00100000
51
+ REPARSE_POINT = 0x00200000
52
+ OVERLAPPED = 0x40000000
53
+ POSIX = 0x0100000
54
+ RANDOM_ACCESS = 0x10000000
55
+ SEQUENTIAL = 0x08000000
56
+ WRITE_THROUGH = 0x80000000
57
+ end
58
+
59
+ module FileAccess
60
+ GENERIC_READ = 0x80000000
61
+ GENERIC_WRITE = 0x40000000
62
+ GENERIC_EXECUTE = 0x20000000
63
+ GENERIC_ALL = 0x10000000
64
+ end
65
+
66
+ module FormatArgs
67
+ FROM_SYSTEM = 4096
68
+ ALLOCATE_BUFFER = 256
69
+ end
70
+
71
+ # Does 2 things:
72
+ # 1. Parses a terse notation for Win32 functions: "module!function:args=return",
73
+ # where "args" and "return" are in String#unpack notation.
74
+ #
75
+ # 2. Memoizes the Win32API lookup.
76
+ #
77
+ # Returns a callable object implementing the specified call.
78
+
79
+ CALLS = Hash.new do |h, str|
80
+ lib = proc = args = ret = nil
81
+ lib, rest = str.split "!"
82
+ proc, rest = rest.split ":"
83
+ args, ret = rest.split("=") if rest
84
+ ret ||= ""
85
+ args ||= []
86
+ raise "need proc" if not proc
87
+ h[str] = Win32API.new(lib, proc, args, ret)
88
+ end
89
+
90
+ # --------------------------------------------------------------------------------------
91
+
92
+ class << self
93
+
94
+ # Get a process handle given a pid
95
+ def open_process(pid)
96
+ r = CALLS["kernel32!OpenProcess:LLL=L"].call(0x1F0FFF, 0, pid)
97
+ raise WinX.new(:open_process) if r == 0
98
+ return r
99
+ end
100
+
101
+ # Get a thread handle given a tid; if a block is provided, the semantics are
102
+ # as File#open with a block.
103
+ def open_thread(tid, &block)
104
+ h = CALLS["kernel32!OpenThread:LLL=L"].call(0x1F03FF, 0, tid)
105
+ raise WinX.new(:open_thread) if h == 0
106
+ if block_given?
107
+ ret = yield h
108
+ close_handle(h)
109
+ return ret
110
+ end
111
+ h
112
+ end
113
+
114
+ # Close any Win32 handle. Reminder: Win32 handles are just integers, like file
115
+ # descriptors in Posix.
116
+ def close_handle(h)
117
+ raise WinX.new(:close_handle) if CALLS["kernel32!CloseHandle:L"].call(h) != 0
118
+ end
119
+
120
+ # Get the last error code (errno) (can't fail)
121
+ def get_last_error
122
+ CALLS["kernel32!GetLastError:=L"].call
123
+ end
124
+
125
+ # strerror(errno) (can't fail)
126
+ def format_message(code=nil)
127
+ code ||= get_last_error
128
+ buf = "\x00" * 4096
129
+ CALLS["kernel32!FormatMessageA:LPLLPLP"].
130
+ call(4096, NULL, code, 0x00000400, buf, 4096, NULL)
131
+ return buf.split("\x00")[0]
132
+ end
133
+
134
+ # Allocate memory in a remote process (or yourself, with handle -1)
135
+ def virtual_alloc_ex(h, sz, addr=NULL, prot=0x40)
136
+ r = CALLS["kernel32!VirtualAllocEx:LLLLL=L"].
137
+ call(h, addr, sz, 0x1000, prot)
138
+ raise WinX.new(:virtual_alloc_ex) if r == 0
139
+ return r
140
+ end
141
+
142
+ # Free memory in a remote process given the pointer returned from virtual_alloc_ex
143
+ def virtual_free_ex(h, ptr, type=0x8000)
144
+ r = CALLS["kernel32!VirtualFreeEx:LLLL=L"].call(h, ptr.to_i, 0, type)
145
+ raise WinX.new(:virtual_free_ex) if r == 0
146
+ return r
147
+ end
148
+
149
+ # Write a string into the memory of a remote process given its handle and an address
150
+ def write_process_memory(h, dst, val)
151
+ val = val.to_s if not val.kind_of? String
152
+ r = CALLS["kernel32!WriteProcessMemory:LLPLL=L"].call(h, dst.to_i, val, val.size, NULL)
153
+ raise WinX.new(:write_process_memory) if r == 0
154
+ return r
155
+ end
156
+
157
+ # Read from a remote process given an address and length, returning a string.
158
+ def read_process_memory(h, ptr, len)
159
+ val = "\x00" * len
160
+ r = CALLS["kernel32!ReadProcessMemory:LLPLL=L"].call(h, ptr.to_i, val, len, NULL)
161
+ raise WinX.new(:read_process_memory) if r == 0
162
+ return val ## don't handle short reads XXX
163
+ end
164
+
165
+ def str2memory_basic_info(mbi)
166
+ s = OpenStruct.new
167
+ s.BaseAddress,
168
+ s.AllocationBase,
169
+ s.AllocationProtect,
170
+ s.RegionSize,
171
+ s.State,
172
+ s.Protect,
173
+ s.Type = mbi.unpack("LLLLLLL")
174
+ return s
175
+ end
176
+
177
+ # Return a struct with the MEMORY_BASIC_INFORMATION for a given address in the
178
+ # memory of a remote process. Gives you addressable memory ranges and protection
179
+ # flags.
180
+ def virtual_query_ex(h, ptr)
181
+ mbi = [0,0,0,0,0,0,0].pack("LLLLLLL")
182
+ if CALLS["kernel32!VirtualQueryEx:LLPL=L"].call(h, ptr, mbi, mbi.size)
183
+ str2memory_basic_info(mbi)
184
+ else
185
+ nil
186
+ end
187
+ end
188
+
189
+ # Change the protection of specific memory regions in a remote process.
190
+ def virtual_protect_ex(h, addr, prot, size=0)
191
+ old = [0].pack("L")
192
+ base = virtual_query_ex(h, addr).BaseAddress if size == 0
193
+ base ||= addr
194
+
195
+ if CALLS["kernel32!VirtualProtectEx:LLLLP=L"].call(h, base, size, prot, old)
196
+ old.unpack("L").first
197
+ else
198
+ raise WinX.new(:virtual_protect_ex)
199
+ end
200
+ end
201
+
202
+ # getpid
203
+ def get_current_process_id
204
+ CALLS["kernel32!GetCurrentProcessId:=L"].call # can't realistically fail
205
+ end
206
+
207
+ # gettid
208
+ def get_current_thread_id
209
+ CALLS["kernel32!GetCurrentThreadId:=L"].call # can't realistically fail
210
+ end
211
+
212
+ # Given a DLL name, get a handle to the DLL.
213
+ def get_module_handle(name)
214
+ name = name.to_utf16
215
+ r = CALLS["kernel32!GetModuleHandleW:P=L"].call(name)
216
+ raise WinX.new(:get_module_handle) if r == 0
217
+ return r
218
+ end
219
+
220
+ # load a library explicitly from a dll
221
+ def load_library(name)
222
+ name = name.to_utf16
223
+ r = CALLS["kernel32!LoadLibraryW:P=L"].call(name)
224
+ raise WinX.new(:load_library) if r == 0
225
+ return r
226
+ end
227
+
228
+ # Using notation x = "foo!bar" or x = handle, y = meth, look up a function's
229
+ # address in a module. Note that this is local, not remote.
230
+ def get_proc_address(x, y=nil)
231
+ if not y
232
+ mod, meth = x.split "!"
233
+ h = get_module_handle(mod)
234
+ else
235
+ h = x
236
+ meth = y
237
+ end
238
+
239
+ r = CALLS["kernel32!GetProcAddress:LP=L"].call(h, meth)
240
+ return r # pass error through
241
+ end
242
+
243
+ # Select(2), for a single object handle.
244
+ def wait_for_single_object(h)
245
+ r = CALLS["kernel32!WaitForSingleObject:LL=L"].call(h, -1)
246
+ raise WinX.new(:wait_for_single_object) if r == -1
247
+ end
248
+
249
+ def str2process_info(str)
250
+ ret = OpenStruct.new
251
+ ret.dwSize,
252
+ ret.cntUsage,
253
+ ret.th32ProcessID,
254
+ ret.th32DefaultHeapID,
255
+ ret.th32ModuleID,
256
+ ret.cntThreads,
257
+ ret.th32ParentProcessID,
258
+ ret.pcPriClassBase,
259
+ ret.dwFlags,
260
+ ret.szExeFile = str.unpack("LLLLLLLLLA2048")
261
+ ret.szExeFile = ret.szExeFile.asciiz
262
+ return ret
263
+ end
264
+
265
+ # Use Toolhelp32 to enumerate all running processes on the box, returning
266
+ # a struct with PIDs and executable names.
267
+ def all_processes
268
+ h = CALLS["kernel32!CreateToolhelp32Snapshot:LL=L"].call(0x2, 0)
269
+ if h != -1
270
+ pi = [(9*4)+2048,0,0,0,0,0,0,0,0,"\x00"*2048].pack("LLLLLLLLLa2048")
271
+ if CALLS["kernel32!Process32First:LP=L"].call(h, pi) != 0
272
+ yield str2process_info(pi)
273
+ while CALLS["kernel32!Process32Next:LP=L"].call(h, pi) != 0
274
+ yield str2process_info(pi)
275
+ end
276
+ end
277
+ else
278
+ raise WinX.new(:create_toolhelp32_snapshot)
279
+ end
280
+ end
281
+
282
+ def str2module_info(str)
283
+ ret = OpenStruct.new
284
+ ret.dwSize,
285
+ ret.th32ModuleID,
286
+ ret.th32ProcessID,
287
+ ret.GlblcntUsage,
288
+ ret.ProccntUsage,
289
+ ret.modBaseAddr,
290
+ ret.modBaseSize,
291
+ ret.hModule,
292
+ ret.szModule,
293
+ ret.szExePath = str.unpack("LLLLLLLLA256A260")
294
+ ret.szModule = ret.szModule.asciiz
295
+ ret.szExePath = ret.szExePath.asciiz
296
+ return ret
297
+ end
298
+
299
+ # Given a pid, enumerate the modules loaded into the process, returning base
300
+ # addresses, memory ranges, and the module name.
301
+ def list_modules(pid=0)
302
+ h = CALLS["kernel32!CreateToolhelp32Snapshot:LL=L"].call(0x8, pid)
303
+ if h != -1
304
+ mi = [260+256+(8*4),0,0,0,0,0,0,0,"\x00"*256,"\x00"*260].pack("LLLLLLLLa256a260")
305
+ if w32("kernel32!Module32First:LP=L").call(h, mi) != 0
306
+ yield str2module_info(mi)
307
+ while w32("kernel32!Module32Next:LP=L").call(h, mi) != 0
308
+ yield str2module_info(mi)
309
+ end
310
+ end
311
+ else
312
+ raise WinX.new(:create_toolhelp32_snapshot)
313
+ end
314
+ end
315
+
316
+ # Use virtual_query_ex to tell whether an address is writable.
317
+ def writeable?(h, off)
318
+ if (x = virtual_query_ex(h, off))
319
+ return PagePerms::WRITEABLE.member?(x.Protect & 0xFF)
320
+ else
321
+ return false
322
+ end
323
+ end
324
+
325
+ # NQIP does a lot of things, the most useful of which are getting the
326
+ # image name of a running process, and telling whether a debugger is loaded. This
327
+ # interface is Ioctl-style; provide an ordinal and a buffer to pass results through.
328
+ def nt_query_information_process(h, ord, buf)
329
+ lenp = [0].pack("L")
330
+ if CALLS["ntdll!NtQueryInformationProcess:LLPLP=L"].call(h, ord, buf, buf.size, lenp) == 0
331
+ len = lenp.unpack("L").first
332
+ return buf[0..(len-1)]
333
+ end
334
+ nil
335
+ end
336
+
337
+ def str2thread_info(str)
338
+ ret = OpenStruct.new
339
+ ret.dwSize,
340
+ ret.cntUsage,
341
+ ret.th32ThreadID,
342
+ ret.th32OwnerProcessID,
343
+ ret.tpBasePri,
344
+ ret.tpDeltaPri,
345
+ ret.thFlags = str.unpack("LLLLLLL")
346
+ return ret
347
+ end
348
+
349
+ # List all the threads in a process given its pid, returning a struct containing
350
+ # tids and run state. This is relatively expensive, because it uses Toolhelp32.
351
+ def threads(pid)
352
+ h = CALLS["kernel32!CreateToolhelp32Snapshot:LL=L"].call(0x4, pid)
353
+ if h != -1
354
+ mi = [(7*4),0,0,0,0,0,0].pack("LLLLLLL")
355
+ if w32("kernel32!Thread32First:LP=L").call(h, mi) != 0
356
+ ti = str2thread_info(mi)
357
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
358
+ while w32("kernel32!Thread32Next:LP=L").call(h, mi) != 0
359
+ ti = str2thread_info(mi)
360
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
361
+ end
362
+ end
363
+ else
364
+ raise WinX.new(:create_toolhelp32_snapshot)
365
+ end
366
+ end
367
+
368
+ # Suspend a thread given its handle.
369
+ def suspend_thread(h)
370
+ r = CALLS["kernel32!SuspendThread:L=L"].call(h)
371
+ raise WinX.new(:suspend_thread) if r == 0
372
+ return r
373
+ end
374
+
375
+ # Resume a suspended thread, returning nonzero if the thread was suspended,
376
+ # and 0 if it was running.
377
+ def resume_thread(h)
378
+ CALLS["kernel32!ResumeThread:L=L"].call(h)
379
+ end
380
+
381
+ # Create a remote thread in the process, starting at the location
382
+ # "start", with the threadproc argument "arg"
383
+ def create_remote_thread(h, start, arg)
384
+ r = CALLS["kernel32!CreateRemoteThread:LLLLLLL=L"].call(h, NULL, 0, start.to_i, arg.to_i, 0, 0)
385
+ raise WinX.new(:create_remote_thread) if r == 0
386
+ return r
387
+ end
388
+
389
+ def sleep(ms=0)
390
+ CALLS["kernel32!Sleep:L=L"].call(ms)
391
+ end
392
+
393
+ # clone a handle out of another open process (or self, with -1)
394
+ def duplicate_handle(ph, h)
395
+ ret = "\x00\x00\x00\x00"
396
+ r = CALLS["kernel32!DuplicateHandle:LLLPLLL=L"].call(ph, h, -1, ret, 0, 0, 0x2)
397
+ raise WinX.new(:duplicate_handle) if r == 0
398
+ ret.to_l32
399
+ end
400
+
401
+ def create_file(name, opts={})
402
+ opts[:disposition] ||= FileDisposition::OPEN_ALWAYS
403
+ opts[:sharing] ||= FileSharing::READ | FileSharing::WRITE
404
+ opts[:access] ||= FileAccess::GENERIC_ALL
405
+ opts[:flags] ||= 0
406
+
407
+ r = CALLS["kernel32!CreateFile:PLLPLLP=L"].
408
+ call(name, opts[:access], opts[:sharing], NULL, opts[:disposition], opts[:flags], NULL)
409
+ raise WinX.new(:create_file) if r == -1
410
+ return r
411
+ end
412
+
413
+ # i haven't made this work, but named handles are kind of silly anyways
414
+ def open_event(name)
415
+ r = CALLS["kernel32!OpenEvent:LLP=L"].call(0, 0, name)
416
+ raise WinX.new(:open_event) if r == 0
417
+ return r
418
+ end
419
+
420
+ # signal an event
421
+ def set_event(h)
422
+ r = CALLS["kernel32!SetEvent:L=L"].call(h)
423
+ raise WinX.new(:set_event) if r == 0
424
+ return r
425
+ end
426
+
427
+ # force-unsignal event (waiting on the event handle also does this)
428
+ def reset_event(h)
429
+ r = CALLS["kernel32!ResetEvent:L=L"].call(h)
430
+ raise WinX.new(:reset_event) if r == 0
431
+ return r
432
+ end
433
+
434
+ # create an event, which you can signal and wait on across processes
435
+ def create_event(name=nil, auto=false, signalled=false)
436
+ auto = (1 if auto) || 0
437
+ signalled = (1 if signalled) || 0
438
+ name ||= 0
439
+
440
+ r = CALLS["kernel32!CreateEvent:LLLP=L"].call(0, auto, signalled, name);
441
+ raise WinX.new(:create_event) if r == 0
442
+ return r
443
+ end
444
+
445
+ def write_file(h, buf, overlapped=nil)
446
+ if overlapped
447
+ opp = overlapped.to_s
448
+ else
449
+ opp = NULL
450
+ end
451
+
452
+ outw = "\x00" * 4
453
+ r = CALLS["kernel32!WriteFile:LPLPP=L"].call(h, buf, buf.size, outw, opp)
454
+ raise WinX.new(:write_file) if r == 0 and get_last_error != 997
455
+ return buf, outw.unpack("L").first
456
+ end
457
+
458
+ def read_file(h, count, overlapped=nil)
459
+ if overlapped
460
+ opp = overlapped.to_s
461
+ else
462
+ opp = NULL
463
+ end
464
+ outw = "\x00" * 4
465
+ if not (buf = overlapped.try(:target)) or buf.size < count
466
+ buf = "\x00" * count
467
+ overlapped.target = buf if overlapped
468
+ end
469
+
470
+ r = CALLS["kernel32!ReadFile:LPLPP=L"].call(h, buf, count, outw, opp)
471
+ raise WinX.new(:read_file) if r == 0 and get_last_error != 997
472
+ return buf, outw.unpack("L").first
473
+ end
474
+
475
+ def device_io_control(h, code, inbuf, outbuf, overlapped=NULL)
476
+ overlapped = overlapped.to_s if overlapped
477
+ outw = "\x00" * 4
478
+ r = CALLS["kernel32!DeviceIoControl:LLPLPLPP=L"].
479
+ call(h, code, inbuf, inbuf.size, outbuf, outbuf.size, outw, overlapped)
480
+ raise WinX.new(:device_io_control) if r == 0 and get_last_error != 997
481
+ return outw.unpack("L").first
482
+ end
483
+
484
+ def get_overlapped_result(h, overlapped)
485
+ overlapped = overlapped.to_s
486
+ outw = "\x00" * 4
487
+ r = CALLS["kernel32!GetOverlappedResult:LPPL=L"].call(h, overlapped, outw, 0)
488
+ raise WinX.new(:get_overlapped_result) if r == 0
489
+ return outw.unpack("L").first
490
+ end
491
+
492
+ # just grab some local memory
493
+ def malloc(sz)
494
+ r = CALLS["msvcrt!malloc:L=L"].call(sz)
495
+ raise WinX.new(:malloc) if r == 0
496
+ return r
497
+ end
498
+
499
+ def memcpy(dst, src, size)
500
+ CALLS["msvcrt!memcpy:PPL=L"].call(dst, src, size)
501
+ end
502
+
503
+ # Block wrapper for thread suspension
504
+ def with_suspended_thread(tid)
505
+ open_thread(tid) do |h|
506
+ begin
507
+ suspend_thread(h)
508
+ ret = yield h
509
+ ensure
510
+ resume_thread(h)
511
+ end
512
+ end
513
+ end
514
+
515
+ def wfmo(handles, ms=100)
516
+ hp = handles.to_ptr
517
+ r = CALLS["kernel32!WaitForMultipleObjects:LPLL=L"].call(handles.size, hp, 0, ms)
518
+ raise WinX(:wait_for_multiple_objects) if r == 0xFFFFFFFF
519
+ if r < handles.size
520
+ return handles[r]
521
+ else
522
+ return nil
523
+ end
524
+ end
525
+ end
526
+ end
@@ -0,0 +1,53 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/wrap32/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Wrap32
6
+
7
+ # :stopdoc:
8
+ VERSION = '0.1.5'
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility method used to require all files ending in .rb that lie in the
36
+ # directory below this file that has the same name as the filename passed
37
+ # in. Optionally, a specific _directory_ name can be passed in such that
38
+ # the _filename_ does not have to be equivalent to the directory.
39
+ #
40
+ def self.require_all_libs_relative_to( fname, dir = nil )
41
+ dir ||= ::File.basename(fname, '.*')
42
+ search_me = ::File.expand_path(
43
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
+
45
+ Dir.glob(search_me).sort.each {|rb| require rb}
46
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
47
+
48
+ end
49
+ end # module Ragweed::Wrap32
50
+
51
+ Ragweed::Wrap32.require_all_libs_relative_to(__FILE__)
52
+
53
+ # EOF
@@ -0,0 +1,101 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx;end
3
+ module Ragweed::Wraposx::Ptrace
4
+ TRACE_ME = 0 # child declares it's being traced
5
+ #(READ|WRITE)_[IDU] are not valid in OSX but defined in ptrace.h
6
+ READ_I = 1 # read word in child's I space
7
+ READ_D = 2 # read word in child's D space
8
+ READ_U = 3 # read word in child's user structure
9
+ WRITE_I = 4 # write word in child's I space
10
+ WRITE_D = 5 # write word in child's D space
11
+ WRITE_U = 6 # write word in child's user structure
12
+ CONTINUE = 7 # continue the child
13
+ KILL = 8 # kill the child process
14
+ STEP = 9 # single step the child
15
+ ATTACH = 10 # trace some running process
16
+ DETACH = 11 # stop tracing a process
17
+ SIGEXC = 12 # signals as exceptions for current_proc
18
+ THUPDATE = 13 # signal for thread
19
+ ATTACHEXC = 14 # attach to running process with signal exception
20
+ FORCEQUOTA = 30 # Enforce quota for root
21
+ DENY_ATTACH = 31 #Prevent process from being traced
22
+ FIRSTMACH = 32 # for machine-specific requests
23
+ end
24
+
25
+ module Ragweed::Wraposx::Signal
26
+ #the Ruby module Signal also has this information
27
+ SIGHUP = 1 # hangup
28
+ SIGINT = 2 # interrupt
29
+ SIGQUIT = 3 # quit
30
+ SIGILL = 4 # illegal instruction (not reset when caught)
31
+ SIGTRAP = 5 # trace trap (not reset when caught)
32
+ SIGABRT = 6 # abort()
33
+ #if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
34
+ SIGPOLL = 7 # pollable event ([XSR] generated, not supported)
35
+ #else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
36
+ SIGIOT = SIGABRT # compatibility
37
+ SIGEMT = 7 # EMT instruction
38
+ #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
39
+ SIGFPE = 8 # floating point exception
40
+ SIGKILL = 9 # kill (cannot be caught or ignored)
41
+ SIGBUS = 10 # bus error
42
+ SIGSEGV = 11 # segmentation violation
43
+ SIGSYS = 12 # bad argument to system call
44
+ SIGPIPE = 13 # write on a pipe with no one to read it
45
+ SIGALRM = 14 # alarm clock
46
+ SIGTERM = 15 # software termination signal from kill
47
+ SIGURG = 16 # urgent condition on IO channel
48
+ SIGSTOP = 17 # sendable stop signal not from tty
49
+ SIGTSTP = 18 # stop signal from tty
50
+ SIGCONT = 19 # continue a stopped process
51
+ SIGCHLD = 20 # to parent on child stop or exit
52
+ SIGTTIN = 21 # to readers pgrp upon background tty read
53
+ SIGTTOU = 22 # like TTIN for output if (tp->t_local&LTOSTOP)
54
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
55
+ SIGIO = 23 # input/output possible signal
56
+ #endif
57
+ SIGXCPU = 24 # exceeded CPU time limit
58
+ SIGXFSZ = 25 # exceeded file size limit
59
+ SIGVTALRM = 26 # virtual time alarm
60
+ SIGPROF = 27 # profiling time alarm
61
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
62
+ SIGWINCH = 28 # window size changes
63
+ SIGINFO = 29 # information request
64
+ #endif
65
+ SIGUSR1 = 30 # user defined signal 1
66
+ SIGUSR2 = 31 # user defined signal 2
67
+ end
68
+
69
+ module Ragweed::Wraposx::Wait
70
+ NOHANG = 0x01 # [XSI] no hang in wait/no child to reap
71
+ UNTRACED = 0x02 # [XSI] notify on stop, untraced child
72
+ EXITED = 0x04 # [XSI] Processes which have exitted
73
+ STOPPED = 0x08 # [XSI] Any child stopped by signal
74
+ CONTINUED = 0x10 # [XSI] Any child stopped then continued
75
+ NOWWAIT = 0x20 # [XSI] Leave process returned waitable
76
+ end
77
+
78
+ module Ragweed::Wraposx::Vm; end
79
+ module Ragweed::Wraposx::Vm::Prot
80
+ #vm_protect permission flags for memory spaces
81
+ READ = 0x1 #read permission
82
+ WRITE = 0x2 #write permission
83
+ EXECUTE = 0x4 #execute permission
84
+ NONE = 0x0 #no rights
85
+ ALL = 0x7 #all permissions
86
+ end
87
+
88
+ module Ragweed::Wraposx::Dl
89
+ RTLD_LAZY = 0x1
90
+ RTLD_NOW = 0x2
91
+ RTLD_LOCAL = 0x4
92
+ RTLD_GLOBAL = 0x8
93
+ RTLD_NOLOAD = 0x10
94
+ RTLD_NODELETE = 0x80
95
+ RTLD_FIRST = 0x100 #/* Mac OS X 10.5 and later */
96
+
97
+ # Special handle arguments for dlsym().
98
+ #define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
99
+ #define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
100
+ #define RTLD_SELF ((void *) -3) /* Search this and subsequent objects (Mac OS X 10.5 and later) */
101
+ end