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,583 @@
1
+ require 'ffi'
2
+ require 'ostruct'
3
+ require 'Win32API'
4
+ require 'pp'
5
+
6
+ module Ragweed;end
7
+ module Ragweed::Wrap32
8
+
9
+ NULL = 0x0
10
+
11
+ module PagePerms
12
+ EXECUTE = 0x10
13
+ EXECUTE_READ = 0x20
14
+ EXECUTE_READWRITE = 0x40
15
+ EXECUTE_WRITECOPY = 0x80
16
+ NOACCESS = 0x1
17
+ READONLY = 0x2
18
+ READWRITE = 0x4
19
+ WRITECOPY = 0x8
20
+
21
+ WRITEABLE = [EXECUTE_READWRITE,
22
+ EXECUTE_WRITECOPY,
23
+ READWRITE,
24
+ WRITECOPY]
25
+ end
26
+
27
+ module FileSharing
28
+ NONE = 0
29
+ DELETE = 4
30
+ READ = 1
31
+ WRITE = 2
32
+ end
33
+
34
+ module FileDisposition
35
+ CREATE_ALWAYS = 2
36
+ CREATE_NEW = 1
37
+ OPEN_ALWAYS = 4
38
+ OPEN_EXISTING = 3
39
+ TRUNCATE_EXISTING = 5
40
+ end
41
+
42
+ module FileAttributes
43
+ ARCHIVE = 0x20
44
+ ENCRYPTED = 0x4000
45
+ HIDDEN = 0x2
46
+ NORMAL = 0x80
47
+ OFFLINE = 0x1000
48
+ READONLY = 1
49
+ SYSTEM = 4
50
+ TEMPORARY = 0x100
51
+ BACKUP = 0x02000000
52
+ DELETE_ON_CLOSE = 0x04000000
53
+ NO_BUFFERING = 0x20000000
54
+ NO_RECALL = 0x00100000
55
+ REPARSE_POINT = 0x00200000
56
+ OVERLAPPED = 0x40000000
57
+ POSIX = 0x0100000
58
+ RANDOM_ACCESS = 0x10000000
59
+ SEQUENTIAL = 0x08000000
60
+ WRITE_THROUGH = 0x80000000
61
+ end
62
+
63
+ module FileAccess
64
+ GENERIC_READ = 0x80000000
65
+ GENERIC_WRITE = 0x40000000
66
+ GENERIC_EXECUTE = 0x20000000
67
+ GENERIC_ALL = 0x10000000
68
+ end
69
+
70
+ module FormatArgs
71
+ FROM_SYSTEM = 4096
72
+ ALLOCATE_BUFFER = 256
73
+ end
74
+
75
+ module Win
76
+ extend FFI::Library
77
+
78
+ ffi_lib 'kernel32', 'Advapi32'
79
+ ffi_convention :stdcall
80
+ attach_function 'OpenProcess', [ :long, :long, :long ], :long
81
+ attach_function 'OpenThread', [ :long, :long, :long ], :long
82
+ attach_function 'CloseHandle', [ :long ], :long
83
+ attach_function 'GetLastError', [ ], :long
84
+ attach_function 'FormatMessageA', [ :long, :pointer, :long, :long, :pointer, :long, :pointer ], :void
85
+ attach_function 'VirtualAllocEx', [ :long, :long, :long, :long, :long ], :long
86
+ attach_function 'VirtualFreeEx', [ :long, :long, :long, :long, ], :long
87
+ attach_function 'WriteProcessMemory', [ :long, :long, :pointer, :long, :long ], :long
88
+ attach_function 'ReadProcessMemory', [ :long, :long, :pointer, :long, :long ], :long
89
+ attach_function 'VirtualQueryEx', [ :long, :long, :pointer, :long ], :long
90
+ attach_function 'VirtualProtectEx', [ :long, :long, :long, :long, :pointer ], :void
91
+ attach_function 'GetCurrentProcessId', [], :long
92
+ attach_function 'GetProcessId', [ :long ], :long
93
+ attach_function 'GetCurrentThreadId', [], :long
94
+ attach_function 'GetModuleHandleA', [ :pointer ], :long
95
+ attach_function 'LoadLibraryA', [ :pointer ], :long
96
+ attach_function 'GetProcAddress', [ :long, :pointer], :long
97
+ attach_function 'WaitForSingleObject', [ :long, :long ], :long
98
+ attach_function 'Process32First', [ :long, :pointer ], :long
99
+ attach_function 'Process32Next', [ :long, :pointer ], :long
100
+ attach_function 'Module32First', [ :long, :pointer ], :long
101
+ attach_function 'Module32Next', [ :long, :pointer ], :long
102
+ attach_function 'CreateToolhelp32Snapshot', [ :long, :long ], :long
103
+ attach_function 'Thread32First', [ :long, :pointer ], :long
104
+ attach_function 'Thread32Next', [ :long, :pointer ], :long
105
+ attach_function 'SuspendThread', [ :long ], :long
106
+ attach_function 'ResumeThread', [ :long ], :long
107
+ attach_function 'CreateRemoteThread', [ :long, :long, :long, :long, :long, :long, :long ], :long
108
+ attach_function 'Sleep', [ :long ], :long
109
+ attach_function 'DuplicateHandle', [ :long, :long, :long, :pointer, :long, :long, :long ], :long
110
+ attach_function 'CreateFileA', [ :pointer, :long, :long, :pointer, :long, :long, :pointer ], :long
111
+ attach_function 'OpenEventA', [ :long, :long, :pointer ], :long
112
+ attach_function 'CreateEventA', [ :long, :long, :long, :pointer ], :long
113
+ attach_function 'SetEvent', [ :long ], :long
114
+ attach_function 'ResetEvent', [ :long ], :long
115
+ attach_function 'WriteFile', [ :long, :pointer, :long, :pointer, :pointer ], :long
116
+ attach_function 'ReadFile', [ :long, :pointer, :long, :pointer, :pointer ], :long
117
+ attach_function 'DeviceIoControl', [ :long, :long, :pointer, :long, :pointer, :long, :pointer, :pointer ], :long
118
+ attach_function 'GetOverlappedResult', [ :long, :pointer, :pointer, :long ], :long
119
+ attach_function 'WaitForMultipleObjects', [ :long, :pointer, :long, :long ], :long
120
+ attach_function 'CreateProcessA', [ :pointer, :pointer, :pointer, :pointer, :bool, :long, :pointer, :pointer, :pointer, :pointer ], :long
121
+ attach_function 'CreateProcessW', [ :pointer, :pointer, :pointer, :pointer, :bool, :long, :pointer, :pointer, :pointer, :pointer ], :long
122
+
123
+ ffi_lib 'ntdll'
124
+ ffi_convention :stdcall
125
+ attach_function 'NtQueryInformationProcess', [ :long, :long, :pointer, :long, :pointer ], :long
126
+
127
+ ffi_lib 'msvcrt'
128
+ ffi_convention :stdcall
129
+ attach_function 'malloc', [ :long ], :long
130
+ attach_function 'memcpy', [ :pointer, :pointer, :long ], :long
131
+
132
+ ## XXX This shouldnt be in psapi in win7, need to clean this up
133
+ ## XXX Also the unicode version should be supported, this is NOT complete
134
+ ffi_lib 'psapi'
135
+ ffi_convention :stdcall
136
+ attach_function 'GetMappedFileNameA', [ :long, :long, :pointer, :long ], :long
137
+ end
138
+
139
+ class << self
140
+
141
+ # Get a process handle given a pid
142
+ def open_process(pid)
143
+ r = Win.OpenProcess(0x1F0FFF, 0, pid)
144
+ raise WinX.new(:open_process) if r == 0
145
+ return r
146
+ end
147
+
148
+ # Get a thread handle given a tid; if a block is provided, the semantics are
149
+ # as File#open with a block.
150
+ def open_thread(tid, &block)
151
+ h = Win.OpenThread(0x1F03FF, 0, tid)
152
+ raise WinX.new(:open_thread) if h == 0
153
+ if block_given?
154
+ ret = yield h
155
+ close_handle(h)
156
+ return ret
157
+ end
158
+ h
159
+ end
160
+
161
+ # Close any Win32 handle. Reminder: Win32 handles are just integers, like file
162
+ # descriptors in Posix.
163
+ def close_handle(h)
164
+ raise WinX.new(:close_handle) if Win.CloseHandle(h) == 0
165
+ end
166
+
167
+ # Get the last error code (errno) (can't fail)
168
+ def get_last_error
169
+ Win.GetLastError()
170
+ end
171
+
172
+ # strerror(errno) (can't fail)
173
+ def format_message(code=nil)
174
+ code ||= get_last_error
175
+ buf = FFI::MemoryPointer.from_string("\x00" * 4096)
176
+ Win.FormatMessageA(4096, nil, code, 0x00000400, buf, 4096, nil)
177
+ return buf.to_s.split("\x00")[0]
178
+ end
179
+
180
+ # Allocate memory in a remote process (or yourself, with handle -1)
181
+ def virtual_alloc_ex(h, sz, addr=NULL, prot=0x40)
182
+ r = Win.VirtualAllocEx(h, addr, sz, 0x1000, prot)
183
+ raise WinX.new(:virtual_alloc_ex) if r == 0
184
+ return r
185
+ end
186
+
187
+ # Free memory in a remote process given the pointer returned from virtual_alloc_ex
188
+ def virtual_free_ex(h, ptr, type=0x8000)
189
+ r = Win.VirtualFreeEx(h, ptr.to_i, 0, type)
190
+ raise WinX.new(:virtual_free_ex) if r == 0
191
+ return r
192
+ end
193
+
194
+ # Write a string into the memory of a remote process given its handle and an address
195
+ def write_process_memory(h, dst, val)
196
+ val = val.to_s if not val.kind_of? String
197
+ r = Win.WriteProcessMemory(h, dst.to_i, val, val.size, NULL)
198
+ raise WinX.new(:write_process_memory) if r == 0
199
+ return r
200
+ end
201
+
202
+ # Read from a remote process given an address and length, returning a string.
203
+ def read_process_memory(h, ptr, len)
204
+ # val = FFI::MemoryPointer.from_string("\x00" * len)
205
+ val = "\x00" * len
206
+ r = Win.ReadProcessMemory(h, ptr.to_i, val, len, NULL)
207
+ raise WinX.new(:read_process_memory) if r == 0
208
+ return val ## don't handle short reads XXX
209
+ end
210
+
211
+ def get_mapped_filename(h, lpv, size)
212
+ val = "\x00" * size
213
+ r = Win.GetMappedFileNameA(h, lpv.to_i, val, size)
214
+ raise WinX.new(:get_mapped_filename) if r == 0
215
+ return val
216
+ end
217
+
218
+ def str2memory_basic_info(mbi)
219
+ s = OpenStruct.new
220
+ s.BaseAddress,
221
+ s.AllocationBase,
222
+ s.AllocationProtect,
223
+ s.RegionSize,
224
+ s.State,
225
+ s.Protect,
226
+ s.Type = mbi.unpack("LLLLLLL")
227
+ return s
228
+ end
229
+
230
+ # Return a struct with the MEMORY_BASIC_INFORMATION for a given address in the
231
+ # memory of a remote process. Gives you addressable memory ranges and protection
232
+ # flags.
233
+ def virtual_query_ex(h, ptr)
234
+ mbi = [0,0,0,0,0,0,0].pack("LLLLLLL")
235
+ if Win.VirtualQueryEx(h, ptr, mbi, mbi.size)
236
+ str2memory_basic_info(mbi)
237
+ else
238
+ nil
239
+ end
240
+ end
241
+
242
+ # Change the protection of specific memory regions in a remote process.
243
+ def virtual_protect_ex(h, addr, prot, size=0)
244
+ old = [0].pack("L")
245
+ base = virtual_query_ex(h, addr).BaseAddress if size == 0
246
+ base ||= addr
247
+
248
+ if Win.VirtualProtectEx(h, base, size, prot, old)
249
+ old.unpack("L").first
250
+ else
251
+ raise WinX.new(:virtual_protect_ex)
252
+ end
253
+ end
254
+
255
+ # getpid
256
+ def get_current_process_id
257
+ Win.GetCurrentProcessId() # can't realistically fail
258
+ end
259
+
260
+ # get_processid
261
+ def get_process_id(h)
262
+ Win.GetProcessId(h)
263
+ end
264
+
265
+ # gettid
266
+ def get_current_thread_id
267
+ Win.GetCurrentThreadId() # can't realistically fail
268
+ end
269
+
270
+ # Given a DLL name, get a handle to the DLL.
271
+ def get_module_handle(name)
272
+ name = name
273
+ r = Win.GetModuleHandleA(name)
274
+ raise WinX.new(:get_module_handle) if r == 0
275
+ return r
276
+ end
277
+
278
+ # load a library explicitly from a dll
279
+ def load_library(name)
280
+ name = name
281
+ r = Win.LoadLibraryA(name)
282
+ raise WinX.new(:load_library) if r == 0
283
+ return r
284
+ end
285
+
286
+ # Using notation x = "foo!bar" or x = handle, y = meth, look up a function's
287
+ # address in a module. Note that this is local, not remote.
288
+ def get_proc_address(x, y=nil)
289
+ if not y
290
+ mod, meth = x.split "!"
291
+ h = get_module_handle(mod)
292
+ else
293
+ h = x
294
+ meth = y
295
+ end
296
+
297
+ r = Win.GetProcAddress(h, meth)
298
+ return r # pass error through
299
+ end
300
+
301
+ # Select(2), for a single object handle.
302
+ def wait_for_single_object(h)
303
+ r = Win.WaitForSingleObject(h, -1)
304
+ raise WinX.new(:wait_for_single_object) if r == -1
305
+ end
306
+
307
+ def str2process_info(str)
308
+ ret = OpenStruct.new
309
+ ret.dwSize,
310
+ ret.cntUsage,
311
+ ret.th32ProcessID,
312
+ ret.th32DefaultHeapID,
313
+ ret.th32ModuleID,
314
+ ret.cntThreads,
315
+ ret.th32ParentProcessID,
316
+ ret.pcPriClassBase,
317
+ ret.dwFlags,
318
+ ret.szExeFile = str.unpack("LLLLLLLLLA2048")
319
+ ret.szExeFile = ret.szExeFile.asciiz
320
+ return ret
321
+ end
322
+
323
+ # Use Toolhelp32 to enumerate all running processes on the box, returning
324
+ # a struct with PIDs and executable names.
325
+ def all_processes
326
+ h = Win.CreateToolhelp32Snapshot(0x2, 0)
327
+ if h != -1
328
+ pi = [(9*4)+2048,0,0,0,0,0,0,0,0,"\x00"*2048].pack("LLLLLLLLLa2048")
329
+ if Win.Process32First(h, pi) != 0
330
+ yield str2process_info(pi)
331
+ while Win.Process32Next(h, pi) != 0
332
+ yield str2process_info(pi)
333
+ end
334
+ end
335
+ else
336
+ raise WinX.new(:create_toolhelp32_snapshot)
337
+ end
338
+ end
339
+
340
+ def str2module_info(str)
341
+ ret = OpenStruct.new
342
+ ret.dwSize,
343
+ ret.th32ModuleID,
344
+ ret.th32ProcessID,
345
+ ret.GlblcntUsage,
346
+ ret.ProccntUsage,
347
+ ret.modBaseAddr,
348
+ ret.modBaseSize,
349
+ ret.hModule,
350
+ ret.szModule,
351
+ ret.szExePath = str.unpack("LLLLLLLLA256A260")
352
+ ret.szModule = ret.szModule.asciiz
353
+ ret.szExePath = ret.szExePath.asciiz
354
+ return ret
355
+ end
356
+
357
+ # Given a pid, enumerate the modules loaded into the process, returning base
358
+ # addresses, memory ranges, and the module name.
359
+ def list_modules(pid=0)
360
+ h = Win.CreateToolhelp32Snapshot(0x8, pid)
361
+ if h != -1
362
+ mi = [260+256+(8*4),0,0,0,0,0,0,0,"\x00"*256,"\x00"*260].pack("LLLLLLLLa256a260")
363
+ if Win.Module32First(h, mi) != 0
364
+ yield str2module_info(mi)
365
+ while Win.Module32Next(h, mi) != 0
366
+ yield str2module_info(mi)
367
+ end
368
+ end
369
+ else
370
+ raise WinX.new(:create_toolhelp32_snapshot)
371
+ end
372
+ end
373
+
374
+ # Use virtual_query_ex to tell whether an address is writable.
375
+ def writeable?(h, off)
376
+ if (x = virtual_query_ex(h, off))
377
+ return PagePerms::WRITEABLE.member?(x.Protect & 0xFF)
378
+ else
379
+ return false
380
+ end
381
+ end
382
+
383
+ # NQIP does a lot of things, the most useful of which are getting the
384
+ # image name of a running process, and telling whether a debugger is loaded. This
385
+ # interface is Ioctl-style; provide an ordinal and a buffer to pass results through.
386
+ def nt_query_information_process(h, ord, buf)
387
+ lenp = [0].pack("L")
388
+ if Win.NtQueryInformationProcess(h, ord, buf, buf.size, lenp) == 0
389
+ len = lenp.unpack("L").first
390
+ return buf[0..(len-1)]
391
+ end
392
+ nil
393
+ end
394
+
395
+ def str2thread_info(str)
396
+ ret = OpenStruct.new
397
+ ret.dwSize,
398
+ ret.cntUsage,
399
+ ret.th32ThreadID,
400
+ ret.th32OwnerProcessID,
401
+ ret.tpBasePri,
402
+ ret.tpDeltaPri,
403
+ ret.thFlags = str.unpack("LLLLLLL")
404
+ return ret
405
+ end
406
+
407
+ # List all the threads in a process given its pid, returning a struct containing
408
+ # tids and run state. This is relatively expensive, because it uses Toolhelp32.
409
+ def threads(pid)
410
+ h = Win.CreateToolhelp32Snapshot(0x4, pid)
411
+ if h != -1
412
+ mi = [(7*4),0,0,0,0,0,0].pack("LLLLLLL")
413
+ if Win.Thread32First(h, mi) != 0
414
+ ti = str2thread_info(mi)
415
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
416
+ while Win.Thread32Next(h, mi) != 0
417
+ ti = str2thread_info(mi)
418
+ yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
419
+ end
420
+ end
421
+ else
422
+ raise WinX.new(:create_toolhelp32_snapshot)
423
+ end
424
+ end
425
+
426
+ # Suspend a thread given its handle.
427
+ def suspend_thread(h)
428
+ r = Win.SuspendThread(h)
429
+ raise WinX.new(:suspend_thread) if r == 0
430
+ return r
431
+ end
432
+
433
+ # Resume a suspended thread, returning nonzero if the thread was suspended,
434
+ # and 0 if it was running.
435
+ def resume_thread(h)
436
+ ResumeThread(h)
437
+ end
438
+
439
+ # Create a remote thread in the process, starting at the location
440
+ # "start", with the threadproc argument "arg"
441
+ def create_remote_thread(h, start, arg)
442
+ r = Win.CreateRemoteThread(h, NULL, 0, start.to_i, arg.to_i, 0, 0)
443
+ raise WinX.new(:create_remote_thread) if r == 0
444
+ return r
445
+ end
446
+
447
+ def sleep(ms=0)
448
+ Win.Sleep(ms)
449
+ end
450
+
451
+ # clone a handle out of another open process (or self, with -1)
452
+ def duplicate_handle(ph, h)
453
+ ret = "\x00\x00\x00\x00"
454
+ r = Win.DuplicateHandle(ph, h, -1, ret, 0, 0, 0x2)
455
+ raise WinX.new(:duplicate_handle) if r == 0
456
+ ret.to_l32
457
+ end
458
+
459
+ def create_file(name, opts={})
460
+ opts[:disposition] ||= FileDisposition::OPEN_ALWAYS
461
+ opts[:sharing] ||= FileSharing::READ | FileSharing::WRITE
462
+ opts[:access] ||= FileAccess::GENERIC_ALL
463
+ opts[:flags] ||= 0
464
+
465
+ r = Win.CreateFileA(name, opts[:access], opts[:sharing], NULL, opts[:disposition], opts[:flags], NULL)
466
+ raise WinX.new(:create_file) if r == -1
467
+ return r
468
+ end
469
+
470
+ # i haven't made this work, but named handles are kind of silly anyways
471
+ def open_event(name)
472
+ r = Win.OpenEventA(0, 0, name)
473
+ raise WinX.new(:open_event) if r == 0
474
+ return r
475
+ end
476
+
477
+ # signal an event
478
+ def set_event(h)
479
+ r = Win.SetEvent(h)
480
+ raise WinX.new(:set_event) if r == 0
481
+ return r
482
+ end
483
+
484
+ # force-unsignal event (waiting on the event handle also does this)
485
+ def reset_event(h)
486
+ r = Win.ResetEvent(h)
487
+ raise WinX.new(:reset_event) if r == 0
488
+ return r
489
+ end
490
+
491
+ # create an event, which you can signal and wait on across processes
492
+ def create_event(name=nil, auto=false, signalled=false)
493
+ auto = (1 if auto) || 0
494
+ signalled = (1 if signalled) || 0
495
+ name ||= 0
496
+
497
+ r = Win.CreateEventA(0, auto, signalled, name);
498
+ raise WinX.new(:create_event) if r == 0
499
+ return r
500
+ end
501
+
502
+ def write_file(h, buf, overlapped=nil)
503
+ if overlapped
504
+ opp = overlapped.to_s
505
+ else
506
+ opp = NULL
507
+ end
508
+
509
+ outw = "\x00" * 4
510
+ r = Win.WriteFile(h, buf, buf.size, outw, opp)
511
+ raise WinX.new(:write_file) if r == 0 and get_last_error != 997
512
+ return buf, outw.unpack("L").first
513
+ end
514
+
515
+ def read_file(h, count, overlapped=nil)
516
+ if overlapped
517
+ opp = overlapped.to_s
518
+ else
519
+ opp = NULL
520
+ end
521
+ outw = "\x00" * 4
522
+ if not (buf = overlapped.try(:target)) or buf.size < count
523
+ buf = "\x00" * count
524
+ overlapped.target = buf if overlapped
525
+ end
526
+
527
+ r = Win.ReadFile(h, buf, count, outw, opp)
528
+ raise WinX.new(:read_file) if r == 0 and get_last_error != 997
529
+ return buf, outw.unpack("L").first
530
+ end
531
+
532
+ def device_io_control(h, code, inbuf, outbuf, overlapped=NULL)
533
+ overlapped = overlapped.to_s if overlapped
534
+ outw = "\x00" * 4
535
+ r = Win.DeviceIoControl(h, code, inbuf, inbuf.size, outbuf, outbuf.size, outw, overlapped)
536
+ raise WinX.new(:device_io_control) if r == 0 and get_last_error != 997
537
+ return outw.unpack("L").first
538
+ end
539
+
540
+ def get_overlapped_result(h, overlapped)
541
+ overlapped = overlapped.to_s
542
+ outw = "\x00" * 4
543
+ r = Win.GetOverlappedResult(h, overlapped, outw, 0)
544
+ raise WinX.new(:get_overlapped_result) if r == 0
545
+ return outw.unpack("L").first
546
+ end
547
+
548
+ # just grab some local memory
549
+ # XXX same as FFI name ?
550
+ def malloc(sz)
551
+ r = Win.malloc(sz)
552
+ raise WinX.new(:malloc) if r == 0
553
+ return r
554
+ end
555
+
556
+ def memcpy(dst, src, size)
557
+ Win.memcpy(dst, src, size)
558
+ end
559
+
560
+ # Block wrapper for thread suspension
561
+ def with_suspended_thread(tid)
562
+ open_thread(tid) do |h|
563
+ begin
564
+ suspend_thread(h)
565
+ ret = yield h
566
+ ensure
567
+ resume_thread(h)
568
+ end
569
+ end
570
+ end
571
+
572
+ def wfmo(handles, ms=100)
573
+ hp = handles.to_ptr
574
+ r = Win.WaitForMultipleObjects(handles.size, hp, 0, ms)
575
+ raise WinX(:wait_for_multiple_objects) if r == 0xFFFFFFFF
576
+ if r < handles.size
577
+ return handles[r]
578
+ else
579
+ return nil
580
+ end
581
+ end
582
+ end
583
+ 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 = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION"))
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