Module: Ragweed::Wraposx
- Defined in:
- lib/ragweed/wraposx.rb,
lib/ragweed/wraposx/structs.rb,
lib/ragweed/wraposx/wraposx.rb,
lib/ragweed/wraposx/constants.rb,
lib/ragweed/wraposx/region_info.rb,
lib/ragweed/wraposx/region_info.rb,
lib/ragweed/wraposx/thread_info.rb,
lib/ragweed/wraposx/kernelerrorx.rb,
lib/ragweed/wraposx/thread_context.rb
Defined Under Namespace
Modules: Dl, KErrno, KernelReturn, Libc, Ptrace, Signal, ThreadContext, ThreadInfo, Vm, Wait Classes: FpControl, FpStatus, KernelCallError, MmstReg, TimeValue, XmmReg
Constant Summary collapse
- VERSION =
:stopdoc:
File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
- LIBPATH =
::File.(::File.dirname(__FILE__)) + ::File::SEPARATOR
- PATH =
::File.dirname(LIBPATH) + ::File::SEPARATOR
Class Method Summary collapse
-
.execv(path, *args) ⇒ Object
Changes execution to file in path with *args as though called from command line.
-
.getpid ⇒ Object
pid_t getpid(void);.
-
.kill(pid, sig) ⇒ Object
Sends a signal to a process.
-
.libpath(*args) ⇒ Object
Returns the library path for the module.
-
.mach_task_self ⇒ Object
From docs at web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html Returns send rights to the task’s kernel port.
-
.path(*args) ⇒ Object
Returns the lpath for the module.
-
.pt_attach(pid) ⇒ Object
ptrace(PT_ATTACH, … ).
-
.pt_continue(pid, addr = 1, sig = 0) ⇒ Object
ptrace(PT_CONTINUE, pid, addr, signal).
-
.pt_deny_attach(pid) ⇒ Object
ptrace(PT_DENY_ATTACH, … ).
-
.pt_detach(pid) ⇒ Object
ptrace(PT_DETACH, … ).
-
.pt_kill(pid) ⇒ Object
ptrace(PT_KILL, … ).
-
.pt_step(pid, addr = 1, sig = 0) ⇒ Object
ptrace(PT_STEP, pid, addr, signal).
-
.pt_trace_me(pid) ⇒ Object
ptrace(PT_TRACE_ME, …).
-
.ptrace(request, pid, addr, data) ⇒ Object
Apple’s ptrace is fairly gimped.
-
.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.
-
.task_for_pid(pid, target = nil) ⇒ Object
Requires sudo to use as of 10.5 or 10.4.11(ish) Returns the task id for a process.
-
.task_resume(task) ⇒ Object
Decrement the target tasks suspend count kern_return_t task_resume (task_t task);.
-
.task_suspend(task) ⇒ Object
Increment the target tasks suspend count kern_return_t task_suspend (task_t task);.
-
.task_threads(port) ⇒ Object
Returns an Array of thread IDs for the given task.
-
.thread_get_state(thread, flavor) ⇒ Object
Returns a thread’s registers for given a thread id.
-
.thread_info(thread, flavor) ⇒ Object
Returns the thread_info_t struct.
-
.thread_resume(thread) ⇒ Object
Resumes a suspended thread by id.
-
.thread_set_state(thread, flavor, state) ⇒ Object
Sets the register state of thread.
-
.thread_suspend(thread) ⇒ Object
Suspends a thread by id.
-
.version ⇒ Object
Returns the version string for the library.
-
.vm_allocate(task, address, size, anywhere) ⇒ Object
Allocates a page in the memory space of the target task.
-
.vm_deallocate(task, address, size) ⇒ Object
deallocates a page in the memoryspace of target task.
-
.vm_protect(task, addr, size, setmax, prot) ⇒ Object
Changes the protection state beginning at addr for size bytes to the mask prot.
-
.vm_read(task, addr, sz = 256) ⇒ Object
Reads sz bytes from task’s address space starting at addr.
-
.vm_write(task, addr, val) ⇒ Object
Writes val to task’s memory space at address addr.
-
.wait ⇒ Object
Originally coded for use in debuggerosx but I’ve switched to waitpid for usability and debugging purposes.
-
.waitpid(pid, opts = 0) ⇒ Object
The wait used in debuggerosx.
Instance Method Summary collapse
-
#vm_region(task, addr, flavor) ⇒ Object
Returns the base address, size, and a pointer to the requested information about the memory region at address in the target_task.
-
#vm_region_64(task, addr, flavor) ⇒ Object
Returns the base address, size, and a pointer to the requested information about the memory region at address in the target_task.
Class Method Details
.execv(path, *args) ⇒ Object
Changes execution to file in path with *args as though called from command line.
int execv(const char *path, char *const argv[]);
348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 348 def execv(path, *args) FFI.errno = 0 args.flatten! argv = FFI::MemoryPointer.new(:pointer, args.size + 2) argv[0].put_pointer(0, FFI::MemoryPointer.from_string(path.to_s)) args.each_with_index do |arg, i| argv[i + 1].put_pointer(0, FFI::MemoryPointer.from_string(arg.to_s)) end argv[args.size + 1].put_pointer(0, nil) Libc.execv(path, argv) # if this ever returns, there's been an error raise SystemCallError(:execv, FFI.errno) end |
.getpid ⇒ Object
pid_t getpid(void);
see also getpid(2)
69 70 71 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 69 def getpid Libc.getpid end |
.kill(pid, sig) ⇒ Object
Sends a signal to a process
int kill(pid_t pid, int sig);
See kill(2)
228 229 230 231 232 233 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 228 def kill(pid, sig) FFI::errno = 0 r = Libc.kill(pid, sig) raise SystemCallError.new "kill", FFI::errno if r != 0 r 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
.
23 24 25 |
# File 'lib/ragweed/wraposx.rb', line 23 def self.libpath( *args ) args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten) end |
.mach_task_self ⇒ Object
From docs at web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html Returns send rights to the task’s kernel port.
mach_port_t mach_task_self(void)
There is no man page for this call.
167 168 169 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 167 def mach_task_self Libc.mach_task_self 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
.
31 32 33 |
# File 'lib/ragweed/wraposx.rb', line 31 def self.path( *args ) args.empty? ? PATH : ::File.join(PATH, args.flatten) end |
.pt_attach(pid) ⇒ Object
ptrace(PT_ATTACH, … )
115 116 117 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 115 def pt_attach pid ptrace(Ragweed::Wraposx::Ptrace::ATTACH, pid, nil, nil).first end |
.pt_continue(pid, addr = 1, sig = 0) ⇒ Object
ptrace(PT_CONTINUE, pid, addr, signal)
100 101 102 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 100 def pt_continue pid, addr = 1, sig = 0 ptrace(Ragweed::Wraposx::Ptrace::CONTINUE, pid, addr, sig).first end |
.pt_deny_attach(pid) ⇒ Object
ptrace(PT_DENY_ATTACH, … )
95 96 97 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 95 def pt_deny_attach pid ptrace(Ragweed::Wraposx::Ptrace::DENY_ATTACH, pid, nil, nil).first end |
.pt_detach(pid) ⇒ Object
ptrace(PT_DETACH, … )
120 121 122 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 120 def pt_detach pid ptrace(Ragweed::Wraposx::Ptrace::DETACH, pid, nil, nil).first end |
.pt_kill(pid) ⇒ Object
ptrace(PT_KILL, … )
110 111 112 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 110 def pt_kill pid ptrace(Ragweed::Wraposx::Ptrace::KILL, pid, nil, nil).first end |
.pt_step(pid, addr = 1, sig = 0) ⇒ Object
ptrace(PT_STEP, pid, addr, signal)
105 106 107 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 105 def pt_step pid, addr = 1, sig = 0 ptrace(Ragweed::Wraposx::Ptrace::STEP, pid, addr, sig).first end |
.pt_trace_me(pid) ⇒ Object
ptrace(PT_TRACE_ME, …)
90 91 92 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 90 def pt_trace_me pid ptrace(Ragweed::Wraposx::Ptrace::TRACE_ME, pid, nil, nil).first end |
.ptrace(request, pid, addr, data) ⇒ Object
Apple’s ptrace is fairly gimped. The memory read and write functionality has been removed. We will be using mach kernel calls for that. see vm_read and vm_write. for details on ptrace and the process for the Wraposx/debuggerosx port see: www.matasano.com/log/1100/what-ive-been-doing-on-my-summer-vacation-or-it-has-to-work-otherwise-gdb-wouldnt/
int ptrace(int request, pid_t pid, caddr_t addr, int data);
see also ptrace(2)
82 83 84 85 86 87 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 82 def ptrace(request, pid, addr, data) FFI.errno = 0 r = Libc.ptrace(request, pid, addr, data) raise SystemCallError.new("ptrace", FFI.errno) if r == -1 and FFI.errno != 0 [r, data] 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.
45 46 47 48 49 50 51 52 53 54 |
# File 'lib/ragweed/wraposx.rb', line 45 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).reject{|rb| rb =~ /#{__FILE__}/}.sort.each {|rb| require rb} # require File.dirname(File.basename(__FILE__)) + "/#{x}" end |
.require_utils ⇒ Object
Utility function to load utility classes and extensions
36 37 38 |
# File 'lib/ragweed/wraposx.rb', line 36 def self.require_utils %w{utils}.each{|r| require self.libpath(r)+'.rb'} end |
.task_for_pid(pid, target = nil) ⇒ Object
Requires sudo to use as of 10.5 or 10.4.11(ish) Returns the task id for a process.
kern_return_t task_for_pid(
mach_port_name_t target_tport,
int pid,
mach_port_name_t *t);
There is no man page for this call.
180 181 182 183 184 185 186 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 180 def task_for_pid(pid, target=nil) target ||= mach_task_self port = FFI::MemoryPointer.new :uint, 1 r = Libc.task_for_pid(target, pid, port) raise KernelCallError.new(:task_for_pid, r) if r != 0 port.read_uint end |
.task_resume(task) ⇒ Object
Decrement the target tasks suspend count kern_return_t task_resume
(task_t task);
207 208 209 210 211 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 207 def task_resume(task) r = Libc.task_resume(task) raise KernelCallError.new(r) if r != 0 r end |
.task_suspend(task) ⇒ Object
Increment the target tasks suspend count kern_return_t task_suspend
(task_t task);
216 217 218 219 220 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 216 def task_suspend(task) r = Libc.task_suspend(task) raise KernelCallError.new(r) if r != 0 r end |
.task_threads(port) ⇒ Object
Returns an Array of thread IDs for the given task
kern_return_t task_threads
(task_t task,
thread_act_port_array_t thread_list,
mach_msg_type_number_t* thread_count);
There is no man page for this funtion.
196 197 198 199 200 201 202 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 196 def task_threads(port) threads = FFI::MemoryPointer.new :pointer, 1 count = FFI::MemoryPointer.new :int, 1 r = Libc.task_threads(port, threads, count) raise KernelCallError.new(:task_threads, r) if r != 0 threads.read_pointer.read_array_of_uint(count.read_uint) end |
.thread_get_state(thread, flavor) ⇒ Object
Returns a thread’s registers for given a thread id
kern_return_t thread_get_state
(thread_act_t target_thread,
thread_state_flavor_t flavor,
thread_state_t old_state,
mach_msg_type_number_t *old_state_count);
1000 1001 1002 1003 1004 1005 1006 |
# File 'lib/ragweed/wraposx/thread_context.rb', line 1000 def thread_get_state(thread,flavor) state = FFI::MemoryPointer.new Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class] count = FFI::MemoryPointer.new(:int, 1).write_uint Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:count] r = Libc.thread_get_state(thread, flavor, state, count) raise KernelCallError.new(:thread_get_state, r) if r != 0 Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state end |
.thread_info(thread, flavor) ⇒ Object
Returns the thread_info_t struct.
kern_return_t thread_info
(thread_act_t target_thread,
thread_flavor_t flavor,
thread_info_t thread_info,
mach_msg_type_number_t thread_info_count);
160 161 162 163 164 165 166 |
# File 'lib/ragweed/wraposx/thread_info.rb', line 160 def thread_info(thread, flavor) info = FFI::MemoryPointer.new(ThreadInfo::FLAVORS[flavor][:class], 1) count = FFI::MemoryPointer.new(:int, 1).write_int(ThreadInfo::FLAVORS[flavor][:count]) r = Libc.thread_info(thread, flavor, info, count) raise KernelCallError.new(r) if r != 0 ThreadInfo::FLAVORS[flavor][:class].new info end |
.thread_resume(thread) ⇒ Object
Resumes a suspended thread by id.
kern_return_t thread_resume
(thread_act_t target_thread);
There is no man page for this function.
326 327 328 329 330 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 326 def thread_resume(thread) r = Libc.thread_resume(thread) raise KernelCallError.new(:thread_resume, r) if r != 0 r end |
.thread_set_state(thread, flavor, state) ⇒ Object
Sets the register state of thread.
kern_return_t thread_set_state
(thread_act_t target_thread,
thread_state_flavor_t flavor,
thread_state_t new_state,
mach_msg_type_number_t new_state_count);
1015 1016 1017 1018 1019 |
# File 'lib/ragweed/wraposx/thread_context.rb', line 1015 def thread_set_state(thread, flavor, state) r = Libc.thread_set_state(thread, flavor, state.to_ptr, ThreadContext::FLAVORS[flavor][:count]) raise KernelCallError.new(:thread_set_state, r) if r!= 0 Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state end |
.thread_suspend(thread) ⇒ Object
Suspends a thread by id.
kern_return_t thread_suspend
(thread_act_t target_thread);
There is no man page for this function.
338 339 340 341 342 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 338 def thread_suspend(thread) r = Libc.thread_suspend(thread) raise KernelCallError.new(:thread_suspend, r) if r != 0 r end |
.version ⇒ Object
Returns the version string for the library.
15 16 17 |
# File 'lib/ragweed/wraposx.rb', line 15 def self.version VERSION end |
.vm_allocate(task, address, size, anywhere) ⇒ Object
Allocates a page in the memory space of the target task.
kern_return_t vm_allocate
(vm_task_t target_task,
vm_address_t address,
vm_size_t size,
boolean_t anywhere);
296 297 298 299 300 301 302 303 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 296 def vm_allocate(task, address, size, anywhere) addr = FFI::MemoryPointer.new :int, 1 addr.write_int(address) anywhere = anywhere ? 1 : 0 r = Libc.vm_allocate(task, addr, size, anywhere) raise KernelCallError.new(r) if r != 0 addr.address end |
.vm_deallocate(task, address, size) ⇒ Object
deallocates a page in the memoryspace of target task.
kern_return_t vm_deallocate
(vm_task_t target_task,
vm_address_t address,
vm_size_t size);
312 313 314 315 316 317 318 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 312 def vm_deallocate(task, address, size) addr = FFI::MemoryPointer.new :int, 1 addr.write_int(address) r = Libc.vm_deallocate(task, addr, size) raise KernelCallError.new(r) if r != 0 r end |
.vm_protect(task, addr, size, setmax, prot) ⇒ Object
Changes the protection state beginning at addr for size bytes to the mask prot. If setmax is true this will set the maximum permissions, otherwise it will set FIXME
kern_return_t vm_protect
(vm_task_t target_task,
vm_address_t address,
vm_size_t size,
boolean_t set_maximum,
vm_prot_t new_protection);
There is no man page for this function.
281 282 283 284 285 286 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 281 def vm_protect(task, addr, size, setmax, prot) setmax = setmax ? 1 : 0 r = Libc.vm_protect(task, addr, size, setmax, prot) raise KernelCallError.new(:vm_protect, r) if r != 0 r end |
.vm_read(task, addr, sz = 256) ⇒ Object
Reads sz bytes from task’s address space starting at addr.
kern_return_t vm_read_overwrite
(vm_task_t target_task,
vm_address_t address,
vm_size_t size,
vm_address_t *data_out,
mach_msg_type_number_t *data_size);
There is no man page for this function.
245 246 247 248 249 250 251 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 245 def vm_read(task, addr, sz=256) buf = FFI::MemoryPointer.new(sz) len = FFI::MemoryPointer.new(:uint).write_uint(sz) r = Libc.vm_read_overwrite(task, addr, sz, buf, len) raise KernelCallError.new(:vm_read, r) if r != 0 buf.read_string(len.read_uint) end |
.vm_write(task, addr, val) ⇒ Object
Writes val to task’s memory space at address addr. It is necessary for val.size to report the size of val in bytes
kern_return_t vm_write
(vm_task_t target_task,
vm_address_t address,
pointer_t data,
mach_msg_type_number_t data_count);
There is no man page for this function.
263 264 265 266 267 268 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 263 def vm_write(task, addr, val) val = FFI::MemoryPointer.new(val) r = Libc.vm_write(task, addr, val, val.size) raise KernelCallError.new(:vm_write, r) if r != 0 r end |
.wait ⇒ Object
Originally coded for use in debuggerosx but I’ve switched to waitpid for usability and debugging purposes.
Returns status of child when child recieves a signal.
pid_t wait(int *stat_loc);
see also wait(2)
133 134 135 136 137 138 139 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 133 def wait stat = FFI::MemoryPointer.new :int, 1 FFI.errno = 0 pid = Libc.wait stat raise SystemCallError.new "wait", FFI.errno if pid == -1 [pid, stat.read_int] end |
.waitpid(pid, opts = 0) ⇒ Object
The wait used in debuggerosx. opt is an OR of the options to be used.
Returns an array. The first element is the pid of the child process as returned by the waitpid system call. The second, the status as an integer of that pid.
pid_t waitpid(pid_t pid, int *stat_loc, int options);
see also wait(2)
152 153 154 155 156 157 158 |
# File 'lib/ragweed/wraposx/wraposx.rb', line 152 def waitpid pid, opts = 0 stat = FFI::MemoryPointer.new :int, 1 FFI.errno = 0 r = Libc.waitpid(pid, stat, opts) raise SystemCallError.new "waitpid", FFI.errno if r == -1 [r, stat.read_int] end |
Instance Method Details
#vm_region(task, addr, flavor) ⇒ Object
Returns the base address, size, and a pointer to the requested information about the memory region at address in the target_task.
Currently, only VM_REGION_BASIC_INFO is supported by Apple. Unless this is being run in 32bits, use vm_region_64 instead.
kern_return_t vm_region
(vm_map_t target_task,
vm_address_t *address,
vm_size_t *size,
vm_region_flavor_t flavor,
vm_region_info_t info,
mach_msg_type_number_t *info_count,
mach_port_t *object_name);
236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/ragweed/wraposx/region_info.rb', line 236 def vm_region(task, addr, flavor) info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class], 1) count = FFI::MemoryPointer.new(:int, 1).write_int(Vm::FLAVORS[flavor][:count]) address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr) sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1) objn = FFI::MemoryPointer.new(Libc.find_type(:mach_port_t), 1) r = Libc.vm_region(task, address, sz, flavor, info, count, objn) raise KernelCallError.new(:vm_region, r) if r != 0 ret = Vm::Flavors[flavor][:class].new info ret.region_size = size.read_ulong ret.base_address = address.read_ulong ret end |
#vm_region_64(task, addr, flavor) ⇒ Object
Returns the base address, size, and a pointer to the requested information about the memory region at address in the target_task.
Currently, only VM_REGION_BASIC_INFO is supported by Apple.
kern_return_t vm_region
(vm_map_t target_task,
vm_address_t *address,
vm_size_t *size,
vm_region_flavor_t flavor,
vm_region_info_t info,
mach_msg_type_number_t *info_count,
mach_port_t *object_name);
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/ragweed/wraposx/region_info.rb', line 264 def vm_region_64(task, addr, flavor) # OSX does this as well, so we need to do it ourselves flavor = Vm::REGION_BASIC_INFO_64 if flavor == Vm::REGION_BASIC_INFO info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class]) count = FFI::MemoryPointer.new(Libc.find_type(:mach_msg_type_number_t), 1).write_uint(Vm::FLAVORS[flavor][:count]) address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr) sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1) objn = FFI::MemoryPointer.new(Libc.find_type(:mach_port_t), 1) r = Libc.vm_region_64(task, address, sz, flavor, info, count, objn) raise KernelCallError.new(:vm_region_64, r) if r != 0 ret = Vm::FLAVORS[flavor][:class].new info ret.region_size = sz.read_ulong ret.base_address = address.read_ulong ret end |