ragweed 0.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|