ragweed 0.1.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +34 -0
  5. data/examples/hittracertux.rb +49 -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 +427 -0
  14. data/lib/ragweed/debuggertux.rb +346 -0
  15. data/lib/ragweed/detour.rb +223 -0
  16. data/lib/ragweed/ptr.rb +48 -0
  17. data/lib/ragweed/rasm/bblock.rb +73 -0
  18. data/lib/ragweed/rasm/isa.rb +1115 -0
  19. data/lib/ragweed/rasm.rb +59 -0
  20. data/lib/ragweed/sbuf.rb +197 -0
  21. data/lib/ragweed/trampoline.rb +103 -0
  22. data/lib/ragweed/utils.rb +156 -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 +59 -0
  34. data/lib/ragweed/wraposx/constants.rb +122 -0
  35. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  36. data/lib/ragweed/wraposx/region_info.rb +254 -0
  37. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  38. data/lib/ragweed/wraposx/thread_info.rb +227 -0
  39. data/lib/ragweed/wraposx/wraposx.rb +433 -0
  40. data/lib/ragweed/wraposx.rb +59 -0
  41. data/lib/ragweed/wraptux/constants.rb +68 -0
  42. data/lib/ragweed/wraptux/threads.rb +7 -0
  43. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  44. data/lib/ragweed/wraptux.rb +59 -0
  45. data/lib/ragweed.rb +84 -0
  46. data/ragweed.gemspec +34 -0
  47. data/spec/ragweed_spec.rb +7 -0
  48. data/spec/spec_helper.rb +16 -0
  49. data/tasks/ann.rake +80 -0
  50. data/tasks/bones.rake +20 -0
  51. data/tasks/gem.rake +201 -0
  52. data/tasks/git.rake +40 -0
  53. data/tasks/notes.rake +27 -0
  54. data/tasks/post_load.rake +34 -0
  55. data/tasks/rdoc.rake +51 -0
  56. data/tasks/rubyforge.rake +55 -0
  57. data/tasks/setup.rb +292 -0
  58. data/tasks/spec.rake +54 -0
  59. data/tasks/svn.rake +47 -0
  60. data/tasks/test.rake +40 -0
  61. data/tasks/zentest.rake +36 -0
  62. data/test/test_ragweed.rb +0 -0
  63. metadata +132 -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 CALLS["kernel32!Module32First:LP=L"].call(h, mi) != 0
