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.
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