ragweed 0.2.1-java → 0.2.3-java
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +4 -9
- data/VERSION +1 -1
- data/lib/ragweed/debuggerosx.rb +23 -14
- data/lib/ragweed/debuggertux.rb +63 -26
- data/lib/ragweed/wrap32/process_token.rb +6 -0
- data/lib/ragweed/wraposx/region_info.rb +12 -6
- data/lib/ragweed/wraposx/thread_context.rb +160 -49
- data/lib/ragweed/wraposx/wraposx.rb +14 -9
- data/lib/ragweed/wraptux/process.rb +2 -1
- data/ragweed.gemspec +4 -17
- metadata +4 -12
- data/lib/ragweed/wraposx/thread_info.rb.old +0 -121
data/README.rdoc
CHANGED
@@ -20,11 +20,10 @@ Ragweed is supported and has been tested on the following platforms (32bit intel
|
|
20
20
|
Mac OS X 10.6
|
21
21
|
Mac OS X 10.5
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
require significant changes to Ragweed.
|
23
|
+
Ragweed works with Ruby 1.8.7, 1.9.1 and 1.9.2 and should work with any Ruby that includes FFI support on 32bit WinXP, Win7, Linux 2.6 and OSX 10.6.
|
24
|
+
We are actively investigating 64 bit support for each platform. Unfortunately, this will require significant changes to Ragweed.
|
26
25
|
|
27
|
-
* We
|
26
|
+
* We have completed switching from Ruby/DL to FFI in 0.2.0. There should be no incompatibilities as a result of this switch. Additionally, ragweed may now work on rubies that include FFI support (jruby, ree, rbx), this has not yet been tested.
|
28
27
|
|
29
28
|
== FEATURES/PROBLEMS:
|
30
29
|
|
@@ -33,10 +32,6 @@ require significant changes to Ragweed.
|
|
33
32
|
|
34
33
|
* Work is ongoing to complete and unify the OSX and Linux portions.
|
35
34
|
|
36
|
-
* The FFI move is mostly complete. There may be a few changes to some structures to come, but everything should mostly match the C APIs.
|
37
|
-
|
38
|
-
* The move to FFI should give us free support for jRuby. This is, however, untested at this time.
|
39
|
-
|
40
35
|
* Struct's Nerve[http://github.com/struct/Nerve] is an example of the API we are heading toward
|
41
36
|
|
42
37
|
== SYNOPSIS:
|
@@ -57,4 +52,4 @@ Please see the examples directory for more. There are hit tracers for each platf
|
|
57
52
|
|
58
53
|
== LICENSE:
|
59
54
|
|
60
|
-
Copyright 2009
|
55
|
+
Copyright 2009-2011 Matasano Security, LLC All Rights Reserved
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.3
|
data/lib/ragweed/debuggerosx.rb
CHANGED
@@ -217,7 +217,7 @@ class Ragweed::Debuggerosx
|
|
217
217
|
on_attach
|
218
218
|
self.hook(opts) if (opts[:hook] and not @hooked)
|
219
219
|
self.install_bps if (opts[:install] and not @installed)
|
220
|
-
return r
|
220
|
+
return r.first
|
221
221
|
end
|
222
222
|
|
223
223
|
# remove breakpoints and release child
|
@@ -229,7 +229,7 @@ class Ragweed::Debuggerosx
|
|
229
229
|
@attached = false
|
230
230
|
on_detach
|
231
231
|
self.unhook(opts) if opts[:hook] and @hooked
|
232
|
-
return r
|
232
|
+
return r.first
|
233
233
|
end
|
234
234
|
|
235
235
|
# get task port for @pid and store in @task so mach calls can be made
|
@@ -253,14 +253,14 @@ class Ragweed::Debuggerosx
|
|
253
253
|
# resumes thread that has been suspended via thread_suspend
|
254
254
|
# thread: thread id of thread to be resumed
|
255
255
|
def resume(thread = nil)
|
256
|
-
thread
|
256
|
+
thread ||= self.threads.first)
|
257
257
|
Ragweed::Wraposx::thread_resume(thread)
|
258
258
|
end
|
259
259
|
|
260
260
|
# suspends thread
|
261
261
|
# thread: thread id of thread to be suspended
|
262
262
|
def suspend(thread = nil)
|
263
|
-
thread
|
263
|
+
thread ||= self.threads.first)
|
264
264
|
Ragweed::Wraposx::thread_suspend(thread)
|
265
265
|
end
|
266
266
|
|
@@ -359,16 +359,17 @@ class Ragweed::Debuggerosx
|
|
359
359
|
# returns a Ragweed::Wraposx::ThreadContext object containing the register states
|
360
360
|
# thread: thread to get the register state of
|
361
361
|
def get_registers(thread=nil)
|
362
|
-
thread
|
363
|
-
Ragweed::Wraposx
|
362
|
+
thread ||= self.threads.first)
|
363
|
+
Ragweed::Wraposx.thread_get_state(thread, Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE)
|
364
364
|
end
|
365
365
|
|
366
366
|
# sets the register state of a thread
|
367
367
|
# thread: thread id to set registers for
|
368
368
|
# regs: Ragweed::Wraposx::ThreadContext object containing the new register state for the thread
|
369
369
|
def set_registers(thread, regs)
|
370
|
-
|
371
|
-
|
370
|
+
# XXX - needs updated conditions
|
371
|
+
# raise "Must supply registers and thread to set" if (not (thread and regs) or not thread.kind_of? Numeric or not regs.kind_of? Ragweed::Wraposx::ThreadContext)
|
372
|
+
Ragweed::Wraposx.thread_set_state(thread, regs.class::FLAVOR, regs)
|
372
373
|
end
|
373
374
|
|
374
375
|
# continue stopped child process.
|
@@ -400,18 +401,26 @@ class Ragweed::Debuggerosx
|
|
400
401
|
def installed?; @installed; end
|
401
402
|
|
402
403
|
def region_info(addr, flavor = :basic)
|
403
|
-
case flavor
|
404
|
+
flav = case flavor
|
404
405
|
when :basic
|
405
|
-
|
406
|
+
Ragweed::Wraposx::Vm::RegionBasicInfo::FLAVOR
|
406
407
|
|
407
408
|
# Extended and Top info flavors are included in case Apple re implements them
|
408
409
|
when :extended
|
409
|
-
|
410
|
+
Ragweed::Wraposx::Vm::RegionExtendedInfo::FLAVOR
|
410
411
|
when :top
|
411
|
-
|
412
|
+
Ragweed::Wraposx::Vm::RegionTopInfo::FLAVOR
|
413
|
+
when Integer
|
414
|
+
flavor
|
412
415
|
else
|
413
416
|
warn "Unknown flavor requested. Returning RegionBasicInfo."
|
414
|
-
|
417
|
+
Ragweed::Wraposx::RegionBasicInfo::FLAVOR
|
418
|
+
end
|
419
|
+
|
420
|
+
if Ragweed::Wraposx.respond_to? :vm_region_64
|
421
|
+
Ragweed::Wraposx.vm_region_64(@task, addr, flav)
|
422
|
+
else
|
423
|
+
Ragweed::Wraposx.vm_region(@task, addr, flav)
|
415
424
|
end
|
416
425
|
end
|
417
426
|
|
@@ -428,7 +437,7 @@ class Ragweed::Debuggerosx
|
|
428
437
|
first
|
429
438
|
if exact && (rtype == name || purpose == name)
|
430
439
|
ret << [saddr, eaddr].map{|x| x.to_i(16)}
|
431
|
-
elsif rtype.match(name) || purpose.match(name)
|
440
|
+
elsif rtype && purpose && (rtype.match(name) || purpose.match(name))
|
432
441
|
ret << [saddr, eaddr].map{|x| x.to_i(16)}
|
433
442
|
end
|
434
443
|
end
|
data/lib/ragweed/debuggertux.rb
CHANGED
@@ -13,7 +13,7 @@ module Ragweed; end
|
|
13
13
|
## that Debuggertux already handles, call "super", too.
|
14
14
|
class Ragweed::Debuggertux
|
15
15
|
attr_reader :pid, :status, :exited, :signal
|
16
|
-
attr_accessor :breakpoints, :mapped_regions, :process
|
16
|
+
attr_accessor :breakpoints, :mapped_regions, :process, :use_ptrace_for_search
|
17
17
|
|
18
18
|
## Class to handle installing/uninstalling breakpoints
|
19
19
|
class Breakpoint
|
@@ -74,6 +74,7 @@ class Ragweed::Debuggertux
|
|
74
74
|
default_opts(opts)
|
75
75
|
@installed = false
|
76
76
|
@attached = false
|
77
|
+
@use_ptrace_for_search = false
|
77
78
|
|
78
79
|
@mapped_regions = Hash.new
|
79
80
|
@breakpoints = Hash.new
|
@@ -132,7 +133,6 @@ class Ragweed::Debuggertux
|
|
132
133
|
## value = Size of the region
|
133
134
|
def mapped
|
134
135
|
@mapped_regions.clear if @mapped_regions
|
135
|
-
|
136
136
|
File.open("/proc/#{pid}/maps") do |f|
|
137
137
|
f.each_line do |l|
|
138
138
|
e = l.split(' ',2).first
|
@@ -209,9 +209,7 @@ class Ragweed::Debuggertux
|
|
209
209
|
lib = l.split(' ', 6)
|
210
210
|
sa = l.split('-', 0)
|
211
211
|
|
212
|
-
if lib[5] =~ /vdso/
|
213
|
-
next
|
214
|
-
end
|
212
|
+
next if lib[5] =~ /vdso/
|
215
213
|
|
216
214
|
lib = lib[5].strip
|
217
215
|
lib.gsub!(/[\s\n]+/, "")
|
@@ -229,50 +227,89 @@ class Ragweed::Debuggertux
|
|
229
227
|
end
|
230
228
|
|
231
229
|
## Search a specific page for a value
|
232
|
-
## Should be used by most
|
233
|
-
def search_page(base, max, val)
|
234
|
-
loc =
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
230
|
+
## Should be used by most search methods
|
231
|
+
def search_page(base, max, val, &block)
|
232
|
+
loc = []
|
233
|
+
if self.use_ptrace_for_search == true
|
234
|
+
while base.to_i < max.to_i
|
235
|
+
r = Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, base, 0)
|
236
|
+
loc << base if r == val
|
237
|
+
base += 4
|
238
|
+
yield loc if block_given?
|
239
|
+
end
|
240
|
+
else
|
241
|
+
sz = max.to_i - base.to_i
|
242
|
+
d = File.new("/proc/#{pid}/mem")
|
243
|
+
d.seek(base.to_i, IO::SEEK_SET)
|
244
|
+
b = d.read(sz)
|
245
|
+
i = 0
|
246
|
+
while(i < sz)
|
247
|
+
if val == b[i,4].unpack('L')
|
248
|
+
loc << base.to_i + i
|
249
|
+
yield(base.to_i + i) if block_given?
|
250
|
+
end
|
251
|
+
i += 4
|
240
252
|
end
|
241
|
-
|
253
|
+
d.close
|
242
254
|
end
|
243
255
|
|
244
256
|
loc
|
245
257
|
end
|
246
258
|
|
247
|
-
|
248
|
-
|
249
|
-
loc = Array.new
|
259
|
+
def search_mem_by_name(name, val, &block)
|
260
|
+
loc = []
|
250
261
|
File.open("/proc/#{pid}/maps") do |f|
|
251
262
|
f.each_line do |l|
|
252
|
-
if l =~ /\[
|
263
|
+
if l =~ /\[#{name}\]/
|
253
264
|
s,e = l.split('-')
|
254
265
|
e = e.split(' ').first
|
255
266
|
s = s.to_i(16)
|
256
267
|
e = e.to_i(16)
|
257
268
|
sz = e - s
|
258
269
|
max = s + sz
|
259
|
-
loc
|
270
|
+
loc << search_page(s, max, val, &block)
|
260
271
|
end
|
261
272
|
end
|
262
273
|
end
|
263
|
-
loc
|
274
|
+
loc
|
275
|
+
end
|
276
|
+
|
277
|
+
def search_mem_by_permission(perm, val, &block)
|
278
|
+
loc = []
|
279
|
+
File.open("/proc/#{pid}/maps") do |f|
|
280
|
+
f.each_line do |l|
|
281
|
+
if l.split(' ')[1] =~ /#{perm}/
|
282
|
+
s,e = l.split('-')
|
283
|
+
e = e.split(' ').first
|
284
|
+
s = s.to_i(16)
|
285
|
+
e = e.to_i(16)
|
286
|
+
sz = e - s
|
287
|
+
max = s + sz
|
288
|
+
loc << search_page(s, max, val, &block)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
loc
|
293
|
+
end
|
294
|
+
|
295
|
+
## Search the heap for a value, returns an array of matches
|
296
|
+
def search_heap(val, &block)
|
297
|
+
search_mem_by_name('heap', &block)
|
298
|
+
end
|
299
|
+
|
300
|
+
## Search the stack for a value, returns an array of matches
|
301
|
+
def search_stack(val, &block)
|
302
|
+
search_mem_by_name('stack', &block)
|
264
303
|
end
|
265
304
|
|
266
305
|
## Search all mapped regions for a value
|
267
|
-
def search_process(val)
|
268
|
-
loc =
|
306
|
+
def search_process(val, &block)
|
307
|
+
loc = []
|
269
308
|
self.mapped
|
270
309
|
@mapped_regions.each_pair do |k,v|
|
271
|
-
if k == 0 or v == 0
|
272
|
-
next
|
273
|
-
end
|
310
|
+
next if k == 0 or v == 0
|
274
311
|
max = k+v
|
275
|
-
loc
|
312
|
+
loc << search_page(k, max, val, &block)
|
276
313
|
end
|
277
314
|
loc
|
278
315
|
end
|
@@ -27,6 +27,7 @@ module Ragweed::Wrap32
|
|
27
27
|
ffi_convention :stdcall
|
28
28
|
attach_function 'OpenProcess', [ :long, :long, :long ], :long
|
29
29
|
attach_function 'OpenProcessToken', [:long, :long, :pointer ], :long
|
30
|
+
attach_function 'TerminateProcess', [:long, :uint], :long
|
30
31
|
|
31
32
|
# ffi_lib 'advapi32'
|
32
33
|
# ffi_convention :stdcall
|
@@ -60,6 +61,11 @@ module Ragweed::Wrap32
|
|
60
61
|
outw.read_long_long
|
61
62
|
end
|
62
63
|
end
|
64
|
+
|
65
|
+
def terminate_process(handle, exit_code)
|
66
|
+
r = Win.TerminateProcess(handle, exit_code)
|
67
|
+
raise WinX.new(:terminate_process) if r != 0
|
68
|
+
end
|
63
69
|
end
|
64
70
|
|
65
71
|
class Ragweed::Wrap32::ProcessToken
|
@@ -39,6 +39,7 @@ module Ragweed::Wraposx::Vm
|
|
39
39
|
end
|
40
40
|
|
41
41
|
class RegionBasicInfo < RegionInfo
|
42
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO
|
42
43
|
|
43
44
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
44
45
|
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
@@ -73,6 +74,7 @@ EOM
|
|
73
74
|
end
|
74
75
|
|
75
76
|
class RegionBasicInfo64 < RegionInfo
|
77
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_BASIC_INFO_64
|
76
78
|
|
77
79
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
78
80
|
:max_protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
@@ -118,6 +120,8 @@ EOM
|
|
118
120
|
# unsigned char share_mode;
|
119
121
|
# };
|
120
122
|
class RegionExtendedInfo < RegionInfo
|
123
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_EXTENDED_INFO
|
124
|
+
|
121
125
|
layout :protection, Ragweed::Wraposx::Libc.find_type(:vm_prot_t),
|
122
126
|
:user_tag, :uint,
|
123
127
|
:pages_resident, :uint,
|
@@ -161,6 +165,8 @@ EOM
|
|
161
165
|
# unsigned char share_mode;
|
162
166
|
# };
|
163
167
|
class RegionTopInfo < RegionInfo
|
168
|
+
FLAVOR = Ragweed::Wraposx::Vm::REGION_TOP_INFO
|
169
|
+
|
164
170
|
layout :obj_id, :uint,
|
165
171
|
:ref_count, :uint,
|
166
172
|
:private_pages_resident, :uint,
|
@@ -230,9 +236,9 @@ module Ragweed::Wraposx
|
|
230
236
|
def vm_region(task, addr, flavor)
|
231
237
|
info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class], 1)
|
232
238
|
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)
|
239
|
+
address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr)
|
240
|
+
sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1)
|
241
|
+
objn = FFI::MemoryPointer.new(Libc.find_type(:mach_port_t), 1)
|
236
242
|
|
237
243
|
r = Libc.vm_region(task, address, sz, flavor, info, count, objn)
|
238
244
|
raise KernelCallError.new(:vm_region, r) if r != 0
|
@@ -258,7 +264,7 @@ module Ragweed::Wraposx
|
|
258
264
|
def vm_region_64(task, addr, flavor)
|
259
265
|
# OSX does this as well, so we need to do it ourselves
|
260
266
|
flavor = Vm::REGION_BASIC_INFO_64 if flavor == Vm::REGION_BASIC_INFO
|
261
|
-
info = FFI::MemoryPointer.new(
|
267
|
+
info = FFI::MemoryPointer.new(Vm::FLAVORS[flavor][:class])
|
262
268
|
count = FFI::MemoryPointer.new(Libc.find_type(:mach_msg_type_number_t), 1).write_uint(Vm::FLAVORS[flavor][:count])
|
263
269
|
address = FFI::MemoryPointer.new(Libc.find_type(:vm_address_t), 1).write_ulong(addr)
|
264
270
|
sz = FFI::MemoryPointer.new(Libc.find_type(:vm_size_t), 1)
|
@@ -266,8 +272,8 @@ module Ragweed::Wraposx
|
|
266
272
|
|
267
273
|
r = Libc.vm_region_64(task, address, sz, flavor, info, count, objn)
|
268
274
|
raise KernelCallError.new(:vm_region_64, r) if r != 0
|
269
|
-
ret = Vm::
|
270
|
-
ret.region_size =
|
275
|
+
ret = Vm::FLAVORS[flavor][:class].new info
|
276
|
+
ret.region_size = sz.read_ulong
|
271
277
|
ret.base_address = address.read_ulong
|
272
278
|
ret
|
273
279
|
end if Libc.find_function "vm_region_64"
|
@@ -34,6 +34,14 @@ module Ragweed::Wraposx::ThreadContext
|
|
34
34
|
I386_FLOAT_STATE = X86_FLOAT_STATE32
|
35
35
|
I386_EXCEPTION_STATE = X86_EXCEPTION_STATE32
|
36
36
|
|
37
|
+
def self.get(thread, flavor = X86_THREAD_STATE)
|
38
|
+
Ragweed::Wraposx.thread_get_state(thread, flavor)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.set(thread, state)
|
42
|
+
Ragweed::Wraposx.thread_set_state(thread, state.class::FLAVOR, state)
|
43
|
+
end
|
44
|
+
|
37
45
|
# struct x86_state_hdr {
|
38
46
|
# int flavor;
|
39
47
|
# int count;
|
@@ -42,6 +50,20 @@ module Ragweed::Wraposx::ThreadContext
|
|
42
50
|
include Ragweed::FFIStructInclude
|
43
51
|
layout :flavor, :int,
|
44
52
|
:count, :int
|
53
|
+
def is_64?
|
54
|
+
case self[:flavor]
|
55
|
+
when 1, 2, 3, 10
|
56
|
+
false
|
57
|
+
when 4, 5, 6, 11
|
58
|
+
true
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def is_32?
|
65
|
+
!is_64?
|
66
|
+
end
|
45
67
|
end
|
46
68
|
|
47
69
|
# _STRUCT_X86_THREAD_STATE32
|
@@ -186,7 +208,7 @@ EOM
|
|
186
208
|
:rflags, :uint64,
|
187
209
|
:cs, :uint64,
|
188
210
|
:fs, :uint64,
|
189
|
-
:gs, :uint64
|
211
|
+
:gs, :uint64
|
190
212
|
|
191
213
|
module Flags
|
192
214
|
CARRY = 0x1
|
@@ -220,16 +242,16 @@ EOM
|
|
220
242
|
string =<<EOM
|
221
243
|
-----------------------------------------------------------------------
|
222
244
|
CONTEXT:
|
223
|
-
RIP: #{self.rip.to_s(16).rjust(16, "0")} #{maybe_dis.call(self.
|
224
|
-
|
225
|
-
RAX: #{self.rax.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
226
|
-
RBX: #{self.rbx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
227
|
-
RCX: #{self.rcx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
228
|
-
RDX: #{self.rdx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
229
|
-
RDI: #{self.rdi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
230
|
-
RSI: #{self.rsi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
231
|
-
RBP: #{self.rbp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
232
|
-
RSP: #{self.rsp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.
|
245
|
+
RIP: #{self.rip.to_s(16).rjust(16, "0")} #{maybe_dis.call(self.rip)}
|
246
|
+
|
247
|
+
RAX: #{self.rax.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rax)}
|
248
|
+
RBX: #{self.rbx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rbx)}
|
249
|
+
RCX: #{self.rcx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rcx)}
|
250
|
+
RDX: #{self.rdx.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rdx)}
|
251
|
+
RDI: #{self.rdi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rdi)}
|
252
|
+
RSI: #{self.rsi.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rsi)}
|
253
|
+
RBP: #{self.rbp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rbp)}
|
254
|
+
RSP: #{self.rsp.to_s(16).rjust(16, "0")} #{maybe_hex.call(self.rsp)}
|
233
255
|
RFL: #{(self.rflags & 0xffffffff).to_s(2).rjust(32, "0")} #{Flags.flag_dump(self.rflags & 0xffffffff)}
|
234
256
|
EOM
|
235
257
|
end
|
@@ -256,6 +278,10 @@ EOM
|
|
256
278
|
layout :tsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
257
279
|
:uts, Ragweed::Wraposx::ThreadContext::UnionThreadState
|
258
280
|
|
281
|
+
def is_64?; self[:tsh].is_64?; end
|
282
|
+
def is_32?; !is_64?; end
|
283
|
+
def header; self[:fsh]; end
|
284
|
+
|
259
285
|
# We have rubified this FFI structure by creating a bunch of proxy
|
260
286
|
# methods that are normally only accessible via self.v.x.y which is
|
261
287
|
# a lot to type. You can still use that method however these proxy
|
@@ -264,11 +290,11 @@ EOM
|
|
264
290
|
def methods regular=true
|
265
291
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
266
292
|
ret += self[:tsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
267
|
-
ret
|
293
|
+
ret += case self[:tsh][:flavor]
|
268
294
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
269
|
-
self[:uts]
|
295
|
+
self[:uts][:ts32].members.map{|x| [x.to_s, x.to_s + "="]}
|
270
296
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
271
|
-
self[:uts]
|
297
|
+
self[:uts][:ts64].members.map{|x| [x.to_s, x.to_s + "="]}
|
272
298
|
else
|
273
299
|
[]
|
274
300
|
end
|
@@ -278,11 +304,11 @@ EOM
|
|
278
304
|
def methods regular=true
|
279
305
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
280
306
|
ret += self[:tsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
281
|
-
ret
|
307
|
+
ret += case self[:tsh][:flavor]
|
282
308
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
283
|
-
self[:uts]
|
309
|
+
self[:uts][:ts32].members.map{|x| [x, (x.to_s + "=").intern]}
|
284
310
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
285
|
-
self[:uts]
|
311
|
+
self[:uts][:ts64].members.map{|x| [x, (x.to_s + "=").intern]}
|
286
312
|
else
|
287
313
|
[]
|
288
314
|
end
|
@@ -302,9 +328,9 @@ EOM
|
|
302
328
|
else
|
303
329
|
case self[:tsh][:flavor]
|
304
330
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
305
|
-
self[:uts]
|
331
|
+
self[:uts][:ts32].__send__(:[]=, mth, *args)
|
306
332
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
307
|
-
self[:uts]
|
333
|
+
self[:uts][:ts64].__send__(:[]=, mth, *args)
|
308
334
|
end
|
309
335
|
end
|
310
336
|
else
|
@@ -316,9 +342,9 @@ EOM
|
|
316
342
|
else
|
317
343
|
case self[:tsh][:flavor]
|
318
344
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
|
319
|
-
self[:uts]
|
345
|
+
self[:uts][:ts32].__send__(:[], meth, *args)
|
320
346
|
when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
|
321
|
-
self[:uts]
|
347
|
+
self[:uts][:ts64].__send__(:[], meth, *args)
|
322
348
|
end
|
323
349
|
end
|
324
350
|
end
|
@@ -427,6 +453,10 @@ EOM
|
|
427
453
|
layout :dsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
428
454
|
:uds, Ragweed::Wraposx::ThreadContext::UnionDebugState
|
429
455
|
|
456
|
+
def is_64?; self[:dsh].is_64?; end
|
457
|
+
def is_32?; !is_64?; end
|
458
|
+
def header; self[:dsh]; end
|
459
|
+
|
430
460
|
# We have rubified this FFI structure by creating a bunch of proxy
|
431
461
|
# methods that are normally only accessible via self.v.x.y which is
|
432
462
|
# a lot to type. You can still use that method however these proxy
|
@@ -435,11 +465,11 @@ EOM
|
|
435
465
|
def methods regular=true
|
436
466
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
437
467
|
ret += self[:dsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
438
|
-
ret
|
468
|
+
ret += case self[:dsh][:flavor]
|
439
469
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
440
|
-
self[:uds]
|
470
|
+
self[:uds][:ds32].members.map{|x| [x.to_s, x.to_s + "="]}
|
441
471
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
442
|
-
self[:uds]
|
472
|
+
self[:uds][:ds64].members.map{|x| [x.to_s, x.to_s + "="]}
|
443
473
|
else
|
444
474
|
[]
|
445
475
|
end
|
@@ -449,11 +479,11 @@ EOM
|
|
449
479
|
def methods regular=true
|
450
480
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
451
481
|
ret += self[:dsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
452
|
-
ret
|
482
|
+
ret += case self[:dsh][:flavor]
|
453
483
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
454
|
-
self[:uds]
|
484
|
+
self[:uds][:ds32].members.map{|x| [x, (x.to_s + "=").intern]}
|
455
485
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
456
|
-
self[:uds]
|
486
|
+
self[:uds][:ds64].members.map{|x| [x, (x.to_s + "=").intern]}
|
457
487
|
else
|
458
488
|
[]
|
459
489
|
end
|
@@ -473,9 +503,9 @@ EOM
|
|
473
503
|
else
|
474
504
|
case self[:dsh][:flavor]
|
475
505
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
476
|
-
self[:uds]
|
506
|
+
self[:uds][:ds32].__send__(:[]=, mth, *args)
|
477
507
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
478
|
-
self[:uds]
|
508
|
+
self[:uds][:ds64].__send__(:[]=, mth, *args)
|
479
509
|
end
|
480
510
|
end
|
481
511
|
else
|
@@ -487,9 +517,9 @@ EOM
|
|
487
517
|
else
|
488
518
|
case self[:dsh][:flavor]
|
489
519
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
|
490
|
-
self[:uds]
|
520
|
+
self[:uds][:ds32].__send__(:[], meth, *args)
|
491
521
|
when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
|
492
|
-
self[:uds]
|
522
|
+
self[:uds][:ds64].__send__(:[], meth, *args)
|
493
523
|
end
|
494
524
|
end
|
495
525
|
end
|
@@ -567,7 +597,11 @@ EOM
|
|
567
597
|
layout :esh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
568
598
|
:ues, Ragweed::Wraposx::ThreadContext::UnionExceptionState
|
569
599
|
|
570
|
-
|
600
|
+
|
601
|
+
def is_64?; self[:esh].is_64?; end
|
602
|
+
def is_32?; !is_64?; end
|
603
|
+
def header; self[:esh]; end
|
604
|
+
|
571
605
|
# We have rubified this FFI structure by creating a bunch of proxy
|
572
606
|
# methods that are normally only accessible via self.v.x.y which is
|
573
607
|
# a lot to type. You can still use that method however these proxy
|
@@ -576,11 +610,11 @@ EOM
|
|
576
610
|
def methods regular=true
|
577
611
|
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
578
612
|
ret += self[:esh].members.map{|x| [x.to_s, x.to_s + "="]}
|
579
|
-
ret
|
613
|
+
ret += case self[:esh][:flavor]
|
580
614
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
581
|
-
self[:ues]
|
615
|
+
self[:ues][:es32].members.map{|x| [x.to_s, x.to_s + "="]}
|
582
616
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
583
|
-
self[:ues]
|
617
|
+
self[:ues][:es64].members.map{|x| [x.to_s, x.to_s + "="]}
|
584
618
|
else
|
585
619
|
[]
|
586
620
|
end
|
@@ -590,11 +624,11 @@ EOM
|
|
590
624
|
def methods regular=true
|
591
625
|
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
592
626
|
ret += self[:esh].members.map{|x| [x, (x.to_s + "=").intern]}
|
593
|
-
ret
|
627
|
+
ret += case self[:esh][:flavor]
|
594
628
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
595
|
-
self[:ues]
|
629
|
+
self[:ues][:es32].members.map{|x| [x, (x.to_s + "=").intern]}
|
596
630
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
597
|
-
self[:ues]
|
631
|
+
self[:ues][:es64].members.map{|x| [x, (x.to_s + "=").intern]}
|
598
632
|
else
|
599
633
|
[]
|
600
634
|
end
|
@@ -614,9 +648,9 @@ EOM
|
|
614
648
|
else
|
615
649
|
case self[:esh][:flavor]
|
616
650
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
617
|
-
self[:ues]
|
651
|
+
self[:ues][:es32].__send__(:[]=, mth, *args)
|
618
652
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
619
|
-
self[:ues]
|
653
|
+
self[:ues][:es64].__send__(:[]=, mth, *args)
|
620
654
|
end
|
621
655
|
end
|
622
656
|
else
|
@@ -628,9 +662,9 @@ EOM
|
|
628
662
|
else
|
629
663
|
case self[:esh][:flavor]
|
630
664
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
631
|
-
self[:ues]
|
665
|
+
self[:ues][:es32].__send__(:[], meth, *args)
|
632
666
|
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
633
|
-
self[:ues]
|
667
|
+
self[:ues][:es64].__send__(:[], meth, *args)
|
634
668
|
end
|
635
669
|
end
|
636
670
|
end
|
@@ -843,6 +877,83 @@ EOM
|
|
843
877
|
FLAVOR = 8
|
844
878
|
layout :fsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
|
845
879
|
:ufs, Ragweed::Wraposx::ThreadContext::UnionFloatState
|
880
|
+
|
881
|
+
def is_64?; self[:fsh].is_64?; end
|
882
|
+
def is_32?; !is_64?; end
|
883
|
+
def header; self[:fsh]; end
|
884
|
+
|
885
|
+
# We have rubified this FFI structure by creating a bunch of proxy
|
886
|
+
# methods that are normally only accessible via self.v.x.y which is
|
887
|
+
# a lot to type. You can still use that method however these proxy
|
888
|
+
# methods should allow for considerably clearer code
|
889
|
+
if RUBY_VERSION < "1.9"
|
890
|
+
def methods regular=true
|
891
|
+
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
892
|
+
ret += self[:fsh].members.map{|x| [x.to_s, x.to_s + "="]}
|
893
|
+
ret += case self[:fsh][:flavor]
|
894
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE32
|
895
|
+
self[:ufs][:fs32].members.map{|x| [x.to_s, x.to_s + "="]}
|
896
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE64
|
897
|
+
self[:ufs][:fs64].members.map{|x| [x.to_s, x.to_s + "="]}
|
898
|
+
else
|
899
|
+
[]
|
900
|
+
end
|
901
|
+
ret.flatten
|
902
|
+
end
|
903
|
+
else
|
904
|
+
def methods regular=true
|
905
|
+
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
906
|
+
ret += self[:fsh].members.map{|x| [x, (x.to_s + "=").intern]}
|
907
|
+
ret += case self[:fsh][:flavor]
|
908
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE32
|
909
|
+
self[:ufs][:fs32].members.map{|x| [x, (x.to_s + "=").intern]}
|
910
|
+
when Ragweed::Wraposx::ThreadContext::X86_FLOAT_STATE64
|
911
|
+
self[:ufs][:fs64].members.map{|x| [x, (x.to_s + "=").intern]}
|
912
|
+
else
|
913
|
+
[]
|
914
|
+
end
|
915
|
+
ret.flatten
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
def method_missing meth, *args
|
920
|
+
super unless self.respond_to? meth
|
921
|
+
if meth.to_s =~ /=$/
|
922
|
+
mth = meth.to_s.gsub(/=$/,'').intern
|
923
|
+
if self.members.include? mth
|
924
|
+
# don't proxy
|
925
|
+
self.__send__(:[]=, mth, *args)
|
926
|
+
elsif self[:fsh].members.include? meth
|
927
|
+
self[:fsh].__send__(:[]=, mth, *args)
|
928
|
+
else
|
929
|
+
case self[:fsh][:flavor]
|
930
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
931
|
+
self[:ufs][:fs32].__send__(:[]=, mth, *args)
|
932
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
933
|
+
self[:ufs][:fs64].__send__(:[]=, mth, *args)
|
934
|
+
end
|
935
|
+
end
|
936
|
+
else
|
937
|
+
if self.members.include? meth
|
938
|
+
# don't proxy
|
939
|
+
self.__send__(:[], meth, *args)
|
940
|
+
elsif self[:fsh].members.include? meth
|
941
|
+
self[:fsh].__send__(:[], meth, *args)
|
942
|
+
else
|
943
|
+
case self[:fsh][:flavor]
|
944
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
|
945
|
+
self[:ufs][:fs32].__send__(:[], meth, *args)
|
946
|
+
when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
|
947
|
+
self[:ufs][:fs64].__send__(:[], meth, *args)
|
948
|
+
end
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
|
953
|
+
def respond_to? meth, include_priv=false
|
954
|
+
mth = meth.to_s.gsub(/=$/,'') # may not be needed anymore
|
955
|
+
self.methods.include? mth || super
|
956
|
+
end
|
846
957
|
end
|
847
958
|
|
848
959
|
FLAVORS = {
|
@@ -866,7 +977,7 @@ module Ragweed::Wraposx
|
|
866
977
|
module Libc
|
867
978
|
extend FFI::Library
|
868
979
|
ffi_lib FFI::Library::LIBC
|
869
|
-
attach_function :thread_get_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :
|
980
|
+
attach_function :thread_get_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :pointer], :kern_return_t
|
870
981
|
attach_function :thread_set_state, [:thread_act_t, :thread_state_flavor_t, :pointer, :mach_msg_type_number_t], :kern_return_t
|
871
982
|
end
|
872
983
|
|
@@ -877,13 +988,13 @@ module Ragweed::Wraposx
|
|
877
988
|
# (thread_act_t target_thread,
|
878
989
|
# thread_state_flavor_t flavor,
|
879
990
|
# thread_state_t old_state,
|
880
|
-
# mach_msg_type_number_t old_state_count);
|
991
|
+
# mach_msg_type_number_t *old_state_count);
|
881
992
|
def thread_get_state(thread,flavor)
|
882
|
-
state = FFI::MemoryPointer.new Ragweed::Wraposx::ThreadContext::
|
883
|
-
count = FFI::MemoryPointer.new(:int, 1).
|
993
|
+
state = FFI::MemoryPointer.new Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class]
|
994
|
+
count = FFI::MemoryPointer.new(:int, 1).write_uint Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:count]
|
884
995
|
r = Libc.thread_get_state(thread, flavor, state, count)
|
885
996
|
raise KernelCallError.new(:thread_get_state, r) if r != 0
|
886
|
-
Ragweed::Wraposx::ThreadContext::
|
997
|
+
Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state
|
887
998
|
end
|
888
999
|
|
889
1000
|
# Sets the register state of thread.
|
@@ -892,11 +1003,11 @@ module Ragweed::Wraposx
|
|
892
1003
|
# (thread_act_t target_thread,
|
893
1004
|
# thread_state_flavor_t flavor,
|
894
1005
|
# thread_state_t new_state,
|
895
|
-
#
|
1006
|
+
# mach_msg_type_number_t new_state_count);
|
896
1007
|
def thread_set_state(thread, flavor, state)
|
897
1008
|
r = Libc.thread_set_state(thread, flavor, state.to_ptr, ThreadContext::FLAVORS[flavor][:count])
|
898
1009
|
raise KernelCallError.new(:thread_set_state, r) if r!= 0
|
899
|
-
Ragweed::Wraposx::ThreadContext::
|
1010
|
+
Ragweed::Wraposx::ThreadContext::FLAVORS[flavor][:class].new state
|
900
1011
|
end
|
901
1012
|
end
|
902
1013
|
end
|
@@ -178,10 +178,10 @@ module Ragweed::Wraposx
|
|
178
178
|
# There is no man page for this call.
|
179
179
|
def task_for_pid(pid, target=nil)
|
180
180
|
target ||= mach_task_self
|
181
|
-
port = FFI::MemoryPointer.new :
|
181
|
+
port = FFI::MemoryPointer.new :uint, 1
|
182
182
|
r = Libc.task_for_pid(target, pid, port)
|
183
183
|
raise KernelCallError.new(:task_for_pid, r) if r != 0
|
184
|
-
port.
|
184
|
+
port.read_uint
|
185
185
|
end
|
186
186
|
|
187
187
|
# Returns an Array of thread IDs for the given task
|
@@ -193,11 +193,11 @@ module Ragweed::Wraposx
|
|
193
193
|
#
|
194
194
|
#There is no man page for this funtion.
|
195
195
|
def task_threads(port)
|
196
|
-
threads = FFI::MemoryPointer.new :
|
196
|
+
threads = FFI::MemoryPointer.new :pointer, 1
|
197
197
|
count = FFI::MemoryPointer.new :int, 1
|
198
198
|
r = Libc.task_threads(port, threads, count)
|
199
199
|
raise KernelCallError.new(:task_threads, r) if r != 0
|
200
|
-
threads.
|
200
|
+
threads.read_pointer.read_array_of_uint(count.read_uint)
|
201
201
|
end
|
202
202
|
|
203
203
|
# Decrement the target tasks suspend count
|
@@ -215,6 +215,7 @@ module Ragweed::Wraposx
|
|
215
215
|
def task_suspend(task)
|
216
216
|
r = Libc.task_suspend(task)
|
217
217
|
raise KernelCallError.new(r) if r != 0
|
218
|
+
r
|
218
219
|
end
|
219
220
|
|
220
221
|
# Sends a signal to a process
|
@@ -227,6 +228,7 @@ module Ragweed::Wraposx
|
|
227
228
|
FFI::errno = 0
|
228
229
|
r = Libc.kill(pid, sig)
|
229
230
|
raise SystemCallError.new "kill", FFI::errno if r != 0
|
231
|
+
r
|
230
232
|
end
|
231
233
|
|
232
234
|
# Reads sz bytes from task's address space starting at addr.
|
@@ -241,10 +243,10 @@ module Ragweed::Wraposx
|
|
241
243
|
# There is no man page for this function.
|
242
244
|
def vm_read(task, addr, sz=256)
|
243
245
|
buf = FFI::MemoryPointer.new(sz)
|
244
|
-
len = FFI::MemoryPointer(sz
|
246
|
+
len = FFI::MemoryPointer.new(:uint).write_uint(sz)
|
245
247
|
r = Libc.vm_read_overwrite(task, addr, sz, buf, len)
|
246
248
|
raise KernelCallError.new(:vm_read, r) if r != 0
|
247
|
-
|
249
|
+
buf.read_string(len.read_uint)
|
248
250
|
end
|
249
251
|
|
250
252
|
# Writes val to task's memory space at address addr.
|
@@ -258,10 +260,10 @@ module Ragweed::Wraposx
|
|
258
260
|
#
|
259
261
|
# There is no man page for this function.
|
260
262
|
def vm_write(task, addr, val)
|
261
|
-
val = FFI::MemoryPointer.new
|
263
|
+
val = FFI::MemoryPointer.new(val)
|
262
264
|
r = Libc.vm_write(task, addr, val, val.size)
|
263
265
|
raise KernelCallError.new(:vm_write, r) if r != 0
|
264
|
-
|
266
|
+
r
|
265
267
|
end
|
266
268
|
|
267
269
|
# Changes the protection state beginning at addr for size bytes to the mask prot.
|
@@ -279,7 +281,7 @@ module Ragweed::Wraposx
|
|
279
281
|
setmax = setmax ? 1 : 0
|
280
282
|
r = Libc.vm_protect(task, addr, size, setmax, prot)
|
281
283
|
raise KernelCallError.new(:vm_protect, r) if r != 0
|
282
|
-
|
284
|
+
r
|
283
285
|
end
|
284
286
|
|
285
287
|
# Allocates a page in the memory space of the target task.
|
@@ -311,6 +313,7 @@ module Ragweed::Wraposx
|
|
311
313
|
addr.write_int(address)
|
312
314
|
r = Libc.vm_deallocate(task, addr, size)
|
313
315
|
raise KernelCallError.new(r) if r != 0
|
316
|
+
r
|
314
317
|
end
|
315
318
|
|
316
319
|
# Resumes a suspended thread by id.
|
@@ -322,6 +325,7 @@ module Ragweed::Wraposx
|
|
322
325
|
def thread_resume(thread)
|
323
326
|
r = Libc.thread_resume(thread)
|
324
327
|
raise KernelCallError.new(:thread_resume, r) if r != 0
|
328
|
+
r
|
325
329
|
end
|
326
330
|
|
327
331
|
# Suspends a thread by id.
|
@@ -333,6 +337,7 @@ module Ragweed::Wraposx
|
|
333
337
|
def thread_suspend(thread)
|
334
338
|
r = Libc.thread_suspend(thread)
|
335
339
|
raise KernelCallError.new(:thread_suspend, r) if r != 0
|
340
|
+
r
|
336
341
|
end
|
337
342
|
|
338
343
|
# Changes execution to file in path with *args as though called from command line.
|
@@ -8,7 +8,8 @@ class Ragweed::Process
|
|
8
8
|
## Read/write ranges of data or fixnums to/from the process by address.
|
9
9
|
def read(off, sz=4096)
|
10
10
|
a = []
|
11
|
-
|
11
|
+
max = off+sz
|
12
|
+
while off < max
|
12
13
|
a.push(Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, off, 0))
|
13
14
|
return a.pack('L*') if a.last == -1 and FFI.errno != 0
|
14
15
|
off+=4
|
data/ragweed.gemspec
CHANGED
@@ -5,11 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{ragweed}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.3"
|
9
|
+
s.platform = %q{java}
|
9
10
|
|
10
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
12
|
s.authors = ["tduehr", "struct", "tqbf"]
|
12
|
-
s.date = %q{2011-
|
13
|
+
s.date = %q{2011-06-09}
|
13
14
|
s.description = %q{General debugging tool written in Ruby for OSX/Win32/Linux}
|
14
15
|
s.email = %q{td@matasano.com}
|
15
16
|
s.extra_rdoc_files = [
|
@@ -59,7 +60,6 @@ Gem::Specification.new do |s|
|
|
59
60
|
"lib/ragweed/wraposx/structs.rb",
|
60
61
|
"lib/ragweed/wraposx/thread_context.rb",
|
61
62
|
"lib/ragweed/wraposx/thread_info.rb",
|
62
|
-
"lib/ragweed/wraposx/thread_info.rb.old",
|
63
63
|
"lib/ragweed/wraposx/wraposx.rb",
|
64
64
|
"lib/ragweed/wraptux.rb",
|
65
65
|
"lib/ragweed/wraptux/constants.rb",
|
@@ -74,29 +74,16 @@ Gem::Specification.new do |s|
|
|
74
74
|
s.homepage = %q{http://github.com/tduehr/ragweed}
|
75
75
|
s.rdoc_options = ["--inline-source", "--line-numbers", "--main", "README.rdoc"]
|
76
76
|
s.require_paths = ["lib"]
|
77
|
-
s.rubygems_version = %q{1.5.
|
77
|
+
s.rubygems_version = %q{1.5.1}
|
78
78
|
s.summary = %q{Scriptable debugger}
|
79
|
-
s.test_files = [
|
80
|
-
"examples/hittracertux.rb",
|
81
|
-
"examples/hittracerx.rb",
|
82
|
-
"examples/hook_notepad.rb",
|
83
|
-
"examples/snicker.rb",
|
84
|
-
"examples/tux-example.rb",
|
85
|
-
"spec/ragweed_spec.rb",
|
86
|
-
"spec/spec_helper.rb",
|
87
|
-
"test/test_ragweed.rb"
|
88
|
-
]
|
89
79
|
|
90
80
|
if s.respond_to? :specification_version then
|
91
81
|
s.specification_version = 3
|
92
82
|
|
93
83
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
94
|
-
s.add_runtime_dependency(%q<ffi>, ["~> 1.0"])
|
95
84
|
else
|
96
|
-
s.add_dependency(%q<ffi>, ["~> 1.0"])
|
97
85
|
end
|
98
86
|
else
|
99
|
-
s.add_dependency(%q<ffi>, ["~> 1.0"])
|
100
87
|
end
|
101
88
|
end
|
102
89
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ragweed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.3
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- tduehr
|
@@ -12,7 +12,7 @@ autorequire:
|
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
14
|
|
15
|
-
date: 2011-
|
15
|
+
date: 2011-06-09 00:00:00 -05:00
|
16
16
|
default_executable:
|
17
17
|
dependencies: []
|
18
18
|
|
@@ -68,7 +68,6 @@ files:
|
|
68
68
|
- lib/ragweed/wraposx/structs.rb
|
69
69
|
- lib/ragweed/wraposx/thread_context.rb
|
70
70
|
- lib/ragweed/wraposx/thread_info.rb
|
71
|
-
- lib/ragweed/wraposx/thread_info.rb.old
|
72
71
|
- lib/ragweed/wraposx/wraposx.rb
|
73
72
|
- lib/ragweed/wraptux.rb
|
74
73
|
- lib/ragweed/wraptux/constants.rb
|
@@ -110,12 +109,5 @@ rubygems_version: 1.5.1
|
|
110
109
|
signing_key:
|
111
110
|
specification_version: 3
|
112
111
|
summary: Scriptable debugger
|
113
|
-
test_files:
|
114
|
-
|
115
|
-
- examples/hittracerx.rb
|
116
|
-
- examples/hook_notepad.rb
|
117
|
-
- examples/snicker.rb
|
118
|
-
- examples/tux-example.rb
|
119
|
-
- spec/ragweed_spec.rb
|
120
|
-
- spec/spec_helper.rb
|
121
|
-
- test/test_ragweed.rb
|
112
|
+
test_files: []
|
113
|
+
|
@@ -1,121 +0,0 @@
|
|
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
|