iZsh-ragweed 0.1.8

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 (62) hide show
  1. data/History.txt +29 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +30 -0
  5. data/examples/hittracertux.rb +49 -0
  6. data/examples/hittracerx.rb +63 -0
  7. data/examples/hook_notepad.rb +9 -0
  8. data/examples/snicker.rb +183 -0
  9. data/examples/tux-example.rb +23 -0
  10. data/lib/ragweed.rb +84 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +338 -0
  14. data/lib/ragweed/debuggerosx.rb +419 -0
  15. data/lib/ragweed/debuggertux.rb +345 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm.rb +53 -0
  19. data/lib/ragweed/rasm/isa.rb +1046 -0
  20. data/lib/ragweed/rasm/util.rb +26 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +88 -0
  24. data/lib/ragweed/wrap32.rb +53 -0
  25. data/lib/ragweed/wrap32/debugging.rb +163 -0
  26. data/lib/ragweed/wrap32/device.rb +49 -0
  27. data/lib/ragweed/wrap32/event.rb +50 -0
  28. data/lib/ragweed/wrap32/hooks.rb +23 -0
  29. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  30. data/lib/ragweed/wrap32/process.rb +506 -0
  31. data/lib/ragweed/wrap32/process_token.rb +59 -0
  32. data/lib/ragweed/wrap32/thread_context.rb +208 -0
  33. data/lib/ragweed/wrap32/winx.rb +16 -0
  34. data/lib/ragweed/wrap32/wrap32.rb +526 -0
  35. data/lib/ragweed/wraposx.rb +53 -0
  36. data/lib/ragweed/wraposx/constants.rb +112 -0
  37. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  38. data/lib/ragweed/wraposx/region_info.rb +250 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +225 -0
  41. data/lib/ragweed/wraposx/wraposx.rb +376 -0
  42. data/lib/ragweed/wraptux.rb +53 -0
  43. data/lib/ragweed/wraptux/constants.rb +68 -0
  44. data/lib/ragweed/wraptux/threads.rb +7 -0
  45. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  46. data/spec/ragweed_spec.rb +7 -0
  47. data/spec/spec_helper.rb +16 -0
  48. data/tasks/ann.rake +80 -0
  49. data/tasks/bones.rake +20 -0
  50. data/tasks/gem.rake +201 -0
  51. data/tasks/git.rake +40 -0
  52. data/tasks/notes.rake +27 -0
  53. data/tasks/post_load.rake +34 -0
  54. data/tasks/rdoc.rake +51 -0
  55. data/tasks/rubyforge.rake +55 -0
  56. data/tasks/setup.rb +292 -0
  57. data/tasks/spec.rake +54 -0
  58. data/tasks/svn.rake +47 -0
  59. data/tasks/test.rake +40 -0
  60. data/tasks/zentest.rake +36 -0
  61. data/test/test_ragweed.rb +0 -0
  62. metadata +127 -0
