ragweed 0.2.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +32 -0
- data/README.rdoc +60 -0
- data/README.txt +9 -0
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/examples/hittracertux.rb +45 -0
- data/examples/hittracerx.rb +63 -0
- data/examples/hook_notepad.rb +9 -0
- data/examples/snicker.rb +183 -0
- data/examples/tux-example.rb +24 -0
- data/lib/ragweed/arena.rb +55 -0
- data/lib/ragweed/blocks.rb +128 -0
- data/lib/ragweed/debugger32.rb +400 -0
- data/lib/ragweed/debuggerosx.rb +456 -0
- data/lib/ragweed/debuggertux.rb +502 -0
- data/lib/ragweed/detour.rb +223 -0
- data/lib/ragweed/ptr.rb +48 -0
- data/lib/ragweed/rasm/bblock.rb +73 -0
- data/lib/ragweed/rasm/isa.rb +1115 -0
- data/lib/ragweed/rasm.rb +59 -0
- data/lib/ragweed/sbuf.rb +197 -0
- data/lib/ragweed/trampoline.rb +103 -0
- data/lib/ragweed/utils.rb +182 -0
- data/lib/ragweed/wrap32/debugging.rb +401 -0
- data/lib/ragweed/wrap32/device.rb +49 -0
- data/lib/ragweed/wrap32/event.rb +50 -0
- data/lib/ragweed/wrap32/hooks.rb +39 -0
- data/lib/ragweed/wrap32/overlapped.rb +46 -0
- data/lib/ragweed/wrap32/process.rb +613 -0
- data/lib/ragweed/wrap32/process_token.rb +75 -0
- data/lib/ragweed/wrap32/thread_context.rb +142 -0
- data/lib/ragweed/wrap32/winx.rb +16 -0
- data/lib/ragweed/wrap32/wrap32.rb +583 -0
- data/lib/ragweed/wrap32.rb +59 -0
- data/lib/ragweed/wraposx/constants.rb +114 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +275 -0
- data/lib/ragweed/wraposx/structs.rb +102 -0
- data/lib/ragweed/wraposx/thread_context.rb +902 -0
- data/lib/ragweed/wraposx/thread_info.rb +160 -0
- data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
- data/lib/ragweed/wraposx/wraposx.rb +356 -0
- data/lib/ragweed/wraposx.rb +60 -0
- data/lib/ragweed/wraptux/constants.rb +101 -0
- data/lib/ragweed/wraptux/process.rb +35 -0
- data/lib/ragweed/wraptux/threads.rb +7 -0
- data/lib/ragweed/wraptux/wraptux.rb +72 -0
- data/lib/ragweed/wraptux.rb +57 -0
- data/lib/ragweed.rb +112 -0
- data/ragweed.gemspec +102 -0
- data/spec/ragweed_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/test/test_ragweed.rb +0 -0
- metadata +121 -0
@@ -0,0 +1,114 @@
|
|
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<OSTOP)
|
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
|
+
|
90
|
+
module Ragweed::Wraposx::Vm::Sm
|
91
|
+
# share mode constants
|
92
|
+
COW = 1
|
93
|
+
PRIVATE = 2
|
94
|
+
EMPTY = 3
|
95
|
+
SHARED = 4
|
96
|
+
TRUESHARED = 5
|
97
|
+
PRIVATE_ALIASED = 6
|
98
|
+
SHARED_ALIASED = 7
|
99
|
+
end
|
100
|
+
|
101
|
+
module Ragweed::Wraposx::Dl
|
102
|
+
RTLD_LAZY = 0x1
|
103
|
+
RTLD_NOW = 0x2
|
104
|
+
RTLD_LOCAL = 0x4
|
105
|
+
RTLD_GLOBAL = 0x8
|
106
|
+
RTLD_NOLOAD = 0x10
|
107
|
+
RTLD_NODELETE = 0x80
|
108
|
+
RTLD_FIRST = 0x100 #/* Mac OS X 10.5 and later */
|
109
|
+
|
110
|
+
# Special handle arguments for dlsym().
|
111
|
+
#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
|
112
|
+
#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
|
113
|
+
#define RTLD_SELF ((void *) -3) /* Search this and subsequent objects (Mac OS X 10.5 and later) */
|
114
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# Exception objects for kernel errors likely in Wraposx
|
2
|
+
# If this were a C extension I'd use #ifdef on each to only create the required ones.
|
3
|
+
|
4
|
+
module Ragweed; end
|
5
|
+
module Ragweed::Wraposx; end
|
6
|
+
module Ragweed::Wraposx::KernelReturn
|
7
|
+
SUCCESS = { :value => 0, :message => 'Not an error'}
|
8
|
+
INVALID_ADDRESS = { :value => 1, :message => 'Specified address is not currently valid.'}
|
9
|
+
PROTECTION_FAILURE = { :value => 2, :message => 'Specified memory is valid, but does not permit the required forms of access.'}
|
10
|
+
NO_SPACE = { :value => 3, :message => 'The address range specified is already in use, or no address range of the size specified could be found.'}
|
11
|
+
INVALID_ARGUMENT = { :value => 4, :message => 'The function requested was not applicable to this type of argument, or an argument is invalid'}
|
12
|
+
FAILURE = { :value => 5, :message => 'The function could not be performed. A catch-all.'}
|
13
|
+
RESOURCE_SHORTAGE = { :value => 6, :message => 'A system resource could not be allocated to fulfill this request. This failure may not be permanent.'}
|
14
|
+
NOT_RECEIVER = { :value => 7, :message => 'The task in question does not hold receive rights for the port argument.'}
|
15
|
+
NO_ACCESS = { :value => 8, :message => 'Bogus access restriction.'}
|
16
|
+
MEMORY_FAILURE = { :value => 9, :message => 'During a page fault, the target address refers to a memory object that has been destroyed. This failure is permanent.'}
|
17
|
+
MEMORY_ERROR = { :value => 10, :message => 'During a page fault, the memory object indicated that the data could not be returned. This failure may be temporary; future attempts to access this same data may succeed, as defined by the memory object.'}
|
18
|
+
ALREADY_IN_SET = { :value => 11, :message => 'The receive right is already a member of the portset.'}
|
19
|
+
NOT_IN_SET = { :value => 12, :message => 'The receive right is not a member of a port set.'}
|
20
|
+
NAME_EXISTS = { :value => 13, :message => 'The name already denotes a right in the task.'}
|
21
|
+
ABORTED = { :value => 14, :message => 'The operation was aborted. Ipc code will catch this and reflect it as a message error.'}
|
22
|
+
INVALID_NAME = { :value => 15, :message => 'The name doesn\'t denote a right in the task.'}
|
23
|
+
INVALID_TASK = { :value => 16, :message => 'Target task isn\'t an active task.'}
|
24
|
+
INVALID_RIGHT = { :value => 17, :message => 'The name denotes a right, but not an appropriate right.'}
|
25
|
+
INVALID_VALUE = { :value => 18, :message => 'A blatant range error.'}
|
26
|
+
UREFS_OVERFLOW = { :value => 19, :message => 'Operation would overflow limit on user-references.'}
|
27
|
+
INVALID_CAPABILITY = { :value => 20, :message => 'The supplied (port) capability is improper.'}
|
28
|
+
RIGHT_EXISTS = { :value => 21, :message => 'The task already has send or receive rights for the port under another name.'}
|
29
|
+
INVALID_HOST = { :value => 22, :message => 'Target host isn\'t actually a host.'}
|
30
|
+
MEMORY_PRESENT = { :value => 23, :message => 'An attempt was made to supply "precious" data for memory that is already present in a memory object.'}
|
31
|
+
MEMORY_DATA_MOVED = { :value => 24, :message => 'A page was requested of a memory manager via memory_object_data_request for an object using a MEMORY_OBJECT_COPY_CALL strategy, with the VM_PROT_WANTS_COPY flag being used to specify that the page desired is for a copy of the object, and the memory manager has detected the page was pushed into a copy of the object while the kernel was walking the shadow chain from the copy to the object. This error code is delivered via memory_object_data_error and is handled by the kernel (it forces the kernel to restart the fault). It will not be seen by users.'}
|
32
|
+
MEMORY_RESTART_COPY = { :value => 25, :message => 'A strategic copy was attempted of an object upon which a quicker copy is now possible. The caller should retry the copy using vm_object_copy_quickly. This error code is seen only by the kernel.'}
|
33
|
+
INVALID_PROCESSOR_SET = { :value => 26, :message => 'An argument applied to assert processor set privilege was not a processor set control port.'}
|
34
|
+
POLICY_LIMIT = { :value => 27, :message => 'The specified scheduling attributes exceed the thread\'s limits.'}
|
35
|
+
INVALID_POLICY = { :value => 28, :message => 'The specified scheduling policy is not currently enabled for the processor set.'}
|
36
|
+
INVALID_OBJECT = { :value => 29, :message => 'The external memory manager failed to initialize the memory object.'}
|
37
|
+
ALREADY_WAITING = { :value => 30, :message => 'A thread is attempting to wait for an event for which there is already a waiting thread.'}
|
38
|
+
DEFAULT_SET = { :value => 31, :message => 'An attempt was made to destroy the default processor set.'}
|
39
|
+
EXCEPTION_PROTECTED = { :value => 32, :message => 'An attempt was made to fetch an exception port that is protected, or to abort a thread while processing a protected exception.'}
|
40
|
+
INVALID_LEDGER = { :value => 33, :message => 'A ledger was required but not supplied.'}
|
41
|
+
INVALID_MEMORY_CONTROL= { :value => 34, :message => 'The port was not a memory cache control port.'}
|
42
|
+
INVALID_SECURITY = { :value => 35, :message => 'An argument supplied to assert security privilege was not a host security port.'}
|
43
|
+
NOT_DEPRESSED = { :value => 36, :message => 'thread_depress_abort was called on a thread which was not currently depressed.'}
|
44
|
+
TERMINATED = { :value => 37, :message => 'Object has been terminated and is no longer available'}
|
45
|
+
LOCK_SET_DESTROYED = { :value => 38, :message => 'Lock set has been destroyed and is no longer available.'}
|
46
|
+
LOCK_UNSTABLE = { :value => 39, :message => 'The thread holding the lock terminated before releasing the lock'}
|
47
|
+
LOCK_OWNED = { :value => 40, :message => 'The lock is already owned by another thread'}
|
48
|
+
LOCK_OWNED_SELF = { :value => 41, :message => 'The lock is already owned by the calling thread'}
|
49
|
+
SEMAPHORE_DESTROYED = { :value => 42, :message => 'Semaphore has been destroyed and is no longer available.'}
|
50
|
+
RPC_SERVER_TERMINATED = { :value => 43, :message => 'Return from RPC indicating the target server was terminated before it successfully replied '}
|
51
|
+
RPC_TERMINATE_ORPHAN = { :value => 44, :message => 'Terminate an orphaned activation.'}
|
52
|
+
RPC_CONTINUE_ORPHAN = { :value => 45, :message => 'Allow an orphaned activation to continue executing.'}
|
53
|
+
NOT_SUPPORTED = { :value => 46, :message => 'Empty thread activation (No thread linked to it)'}
|
54
|
+
NODE_DOWN = { :value => 47, :message => 'Remote node down or inaccessible.'}
|
55
|
+
NOT_WAITING = { :value => 48, :message => 'A signalled thread was not actually waiting.'}
|
56
|
+
OPERATION_TIMED_OUT = { :value => 49, :message => 'Some thread-oriented operation (semaphore_wait) timed out'}
|
57
|
+
RETURN_MAX = { :value => 0x100, :message => 'Maximum return value allowable'}
|
58
|
+
|
59
|
+
module_function
|
60
|
+
# Much like Signals.list returns a hash of the possible kernel call return values.
|
61
|
+
def list
|
62
|
+
@@list ||= constants.inject({}){|a, c| a.merge! c => const_get(c)}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module Ragweed::Wraposx::KErrno; end
|
67
|
+
|
68
|
+
# Exception class for mach kernel calls. Works mostly like SystemCallError.
|
69
|
+
# Subclasses are individual error conditions and case equality (===) is done by class then error number (KErrno)
|
70
|
+
class Ragweed::Wraposx::KernelCallError < StandardError
|
71
|
+
DEFAULT_MESSAGE = "Unknown Error"
|
72
|
+
attr_reader :kerrno
|
73
|
+
|
74
|
+
# Returns a subclass of KernelCallError based on the KernelReturn value err
|
75
|
+
def self.new(msg = "", err = nil)
|
76
|
+
if msg.kind_of? Fixnum
|
77
|
+
err = msg
|
78
|
+
msg = ""
|
79
|
+
end
|
80
|
+
mesg = ""
|
81
|
+
|
82
|
+
klass = Ragweed::Wraposx::KErrno.constants.detect{|x| Ragweed::Wraposx::KErrno.const_get(x).const_get("KErrno") == err}
|
83
|
+
if (klass.nil? or klass.empty?)
|
84
|
+
o = self.allocate
|
85
|
+
o.instance_variable_set("@kerrno", err)
|
86
|
+
mesg = "Unknown kernel error"
|
87
|
+
else
|
88
|
+
o = Ragweed::Wraposx::KErrno.const_get(klass).allocate
|
89
|
+
mesg = Ragweed::Wraposx::KernelReturn.const_get(klass)[:message]
|
90
|
+
end
|
91
|
+
|
92
|
+
if o.class.const_defined?("KErrno")
|
93
|
+
o.instance_variable_set("@kerrno", o.class.const_get("KErrno"))
|
94
|
+
else
|
95
|
+
o.instance_variable_set("@kerrno", err)
|
96
|
+
mesg = "#{mesg}: #{err}" if err
|
97
|
+
end
|
98
|
+
|
99
|
+
mesg = "#{mesg} - #{msg}" if !(msg.nil? or msg.to_s.empty?)
|
100
|
+
o.send(:initialize, mesg)
|
101
|
+
return o
|
102
|
+
end
|
103
|
+
|
104
|
+
# Case equality. Returns true if self and other are KernelCallError or when error numbers match.
|
105
|
+
def self.===(other)
|
106
|
+
return false if not other.kind_of?(Ragweed::Wraposx::KernelCallError)
|
107
|
+
return true if self == Ragweed::Wraposx::KernelCallError
|
108
|
+
|
109
|
+
begin
|
110
|
+
return self.const_get("KErrno") == other.const_get("KErrno")
|
111
|
+
rescue
|
112
|
+
return false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def initialize(msg)
|
117
|
+
super msg
|
118
|
+
end
|
119
|
+
|
120
|
+
# This block builds the subclasses for KernelCallError
|
121
|
+
Ragweed::Wraposx::KernelReturn.list.each do |k, v|
|
122
|
+
case k.intern
|
123
|
+
when :SUCCESS
|
124
|
+
when :RETURN_MAX
|
125
|
+
else
|
126
|
+
klass = Ragweed::Wraposx::KErrno.const_set(k, Class.new(Ragweed::Wraposx::KernelCallError){
|
127
|
+
def self.new(msg = "")
|
128
|
+
o = self.allocate
|
129
|
+
o.instance_variable_set "@kerrno", self.const_get("KErrno")
|
130
|
+
mesg = ""
|
131
|
+
klass = self.name.split("::").last
|
132
|
+
if Ragweed::Wraposx::KernelReturn.const_defined?(klass)
|
133
|
+
mesg = Ragweed::Wraposx::KernelReturn.const_get(klass)[:message]
|
134
|
+
else
|
135
|
+
mesg = "Unknown kernel error"
|
136
|
+
end
|
137
|
+
mesg = "#{mesg} - #{msg}" if not (msg.nil? or msg.empty?)
|
138
|
+
o.send(:initialize, mesg)
|
139
|
+
puts self
|
140
|
+
return o
|
141
|
+
end
|
142
|
+
})
|
143
|
+
klass.const_set "KErrno", v[:value]
|
144
|
+
klass.const_set "DEFAULT_MESSAGE", v[:message]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
module Ragweed; end
|
2
|
+
module Ragweed::Wraposx; end
|
3
|
+
module Ragweed::Wraposx::Vm
|
4
|
+
# these are flavor arguments for vm_region
|
5
|
+
# only basic info is supported by apple
|
6
|
+
REGION_BASIC_INFO_64 = 9
|
7
|
+
REGION_BASIC_INFO = 10
|
8
|
+
REGION_EXTENDED_INFO = 11
|
9
|
+
REGION_TOP_INFO = 12
|
10
|
+
|
11
|
+
# behavior identifiers
|
12
|
+
BEHAVIOR_DEFAULT = 0 # /* default */
|
13
|
+
BEHAVIOR_RANDOM = 1 # /* random */
|
14
|
+
BEHAVIOR_SEQUENTIAL = 2 # /* forward sequential */
|
15
|
+
BEHAVIOR_RSEQNTL = 3 # /* reverse sequential */
|
16
|
+
BEHAVIOR_WILLNEED = 4 # /* will need in near future */
|
17
|
+
BEHAVIOR_DONTNEED = 5 # /* dont need in near future */
|
18
|
+
|
19
|
+
#Virtual memory map inheritance values for vm_inherit_t
|
20
|
+
INHERIT_SHARE = 0 # /* share with child */
|
21
|
+
INHERIT_COPY = 1 # /* copy into child */
|
22
|
+
INHERIT_NONE = 2 # /* absent from child */
|
23
|
+
INHERIT_DONATE_COPY = 3 # /* copy and delete */
|
24
|
+
INHERIT_DEFAULT = 1 # VM_INHERIT_COPY
|
25
|
+
INHERIT_LAST_VALID = 2 # VM_INHERIT_NONE
|
26
|
+
|
27
|
+
module Pflags
|
28
|
+
READ = 0x1 #read permission
|
29
|
+
WRITE = 0x2 #write permission
|
30
|
+
EXECUTE = 0x4 #execute permission
|
31
|
+
end
|
32
|
+
|
33
|
+
# Memory region info base class.
|
34
|
+
#
|
35
|
+
class RegionInfo < FFI::Struct
|
36
|
+
include Ragweed::FFIStructInclude
|
37
|
+
attr_accessor :region_size
|
38
|
+
attr_accessor :base_address
|
39
|
+
end
|
40
|
+
|
41
|
+
class RegionBasicInfo < RegionInfo
|
42
|
+
|
43
|
+
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
44
|
+
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
45
|
+
:inheritance, Ragweed::Wraposx::Libc.find_type(:vm_inherit_t),
|
46
|
+
:shared, Ragweed::Wraposx::Libc.find_type(:boolean_t),
|
47
|
+
:reserved, Ragweed::Wraposx::Libc.find_type(:boolean_t),
|
48
|
+
:offset, :uint32,
|
49
|
+
:behavior, Ragweed::Wraposx::Libc.find_type(:vm_behavior_t),
|
50
|
+
:user_wired_count, :ushort
|
51
|
+
|
52
|
+
|
53
|
+
def dump(&block)
|
54
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
55
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
56
|
+
|
57
|
+
string =<<EOM
|
58
|
+
-----------------------------------------------------------------------
|
59
|
+
BASIC INFO:
|
60
|
+
base address: #{self.base_address.to_s(16).rjust(8, "0")}
|
61
|
+
|
62
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
63
|
+
max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
|
64
|
+
inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
|
65
|
+
shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
|
66
|
+
reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
|
67
|
+
offset: #{self.offset.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.offset)}
|
68
|
+
behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
|
69
|
+
user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
|
70
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
71
|
+
EOM
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class RegionBasicInfo64 < RegionInfo
|
76
|
+
|
77
|
+
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
78
|
+
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
79
|
+
:inheritance, Ragweed::Wraposx::Libc.find_type(:vm_inherit_t),
|
80
|
+
:shared, Ragweed::Wraposx::Libc.find_type(:boolean_t),
|
81
|
+
:reserved, Ragweed::Wraposx::Libc.find_type(:boolean_t),
|
82
|
+
:offset, Ragweed::Wraposx::Libc.find_type(:memory_object_offset_t),
|
83
|
+
:behavior, Ragweed::Wraposx::Libc.find_type(:vm_behavior_t),
|
84
|
+
:user_wired_count, :ushort
|
85
|
+
|
86
|
+
def dump(&block)
|
87
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
88
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
89
|
+
|
90
|
+
string =<<EOM
|
91
|
+
-----------------------------------------------------------------------
|
92
|
+
BASIC INFO:
|
93
|
+
base address: #{self.base_address.to_s(16).rjust(8, "0")}
|
94
|
+
|
95
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
96
|
+
max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
|
97
|
+
inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
|
98
|
+
shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
|
99
|
+
reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
|
100
|
+
offset: #{self.offset.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.offset)}
|
101
|
+
behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
|
102
|
+
user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
|
103
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
104
|
+
EOM
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# struct vm_region_extended_info {
|
109
|
+
# vm_prot_t protection;
|
110
|
+
# unsigned int user_tag;
|
111
|
+
# unsigned int pages_resident;
|
112
|
+
# unsigned int pages_shared_now_private;
|
113
|
+
# unsigned int pages_swapped_out;
|
114
|
+
# unsigned int pages_dirtied;
|
115
|
+
# unsigned int ref_count;
|
116
|
+
# unsigned short shadow_depth;
|
117
|
+
# unsigned char external_pager;
|
118
|
+
# unsigned char share_mode;
|
119
|
+
# };
|
120
|
+
class RegionExtendedInfo < RegionInfo
|
121
|
+
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
122
|
+
:user_tag, :uint,
|
123
|
+
:pages_resident, :uint,
|
124
|
+
:pages_shared_now_private, :uint,
|
125
|
+
:pages_swapped_out, :uint,
|
126
|
+
:pages_dirtied, :uint,
|
127
|
+
:ref_count, :uint,
|
128
|
+
:shadow_depth, :ushort,
|
129
|
+
:external_pager, :uchar,
|
130
|
+
:share_mode, :uchar
|
131
|
+
|
132
|
+
def dump(&block)
|
133
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
134
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
135
|
+
|
136
|
+
string =<<EOM
|
137
|
+
-----------------------------------------------------------------------
|
138
|
+
EXTENDED INFO:
|
139
|
+
base address: #{self.base_address.to_s(16).rjust(8, "0")}
|
140
|
+
|
141
|
+
protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
|
142
|
+
user_tag: #{self.user_tag.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_tag)}
|
143
|
+
pages_resident: #{self.pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_resident)}
|
144
|
+
pages_shared_now_private: #{self.pages_shared_now_private.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_shared_now_private)}
|
145
|
+
pages_swapped_out: #{self.pages_swapped_out.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_swapped_out)}
|
146
|
+
pages_dirtied: #{self.pages_dirtied.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_dirtied)}
|
147
|
+
ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
|
148
|
+
shadow_depth: #{self.shadow_depth.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shadow_depth)}
|
149
|
+
external_pager: #{self.external_pager.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.external_pager)}
|
150
|
+
share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
|
151
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
152
|
+
EOM
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# struct vm_region_top_info {
|
157
|
+
# unsigned int obj_id;
|
158
|
+
# unsigned int ref_count;
|
159
|
+
# unsigned int private_pages_resident;
|
160
|
+
# unsigned int shared_pages_resident;
|
161
|
+
# unsigned char share_mode;
|
162
|
+
# };
|
163
|
+
class RegionTopInfo < RegionInfo
|
164
|
+
layout :obj_id, :uint,
|
165
|
+
:ref_count, :uint,
|
166
|
+
:private_pages_resident, :uint,
|
167
|
+
:shared_pages_resident, :uint,
|
168
|
+
:share_mode, :uchar
|
169
|
+
|
170
|
+
def dump(&block)
|
171
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
172
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
173
|
+
|
174
|
+
string =<<EOM
|
175
|
+
-----------------------------------------------------------------------
|
176
|
+
TOP INFO:
|
177
|
+
base address: #{self.base_address.to_s(16).rjust(8, "0")}
|
178
|
+
|
179
|
+
obj_id: #{self.obj_id.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.obj_id)}
|
180
|
+
ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
|
181
|
+
private_pages_resident: #{self.private_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.private_pages_resident)}
|
182
|
+
shared_pages_resident: #{self.shared_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared_pages_resident)}
|
183
|
+
share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
|
184
|
+
size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
|
185
|
+
EOM
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
#define VM_REGION_BASIC_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_basic_info_data_t)/sizeof(int)))
|
190
|
+
#define VM_REGION_BASIC_INFO_COUNT_64 ((mach_msg_type_number_t) (sizeof(vm_region_basic_info_data_64_t)/sizeof(int)))
|
191
|
+
#define VM_REGION_EXTENDED_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_extended_info_data_t)/sizeof(int)))
|
192
|
+
#define VM_REGION_TOP_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_top_info_data_t)/sizeof(int)))
|
193
|
+
FLAVORS = { REGION_BASIC_INFO => {:size => 30, :count => 8, :class => RegionBasicInfo},
|
194
|
+
REGION_BASIC_INFO_64 => {:size => 30, :count => 9, :class => RegionBasicInfo64},
|
195
|
+
REGION_EXTENDED_INFO => {:size => 32, :count => 8, :class => RegionExtendedInfo},
|
196
|
+
REGION_TOP_INFO => {:size => 17,:count => 5, :class => RegionTopInfo}
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
module Ragweed::Wraposx
|
201
|
+
module Libc
|
202
|
+
extend FFI::Library
|
203
|
+
ffi_lib FFI::Library::LIBC
|
204
|
+
|
205
|
+
# determine if a function is defined in the attached libraries
|
206
|
+
def self.find_function func
|
207
|
+
ffi_libraries.detect{|lib| lib.find_function(func)}
|
208
|
+
end
|
209
|
+
|
210
|
+
attach_function :vm_region, [:vm_map_t, :pointer, :pointer, :vm_region_flavor_t, :pointer, :pointer, :pointer], :int if find_function "vm_region"
|
211
|
+
attach_function :vm_region_64, [:vm_map_t, :pointer, :pointer, :vm_region_flavor_t, :pointer, :pointer, :pointer], :int if find_function "vm_region_64"
|
212
|
+
end
|
213
|
+
|
214
|
+
class << self
|
215
|
+
|
216
|
+
# Returns the base address, size, and a pointer to the requested information
|
217
|
+
# about the memory region at address in the target_task.
|
218
|
+
#
|
219
|
+
# Currently, only VM_REGION_BASIC_INFO is supported by Apple.
|
220
|
+
# Unless this is being run in 32bits, use vm_region_64 instead.
|
221
|
+
#
|
222
|
+
# kern_return_t vm_region
|
223
|
+
# (vm_map_t target_task,
|
224
|
+
# vm_address_t *address,
|
225
|
+
# vm_size_t *size,
|
226
|
+
# vm_region_flavor_t flavor,
|
227
|
+
# vm_region_info_t info,
|
228
|
+
# mach_msg_type_number_t *info_count,
|
229
|
+
# mach_port_t *object_name);
|
230
|
+
def vm_region(task, addr, flavor)
|
231
|
+
info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class], 1)
|
232
|
+
count = FFI::MemoryPointer.new(:int, 1).write_int(Vm::FLAVORS[flavor][:count])
|
233
|
+
address = FFI::MemoryPointer.new(:vm_address_t, 1).write_ulong(addr)
|
234
|
+
sz = FFI::MemoryPointer.new(:vm_size_t, 1)
|
235
|
+
objn = FFI::MemoryPointer.new(:mach_port_t, 1)
|
236
|
+
|
237
|
+
r = Libc.vm_region(task, address, sz, flavor, info, count, objn)
|
238
|
+
raise KernelCallError.new(:vm_region, r) if r != 0
|
239
|
+
ret = Vm::Flavors[flavor][:class].new info
|
240
|
+
ret.region_size = size.read_ulong
|
241
|
+
ret.base_address = address.read_ulong
|
242
|
+
ret
|
243
|
+
end if Libc.find_function "vm_region"
|
244
|
+
|
245
|
+
# Returns the base address, size, and a pointer to the requested information
|
246
|
+
# about the memory region at address in the target_task.
|
247
|
+
#
|
248
|
+
# Currently, only VM_REGION_BASIC_INFO is supported by Apple.
|
249
|
+
#
|
250
|
+
# kern_return_t vm_region
|
251
|
+
# (vm_map_t target_task,
|
252
|
+
# vm_address_t *address,
|
253
|
+
# vm_size_t *size,
|
254
|
+
# vm_region_flavor_t flavor,
|
255
|
+
# vm_region_info_t info,
|
256
|
+
# mach_msg_type_number_t *info_count,
|
257
|
+
# mach_port_t *object_name);
|
258
|
+
def vm_region_64(task, addr, flavor)
|
259
|
+
# OSX does this as well, so we need to do it ourselves
|
260
|
+
flavor = Vm::REGION_BASIC_INFO_64 if flavor == Vm::REGION_BASIC_INFO
|
261
|
+
info = FFI::MemoryPointer.new(:uint8, Vm::FLAVORS[flavor][:size])
|
262
|
+
count = FFI::MemoryPointer.new(Libc.find_type(:mach_msg_type_number_t), 1).write_uint(Vm::FLAVORS[flavor][:count])
|
263
|
+
address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr)
|
264
|
+
sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1)
|
265
|
+
objn = FFI::MemoryPointer.new(Libc.find_type(:mach_port_t), 1)
|
266
|
+
|
267
|
+
r = Libc.vm_region_64(task, address, sz, flavor, info, count, objn)
|
268
|
+
raise KernelCallError.new(:vm_region_64, r) if r != 0
|
269
|
+
ret = Vm::Flavors[flavor][:class].new info
|
270
|
+
ret.region_size = size.read_ulong
|
271
|
+
ret.base_address = address.read_ulong
|
272
|
+
ret
|
273
|
+
end if Libc.find_function "vm_region_64"
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# miscelaneous structs needed for other calls/structures
|
2
|
+
|
3
|
+
module Ragweed; end
|
4
|
+
module Ragweed::Wraposx
|
5
|
+
class FpControl < FFI::Struct
|
6
|
+
layout :value, :ushort
|
7
|
+
|
8
|
+
def invalid
|
9
|
+
self.value >> 15
|
10
|
+
end
|
11
|
+
def denorm
|
12
|
+
(self.value >> 14) & 1
|
13
|
+
end
|
14
|
+
def zdiv
|
15
|
+
(self.value >> 13) & 1
|
16
|
+
end
|
17
|
+
def ovrfl
|
18
|
+
(self.value >> 12) & 1
|
19
|
+
end
|
20
|
+
def undfl
|
21
|
+
(self.value >> 11) & 1
|
22
|
+
end
|
23
|
+
def precis
|
24
|
+
(self.value >> 10) & 1
|
25
|
+
end
|
26
|
+
def res0
|
27
|
+
(self.value >> 8) & 3
|
28
|
+
end
|
29
|
+
def pc
|
30
|
+
(self.value >> 6) & 3
|
31
|
+
end
|
32
|
+
def rc
|
33
|
+
(self.value >> 4) & 3
|
34
|
+
end
|
35
|
+
def res1
|
36
|
+
(self.value >> 3) & 1
|
37
|
+
end
|
38
|
+
def res2
|
39
|
+
self.value & 7
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class FpStatus < FFI::Struct
|
44
|
+
layout :value, :ushort
|
45
|
+
def invalid
|
46
|
+
self.value >> 15
|
47
|
+
end
|
48
|
+
def denorm
|
49
|
+
(self.value >> 14) & 1
|
50
|
+
end
|
51
|
+
def zdiv
|
52
|
+
(self.value >> 13) & 1
|
53
|
+
end
|
54
|
+
def ovrfl
|
55
|
+
(self.value >> 12) & 1
|
56
|
+
end
|
57
|
+
def undfl
|
58
|
+
(self.value >> 11) & 1
|
59
|
+
end
|
60
|
+
def precis
|
61
|
+
(self.value >> 10) & 1
|
62
|
+
end
|
63
|
+
def stkflt
|
64
|
+
(self.value >> 9) & 1
|
65
|
+
end
|
66
|
+
def errsumm
|
67
|
+
(self.value >> 8) & 1
|
68
|
+
end
|
69
|
+
def c0
|
70
|
+
(self.value >> 7) & 1
|
71
|
+
end
|
72
|
+
def c1
|
73
|
+
(self.value >> 6) & 1
|
74
|
+
end
|
75
|
+
def c2
|
76
|
+
(self.value >> 5) & 1
|
77
|
+
end
|
78
|
+
def tos
|
79
|
+
(self.value >> 2) & 7
|
80
|
+
end
|
81
|
+
def c2
|
82
|
+
(self.value >> 1) & 1
|
83
|
+
end
|
84
|
+
def busy
|
85
|
+
self.value & 1
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class MmstReg < FFI::Struct
|
90
|
+
layout :mmst_reg, [:char, 10],
|
91
|
+
:mmst_rsrv, [:char, 6]
|
92
|
+
end
|
93
|
+
|
94
|
+
class XmmReg < FFI::Struct
|
95
|
+
layout :xmm_reg, [:char, 16]
|
96
|
+
end
|
97
|
+
|
98
|
+
class TimeValue < FFI::Struct
|
99
|
+
layout :seconds, :int,
|
100
|
+
:microseconds, :int
|
101
|
+
end
|
102
|
+
end
|