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,160 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx::ThreadInfo
3
+ # info interfaces
4
+ BASIC_INFO = 3 #basic information
5
+
6
+ # following are obsolete interfaces
7
+ # according to the source @ fxr they still work except FIFO
8
+ SCHED_TIMESHARE_INFO = 10
9
+ SCHED_RR_INFO = 11
10
+ # SCHED_FIFO_INFO = 12
11
+
12
+ module State
13
+ #Thread run states
14
+ RUNNING = 1 #/* thread is running normally */
15
+ STOPPED = 2 #/* thread is stopped */
16
+ WAITING = 3 #/* thread is waiting normally */
17
+ UNINTERRUPTIBLE = 4 #/* thread is in an uninterruptible wait */
18
+ HALTED = 5 #/* thread is halted at a clean point */
19
+ end
20
+
21
+ # struct thread_basic_info
22
+ # {
23
+ # time_value_t user_time;
24
+ # time_value_t system_time;
25
+ # integer_t cpu_usage;
26
+ # policy_t policy;
27
+ # integer_t run_state;
28
+ # integer_t flags;
29
+ # integer_t suspend_count;
30
+ # integer_t sleep_time;
31
+ # };
32
+ class Basic < FFI::Struct
33
+ include Ragweed::FFIStructInclude
34
+ module Flags
35
+ #Thread flags (flags field).
36
+ SWAPPED = 0x1 #/* thread is swapped out */
37
+ IDLE = 0x2 #/* thread is an idle thread */
38
+ end
39
+
40
+ FLAVOR = Ragweed::Wraposx::ThreadInfo::BASIC_INFO
41
+ layout :user_time, Ragweed::Wraposx::TimeValue,
42
+ :system_time, Ragweed::Wraposx::TimeValue,
43
+ :cpu_usage, :int,
44
+ :policy, Ragweed::Wraposx::Libc.find_type(:policy_t),
45
+ :run_state, :int,
46
+ :flags, :int,
47
+ :suspend_count, :int,
48
+ :sleep_time, :int
49
+
50
+ def dump(&block)
51
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
52
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
53
+
54
+ string =<<EOM
55
+ -----------------------------------------------------------------------
56
+ INFO:
57
+ user_time: #{self.user_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.user_time)}
58
+ system_time: #{self.system_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.system_time)}
59
+ cpu_usage: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cpu_usage)}
60
+ policy: #{self.policy.to_s.rjust(8, "0")} #{maybe_hex.call(self.policy)}
61
+ run_state: #{self.run_state.to_s.rjust(8, "0")} #{maybe_hex.call(self.run_state)}
62
+ suspend_count: #{self.suspend_count.to_s.rjust(8, "0")} #{maybe_hex.call(self.suspend_count)}
63
+ sleep_time: #{self.sleep_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.sleep_time)}
64
+ flags: #{self.flags.to_s(2).rjust(32, "0")} #{Flags.flag_dump(self.flags)}
65
+ EOM
66
+ end
67
+ end
68
+
69
+ # struct policy_timeshare_info
70
+ # {
71
+ # int max_priority;
72
+ # int base_priority;
73
+ # int cur_priority;
74
+ # boolean_t depressed;
75
+ # int depress_priority;
76
+ # };
77
+ class SchedTimeshare < FFI::Struct
78
+ include Ragweed::FFIStructInclude
79
+ layout :max_priority, :int,
80
+ :base_priority, :int,
81
+ :cur_priority, :int,
82
+ :depress_priority, :int
83
+
84
+ def dump(&block)
85
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
86
+
87
+ string =<<EOM
88
+ -----------------------------------------------------------------------
89
+ Timeshare Info:
90
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
91
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
92
+ cur_priority: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cur_priority)}
93
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
94
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
95
+ EOM
96
+ end
97
+ end
98
+
99
+ # struct policy_rr_info
100
+ # {
101
+ # int max_priority;
102
+ # int base_priority;
103
+ # int quantum;
104
+ # boolean_t depressed;
105
+ # int depress_priority;
106
+ # };
107
+ class SchedRr < FFI::Struct
108
+ include Ragweed::FFIStructInclude
109
+ layout :max_priority, :int,
110
+ :base_priority, :int,
111
+ :quantum, :int,
112
+ :depressed, Ragweed::Wraposx::Libc.find_type(:boolean_t),
113
+ :depress_priority, :int
114
+
115
+ def dump(&block)
116
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
117
+
118
+ string =<<EOM
119
+ -----------------------------------------------------------------------
120
+ Round Robin Info:
121
+ max_priority: #{self.max_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.max_priority)}
122
+ base_priority: #{self.base_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.base_priority)}
123
+ quantum: #{self.quantum.to_s.rjust(8, "0")} #{maybe_hex.call(self.quantum)}
124
+ depressed: #{(!self.depressed.zero?).to_s.rjust(8, " ")} #{maybe_hex.call(self.depressed)}
125
+ depress_priority: #{self.depress_priority.to_s.rjust(8, "0")} #{maybe_hex.call(self.depressed_priority)}
126
+ EOM
127
+ end
128
+ end
129
+
130
+ FLAVORS = {
131
+ # define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
132
+ BASIC_INFO => {:size => 30, :count => 10, :class => Basic},
133
+ # define POLICY_TIMESHARE_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_timeshare_info)/sizeof(integer_t)))
134
+ SCHED_TIMESHARE_INFO => {:size => 20, :count => 5, :class => SchedTimeshare},
135
+ # define POLICY_RR_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_rr_info)/sizeof(integer_t)))
136
+ SCHED_RR_INFO => {:size => 20,:count => 5, :class => SchedRr},
137
+ # define POLICY_FIFO_INFO_COUNT ((mach_msg_type_number_t)(sizeof(struct policy_fifo_info)/sizeof(integer_t)))
138
+ # SCHED_FIFO_INFO => {:size => 16,:count => 4} # immediately returns KERNEL_INVALID_POLICY on osx
139
+ }
140
+ end
141
+
142
+ module Ragweed::Wraposx
143
+ class << self
144
+
145
+ # Returns the packed string representation of the thread_info_t struct for later parsing.
146
+ #
147
+ # kern_return_t thread_info
148
+ # (thread_act_t target_thread,
149
+ # thread_flavor_t flavor,
150
+ # thread_info_t thread_info,
151
+ # mach_msg_type_number_t thread_info_count);
152
+ def thread_info(thread, flavor)
153
+ info = FFI::MemoryPointer.new(ThreadInfo::FLAVORS[flavor][:class], 1)
154
+ count = FFI::MemoryPointer.new(:int, 1).write_int(ThreadInfo::FLAVORS[flavor][:count])
155
+ r = Libc.thread_info(thread, flavor, info, count)
156
+ raise KernelCallError.new(r) if r != 0
157
+ ThreadInfo::FLAVORS[flavor][:class].new info
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,121 @@
1
+ module Ragweed; end
2
+ module Ragweed::Wraposx::ThreadState
3
+ #Thread run states
4
+ RUNNING = 1 #/* thread is running normally */
5
+ STOPPED = 2 #/* thread is stopped */
6
+ WAITING = 3 #/* thread is waiting normally */
7
+ UNINTERRUPTIBLE = 4 #/* thread is in an uninterruptible wait */
8
+ HALTED = 5 #/* thread is halted at a clean point */
9
+ end
10
+
11
+ module Ragweed::Wraposx::TFlags
12
+ #Thread flags (flags field).
13
+ SWAPPED = 0x1 #/* thread is swapped out */
14
+ IDLE = 0x2 #/* thread is an idle thread */
15
+ end
16
+
17
+ class Ragweed::Wraposx::ThreadInfo
18
+ include Ragweed
19
+ attr_accessor :user_time
20
+ attr_accessor :system_time
21
+ (FIELDS = [ [:user_time_s, "I"],
22
+ [:user_time_us, "I"],
23
+ [:system_time_s, "I"],
24
+ [:system_time_us, "I"],
25
+ [:cpu_usage, "I"],
26
+ [:policy, "I"],
27
+ [:run_state, "I"],
28
+ [:flags, "I"],
29
+ [:suspend_count, "I"],
30
+ [:sleep_time, "I"]]).each {|x| attr_accessor x[0]}
31
+
32
+ def initialize(str=nil)
33
+ refresh(str) if str
34
+ end
35
+
36
+ #(re)loads the data from str
37
+ def refresh(str)
38
+ if str and not str.empty?
39
+ str.unpack(FIELDS.map {|x| x[1]}.join("")).each_with_index do |val, i|
40
+ raise "i is nil" if i.nil?
41
+ instance_variable_set "@#{ FIELDS[i][0] }".intern, val
42
+ end
43
+ end
44
+ @user_time = @user_time_s + (@user_time_us/1000000.0)
45
+ @system_time = @system_time_s + (@system_time_us/1000000.0)
46
+ end
47
+
48
+ def to_s
49
+ FIELDS.map {|f| send(f[0])}.pack(FIELDS.map {|x| x[1]}.join(""))
50
+ end
51
+
52
+ def self.get(t)
53
+ self.new(Wraposx::thread_info_raw(t))
54
+ end
55
+
56
+ def get(t)
57
+ refresh(Wraposx::thread_info_raw(t))
58
+ end
59
+
60
+ def inspect
61
+ body = lambda do
62
+ FIELDS.map do |f|
63
+ "#{f[0]}=#{send(f[0]).to_s}"
64
+ end.join(", ")
65
+ end
66
+ "#<ThreadInfo #{body.call}>"
67
+ end
68
+
69
+ def dump(&block)
70
+ maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
71
+ maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
72
+
73
+ string =<<EOM
74
+ -----------------------------------------------------------------------
75
+ INFO:
76
+ user_time: #{self.user_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.user_time)}
77
+ system_time: #{self.system_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.system_time)}
78
+ cpu_usage: #{self.cpu_usage.to_s.rjust(8, "0")} #{maybe_hex.call(self.cpu_usage)}
79
+ policy: #{self.policy.to_s.rjust(8, "0")} #{maybe_hex.call(self.policy)}
80
+ run_state: #{self.run_state.to_s.rjust(8, "0")} #{maybe_hex.call(self.run_state)}
81
+ suspend_count: #{self.suspend_count.to_s.rjust(8, "0")} #{maybe_hex.call(self.suspend_count)}
82
+ sleep_time: #{self.sleep_time.to_s.rjust(8, "0")} #{maybe_hex.call(self.sleep_time)}
83
+ flags: #{self.flags.to_s(2).rjust(32, "0")} #{Wraposx::TFlags.flag_dump(self.flags)}
84
+ EOM
85
+ end
86
+ end
87
+
88
+ module Ragweed::Wraposx
89
+
90
+ # FIXME - constants should be under separate sub-modules
91
+ # XXX - implement more thread info flavors (if possible)
92
+ # XXX - move to class based implementation a la region_info
93
+ # info interfaces
94
+ THREAD_BASIC_INFO = 3 #basic information
95
+
96
+ # following are obsolete interfaces
97
+ THREAD_SCHED_TIMESHARE_INFO = 10
98
+ THREAD_SCHED_RR_INFO = 11
99
+ THREAD_SCHED_FIFO_INFO = 12
100
+
101
+ # define THREAD_BASIC_INFO_COUNT ((mach_msg_type_number_t)(sizeof(thread_basic_info_data_t) / sizeof(natural_t)))
102
+ # the two time fields are each two ints
103
+ THREAD_BASIC_INFO_COUNT = 10
104
+
105
+ class << self
106
+
107
+ # Returns the packed string representation of the thread_info_t struct for later parsing.
108
+ # kern_return_t thread_info
109
+ # (thread_act_t target_thread,
110
+ # thread_flavor_t flavor,
111
+ # thread_info_t thread_info,
112
+ # mach_msg_type_number_t thread_info_count);
113
+ def thread_info_raw(thread)
114
+ info = ("\x00"*1024).to_ptr
115
+ count = ([THREAD_BASIC_INFO_COUNT].pack("I_")).to_ptr
116
+ r = CALLS["libc!thread_info:IIPP=I"].call(thread,THREAD_BASIC_INFO,info,count).first
117
+ raise KernelCallError.new(:thread_info, r) if r != 0
118
+ return info.to_s(SIZEOFINT*THREAD_BASIC_INFO_COUNT)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,356 @@
1
+ require 'ffi'
2
+
3
+ module Ragweed; end
4
+ module Ragweed::Wraposx
5
+
6
+ module Libc
7
+ extend FFI::Library
8
+ ffi_lib FFI::Library::LIBC
9
+ typedef :int, :kern_return_t
10
+
11
+ typedef :ulong_long, :memory_object_offset_t
12
+ typedef :uint, :vm_inherit_t
13
+ typedef :uint, :natural_t
14
+ typedef :natural_t, :mach_msg_type_number_t
15
+ typedef :natural_t, :mach_port_name_t
16
+ typedef :mach_port_name_t, :mach_port_t
17
+ typedef :mach_port_t, :vm_map_t
18
+ typedef :mach_port_t, :task_t
19
+ typedef :mach_port_t, :thread_act_t
20
+ typedef :int, :vm_region_flavor_t
21
+ typedef :int, :vm_prot_t
22
+ typedef :int, :vm_behavior_t
23
+ typedef :int, :policy_t
24
+ typedef :int, :boolean_t
25
+ typedef :int, :thread_state_flavor_t
26
+ case FFI::Platform::LONG_SIZE
27
+ when 64
28
+ # ifdef __LP64__
29
+ typedef :uintptr_t, :vm_size_t
30
+ typedef :uintptr_t, :vm_offset_t
31
+ when 32
32
+ # else /* __LP64__ */
33
+ typedef :natural_t, :vm_size_t
34
+ typedef :natural_t, :vm_offset_t
35
+ else
36
+ raise "Unsupported Platform"
37
+ end
38
+
39
+ typedef :vm_offset_t, :vm_address_t
40
+
41
+ attach_function :getpid, [], :pid_t
42
+ attach_function :ptrace, [:int, :pid_t, :ulong, :int], :int
43
+ attach_function :wait, [:pointer], :pid_t
44
+ attach_function :waitpid, [:pid_t, :pointer, :int], :pid_t
45
+ attach_function :mach_task_self, [], :mach_port_t
46
+ attach_function :task_for_pid, [:mach_port_name_t, :int, :pointer], :kern_return_t
47
+ attach_function :task_threads, [:task_t, :pointer, :pointer], :kern_return_t
48
+ attach_function :kill, [:pid_t, :int], :int
49
+ attach_function :vm_read_overwrite, [:vm_map_t, :vm_address_t, :vm_size_t, :vm_address_t, :pointer], :kern_return_t
50
+ attach_function :vm_write, [:vm_map_t, :vm_address_t, :vm_offset_t, :mach_msg_type_number_t], :kern_return_t
51
+ attach_function :vm_protect, [:vm_map_t, :vm_address_t, :vm_size_t, :boolean_t, :vm_prot_t], :kern_return_t
52
+ attach_function :vm_allocate, [:vm_map_t, :pointer, :vm_size_t, :int], :kern_return_t
53
+ attach_function :vm_deallocate, [:vm_map_t, :vm_address_t, :vm_size_t], :kern_return_t
54
+ attach_function :thread_resume, [:thread_act_t], :kern_return_t
55
+ attach_function :thread_suspend, [:thread_act_t], :kern_return_t
56
+ attach_function :task_suspend, [:int], :kern_return_t
57
+ attach_function :task_resume, [:int], :kern_return_t
58
+ attach_function :sysctl, [:pointer, :int, :pointer, :pointer, :pointer, :int], :int
59
+ attach_function :execv, [:string, :pointer], :int
60
+ end
61
+
62
+ class << self
63
+
64
+ # pid_t
65
+ # getpid(void);
66
+ #
67
+ # see also getpid(2)
68
+ def getpid
69
+ Libc.getpid
70
+ end
71
+
72
+ # Apple's ptrace is fairly gimped. The memory read and write functionality has been
73
+ # removed. We will be using mach kernel calls for that. see vm_read and vm_write.
74
+ # for details on ptrace and the process for the Wraposx/debuggerosx port see:
75
+ # http://www.matasano.com/log/1100/what-ive-been-doing-on-my-summer-vacation-or-it-has-to-work-otherwise-gdb-wouldnt/
76
+ #
77
+ #int
78
+ #ptrace(int request, pid_t pid, caddr_t addr, int data);
79
+ #
80
+ # see also ptrace(2)
81
+ def ptrace(request, pid, addr, data)
82
+ FFI.errno = 0
83
+ r = Libc.ptrace(request, pid, addr, data)
84
+ raise SystemCallError.new("ptrace", FFI.errno) if r == -1 and FFI.errno != 0
85
+ [r, data]
86
+ end
87
+
88
+ # ptrace(PT_TRACE_ME, ...)
89
+ def pt_trace_me pid
90
+ ptrace(Ragweed::Wraposx::Ptrace::TRACE_ME, pid, nil, nil).first
91
+ end
92
+
93
+ # ptrace(PT_DENY_ATTACH, ... )
94
+ def pt_deny_attach pid
95
+ ptrace(Ragweed::Wraposx::Ptrace::DENY_ATTACH, pid, nil, nil).first
96
+ end
97
+
98
+ # ptrace(PT_CONTINUE, pid, addr, signal)
99
+ def pt_continue pid, addr = 1, sig = 0
100
+ ptrace(Ragweed::Wraposx::Ptrace::CONTINUE, pid, addr, sig).first
101
+ end
102
+
103
+ # ptrace(PT_STEP, pid, addr, signal)
104
+ def pt_step pid, addr = 1, sig = 0
105
+ ptrace(Ragweed::Wraposx::Ptrace::STEP, pid, addr, sig).first
106
+ end
107
+
108
+ # ptrace(PT_KILL, ... )
109
+ def pt_kill pid
110
+ ptrace(Ragweed::Wraposx::Ptrace::KILL, pid, nil, nil).first
111
+ end
112
+
113
+ # ptrace(PT_ATTACH, ... )
114
+ def pt_attach pid
115
+ ptrace(Ragweed::Wraposx::Ptrace::ATTACH, pid, nil, nil).first
116
+ end
117
+
118
+ # ptrace(PT_DETACH, ... )
119
+ def pt_detach pid
120
+ ptrace(Ragweed::Wraposx::Ptrace::DETACH, pid, nil, nil).first
121
+ end
122
+
123
+ # Originally coded for use in debuggerosx but I've switched to waitpid for
124
+ # usability and debugging purposes.
125
+ #
126
+ # Returns status of child when child recieves a signal.
127
+ #
128
+ # pid_t
129
+ # wait(int *stat_loc);
130
+ #
131
+ # see also wait(2)
132
+ def wait
133
+ stat = FFI::MemoryPointer.new :int, 1
134
+ FFI.errno = 0
135
+ pid = Libc.wait stat
136
+ raise SystemCallError.new "wait", FFI.errno if pid == -1
137
+ [pid, stat.read_int]
138
+ end
139
+
140
+ # The wait used in debuggerosx.
141
+ # opt is an OR of the options to be used.
142
+ #
143
+ # Returns an array. The first element is the pid of the child process
144
+ # as returned by the waitpid system call. The second, the status as
145
+ # an integer of that pid.
146
+ #
147
+ # pid_t
148
+ # waitpid(pid_t pid, int *stat_loc, int options);
149
+ #
150
+ # see also wait(2)
151
+ def waitpid pid, opts = 0
152
+ stat = FFI::MemoryPointer.new :int, 1
153
+ FFI.errno = 0
154
+ r = Libc.waitpid(pid, stat, opts)
155
+ raise SystemCallError.new "waitpid", FFI.errno if r == -1
156
+ [r, stat.read_int]
157
+ end
158
+
159
+ # From docs at http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html
160
+ # Returns send rights to the task's kernel port.
161
+ #
162
+ # mach_port_t
163
+ # mach_task_self(void)
164
+ #
165
+ # There is no man page for this call.
166
+ def mach_task_self
167
+ Libc.mach_task_self
168
+ end
169
+
170
+ # Requires sudo to use as of 10.5 or 10.4.11(ish)
171
+ # Returns the task id for a process.
172
+ #
173
+ # kern_return_t task_for_pid(
174
+ # mach_port_name_t target_tport,
175
+ # int pid,
176
+ # mach_port_name_t *t);
177
+ #
178
+ # There is no man page for this call.
179
+ def task_for_pid(pid, target=nil)
180
+ target ||= mach_task_self
181
+ port = FFI::MemoryPointer.new :int, 1
182
+ r = Libc.task_for_pid(target, pid, port)
183
+ raise KernelCallError.new(:task_for_pid, r) if r != 0
184
+ port.read_int
185
+ end
186
+
187
+ # Returns an Array of thread IDs for the given task
188
+ #
189
+ # kern_return_t task_threads
190
+ # (task_t task,
191
+ # thread_act_port_array_t thread_list,
192
+ # mach_msg_type_number_t* thread_count);
193
+ #
194
+ #There is no man page for this funtion.
195
+ def task_threads(port)
196
+ threads = FFI::MemoryPointer.new :int, 1
197
+ count = FFI::MemoryPointer.new :int, 1
198
+ r = Libc.task_threads(port, threads, count)
199
+ raise KernelCallError.new(:task_threads, r) if r != 0
200
+ threads.read_array_of_int(count.read_int)
201
+ end
202
+
203
+ # Decrement the target tasks suspend count
204
+ # kern_return_t task_resume
205
+ # (task_t task);
206
+ def task_resume(task)
207
+ r = Libc.task_resume(task)
208
+ raise KernelCallError.new(r) if r != 0
209
+ r
210
+ end
211
+
212
+ # Increment the target tasks suspend count
213
+ # kern_return_t task_suspend
214
+ # (task_t task);
215
+ def task_suspend(task)
216
+ r = Libc.task_suspend(task)
217
+ raise KernelCallError.new(r) if r != 0
218
+ end
219
+
220
+ # Sends a signal to a process
221
+ #
222
+ # int
223
+ # kill(pid_t pid, int sig);
224
+ #
225
+ # See kill(2)
226
+ def kill(pid, sig)
227
+ FFI::errno = 0
228
+ r = Libc.kill(pid, sig)
229
+ raise SystemCallError.new "kill", FFI::errno if r != 0
230
+ end
231
+
232
+ # Reads sz bytes from task's address space starting at addr.
233
+ #
234
+ # kern_return_t vm_read_overwrite
235
+ # (vm_task_t target_task,
236
+ # vm_address_t address,
237
+ # vm_size_t size,
238
+ # vm_address_t *data_out,
239
+ # mach_msg_type_number_t *data_size);
240
+ #
241
+ # There is no man page for this function.
242
+ def vm_read(task, addr, sz=256)
243
+ buf = FFI::MemoryPointer.new(sz)
244
+ len = FFI::MemoryPointer(sz.to_l32)
245
+ r = Libc.vm_read_overwrite(task, addr, sz, buf, len)
246
+ raise KernelCallError.new(:vm_read, r) if r != 0
247
+ return buf.to_str(len.to_str(4).to_l32)
248
+ end
249
+
250
+ # Writes val to task's memory space at address addr.
251
+ # It is necessary for val.size to report the size of val in bytes
252
+ #
253
+ # kern_return_t vm_write
254
+ # (vm_task_t target_task,
255
+ # vm_address_t address,
256
+ # pointer_t data,
257
+ # mach_msg_type_number_t data_count);
258
+ #
259
+ # There is no man page for this function.
260
+ def vm_write(task, addr, val)
261
+ val = FFI::MemoryPointer.new
262
+ r = Libc.vm_write(task, addr, val, val.size)
263
+ raise KernelCallError.new(:vm_write, r) if r != 0
264
+ return nil
265
+ end
266
+
267
+ # Changes the protection state beginning at addr for size bytes to the mask prot.
268
+ # If setmax is true this will set the maximum permissions, otherwise it will set FIXME
269
+ #
270
+ # kern_return_t vm_protect
271
+ # (vm_task_t target_task,
272
+ # vm_address_t address,
273
+ # vm_size_t size,
274
+ # boolean_t set_maximum,
275
+ # vm_prot_t new_protection);
276
+ #
277
+ # There is no man page for this function.
278
+ def vm_protect(task, addr, size, setmax, prot)
279
+ setmax = setmax ? 1 : 0
280
+ r = Libc.vm_protect(task, addr, size, setmax, prot)
281
+ raise KernelCallError.new(:vm_protect, r) if r != 0
282
+ return nil
283
+ end
284
+
285
+ # Allocates a page in the memory space of the target task.
286
+ #
287
+ # kern_return_t vm_allocate
288
+ # (vm_task_t target_task,
289
+ # vm_address_t address,
290
+ # vm_size_t size,
291
+ # boolean_t anywhere);
292
+ #
293
+ def vm_allocate(task, address, size, anywhere)
294
+ addr = FFI::MemoryPointer.new :int, 1
295
+ addr.write_int(address)
296
+ anywhere = anywhere ? 1 : 0
297
+ r = Libc.vm_allocate(task, addr, size, anywhere)
298
+ raise KernelCallError.new(r) if r != 0
299
+ addr.address
300
+ end
301
+
302
+ # deallocates a page in the memoryspace of target task.
303
+ #
304
+ # kern_return_t vm_deallocate
305
+ # (vm_task_t target_task,
306
+ # vm_address_t address,
307
+ # vm_size_t size);
308
+ #
309
+ def vm_deallocate(task, address, size)
310
+ addr = FFI::MemoryPointer.new :int, 1
311
+ addr.write_int(address)
312
+ r = Libc.vm_deallocate(task, addr, size)
313
+ raise KernelCallError.new(r) if r != 0
314
+ end
315
+
316
+ # Resumes a suspended thread by id.
317
+ #
318
+ # kern_return_t thread_resume
319
+ # (thread_act_t target_thread);
320
+ #
321
+ # There is no man page for this function.
322
+ def thread_resume(thread)
323
+ r = Libc.thread_resume(thread)
324
+ raise KernelCallError.new(:thread_resume, r) if r != 0
325
+ end
326
+
327
+ # Suspends a thread by id.
328
+ #
329
+ # kern_return_t thread_suspend
330
+ # (thread_act_t target_thread);
331
+ #
332
+ # There is no man page for this function.
333
+ def thread_suspend(thread)
334
+ r = Libc.thread_suspend(thread)
335
+ raise KernelCallError.new(:thread_suspend, r) if r != 0
336
+ end
337
+
338
+ # Changes execution to file in path with *args as though called from command line.
339
+ #
340
+ # int
341
+ # execv(const char *path, char *const argv[]);
342
+ def execv(path, *args)
343
+ FFI.errno = 0
344
+ args.flatten!
345
+ argv = FFI::MemoryPointer.new(:pointer, args.size + 1)
346
+ args.each_with_index do |arg, i|
347
+ argv[i].put_pointer(0, FFI::MemoryPointer.from_string(arg.to_s))
348
+ end
349
+ argv[args.size].put_pointer(0, nil)
350
+
351
+ r = Libc.execv(path, argv)
352
+ # if this ever returns, there's been an error
353
+ raise SystemCallError(:execv, FFI.errno)
354
+ end
355
+ end
356
+ end
@@ -0,0 +1,60 @@
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 = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
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 function to load utility classes and extensions
36
+ def self.require_utils
37
+ %w{utils}.each{|r| require self.libpath(r)+'.rb'}
38
+ end
39
+
40
+ # Utility method used to require all files ending in .rb that lie in the
41
+ # directory below this file that has the same name as the filename passed
42
+ # in. Optionally, a specific _directory_ name can be passed in such that
43
+ # the _filename_ does not have to be equivalent to the directory.
44
+ #
45
+ def self.require_all_libs_relative_to( fname, dir = nil )
46
+ self.require_utils
47
+ dir ||= ::File.basename(fname, '.*')
48
+ search_me = ::File.expand_path(
49
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
50
+
51
+ Dir.glob(search_me).reject{|rb| rb =~ /#{__FILE__}/}.sort.each {|rb| require rb}
52
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
53
+
54
+ end
55
+ end # module Ragweed::Wraposx
56
+
57
+ require 'ragweed/wraposx/wraposx'
58
+ Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
59
+
60
+ # EOF