Module: Ragweed::Wrap32
- Defined in:
- lib/ragweed/wrap32/debugging.rb,
lib/ragweed/wrap32.rb,
lib/ragweed/wrap32/winx.rb,
lib/ragweed/wrap32/wrap32.rb,
lib/ragweed/wrap32/debugging.rb,
lib/ragweed/wrap32/process_token.rb,
lib/ragweed/wrap32/thread_context.rb,
lib/ragweed/wrap32/thread_context.rb
Overview
Wrap the Win32 debugging specific APIs
Defined Under Namespace
Modules: ContextFlags, ContinueCodes, DebugCodes, EFlags, ExceptionCodes, ExceptionSubTypes, FileAccess, FileAttributes, FileDisposition, FileSharing, FormatArgs, PagePermissions, PagePerms, PipeMode, PipeOpenMode, PrivilegeAttribute, TokenAccess, Win Classes: CreateProcessDebugInfo, CreateThreadDebugInfo, DebugEvent, DebugEventU, ExceptionDebugInfo, ExceptionRecord, ExitProcessDebugInfo, ExitThreadDebugInfo, LoadDLLDebugInfo, OutputDebugStringInfo, Overlapped, ProcessInfo, ProcessToken, RipInfo, StartupInfo, ThreadContext, UnloadDLLDebugInfo, WinX
Constant Summary collapse
- VERSION =
:stopdoc:
File.read(File.join(File.dirname(__FILE__),"..","..","VERSION"))
- LIBPATH =
::File.(::File.dirname(__FILE__)) + ::File::SEPARATOR
- PATH =
::File.dirname(LIBPATH) + ::File::SEPARATOR
- NULL =
0x0
Class Method Summary collapse
- .adjust_token_privileges(t, disable, *args) ⇒ Object
-
.all_processes ⇒ Object
Use Toolhelp32 to enumerate all running processes on the box, returning a struct with PIDs and executable names.
-
.close_handle(h) ⇒ Object
Close any Win32 handle.
- .continue_debug_event(pid, tid, code) ⇒ Object
-
.create_event(name = nil, auto = false, signalled = false) ⇒ Object
create an event, which you can signal and wait on across processes.
- .create_file(name, opts = {}) ⇒ Object
- .create_named_pipe(name, opts = {}) ⇒ Object
-
.create_remote_thread(h, start, arg) ⇒ Object
Create a remote thread in the process, starting at the location “start”, with the threadproc argument “arg”.
- .debug_active_process(pid) ⇒ Object
- .debug_active_process_stop(pid) ⇒ Object
- .debug_set_process_kill_on_exit(val = 0) ⇒ Object
- .device_io_control(h, code, inbuf, outbuf, overlapped = FFI::Pointer::NULL) ⇒ Object
-
.duplicate_handle(ph, h) ⇒ Object
clone a handle out of another open process (or self, with -1).
- .flush_instruction_cache(h, v1 = 0, v2 = 0) ⇒ Object
-
.format_message(code = nil) ⇒ Object
strerror(errno) (can’t fail).
-
.get_current_process_id ⇒ Object
getpid.
-
.get_current_thread_id ⇒ Object
gettid.
-
.get_last_error ⇒ Object
Get the last error code (errno) (can’t fail).
- .get_mapped_filename(h, lpv, size) ⇒ Object
-
.get_module_handle(name) ⇒ Object
Given a DLL name, get a handle to the DLL.
- .get_overlapped_result(h, overlapped) ⇒ Object
-
.get_proc_address(x, y = nil) ⇒ Object
Using notation x = “foo!bar” or x = handle, y = meth, look up a function’s address in a module.
-
.get_process_id(h) ⇒ Object
get_processid.
- .get_thread_context(h) ⇒ Object
-
.libpath(*args) ⇒ Object
Returns the library path for the module.
-
.list_modules(pid = 0) ⇒ Object
Given a pid, enumerate the modules loaded into the process, returning base addresses, memory ranges, and the module name.
-
.load_library(name) ⇒ Object
load a library explicitly from a dll.
- .lookup_privilege_value(name) ⇒ Object
-
.malloc(sz) ⇒ Object
just grab some local memory XXX same as FFI name ?.
- .memcpy(dst, src, size) ⇒ Object
-
.nt_query_information_process(h, ord, buf) ⇒ Object
NQIP does a lot of things, the most useful of which are getting the image name of a running process, and telling whether a debugger is loaded.
-
.open_event(name) ⇒ Object
i haven’t made this work, but named handles are kind of silly anyways.
-
.open_process(pid) ⇒ Object
Get a process handle given a pid.
- .open_process_token(h, access = Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES) ⇒ Object
-
.open_thread(tid, &block) ⇒ Object
Get a thread handle given a tid; if a block is provided, the semantics are as File#open with a block.
-
.path(*args) ⇒ Object
Returns the lpath for the module.
- .read_file(h, count, overlapped = nil) ⇒ Object
-
.read_process_memory(h, ptr, len) ⇒ Object
Read from a remote process given an address and length, returning a string.
-
.require_all_libs_relative_to(fname, dir = nil) ⇒ Object
Utility method used to require all files ending in .rb that lie in the directory below this file that has the same name as the filename passed in.
-
.require_utils ⇒ Object
Utility function to load utility classes and extensions.
-
.reset_event(h) ⇒ Object
force-unsignal event (waiting on the event handle also does this).
-
.resume_thread(h) ⇒ Object
Resume a suspended thread, returning nonzero if the thread was suspended, and 0 if it was running.
-
.set_event(h) ⇒ Object
signal an event.
- .set_thread_context(h, ctx) ⇒ Object
- .sleep(ms = 0) ⇒ Object
-
.str2memory_basic_info(mbi) ⇒ Object
deprecated
Deprecated.
-
will be replaced with a proper object
-
-
.str2module_info(str) ⇒ Object
deprecated
Deprecated.
-
will be replaced with a proper object
-
-
.str2process_info(str) ⇒ Object
deprecated
Deprecated.
-
will be replaced with a proper object
-
-
.str2thread_info(str) ⇒ Object
deprecated
Deprecated.
-
will be replaced with a proper object
-
-
.suspend_thread(h) ⇒ Object
Suspend a thread given its handle.
-
.threads(pid) ⇒ Object
List all the threads in a process given its pid, returning a struct containing tids and run state.
-
.version ⇒ Object
Returns the version string for the library.
-
.virtual_alloc_ex(h, sz, addr = NULL, prot = 0x40) ⇒ Object
Allocate memory in a remote process (or yourself, with handle -1).
-
.virtual_free_ex(h, ptr, type = 0x8000) ⇒ Object
Free memory in a remote process given the pointer returned from virtual_alloc_ex.
-
.virtual_protect_ex(h, addr, prot, size = 0) ⇒ Object
Change the protection of specific memory regions in a remote process.
-
.virtual_query_ex(h, ptr) ⇒ Object
Return a struct with the MEMORY_BASIC_INFORMATION for a given address in the memory of a remote process.
- .wait_for_debug_event(ms = 1000) ⇒ Object
-
.wait_for_single_object(h) ⇒ Object
Select(2), for a single object handle.
- .wfmo(handles, ms = 100) ⇒ Object
-
.with_suspended_thread(tid) ⇒ Object
Block wrapper for thread suspension.
- .write_file(h, buf, overlapped = nil) ⇒ Object
-
.write_process_memory(h, dst, val) ⇒ Object
Write a string into the memory of a remote process given its handle and an address.
-
.writeable?(h, off) ⇒ Boolean
Use virtual_query_ex to tell whether an address is writable.
Instance Method Summary collapse
Class Method Details
.adjust_token_privileges(t, disable, *args) ⇒ Object
47 48 49 50 51 52 53 |
# File 'lib/ragweed/wrap32/process_token.rb', line 47 def adjust_token_privileges(t, disable, *args) buf = FFI::MemoryPointer.from_string( [args.size].pack("L") + (args.map {|tup| tup.pack("QL") }.join("")) ) r = Win.AdjustTokenPrivileges(t, disable, buf, buf.size, nil, nil) raise WinX.new(:adjust_token_privileges) if r == 0 end |
.all_processes ⇒ Object
Use Toolhelp32 to enumerate all running processes on the box, returning a struct with PIDs and executable names.
351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 351 def all_processes h = Win.CreateToolhelp32Snapshot(0x2, 0) if h != -1 pi = [(9*4)+2048,0,0,0,0,0,0,0,0,"\x00"*2048].pack("LLLLLLLLLa2048") if Win.Process32First(h, pi) != 0 yield str2process_info(pi) while Win.Process32Next(h, pi) != 0 yield str2process_info(pi) end end else raise WinX.new(:create_toolhelp32_snapshot) end end |
.close_handle(h) ⇒ Object
Close any Win32 handle. Reminder: Win32 handles are just integers, like file descriptors in Posix.
187 188 189 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 187 def close_handle(h) raise WinX.new(:close_handle) if Win.CloseHandle(h) == 0 end |
.continue_debug_event(pid, tid, code) ⇒ Object
374 375 376 377 378 |
# File 'lib/ragweed/wrap32/debugging.rb', line 374 def continue_debug_event(pid, tid, code) r = Win.ContinueDebugEvent(pid, tid, code) raise WinX.new(:continue_debug_event) if r == 0 return r end |
.create_event(name = nil, auto = false, signalled = false) ⇒ Object
create an event, which you can signal and wait on across processes
530 531 532 533 534 535 536 537 538 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 530 def create_event(name=nil, auto=false, signalled=false) auto = (1 if auto) || 0 signalled = (1 if signalled) || 0 name ||= 0 r = Win.CreateEventA(0, auto, signalled, name); raise WinX.new(:create_event) if r == 0 return r end |
.create_file(name, opts = {}) ⇒ Object
487 488 489 490 491 492 493 494 495 496 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 487 def create_file(name, opts={}) opts[:disposition] ||= FileDisposition::OPEN_ALWAYS opts[:sharing] ||= FileSharing::READ | FileSharing::WRITE opts[:access] ||= FileAccess::GENERIC_ALL opts[:flags] ||= 0 r = Win.CreateFileA(name, opts[:access], opts[:sharing], FFI::Pointer::NULL, opts[:disposition], opts[:flags], FFI::Pointer::NULL) raise WinX.new(:create_file) if r == -1 return r end |
.create_named_pipe(name, opts = {}) ⇒ Object
498 499 500 501 502 503 504 505 506 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 498 def create_named_pipe(name, opts={}) opts[:open_mode] ||= PipeOpenMode::PIPE_ACCESS_DUPLEX | PipeOpenMode::FILE_FLAG_OVERLAPPED opts[:pipe_mode] ||= PipeMode::PIPE_TYPE_MESSAGE | PipeMode::PIPE_READMODE_MESSAGE | PipeMode::PIPE_WAIT opts[:max_inst] ||= 4 opts[:def_timeout] ||= 5000 r = Win.CreateNamedPipeA(name, opts[:open_mode], opts[:pipe_mode], opts[:max_inst], opts[:out_buf_sz], opts[:in_buf_sz], opts[:def_timeout], FFI::Pointer::NULL) raise WinX.new(:create_named_pipe) if r == -1 return r end |
.create_remote_thread(h, start, arg) ⇒ Object
Create a remote thread in the process, starting at the location “start”, with the threadproc argument “arg”
469 470 471 472 473 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 469 def create_remote_thread(h, start, arg) r = Win.CreateRemoteThread(h, NULL, 0, start.to_i, arg.to_i, 0, 0) raise WinX.new(:create_remote_thread) if r == 0 return r end |
.debug_active_process(pid) ⇒ Object
380 381 382 383 384 |
# File 'lib/ragweed/wrap32/debugging.rb', line 380 def debug_active_process(pid) r = Win.DebugActiveProcess(pid) raise WinX.new(:debug_active_process) if r == 0 return r end |
.debug_active_process_stop(pid) ⇒ Object
392 393 394 395 |
# File 'lib/ragweed/wrap32/debugging.rb', line 392 def debug_active_process_stop(pid) # don't care about failure Win.DebugActiveProcessStop(pid) end |
.debug_set_process_kill_on_exit(val = 0) ⇒ Object
386 387 388 389 390 |
# File 'lib/ragweed/wrap32/debugging.rb', line 386 def debug_set_process_kill_on_exit(val=0) r = Win.DebugSetProcessKillOnExit(val) raise WinX.new(:debug_set_process_kill_on_exit) if r == 0 return r end |
.device_io_control(h, code, inbuf, outbuf, overlapped = FFI::Pointer::NULL) ⇒ Object
570 571 572 573 574 575 576 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 570 def device_io_control(h, code, inbuf, outbuf, overlapped=FFI::Pointer::NULL) overlapped = overlapped.to_s if overlapped outw = "\x00" * 4 r = Win.DeviceIoControl(h, code, inbuf, inbuf.size, outbuf, outbuf.size, outw, overlapped) raise WinX.new(:device_io_control) if r == 0 and get_last_error != 997 return outw.unpack("L").first end |
.duplicate_handle(ph, h) ⇒ Object
clone a handle out of another open process (or self, with -1)
480 481 482 483 484 485 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 480 def duplicate_handle(ph, h) ret = "\x00\x00\x00\x00" r = Win.DuplicateHandle(ph, h, -1, ret, 0, 0, 0x2) raise WinX.new(:duplicate_handle) if r == 0 ret.to_l32 end |
.flush_instruction_cache(h, v1 = 0, v2 = 0) ⇒ Object
397 398 399 |
# File 'lib/ragweed/wrap32/debugging.rb', line 397 def flush_instruction_cache(h, v1=0, v2=0) Win.FlushInstructionCache(h, v1, v2) end |
.format_message(code = nil) ⇒ Object
strerror(errno) (can’t fail)
197 198 199 200 201 202 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 197 def (code=nil) code ||= get_last_error buf = FFI::MemoryPointer.from_string("\x00" * 4096) Win.FormatMessageA(4096, nil, code, 0x00000400, buf, 4096, nil) return buf.to_s.split("\x00")[0] end |
.get_current_process_id ⇒ Object
getpid
281 282 283 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 281 def get_current_process_id Win.GetCurrentProcessId() # can't realistically fail end |
.get_current_thread_id ⇒ Object
gettid
291 292 293 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 291 def get_current_thread_id Win.GetCurrentThreadId() # can't realistically fail end |
.get_last_error ⇒ Object
Get the last error code (errno) (can’t fail)
192 193 194 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 192 def get_last_error Win.GetLastError() end |
.get_mapped_filename(h, lpv, size) ⇒ Object
235 236 237 238 239 240 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 235 def get_mapped_filename(h, lpv, size) val = "\x00" * size r = Win.GetMappedFileNameA(h, lpv.to_i, val, size) raise WinX.new(:get_mapped_filename) if r == 0 return val end |
.get_module_handle(name) ⇒ Object
Given a DLL name, get a handle to the DLL.
296 297 298 299 300 301 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 296 def get_module_handle(name) name = name r = Win.GetModuleHandleA(name) raise WinX.new(:get_module_handle) if r == 0 return r end |
.get_overlapped_result(h, overlapped) ⇒ Object
578 579 580 581 582 583 584 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 578 def get_overlapped_result(h, overlapped) overlapped = overlapped.to_s outw = "\x00" * 4 r = Win.GetOverlappedResult(h, overlapped, outw, 0) raise WinX.new(:get_overlapped_result) if r == 0 return outw.unpack("L").first end |
.get_proc_address(x, y = nil) ⇒ Object
Using notation x = “foo!bar” or x = handle, y = meth, look up a function’s address in a module. Note that this is local, not remote.
313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 313 def get_proc_address(x, y=nil) if not y mod, meth = x.split "!" h = get_module_handle(mod) else h = x meth = y end r = Win.GetProcAddress(h, meth) return r # pass error through end |
.get_process_id(h) ⇒ Object
get_processid
286 287 288 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 286 def get_process_id(h) Win.GetProcessId(h) end |
.get_thread_context(h) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/ragweed/wrap32/thread_context.rb', line 122 def get_thread_context(h) c = FFI::MemoryPointer.new(Ragweed::Wrap32::ThreadContext, 1) ctx = Ragweed::Wrap32::ThreadContext.new c ctx.context_flags = Ragweed::Wrap32::ContextFlags::DEBUG #suspend_thread(h) ret = Win.GetThreadContext(h, ctx) #resume_thread(h) if ret != 0 return ctx else raise WinX.new(:get_thread_context) end end |
.libpath(*args) ⇒ Object
Returns the library path for the module. If any arguments are given, they will be joined to the end of the libray path using File.join
.
20 21 22 |
# File 'lib/ragweed/wrap32.rb', line 20 def self.libpath( *args ) args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten) end |
.list_modules(pid = 0) ⇒ Object
Given a pid, enumerate the modules loaded into the process, returning base addresses, memory ranges, and the module name.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 386 def list_modules(pid=0) h = Win.CreateToolhelp32Snapshot(0x8, pid) if h != -1 mi = [260+256+(8*4),0,0,0,0,0,0,0,"\x00"*256,"\x00"*260].pack("LLLLLLLLa256a260") if Win.Module32First(h, mi) != 0 yield str2module_info(mi) while Win.Module32Next(h, mi) != 0 yield str2module_info(mi) end end else raise WinX.new(:create_toolhelp32_snapshot) end end |
.load_library(name) ⇒ Object
load a library explicitly from a dll
304 305 306 307 308 309 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 304 def load_library(name) name = name r = Win.LoadLibraryA(name) raise WinX.new(:load_library) if r == 0 return r end |
.lookup_privilege_value(name) ⇒ Object
55 56 57 58 59 60 61 62 |
# File 'lib/ragweed/wrap32/process_token.rb', line 55 def lookup_privilege_value(name) namep = FFI::MemoryPointer.from_string(name) outw = FFI::MemoryPointer.new(:int64, 1) r = Win.LookupPrivilegeValueA(nil, namep, outw) r = Win.LookupPrivilegeValueA(nil, name, outw) raise WinX.new(:lookup_privilege_value) if r == 0 outw.read_long_long end |
.malloc(sz) ⇒ Object
just grab some local memory XXX same as FFI name ?
588 589 590 591 592 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 588 def malloc(sz) r = Win.malloc(sz) raise WinX.new(:malloc) if r == 0 return r end |
.memcpy(dst, src, size) ⇒ Object
594 595 596 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 594 def memcpy(dst, src, size) Win.memcpy(dst, src, size) end |
.nt_query_information_process(h, ord, buf) ⇒ Object
NQIP does a lot of things, the most useful of which are getting the image name of a running process, and telling whether a debugger is loaded. This interface is Ioctl-style; provide an ordinal and a buffer to pass results through.
413 414 415 416 417 418 419 420 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 413 def nt_query_information_process(h, ord, buf) lenp = [0].pack("L") if Win.NtQueryInformationProcess(h, ord, buf, buf.size, lenp) == 0 len = lenp.unpack("L").first return buf[0..(len-1)] end nil end |
.open_event(name) ⇒ Object
i haven’t made this work, but named handles are kind of silly anyways
509 510 511 512 513 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 509 def open_event(name) r = Win.OpenEventA(0, 0, name) raise WinX.new(:open_event) if r == 0 return r end |
.open_process(pid) ⇒ Object
Get a process handle given a pid
166 167 168 169 170 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 166 def open_process(pid) r = Win.OpenProcess(0x1F0FFF, 0, pid) raise WinX.new(:open_process) if r == 0 return r end |
.open_process_token(h, access = Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES) ⇒ Object
40 41 42 43 44 45 |
# File 'lib/ragweed/wrap32/process_token.rb', line 40 def open_process_token(h, access=Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES) outw = "\x00" * 4 r = Win.OpenProcessToken(h, access, outw) raise WinX.new(:open_process_token) if r == 0 return outw.unpack("L").first end |
.open_thread(tid, &block) ⇒ Object
Get a thread handle given a tid; if a block is provided, the semantics are as File#open with a block.
174 175 176 177 178 179 180 181 182 183 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 174 def open_thread(tid, &block) h = Win.OpenThread(0x1F03FF, 0, tid) raise WinX.new(:open_thread) if h == 0 if block_given? ret = yield h close_handle(h) return ret end h end |
.path(*args) ⇒ Object
Returns the lpath for the module. If any arguments are given, they will be joined to the end of the path using File.join
.
28 29 30 |
# File 'lib/ragweed/wrap32.rb', line 28 def self.path( *args ) args.empty? ? PATH : ::File.join(PATH, args.flatten) end |
.read_file(h, count, overlapped = nil) ⇒ Object
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 553 def read_file(h, count, overlapped=nil) if overlapped opp = overlapped.to_s else opp = NULL end outw = "\x00" * 4 if not (buf = overlapped.try(:target)) or buf.size < count buf = "\x00" * count overlapped.target = buf if overlapped end r = Win.ReadFile(h, buf, count, outw, opp) raise WinX.new(:read_file) if r == 0 and get_last_error != 997 return buf, outw.unpack("L").first end |
.read_process_memory(h, ptr, len) ⇒ Object
Read from a remote process given an address and length, returning a string.
227 228 229 230 231 232 233 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 227 def read_process_memory(h, ptr, len) # val = FFI::MemoryPointer.from_string("\x00" * len) val = "\x00" * len r = Win.ReadProcessMemory(h, ptr.to_i, val, len, NULL) raise WinX.new(:read_process_memory) if r == 0 return val ## don't handle short reads XXX end |
.require_all_libs_relative_to(fname, dir = nil) ⇒ Object
Utility method used to require all files ending in .rb that lie in the directory below this file that has the same name as the filename passed in. Optionally, a specific directory name can be passed in such that the filename does not have to be equivalent to the directory.
42 43 44 45 46 47 48 49 50 51 |
# File 'lib/ragweed/wrap32.rb', line 42 def self.require_all_libs_relative_to( fname, dir = nil ) self.require_utils dir ||= ::File.basename(fname, '.*') search_me = ::File.( ::File.join(::File.dirname(fname), dir, '**', '*.rb')) Dir.glob(search_me).sort.each {|rb| require rb} # require File.dirname(File.basename(__FILE__)) + "/#{x}" end |
.require_utils ⇒ Object
Utility function to load utility classes and extensions
33 34 35 |
# File 'lib/ragweed/wrap32.rb', line 33 def self.require_utils %w{utils}.each{|r| require self.libpath(r)+'.rb'} end |
.reset_event(h) ⇒ Object
force-unsignal event (waiting on the event handle also does this)
523 524 525 526 527 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 523 def reset_event(h) r = Win.ResetEvent(h) raise WinX.new(:reset_event) if r == 0 return r end |
.resume_thread(h) ⇒ Object
Resume a suspended thread, returning nonzero if the thread was suspended, and 0 if it was running.
463 464 465 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 463 def resume_thread(h) ResumeThread(h) end |
.set_event(h) ⇒ Object
signal an event
516 517 518 519 520 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 516 def set_event(h) r = Win.SetEvent(h) raise WinX.new(:set_event) if r == 0 return r end |
.set_thread_context(h, ctx) ⇒ Object
136 137 138 139 140 |
# File 'lib/ragweed/wrap32/thread_context.rb', line 136 def set_thread_context(h, ctx) ret = Win.SetThreadContext(h, ctx) raise WinX.new(:set_thread_context) if ret == 0 return ret end |
.sleep(ms = 0) ⇒ Object
475 476 477 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 475 def sleep(ms=0) Win.Sleep(ms) end |
.str2memory_basic_info(mbi) ⇒ Object
-
will be replaced with a proper object
243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 243 def str2memory_basic_info(mbi) s = OpenStruct.new s.BaseAddress, s.AllocationBase, s.AllocationProtect, s.RegionSize, s.State, s.Protect, s.Type = mbi.unpack("LLLLLLL") return s end |
.str2module_info(str) ⇒ Object
-
will be replaced with a proper object
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 367 def str2module_info(str) ret = OpenStruct.new ret.dwSize, ret.th32ModuleID, ret.th32ProcessID, ret.GlblcntUsage, ret.ProccntUsage, ret.modBaseAddr, ret.modBaseSize, ret.hModule, ret.szModule, ret.szExePath = str.unpack("LLLLLLLLA256A260") ret.szModule = ret.szModule.asciiz ret.szExePath = ret.szExePath.asciiz return ret end |
.str2process_info(str) ⇒ Object
-
will be replaced with a proper object
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 333 def str2process_info(str) ret = OpenStruct.new ret.dwSize, ret.cntUsage, ret.th32ProcessID, ret.th32DefaultHeapID, ret.th32ModuleID, ret.cntThreads, ret.th32ParentProcessID, ret.pcPriClassBase, ret.dwFlags, ret.szExeFile = str.unpack("LLLLLLLLLA2048") ret.szExeFile = ret.szExeFile.asciiz return ret end |
.str2thread_info(str) ⇒ Object
-
will be replaced with a proper object
423 424 425 426 427 428 429 430 431 432 433 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 423 def str2thread_info(str) ret = OpenStruct.new ret.dwSize, ret.cntUsage, ret.th32ThreadID, ret.th32OwnerProcessID, ret.tpBasePri, ret.tpDeltaPri, ret.thFlags = str.unpack("LLLLLLL") return ret end |
.suspend_thread(h) ⇒ Object
Suspend a thread given its handle.
455 456 457 458 459 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 455 def suspend_thread(h) r = Win.SuspendThread(h) raise WinX.new(:suspend_thread) if r == 0 return r end |
.threads(pid) ⇒ Object
List all the threads in a process given its pid, returning a struct containing tids and run state. This is relatively expensive, because it uses Toolhelp32.
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 437 def threads(pid) h = Win.CreateToolhelp32Snapshot(0x4, pid) if h != -1 mi = [(7*4),0,0,0,0,0,0].pack("LLLLLLL") if Win.Thread32First(h, mi) != 0 ti = str2thread_info(mi) yield str2thread_info(mi) if ti.th32OwnerProcessID == pid while Win.Thread32Next(h, mi) != 0 ti = str2thread_info(mi) yield str2thread_info(mi) if ti.th32OwnerProcessID == pid end end else raise WinX.new(:create_toolhelp32_snapshot) end end |
.version ⇒ Object
Returns the version string for the library.
12 13 14 |
# File 'lib/ragweed/wrap32.rb', line 12 def self.version VERSION end |
.virtual_alloc_ex(h, sz, addr = NULL, prot = 0x40) ⇒ Object
Allocate memory in a remote process (or yourself, with handle -1)
205 206 207 208 209 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 205 def virtual_alloc_ex(h, sz, addr=NULL, prot=0x40) r = Win.VirtualAllocEx(h, addr, sz, 0x1000, prot) raise WinX.new(:virtual_alloc_ex) if r == 0 return r end |
.virtual_free_ex(h, ptr, type = 0x8000) ⇒ Object
Free memory in a remote process given the pointer returned from virtual_alloc_ex
212 213 214 215 216 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 212 def virtual_free_ex(h, ptr, type=0x8000) r = Win.VirtualFreeEx(h, ptr.to_i, 0, type) raise WinX.new(:virtual_free_ex) if r == 0 return r end |
.virtual_protect_ex(h, addr, prot, size = 0) ⇒ Object
Change the protection of specific memory regions in a remote process.
268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 268 def virtual_protect_ex(h, addr, prot, size=0) old = [0].pack("L") base = virtual_query_ex(h, addr).BaseAddress if size == 0 base ||= addr if Win.VirtualProtectEx(h, base, size, prot, old) old.unpack("L").first else raise WinX.new(:virtual_protect_ex) end end |
.virtual_query_ex(h, ptr) ⇒ Object
Return a struct with the MEMORY_BASIC_INFORMATION for a given address in the memory of a remote process. Gives you addressable memory ranges and protection flags.
258 259 260 261 262 263 264 265 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 258 def virtual_query_ex(h, ptr) mbi = [0,0,0,0,0,0,0].pack("LLLLLLL") if Win.VirtualQueryEx(h, ptr, mbi, mbi.size) str2memory_basic_info(mbi) else nil end end |
.wait_for_debug_event(ms = 1000) ⇒ Object
365 366 367 368 369 370 371 372 |
# File 'lib/ragweed/wrap32/debugging.rb', line 365 def wait_for_debug_event(ms=1000) # buf = FFI::MemoryPointer.new(Ragweed::Wrap32::DebugEvent, 1) buf = FFI::MemoryPointer.from_string("\x00" * 1024) r = Win.WaitForDebugEvent(buf, ms) raise WinX.new(:wait_for_debug_event) if r == 0 and get_last_error != 121 return Ragweed::Wrap32::DebugEvent.new(buf) if r != 0 return nil end |
.wait_for_single_object(h) ⇒ Object
Select(2), for a single object handle.
327 328 329 330 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 327 def wait_for_single_object(h) r = Win.WaitForSingleObject(h, -1) raise WinX.new(:wait_for_single_object) if r == -1 end |
.wfmo(handles, ms = 100) ⇒ Object
610 611 612 613 614 615 616 617 618 619 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 610 def wfmo(handles, ms=100) hp = handles.to_ptr r = Win.WaitForMultipleObjects(handles.size, hp, 0, ms) raise WinX(:wait_for_multiple_objects) if r == 0xFFFFFFFF if r < handles.size return handles[r] else return nil end end |
.with_suspended_thread(tid) ⇒ Object
Block wrapper for thread suspension
599 600 601 602 603 604 605 606 607 608 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 599 def with_suspended_thread(tid) open_thread(tid) do |h| begin suspend_thread(h) ret = yield h ensure resume_thread(h) end end end |
.write_file(h, buf, overlapped = nil) ⇒ Object
540 541 542 543 544 545 546 547 548 549 550 551 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 540 def write_file(h, buf, overlapped=nil) if overlapped opp = overlapped.to_s else opp = NULL end outw = "\x00" * 4 r = Win.WriteFile(h, buf, buf.size, outw, opp) raise WinX.new(:write_file) if r == 0 and get_last_error != 997 return buf, outw.unpack("L").first end |
.write_process_memory(h, dst, val) ⇒ Object
Write a string into the memory of a remote process given its handle and an address
219 220 221 222 223 224 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 219 def write_process_memory(h, dst, val) val = val.to_s if not val.kind_of? String r = Win.WriteProcessMemory(h, dst.to_i, val, val.size, NULL) raise WinX.new(:write_process_memory) if r == 0 return r end |
.writeable?(h, off) ⇒ Boolean
Use virtual_query_ex to tell whether an address is writable.
402 403 404 405 406 407 408 |
# File 'lib/ragweed/wrap32/wrap32.rb', line 402 def writeable?(h, off) if (x = virtual_query_ex(h, off)) return PagePerms::WRITEABLE.member?(x.Protect & 0xFF) else return false end end |