@@ -0,0 +1,53 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/wraposx/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Wraposx
6
+
7
+ # :stopdoc:
8
+ VERSION = '0.1.6'
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility method used to require all files ending in .rb that lie in the
36
+ # directory below this file that has the same name as the filename passed
37
+ # in. Optionally, a specific _directory_ name can be passed in such that
38
+ # the _filename_ does not have to be equivalent to the directory.
39
+ #
40
+ def self.require_all_libs_relative_to( fname, dir = nil )
41
+ dir ||= ::File.basename(fname, '.*')
42
+ search_me = ::File.expand_path(
43
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
+
45
+ Dir.glob(search_me).sort.each {|rb| require rb}
46
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
47
+
48
+ end
49
+ end # module Ragweed::Wraposx
50
+
51
+ Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
52
+
53
+ # EOF
@@ -0,0 +1,112 @@
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
+ SIGHUP = 1 # hangup
28
+ SIGINT = 2 # interrupt
29
+ SIGQUIT = 3 # quit
30
+ SIGILL = 4 # illegal instruction (not reset when caught)
31
+ SIGTRAP = 5 # trace trap (not reset when caught)
32
+ SIGABRT = 6 # abort()
33
+ #if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
34
+ SIGPOLL = 7 # pollable event ([XSR] generated, not supported)
35
+ #else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
36
+ SIGIOT = SIGABRT # compatibility
37
+ SIGEMT = 7 # EMT instruction
38
+ #endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
39
+ SIGFPE = 8 # floating point exception
40
+ SIGKILL = 9 # kill (cannot be caught or ignored)
41
+ SIGBUS = 10 # bus error
42
+ SIGSEGV = 11 # segmentation violation
43
+ SIGSYS = 12 # bad argument to system call
44
+ SIGPIPE = 13 # write on a pipe with no one to read it
45
+ SIGALRM = 14 # alarm clock
46
+ SIGTERM = 15 # software termination signal from kill
47
+ SIGURG = 16 # urgent condition on IO channel
48
+ SIGSTOP = 17 # sendable stop signal not from tty
49
+ SIGTSTP = 18 # stop signal from tty
50
+ SIGCONT = 19 # continue a stopped process
51
+ SIGCHLD = 20 # to parent on child stop or exit
52
+ SIGTTIN = 21 # to readers pgrp upon background tty read
53
+ SIGTTOU = 22 # like TTIN for output if (tp->t_local&LTOSTOP)
54
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
55
+ SIGIO = 23 # input/output possible signal
56
+ #endif
57
+ SIGXCPU = 24 # exceeded CPU time limit
58
+ SIGXFSZ = 25 # exceeded file size limit
59
+ SIGVTALRM = 26 # virtual time alarm
60
+ SIGPROF = 27 # profiling time alarm
61
+ #if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
62
+ SIGWINCH = 28 # window size changes
63
+ SIGINFO = 29 # information request
64
+ #endif
65
+ SIGUSR1 = 30 # user defined signal 1
66
+ SIGUSR2 = 31 # user defined signal 2
67
+ end
68
+
69
+ module Ragweed::Wraposx::Wait
70
+ NOHANG = 0x01 # [XSI] no hang in wait/no child to reap
71
+ UNTRACED = 0x02 # [XSI] notify on stop, untraced child
72
+ EXITED = 0x04 # [XSI] Processes which have exitted
73
+ STOPPED = 0x08 # [XSI] Any child stopped by signal
74
+ CONTINUED = 0x10 # [XSI] Any child stopped then continued
75
+ NOWWAIT = 0x20 # [XSI] Leave process returned waitable
76
+ end
77
+
78
+ module Ragweed::Wraposx::Vm; end
79
+ module Ragweed::Wraposx::Vm::Prot
80
+ #vm_protect permission flags for memory spaces
81
+ READ = 0x1 #read permission
82
+ WRITE = 0x2 #write permission
83
+ EXECUTE = 0x4 #execute permission
84
+ NONE = 0x0 #no rights
85
+ ALL = 0x7 #all permissions
86
+ end
87
+
88
+ module Ragweed::Wraposx::Vm::Sm
89
+ # share_mode
90
+ SM_COW = 0x1
91
+ SM_PRIVATE = 0x2
92
+ SM_EMPTY = 0x3
93
+ SM_SHARED = 0x4
94
+ SM_TRUESHARED = 0x5
95
+ SM_PRIVATE_ALIASED = 0x6
96
+ SM_SHARED_ALIASED = 0x7
97
+ end
98
+
99
+ module Ragweed::Wraposx::Dl
100
+ RTLD_LAZY = 0x1
101
+ RTLD_NOW = 0x2
102
+ RTLD_LOCAL = 0x4
103
+ RTLD_GLOBAL = 0x8
104
+ RTLD_NOLOAD = 0x10
105
+ RTLD_NODELETE = 0x80
106
+ RTLD_FIRST = 0x100 #/* Mac OS X 10.5 and later */
107
+
108
+ # Special handle arguments for dlsym().
109
+ #define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */
110
+ #define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */
111
+ #define RTLD_SELF ((void *) -3) /* Search this and subsequent objects (Mac OS X 10.5 and later) */
112
+ 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
+ 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,250 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx; end
3
+ module Ragweed::Wraposx::Vm
4
+ # these are flavor arguments for vm_region
5
+ # more to be added as support for 64bit processes gets added
6
+ REGION_BASIC_INFO = 10
7
+ REGION_EXTENDED_INFO = 11
8
+ REGION_TOP_INFO = 12
9
+
10
+ # behavior identifiers
11
+ BEHAVIOR_DEFAULT = 0 # /* default */
12
+ BEHAVIOR_RANDOM = 1 # /* random */
13
+ BEHAVIOR_SEQUENTIAL = 2 # /* forward sequential */
14
+ BEHAVIOR_RSEQNTL = 3 # /* reverse sequential */
15
+ BEHAVIOR_WILLNEED = 4 # /* will need in near future */
16
+ BEHAVIOR_DONTNEED = 5 # /* dont need in near future */
17
+
18
+ #Virtual memory map inheritance values for vm_inherit_t
19
+ INHERIT_SHARE = 0 # /* share with child */
20
+ INHERIT_COPY = 1 # /* copy into child */
21
+ INHERIT_NONE = 2 # /* absent from child */
22
+ INHERIT_DONATE_COPY = 3 # /* copy and delete */
23
+ INHERIT_DEFAULT = 1 # VM_INHERIT_COPY
24
+ INHERIT_LAST_VALID = 2 # VM_INHERIT_NONE
25
+
26
+ #define VM_REGION_BASIC_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_basic_info_data_t)/sizeof(int)))
27
+ #define VM_REGION_EXTENDED_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_extended_info_data_t)/sizeof(int)))
28
+ #define VM_REGION_TOP_INFO_COUNT ((mach_msg_type_number_t) (sizeof(vm_region_top_info_data_t)/sizeof(int)))
29
+ FLAVORS = { REGION_BASIC_INFO => {:size => 30, :count => 8},
30
+ REGION_EXTENDED_INFO => {:size => 32, :count => 8},
31
+ REGION_TOP_INFO => {:size => 17,:count => 5}
32
+ }
33
+
34
+ module Pflags
35
+ READ = 0x1 #read permission
36
+ WRITE = 0x2 #write permission
37
+ EXECUTE = 0x4 #execute permission
38
+ end
39
+ end
40
+
41
+ # Memory region info base class.
42
+ # Currently Apple only supports the basic flavor. The other two flavors
43
+ # are included for completeness.
44
+ #
45
+ class Ragweed::Wraposx::RegionInfo
46
+ def initialize(str=nil)
47
+ refresh(str) if str
48
+ end
49
+
50
+ # (re)loads the data from str
51
+ def refresh(str)
52
+ fields = self.class.const_get :FIELDS
53
+ if str and not str.empty?
54
+ str.unpack(fields.map {|x| x[1]}.join("")).each_with_index do |val, i|
55
+ raise "i is nil" if i.nil?
56
+ instance_variable_set "@#{ fields[i][0] }".intern, val
57
+ end
58
+ end
59
+ end
60
+
61
+ def to_s
62
+ fields = self.class.const_get :FIELDS
63
+ fields.map {|f| send(f[0])}.pack(fields.map {|x| x[1]}.join(""))
64
+ end
65
+
66
+ def self.get(t, a, flavor)
67
+ self.new(Ragweed::Wraposx::vm_region_raw(t, a, flavor))
68
+ end
69
+
70
+ def get(t, a)
71
+ refresh(Ragweed::Wraposx::vm_region_raw(t, a, self.class.const_get(:FLAVOR)))
72
+ end
73
+
74
+ def inspect
75
+ fields = self.class.const_get(:FIELDS)
76
+ body = lambda do
77
+ fields.map do |f|
78
+ "#{f[0]}=#{send(f[0]).to_s}"
79
+ end.join(", ")
80
+ end
81
+ "#<#{self.class.name.split("::").last} #{body.call}>"
82
+ end
83
+
84
+ def dump(&block)
85
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
86
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
87
+
88
+ string =<<EOM
89
+ -----------------------------------------------------------------------
90
+ INFO:
91
+ protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
92
+ max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
93
+ inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
94
+ shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
95
+ reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
96
+ offset: #{self.offset.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.offset)}
97
+ behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
98
+ user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
99
+ address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
100
+ size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
101
+ EOM
102
+ end
103
+ end
104
+
105
+ class Ragweed::Wraposx::RegionBasicInfo < Ragweed::Wraposx::RegionInfo
106
+
107
+ FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO
108
+
109
+ (FIELDS = [ [:protection, "i"], # The current protection for the region.
110
+ [:max_protection, "i"], # The maximum protection allowed for the region.
111
+ [:inheritance, "I"], # The inheritance attribute for the region.
112
+ [:shared, "I"], # Shared indicator. If true, the region is shared by another task. If false, the region is not shared.
113
+ [:reserved, "I"], # If true the region is protected from random allocation.
114
+ [:offset, "L"], # The region's offset into the memory object. The region begins at this offset.
115
+ [:behavior, "i"], # Expected reference pattern for the memory.
116
+ [:user_wired_count, "S"],
117
+ [:address, "L"], # The returned address
118
+ [:size, "I"] # size of memory region returned
119
+ ]).each {|x| attr_accessor x[0]}
120
+
121
+ def dump(&block)
122
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
123
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
124
+
125
+ string =<<EOM
126
+ -----------------------------------------------------------------------
127
+ INFO:
128
+ protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
129
+ max_protection: #{self.max_protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.max_protection)}
130
+ inheritance: #{self.inheritance.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.inheritance)}
131
+ shared: #{self.shared.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared)}
132
+ reserved: #{self.reserved.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.reserved)}
133
+ offset: #{self.offset.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.offset)}
134
+ behavior: #{self.behavior.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.behavior)}
135
+ user_wired_count: #{self.user_wired_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_wired_count)}
136
+ address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
137
+ size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
138
+ EOM
139
+ end
140
+
141
+ def self.get(t, a)
142
+ self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
143
+ end
144
+ end
145
+
146
+ class Ragweed::Wraposx::RegionExtendedInfo < Ragweed::Wraposx::RegionInfo
147
+
148
+ FLAVOR = Ragweed::Wraposx::Vm::REGION_EXTENDED_INFO
149
+ (FIELDS = [ [:protection, "i"],
150
+ [:user_tag, "I"],
151
+ [:pages_resident, "I"],
152
+ [:pages_shared_now_private, "I"],
153
+ [:pages_swapped_out, "I"],
154
+ [:pages_dirtied, "I"],
155
+ [:ref_count, "I"],
156
+ [:shadow_depth, "S"],
157
+ [:external_pager, "C"],
158
+ [:share_mode, "C"],
159
+ [:address, "L"],
160
+ [:size, "I"] ]).each {|x| attr_accessor x[0]}
161
+
162
+ def dump(&block)
163
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
164
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
165
+
166
+ string =<<EOM
167
+ -----------------------------------------------------------------------
168
+ INFO:
169
+ protection: #{self.protection.to_s(2).rjust(8, "0")} #{Ragweed::Wraposx::Vm::Pflags.flag_dump(self.protection)}
170
+ user_tag: #{self.user_tag.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.user_tag)}
171
+ pages_resident: #{self.pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_resident)}
172
+ pages_shared_now_private: #{self.pages_shared_now_private.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_shared_now_private)}
173
+ pages_swapped_out: #{self.pages_swapped_out.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_swapped_out)}
174
+ pages_dirtied: #{self.pages_dirtied.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.pages_dirtied)}
175
+ ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
176
+ shadow_depth: #{self.shadow_depth.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shadow_depth)}
177
+ external_pager: #{self.external_pager.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.external_pager)}
178
+ share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
179
+ address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
180
+ size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
181
+ EOM
182
+ end
183
+
184
+ def self.get(t, a)
185
+ self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
186
+ end
187
+ end
188
+
189
+ class Ragweed::Wraposx::RegionTopInfo < Ragweed::Wraposx::RegionInfo
190
+
191
+ FLAVOR = Ragweed::Wraposx::Vm::REGION_TOP_INFO
192
+
193
+ (FIELDS = [ [:obj_id, "I"],
194
+ [:ref_count, "I"],
195
+ [:private_pages_resident, "I"],
196
+ [:shared_pages_resident, "I"],
197
+ [:share_mode, "C"],
198
+ [:address, "L"],
199
+ [:size, "I"]]).each {|x| attr_accessor x[0]}
200
+
201
+ def dump(&block)
202
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
203
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
204
+
205
+ string =<<EOM
206
+ -----------------------------------------------------------------------
207
+ INFO:
208
+ obj_id: #{self.obj_id.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.obj_id)}
209
+ ref_count: #{self.ref_count.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ref_count)}
210
+ private_pages_resident: #{self.private_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.private_pages_resident)}
211
+ shared_pages_resident: #{self.shared_pages_resident.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.shared_pages_resident)}
212
+ share_mode: #{self.share_mode.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.share_mode)}
213
+ address: #{self.address.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.address)}
214
+ size: #{self.size.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.size)}
215
+ EOM
216
+ end
217
+
218
+ def self.get(t, a)
219
+ self.new(Ragweed::Wraposx::vm_region_raw(t, a, FLAVOR))
220
+ end
221
+ end
222
+
223
+ module Ragweed::Wraposx
224
+ class << self
225
+
226
+ # Returns a string containing the memory region information for task
227
+ # at address.
228
+ # Currently Apple only supports the basic flavor. The other two flavors
229
+ # are included for completeness.
230
+ #
231
+ # kern_return_t vm_region
232
+ # (vm_task_t target_task,
233
+ # vm_address_t address,
234
+ # vm_size_t size,
235
+ # vm_region_flavor_t flavor,
236
+ # vm_region_info_t info,
237
+ # mach_msg_type_number_t info_count,
238
+ # memory_object_name_t object_name);
239
+ def vm_region_raw(task, address, flavor)
240
+ info = ("\x00"*64).to_ptr
241
+ count = ([Vm::FLAVORS[flavor][:count]].pack("I_")).to_ptr
242
+ address = ([address].pack("L_")).to_ptr
243
+ objn = ([0].pack("I_")).to_ptr
244
+ sz = ("\x00"*SIZEOFINT).to_ptr
245
+ r = CALLS["libc!vm_region:IPPIPPP=I"].call(task, address, sz, flavor, info, count, objn).first
246
+ raise KernelCallError.new(:vm_region, r) if r != 0
247
+ return "#{info.to_s(Vm::FLAVORS[flavor][:size])}#{address.to_s(SIZEOFLONG)}#{sz.to_s(SIZEOFINT)}"
248
+ end
249
+ end
250
+ end