306
+ yield str2module_info(mi)
307
+ while CALLS["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 CALLS["kernel32!Thread32First:LP=L"].call(h, mi) != 0
356
+ ti = str2thread_info(mi)
357
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
358
+ while CALLS["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,59 @@
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.7.2'
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 function to load utility classes and extensions
36
+ def self.require_utils
37
+ %w{utils}.each{|r| require self.libpath(r)+'.rb'}
38
+ end
39
+
40
+ # Utility method used to require all files ending in .rb that lie in the
41
+ # directory below this file that has the same name as the filename passed
42
+ # in. Optionally, a specific _directory_ name can be passed in such that
43
+ # the _filename_ does not have to be equivalent to the directory.
44
+ #
45
+ def self.require_all_libs_relative_to( fname, dir = nil )
46
+ self.require_utils
47
+ dir ||= ::File.basename(fname, '.*')
48
+ search_me = ::File.expand_path(
49
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
50
+
51
+ Dir.glob(search_me).sort.each {|rb| require rb}
52
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
53
+
54
+ end
55
+ end # module Ragweed::Wrap32
56
+
57
+ Ragweed::Wrap32.require_all_libs_relative_to(__FILE__)
58
+
59
+ # EOF
@@ -0,0 +1,122 @@
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
+ # in reality, that is a better source since it's based on the signals
28
+ # available at the time ruby was compiled.
29
+ SIGHUP = 1 # hangup
30
+ SIGINT = 2 # interrupt
31
+ SIGQUIT = 3 # quit
32
+ SIGILL = 4 # illegal instruction (not reset when caught)
33
+ SIGTRAP = 5 # trace trap (not reset when caught)
34
+ SIGABRT = 6 # abort()
35
+ #if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
36
+ SIGPOLL = 7 # pollable event ([XSR] generated, not supported)
37
+ #else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
38
+ SIGIOT = SIGABRT # compatibility
39
+ SIGEMT = 7 # EMT instruction
40
+ #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
41
+ SIGFPE = 8 # floating point exception
42
+ SIGKILL = 9 # kill (cannot be caught or ignored)
43
+ SIGBUS = 10 # bus error
44
+ SIGSEGV = 11 # segmentation violation
45
+ SIGSYS = 12 # bad argument to system call
46
+ SIGPIPE = 13 # write on a pipe with no one to read it
47
+ SIGALRM = 14 # alarm clock
48
+ SIGTERM = 15 # software termination signal from kill
49
+ SIGURG = 16 # urgent condition on IO channel
50
+ SIGSTOP = 17 # sendable stop signal not from tty
51
+ SIGTSTP = 18 # stop signal from tty
52
+ SIGCONT = 19 # continue a stopped process
53
+ SIGCHLD = 20 # to parent on child stop or exit
54
+ SIGTTIN = 21 # to readers pgrp upon background tty read
55
+ SIGTTOU = 22 # like TTIN for output if (tp->t_local&LTOSTOP)
56
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
57
+ SIGIO = 23 # input/output possible signal
58
+ #endif
59
+ SIGXCPU = 24 # exceeded CPU time limit
60
+ SIGXFSZ = 25 # exceeded file size limit
61
+ SIGVTALRM = 26 # virtual time alarm
62
+ SIGPROF = 27 # profiling time alarm
63
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
64
+ SIGWINCH = 28 # window size changes
65
+ SIGINFO = 29 # information request
66
+ #endif
67
+ SIGUSR1 = 30 # user defined signal 1
68
+ SIGUSR2 = 31 # user defined signal 2
69
+ end
70
+
71
+ module Ragweed::Wraposx::Wait
72
+ NOHANG = 0x01 # [XSI] no hang in wait/no child to reap
73
+ UNTRACED = 0x02 # [XSI] notify on stop, untraced child
74
+ EXITED = 0x04 # [XSI] Processes which have exitted
75
+ STOPPED = 0x08 # [XSI] Any child stopped by signal
76
+ CONTINUED = 0x10 # [XSI] Any child stopped then continued
77
+ NOWWAIT = 0x20 # [XSI] Leave process returned waitable
78
+ end
79
+
80
+ module Ragweed::Wraposx::Vm; end
81
+ module Ragweed::Wraposx::Vm::Prot
82
+ # vm_protect permission flags for memory spaces
83
+ READ = 0x1 #read permission
84
+ WRITE = 0x2 #write permission
85
+ EXECUTE = 0x4 #execute permission
86
+ NONE = 0x0 #no rights
87
+ ALL = 0x7 #all permissions
88
+ end
89
+ module Ragweed::Wraposx::Vm::Sm
90
+ # share mode constants
91
+ COW = 1
92
+ PRIVATE = 2
93
+ EMPTY = 3
94
+ SHARED = 4
95
+ TRUESHARED = 5
96
+ PRIVATE_ALIASED = 6
97
+ SHARED_ALIASED = 7
98
+ end
99
+
100
+ # this should be moved to an include for all wrappers
101
+ module Ragweed::Wraposx::SizeOf
102
+ INT = [1].pack("I_").size
103
+ SHORT = [1].pack("S_").size
104
+ LONG = [1].pack("L_").size
105
+ DOUBLE = [1].pack("D").size
106
+ FLOAT = [1].pack("F").size
107
+ end
108
+
109
+ module Ragweed::Wraposx::Dl
110
+ RTLD_LAZY = 0x1
111
+ RTLD_NOW = 0x2
112
+ RTLD_LOCAL = 0x4
113
+ RTLD_GLOBAL = 0x8
114
+ RTLD_NOLOAD = 0x10
115
+ RTLD_NODELETE = 0x80
116
+ RTLD_FIRST = 0x100 #/* Mac OS X 10.5 and later */
117
+
118
+ # Special handle arguments for dlsym().
119
+ #define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
120
+ #define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
121
+ #define RTLD_SELF ((void *) -3) /* Search this and subsequent objects (Mac OS X 10.5 and later) */
122
+ end