ragweed 0.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -0
@@ -0,0 +1,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&LTOSTOP)
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