ragweed 0.1.7.3 → 0.2.0.pre1
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.
- data/README.rdoc +33 -8
- data/Rakefile +80 -23
- data/VERSION +1 -0
- data/examples/hittracertux.rb +2 -6
- data/examples/hook_notepad.rb +1 -1
- data/examples/tux-example.rb +3 -2
- data/lib/.DS_Store +0 -0
- data/lib/ragweed/debugger32.rb +188 -145
- data/lib/ragweed/debuggerosx.rb +13 -13
- data/lib/ragweed/debuggertux.rb +267 -140
- data/lib/ragweed/rasm.rb +1 -1
- data/lib/ragweed/wrap32/debugging.rb +184 -64
- data/lib/ragweed/wrap32/hooks.rb +27 -11
- data/lib/ragweed/wrap32/process.rb +114 -7
- data/lib/ragweed/wrap32/process_token.rb +23 -7
- data/lib/ragweed/wrap32/thread_context.rb +100 -166
- data/lib/ragweed/wrap32/wrap32.rb +127 -72
- data/lib/ragweed/wrap32.rb +1 -1
- data/lib/ragweed/wraposx/constants.rb +1 -9
- data/lib/ragweed/wraposx/region_info.rb +209 -188
- data/lib/ragweed/wraposx/structs.rb +102 -0
- data/lib/ragweed/wraposx/thread_context.rb +636 -159
- data/lib/ragweed/wraposx/thread_info.rb +40 -107
- data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
- data/lib/ragweed/wraposx/wraposx.rb +154 -231
- data/lib/ragweed/wraposx.rb +2 -1
- data/lib/ragweed/wraptux/constants.rb +46 -22
- data/lib/ragweed/wraptux/struct_helpers.rb +25 -0
- data/lib/ragweed/wraptux/threads.rb +0 -0
- data/lib/ragweed/wraptux/wraptux.rb +58 -62
- data/lib/ragweed/wraptux.rb +3 -4
- data/lib/ragweed.rb +36 -8
- data/ragweed.gemspec +85 -15
- metadata +50 -18
@@ -1,55 +1,72 @@
|
|
1
|
-
require '
|
1
|
+
require 'ffi'
|
2
2
|
|
3
3
|
module Ragweed; end
|
4
4
|
module Ragweed::Wraposx
|
5
|
-
|
6
|
-
# These hashes are the magic glue of the ragweed system calls.
|
7
|
-
# This one holds the library references from Ruby/DL.
|
8
|
-
LIBS = Hash.new do |h, str|
|
9
|
-
if not str =~ /^[\.\/].*/
|
10
|
-
str = "/usr/lib/" + str
|
11
|
-
end
|
12
|
-
if not str =~ /.*\.dylib$/
|
13
|
-
str = str + ".dylib"
|
14
|
-
end
|
15
|
-
h[str] = DL.dlopen(str)
|
16
|
-
end
|
17
|
-
|
18
|
-
# This hash holds the function references from Ruby/DL.
|
19
|
-
# It also auto populates LIBS.
|
20
|
-
# CALLS["<library>!<function>:<argument types>=<return type>"]
|
21
|
-
# Hash.new is a beautiful thing.
|
22
|
-
CALLS = Hash.new do |h, str|
|
23
|
-
lib = proc = args = ret = nil
|
24
|
-
lib, rest = str.split "!"
|
25
|
-
proc, rest = rest.split ":"
|
26
|
-
args, ret = rest.split("=") if rest
|
27
|
-
ret ||= "0"
|
28
|
-
raise "need proc" if not proc
|
29
|
-
h[str] = LIBS[lib][proc, ret + args]
|
30
|
-
end
|
31
5
|
|
32
|
-
|
6
|
+
module Libc
|
7
|
+
extend FFI::Library
|
8
|
+
ffi_lib FFI::Library::LIBC
|
9
|
+
typedef :int, :kern_return_t
|
33
10
|
|
34
|
-
|
35
|
-
|
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
|
36
61
|
|
37
62
|
class << self
|
38
63
|
|
39
|
-
# time_t
|
40
|
-
# time(time_t *tloc);
|
41
|
-
#
|
42
|
-
# see also time(3)
|
43
|
-
def time
|
44
|
-
CALLS["libc!time:=I"].call.first
|
45
|
-
end
|
46
|
-
|
47
64
|
# pid_t
|
48
65
|
# getpid(void);
|
49
66
|
#
|
50
67
|
# see also getpid(2)
|
51
68
|
def getpid
|
52
|
-
|
69
|
+
Libc.getpid
|
53
70
|
end
|
54
71
|
|
55
72
|
# Apple's ptrace is fairly gimped. The memory read and write functionality has been
|
@@ -62,13 +79,48 @@ module Ragweed::Wraposx
|
|
62
79
|
#
|
63
80
|
# see also ptrace(2)
|
64
81
|
def ptrace(request, pid, addr, data)
|
65
|
-
|
66
|
-
r =
|
67
|
-
raise SystemCallError.new("ptrace",
|
68
|
-
|
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
|
69
96
|
end
|
70
97
|
|
71
|
-
#
|
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
|
72
124
|
# usability and debugging purposes.
|
73
125
|
#
|
74
126
|
# Returns status of child when child recieves a signal.
|
@@ -78,10 +130,11 @@ module Ragweed::Wraposx
|
|
78
130
|
#
|
79
131
|
# see also wait(2)
|
80
132
|
def wait
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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]
|
85
138
|
end
|
86
139
|
|
87
140
|
# The wait used in debuggerosx.
|
@@ -95,13 +148,12 @@ module Ragweed::Wraposx
|
|
95
148
|
# waitpid(pid_t pid, int *stat_loc, int options);
|
96
149
|
#
|
97
150
|
# see also wait(2)
|
98
|
-
def waitpid
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
return [r, pstatus.to_s(SIZEOFINT).unpack('i_').first]
|
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]
|
105
157
|
end
|
106
158
|
|
107
159
|
# From docs at http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_task_self.html
|
@@ -112,9 +164,9 @@ module Ragweed::Wraposx
|
|
112
164
|
#
|
113
165
|
# There is no man page for this call.
|
114
166
|
def mach_task_self
|
115
|
-
|
167
|
+
Libc.mach_task_self
|
116
168
|
end
|
117
|
-
|
169
|
+
|
118
170
|
# Requires sudo to use as of 10.5 or 10.4.11(ish)
|
119
171
|
# Returns the task id for a process.
|
120
172
|
#
|
@@ -125,12 +177,12 @@ module Ragweed::Wraposx
|
|
125
177
|
#
|
126
178
|
# There is no man page for this call.
|
127
179
|
def task_for_pid(pid, target=nil)
|
128
|
-
target ||= mach_task_self
|
129
|
-
port =
|
130
|
-
r =
|
180
|
+
target ||= mach_task_self
|
181
|
+
port = FFI::MemoryPointer.new :int, 1
|
182
|
+
r = Libc.task_for_pid(target, pid, port)
|
131
183
|
raise KernelCallError.new(:task_for_pid, r) if r != 0
|
132
|
-
|
133
|
-
end
|
184
|
+
port.read_int
|
185
|
+
end
|
134
186
|
|
135
187
|
# Returns an Array of thread IDs for the given task
|
136
188
|
#
|
@@ -139,30 +191,29 @@ module Ragweed::Wraposx
|
|
139
191
|
# thread_act_port_array_t thread_list,
|
140
192
|
# mach_msg_type_number_t* thread_count);
|
141
193
|
#
|
142
|
-
#There is no man page for this funtion.
|
194
|
+
#There is no man page for this funtion.
|
143
195
|
def task_threads(port)
|
144
|
-
threads =
|
145
|
-
|
146
|
-
|
147
|
-
r = CALLS["libc!task_threads:IPP=I"].call(port, threads, count).first
|
148
|
-
t = DL::PtrData.new(threads.to_s(SIZEOFINT).unpack('i_').first)
|
196
|
+
threads = FFI::MemoryPointer.new :int, 1
|
197
|
+
count = FFI::MemoryPointer.new :int, 1
|
198
|
+
r = Libc.task_threads(port, threads, count)
|
149
199
|
raise KernelCallError.new(:task_threads, r) if r != 0
|
150
|
-
|
200
|
+
threads.read_array_of_int(count.read_int)
|
151
201
|
end
|
152
202
|
|
153
203
|
# Decrement the target tasks suspend count
|
154
204
|
# kern_return_t task_resume
|
155
205
|
# (task_t task);
|
156
206
|
def task_resume(task)
|
157
|
-
r =
|
207
|
+
r = Libc.task_resume(task)
|
158
208
|
raise KernelCallError.new(r) if r != 0
|
209
|
+
r
|
159
210
|
end
|
160
211
|
|
161
212
|
# Increment the target tasks suspend count
|
162
213
|
# kern_return_t task_suspend
|
163
214
|
# (task_t task);
|
164
215
|
def task_suspend(task)
|
165
|
-
r =
|
216
|
+
r = Libc.task_suspend(task)
|
166
217
|
raise KernelCallError.new(r) if r != 0
|
167
218
|
end
|
168
219
|
|
@@ -173,28 +224,9 @@ module Ragweed::Wraposx
|
|
173
224
|
#
|
174
225
|
# See kill(2)
|
175
226
|
def kill(pid, sig)
|
176
|
-
|
177
|
-
r =
|
178
|
-
raise SystemCallError.new
|
179
|
-
end
|
180
|
-
|
181
|
-
# function to marshal 32bit integers into DL::PtrData objects
|
182
|
-
# necessary due to Ruby/DL not properly dealing with 31 and 32 bit integers
|
183
|
-
def dl_bignum_to_ulong(x)
|
184
|
-
if x.class == Fixnum
|
185
|
-
return DL::PtrData.new(x)
|
186
|
-
else
|
187
|
-
# shut up
|
188
|
-
c = x / 4
|
189
|
-
e = x - (c * 4)
|
190
|
-
v = DL::PtrData.new 0
|
191
|
-
v += c
|
192
|
-
v += c
|
193
|
-
v += c
|
194
|
-
v += c
|
195
|
-
v += e
|
196
|
-
return v
|
197
|
-
end
|
227
|
+
FFI::errno = 0
|
228
|
+
r = Libc.kill(pid, sig)
|
229
|
+
raise SystemCallError.new "kill", FFI::errno if r != 0
|
198
230
|
end
|
199
231
|
|
200
232
|
# Reads sz bytes from task's address space starting at addr.
|
@@ -208,10 +240,9 @@ module Ragweed::Wraposx
|
|
208
240
|
#
|
209
241
|
# There is no man page for this function.
|
210
242
|
def vm_read(task, addr, sz=256)
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
r = CALLS["libc!vm_read_overwrite:IPIPP=I"].call(task, addr, sz, buf, len).first
|
243
|
+
buf = FFI::MemoryPointer.new(sz)
|
244
|
+
len = FFI::MemoryPointer(sz.to_l32)
|
245
|
+
r = Libc.vm_read_overwrite(task, addr, sz, buf, len)
|
215
246
|
raise KernelCallError.new(:vm_read, r) if r != 0
|
216
247
|
return buf.to_str(len.to_str(4).to_l32)
|
217
248
|
end
|
@@ -227,9 +258,8 @@ module Ragweed::Wraposx
|
|
227
258
|
#
|
228
259
|
# There is no man page for this function.
|
229
260
|
def vm_write(task, addr, val)
|
230
|
-
|
231
|
-
|
232
|
-
r = CALLS["libc!vm_write:IPPI=I"].call(task, addr, val, val.size).first
|
261
|
+
val = FFI::MemoryPointer.new
|
262
|
+
r = Libc.vm_write(task, addr, val, val.size)
|
233
263
|
raise KernelCallError.new(:vm_write, r) if r != 0
|
234
264
|
return nil
|
235
265
|
end
|
@@ -246,14 +276,12 @@ module Ragweed::Wraposx
|
|
246
276
|
#
|
247
277
|
# There is no man page for this function.
|
248
278
|
def vm_protect(task, addr, size, setmax, prot)
|
249
|
-
addr = dl_bignum_to_ulong(addr)
|
250
279
|
setmax = setmax ? 1 : 0
|
251
|
-
r =
|
280
|
+
r = Libc.vm_protect(task, addr, size, setmax, prot)
|
252
281
|
raise KernelCallError.new(:vm_protect, r) if r != 0
|
253
282
|
return nil
|
254
283
|
end
|
255
284
|
|
256
|
-
|
257
285
|
# Allocates a page in the memory space of the target task.
|
258
286
|
#
|
259
287
|
# kern_return_t vm_allocate
|
@@ -263,13 +291,14 @@ module Ragweed::Wraposx
|
|
263
291
|
# boolean_t anywhere);
|
264
292
|
#
|
265
293
|
def vm_allocate(task, address, size, anywhere)
|
266
|
-
addr =
|
294
|
+
addr = FFI::MemoryPointer.new :int, 1
|
295
|
+
addr.write_int(address)
|
267
296
|
anywhere = anywhere ? 1 : 0
|
268
|
-
r =
|
297
|
+
r = Libc.vm_allocate(task, addr, size, anywhere)
|
269
298
|
raise KernelCallError.new(r) if r != 0
|
270
|
-
addr.
|
299
|
+
addr.address
|
271
300
|
end
|
272
|
-
|
301
|
+
|
273
302
|
# deallocates a page in the memoryspace of target task.
|
274
303
|
#
|
275
304
|
# kern_return_t vm_deallocate
|
@@ -277,12 +306,13 @@ module Ragweed::Wraposx
|
|
277
306
|
# vm_address_t address,
|
278
307
|
# vm_size_t size);
|
279
308
|
#
|
280
|
-
def vm_deallocate(task,address,size)
|
281
|
-
addr =
|
282
|
-
|
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)
|
283
313
|
raise KernelCallError.new(r) if r != 0
|
284
314
|
end
|
285
|
-
|
315
|
+
|
286
316
|
# Resumes a suspended thread by id.
|
287
317
|
#
|
288
318
|
# kern_return_t thread_resume
|
@@ -290,7 +320,7 @@ module Ragweed::Wraposx
|
|
290
320
|
#
|
291
321
|
# There is no man page for this function.
|
292
322
|
def thread_resume(thread)
|
293
|
-
r =
|
323
|
+
r = Libc.thread_resume(thread)
|
294
324
|
raise KernelCallError.new(:thread_resume, r) if r != 0
|
295
325
|
end
|
296
326
|
|
@@ -301,133 +331,26 @@ module Ragweed::Wraposx
|
|
301
331
|
#
|
302
332
|
# There is no man page for this function.
|
303
333
|
def thread_suspend(thread)
|
304
|
-
r =
|
334
|
+
r = Libc.thread_suspend(thread)
|
305
335
|
raise KernelCallError.new(:thread_suspend, r) if r != 0
|
306
336
|
end
|
307
337
|
|
308
|
-
# Suspends a task by id.
|
309
|
-
#
|
310
|
-
# kern_return_t task_suspend
|
311
|
-
# (task_t task);
|
312
|
-
#
|
313
|
-
# There is no man page for this function.
|
314
|
-
def task_suspend(task)
|
315
|
-
r = CALLS["libc!task_suspend:I=I"].call(task).first
|
316
|
-
raise KernelCallError.new(:task_suspend, r) if r != 0
|
317
|
-
end
|
318
|
-
|
319
|
-
# Resumes a suspended task by id.
|
320
|
-
#
|
321
|
-
# kern_return_t task_resume
|
322
|
-
# (task_t task);
|
323
|
-
#
|
324
|
-
# There is no man page for this function.
|
325
|
-
def task_resume(task)
|
326
|
-
r = CALLS["libc!task_resume:I=I"].call(task).first
|
327
|
-
raise KernelCallError.new(:task_resume, r) if r != 0
|
328
|
-
end
|
329
|
-
|
330
|
-
# Used to query kernel state.
|
331
|
-
# Returns output buffer on successful call or required buffer size on ENOMEM.
|
332
|
-
#
|
333
|
-
# mib: and array of integers decribing the MIB
|
334
|
-
# newb: the buffer to replace the old information (only used on some commands so it defaults to empty)
|
335
|
-
# oldlenp: output buffer size
|
336
|
-
#
|
337
|
-
# int
|
338
|
-
# sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
|
339
|
-
#
|
340
|
-
# this function doesn't really match the Ruby Way(tm)
|
341
|
-
#
|
342
|
-
# see sysctl(8)
|
343
|
-
def sysctl(mib,oldlen=0,newb="")
|
344
|
-
DL.last_error = 0
|
345
|
-
mibp = mib.pack("I_"*mib.size).to_ptr
|
346
|
-
oldlenp = [oldlen].pack("I_").to_ptr
|
347
|
-
namelen = mib.size
|
348
|
-
oldp = (oldlen > 0 ? "\x00"*oldlen : NULL)
|
349
|
-
newp = (newb.empty? ? NULL : newb.to_ptr)
|
350
|
-
newlen = newb.size
|
351
|
-
r = CALLS["libc!sysctl:PIPPPI=I"].call(mibp, namelen, oldp, oldlenp, newp, newlen).first
|
352
|
-
return oldlenp.to_str(SIZEOFINT).unpack("I_").first if (r == -1 and DL.last_error == Errno::ENOMEM::Errno)
|
353
|
-
raise SystemCallError.new("sysctl", DL.last_error) if r != 0
|
354
|
-
return oldp.to_str(oldlenp.to_str(SIZEOFINT).unpack("I_").first)
|
355
|
-
end
|
356
|
-
|
357
|
-
# Used to query kernel state.
|
358
|
-
# Returns output buffer on successful call and required buffer size as an Array.
|
359
|
-
#
|
360
|
-
# mib: and array of integers decribing the MIB
|
361
|
-
# newb: the buffer to replace the old information (only used on some commands so it defaults to empty)
|
362
|
-
# oldlenp: output buffer size
|
363
|
-
#
|
364
|
-
# int
|
365
|
-
# sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
|
366
|
-
#
|
367
|
-
# this function doesn't really match the Ruby Way(tm)
|
368
|
-
#
|
369
|
-
# see sysctl(8)
|
370
|
-
def sysctl_raw(mib,oldlen=0,newb="")
|
371
|
-
DL.last_error = 0
|
372
|
-
mibp = mib.pack('I_'*mib.size).to_ptr
|
373
|
-
oldlenp = [oldlen].pack("I_").to_ptr
|
374
|
-
namelen = mib.size
|
375
|
-
oldp = (oldlen > 0 ? ("\x00"*oldlen).to_ptr : NULL)
|
376
|
-
newp = (newb.empty? ? NULL : newb.to_ptr)
|
377
|
-
newlen = newb.size
|
378
|
-
r = CALLS["libc!sysctl:PIPPPI=I"].call(mibp, namelen, oldp, oldlenp, newp, newlen).first
|
379
|
-
ret = (DL.last_error == Errno::ENOMEM::Errno ? NULL : oldp)
|
380
|
-
raise SystemCallError.new("sysctl", DL.last_error) if (r != 0 and DL.last_error != Errno::ENOMEM::Errno)
|
381
|
-
return [ret,oldlenp.to_str(SIZEOFINT).unpack("I_").first]
|
382
|
-
end
|
383
|
-
|
384
338
|
# Changes execution to file in path with *args as though called from command line.
|
385
339
|
#
|
386
340
|
# int
|
387
341
|
# execv(const char *path, char *const argv[]);
|
388
|
-
def execv(path
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
raise SystemCallError.new("execv", DL.last_error) if r == -1
|
395
|
-
return r
|
396
|
-
end
|
397
|
-
|
398
|
-
def int_to_intptr(i)
|
399
|
-
case i
|
400
|
-
when Integer
|
401
|
-
return [i].pack("I").to_ptr
|
402
|
-
when DL::PtrData
|
403
|
-
return i
|
404
|
-
else
|
405
|
-
raise ArgumentError, "Not an Integer"
|
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))
|
406
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)
|
407
354
|
end
|
408
355
|
end
|
409
356
|
end
|
410
|
-
|
411
|
-
# if __FILE__ == $0
|
412
|
-
# include Ragweed
|
413
|
-
# require 'pp'
|
414
|
-
# require 'constants'
|
415
|
-
# addr = data = 0
|
416
|
-
# pid = 1319
|
417
|
-
# int = "\x00" * 4
|
418
|
-
# port = 0
|
419
|
-
# Wraposx::ptrace(Wraposx::Ptrace::ATTACH,pid,0,0)
|
420
|
-
# # status = Wraposx::waitpid(pid,0)
|
421
|
-
# # Wraposx::ptrace(Wraposx::Ptrace::CONTINUE,pid,1,0)
|
422
|
-
# mts = Wraposx::mach_task_self
|
423
|
-
# port = Wraposx::task_for_pid(mts,pid)
|
424
|
-
# port2 = Wraposx::task_for_pid(mts,pid)
|
425
|
-
# threads = Wraposx::task_threads(port)
|
426
|
-
# state = Wraposx::thread_get_state(threads.first)
|
427
|
-
# pp port
|
428
|
-
# pp port2
|
429
|
-
# pp threads
|
430
|
-
# pp state
|
431
|
-
# # Wraposx::thread_set_state(threads.first,state)
|
432
|
-
# Wraposx::ptrace(Wraposx::Ptrace::DETACH,pid,0,0)
|
433
|
-
# end
|
data/lib/ragweed/wraposx.rb
CHANGED
@@ -5,7 +5,7 @@ module Ragweed; end
|
|
5
5
|
module Ragweed::Wraposx
|
6
6
|
|
7
7
|
# :stopdoc:
|
8
|
-
VERSION =
|
8
|
+
VERSION = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
|
9
9
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
10
10
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
11
11
|
# :startdoc:
|
@@ -54,6 +54,7 @@ module Ragweed::Wraposx
|
|
54
54
|
end
|
55
55
|
end # module Ragweed::Wraposx
|
56
56
|
|
57
|
+
require 'ragweed/wraposx/wraposx'
|
57
58
|
Ragweed::Wraposx.require_all_libs_relative_to(__FILE__)
|
58
59
|
|
59
60
|
# EOF
|
@@ -3,27 +3,51 @@ module Ragweed; end
|
|
3
3
|
module Ragweed::Wraptux;end
|
4
4
|
|
5
5
|
module Ragweed::Wraptux::Ptrace
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
6
|
+
TRACE_ME = 0
|
7
|
+
PEEK_TEXT = 1
|
8
|
+
PEEK_DATA = 2
|
9
|
+
PEEK_USER = 3
|
10
|
+
POKE_TEXT = 4
|
11
|
+
POKE_DATA = 5
|
12
|
+
POKE_USER = 6
|
13
|
+
CONTINUE = 7
|
14
|
+
KILL = 8
|
15
|
+
STEP = 9
|
16
|
+
GETREGS = 12
|
17
|
+
SETREGS = 13
|
18
|
+
ATTACH = 16
|
19
|
+
DETACH = 17
|
20
|
+
SYSCALL = 24
|
21
|
+
SETOPTIONS = 0x4200
|
22
|
+
GETEVENTMSG = 0x4201
|
23
|
+
GETSIGINFO = 0x4202
|
24
|
+
SETSIGINFO = 0x4203
|
25
|
+
end
|
26
|
+
|
27
|
+
module Ragweed::Wraptux::Ptrace::SetOptions
|
28
|
+
TRACESYSGOOD = 0x00000001
|
29
|
+
TRACEFORK = 0x00000002
|
30
|
+
TRACEVFORK = 0x00000004
|
31
|
+
TRACECLONE = 0x00000008
|
32
|
+
TRACEEXEC = 0x00000010
|
33
|
+
TRACEVFORKDONE = 0x00000020
|
34
|
+
TRACEEXIT = 0x00000040
|
35
|
+
MASK = 0x0000007f
|
36
|
+
end
|
37
|
+
|
38
|
+
module Ragweed::Wraptux::Ptrace::EventCodes
|
39
|
+
FORK = 1
|
40
|
+
VFORK = 2
|
41
|
+
CLONE = 3
|
42
|
+
EXEC = 4
|
43
|
+
VFORK_DONE = 5
|
44
|
+
EXIT = 6
|
21
45
|
end
|
22
46
|
|
23
47
|
module Ragweed::Wraptux::Signal
|
24
48
|
SIGHUP = 1
|
25
49
|
SIGINT = 2
|
26
|
-
SIGQUIT =
|
50
|
+
SIGQUIT = 3
|
27
51
|
SIGILL = 4
|
28
52
|
SIGTRAP = 5
|
29
53
|
SIGABRT = 6
|
@@ -59,10 +83,10 @@ module Ragweed::Wraptux::Signal
|
|
59
83
|
end
|
60
84
|
|
61
85
|
module Ragweed::Wraptux::Wait
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
86
|
+
NOHANG = 1
|
87
|
+
UNTRACED = 2
|
88
|
+
EXITED = 4
|
89
|
+
STOPPED = 8
|
90
|
+
CONTINUED = 10
|
91
|
+
NOWWAIT = 20
|
68
92
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Ragweed::FFIStructInclude
|
2
|
+
if RUBY_VERSION < "1.9"
|
3
|
+
def methods regular=true
|
4
|
+
super + self.offsets.map{|x| x.first.to_s}
|
5
|
+
end
|
6
|
+
else
|
7
|
+
def methods regular=true
|
8
|
+
super + self.offsets.map{|x| x.first}
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing meth, *args
|
13
|
+
super unless self.respond_to? meth
|
14
|
+
if meth.to_s =~ /=$/
|
15
|
+
self.__send__(:[]=, meth.to_s.gsub(/=$/,'').intern, *args)
|
16
|
+
else
|
17
|
+
self.__send__(:[], meth, *args)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to? meth, include_priv=false
|
22
|
+
mth = meth.to_s.gsub(/=$/,'')
|
23
|
+
self.offsets.map{|x| x.first.to_s}.include? mth || super
|
24
|
+
end
|
25
|
+
end
|
File without changes
|