tduehr-ragweed 0.1.7 → 0.1.7.1
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/History.txt +5 -0
- data/Rakefile +4 -2
- data/examples/tux-example.rb +1 -1
- data/lib/ragweed/debugger32.rb +40 -40
- data/lib/ragweed/debuggerosx.rb +10 -2
- data/lib/ragweed/debuggertux.rb +33 -33
- data/lib/ragweed/rasm/bblock.rb +68 -0
- data/lib/ragweed/rasm/isa.rb +38 -5
- data/lib/ragweed/rasm.rb +1 -1
- data/lib/ragweed/sbuf.rb +1 -1
- data/lib/ragweed/trampoline.rb +5 -5
- data/lib/ragweed/utils.rb +83 -41
- data/lib/ragweed/wrap32/debugging.rb +12 -12
- data/lib/ragweed/wrap32/device.rb +6 -6
- data/lib/ragweed/wrap32/event.rb +3 -3
- data/lib/ragweed/wrap32/process.rb +20 -20
- data/lib/ragweed/wrap32/process_token.rb +5 -5
- data/lib/ragweed/wrap32/thread_context.rb +9 -9
- data/lib/ragweed/wrap32/wrap32.rb +4 -4
- data/lib/ragweed/wrap32.rb +1 -1
- data/lib/ragweed/wraposx/kernelerrorx.rb +1 -1
- data/lib/ragweed/wraposx/thread_info.rb +1 -1
- data/lib/ragweed/wraposx/wraposx.rb +63 -0
- data/lib/ragweed/wraposx.rb +1 -1
- data/lib/ragweed/wraptux.rb +1 -1
- data/lib/ragweed.rb +1 -1
- data/ragweed.gemspec +34 -0
- metadata +13 -10
data/lib/ragweed/utils.rb
CHANGED
@@ -1,41 +1,59 @@
|
|
1
|
+
class Array
|
2
|
+
module ArrayExtensions
|
3
|
+
# Convert to hash
|
4
|
+
##
|
5
|
+
def to_hash
|
6
|
+
# too clever.
|
7
|
+
# Hash[*self.flatten]
|
8
|
+
|
9
|
+
h = Hash.new
|
10
|
+
each do |k,v|
|
11
|
+
h[k] = v
|
12
|
+
end
|
13
|
+
h
|
14
|
+
end
|
15
|
+
end
|
16
|
+
include ArrayExtensions
|
17
|
+
end
|
18
|
+
|
1
19
|
# These should probably be extensions to Module since that's the location of instance_eval and friends.
|
2
20
|
class Object
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def through(meth, *args)
|
13
|
-
if respond_to? meth
|
14
|
-
send(meth, *args)
|
15
|
-
else
|
16
|
-
self
|
17
|
-
end
|
18
|
-
end
|
21
|
+
module ObjectExtensions
|
22
|
+
# Every object has a "singleton" class, which you can think
|
23
|
+
# of as the class (ie, 1.metaclass =~ Fixnum) --- but that you
|
24
|
+
# can modify and extend without fucking up the actual class.
|
25
|
+
def metaclass; class << self; self; end; end
|
26
|
+
def meta_eval(&blk) metaclass.instance_eval &blk; end
|
27
|
+
def meta_def(name, &blk) meta_eval { define_method name, &blk }; end
|
28
|
+
def try(meth, *args); send(meth, *args) if respond_to? meth; end
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
(
|
30
|
+
def through(meth, *args)
|
31
|
+
if respond_to? meth
|
32
|
+
send(meth, *args)
|
33
|
+
else
|
34
|
+
self
|
23
35
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
end
|
37
|
+
|
38
|
+
## This is from Topher Cyll's Stupd IRB tricks
|
39
|
+
def mymethods
|
40
|
+
(self.methods - self.class.superclass.methods).sort
|
41
|
+
end
|
42
|
+
# self-evident
|
43
|
+
def callable?; respond_to? :call; end
|
44
|
+
def number?; kind_of? Numeric; end
|
45
|
+
|
46
|
+
# while X remains callable, keep calling it to get its value
|
47
|
+
def derive
|
48
|
+
# also, don't drink and derive
|
49
|
+
x = self
|
50
|
+
while x.callable?
|
51
|
+
x = x()
|
36
52
|
end
|
53
|
+
return x
|
37
54
|
end
|
38
|
-
|
55
|
+
end
|
56
|
+
include ObjectExtensions
|
39
57
|
end
|
40
58
|
|
41
59
|
class String
|
@@ -51,21 +69,31 @@ class String
|
|
51
69
|
def shift_u8; shift(1).to_u8; end
|
52
70
|
|
53
71
|
def shift(count=1)
|
54
|
-
|
55
|
-
|
72
|
+
return self if count == 0
|
73
|
+
slice! 0..(count-1)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Sometimes string buffers passed through Win32 interfaces come with
|
77
|
+
# garbage after the trailing NUL; this method gets rid of that, like
|
78
|
+
# String#trim
|
79
|
+
def asciiz
|
80
|
+
begin
|
81
|
+
self[0..self.index("\x00")-1]
|
82
|
+
rescue
|
83
|
+
self
|
84
|
+
end
|
56
85
|
end
|
86
|
+
|
87
|
+
def asciiz!; replace asciiz; end
|
57
88
|
|
58
89
|
# Convert a string into hex characters
|
59
90
|
def hexify
|
60
|
-
|
61
|
-
each_byte{|b| l << "%02x" % b}
|
62
|
-
l.join
|
91
|
+
self.unpack("H*").first
|
63
92
|
end
|
64
93
|
|
65
94
|
# Convert a string of raw hex characters (no %'s or anything) into binary
|
66
95
|
def dehexify
|
67
|
-
|
68
|
-
return ret
|
96
|
+
[self].pack("H*")
|
69
97
|
end
|
70
98
|
end
|
71
99
|
|
@@ -77,11 +105,17 @@ class Integer
|
|
77
105
|
def to_l16; [self].pack "v"; end
|
78
106
|
def to_b16; [self].pack "n"; end
|
79
107
|
def to_u8; [self].pack "C"; end
|
108
|
+
|
109
|
+
# sign extend
|
110
|
+
def sx8; ([self].pack "c").unpack("C").first; end
|
111
|
+
def sx16; ([self].pack "s").unpack("S").first; end
|
112
|
+
def sx32; ([self].pack "l").unpack("L").first; end
|
113
|
+
|
80
114
|
def ffs
|
81
115
|
i = 0
|
82
116
|
v = self
|
83
117
|
while((v >>= 1) != 0)
|
84
|
-
|
118
|
+
i += 1
|
85
119
|
end
|
86
120
|
return i
|
87
121
|
end
|
@@ -90,6 +124,14 @@ class Integer
|
|
90
124
|
end
|
91
125
|
|
92
126
|
class Module
|
127
|
+
def to_name_hash
|
128
|
+
@name_hash ||= constants.map {|k| [k.intern, const_get(k.intern)]}.to_hash
|
129
|
+
end
|
130
|
+
|
131
|
+
def to_key_hash
|
132
|
+
@key_hash ||= constants.map {|k| [const_get(k.intern), k.intern]}.to_hash
|
133
|
+
end
|
134
|
+
|
93
135
|
def flag_dump(i)
|
94
136
|
@bit_map ||= constants.map do |k|
|
95
137
|
[k, const_get(k.intern).ffs]
|
@@ -111,4 +153,4 @@ class Module
|
|
111
153
|
end
|
112
154
|
return r.reverse
|
113
155
|
end
|
114
|
-
end
|
156
|
+
end
|
@@ -63,14 +63,14 @@ class Ragweed::Wrap32::DebugEvent
|
|
63
63
|
@code, @pid, @tid = str.unpack("LLL")
|
64
64
|
str.shift 12
|
65
65
|
case @code
|
66
|
-
when Wrap32::DebugCodes::CREATE_PROCESS
|
66
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
67
67
|
@file_handle, @process_handle, @thread_handle,
|
68
68
|
@base, @offset,
|
69
69
|
@info_size, @thread_base, @start_address,
|
70
70
|
@image_name, @unicode = str.unpack("LLLLLLLLLH")
|
71
|
-
when Wrap32::DebugCodes::CREATE_THREAD
|
71
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
72
72
|
@thread_handle, @thread_base, @start_address = str.unpack("LLL")
|
73
|
-
when Wrap32::DebugCodes::EXCEPTION
|
73
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
74
74
|
@exception_code, @exception_flags,
|
75
75
|
@exception_record, @exception_address, @parameter_count = str.unpack("LLLLL")
|
76
76
|
str = str[20..-1]
|
@@ -81,17 +81,17 @@ class Ragweed::Wrap32::DebugEvent
|
|
81
81
|
str = str[4..-1]
|
82
82
|
rescue;end
|
83
83
|
end
|
84
|
-
when Wrap32::DebugCodes::EXIT_PROCESS
|
84
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
85
85
|
@exit_code = str.unpack("L").first
|
86
|
-
when Wrap32::DebugCodes::EXIT_THREAD
|
86
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
87
87
|
@exit_code = str.unpack("L").first
|
88
|
-
when Wrap32::DebugCodes::LOAD_DLL
|
88
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
89
89
|
@file_handle, @dll_base, @offset,
|
90
90
|
@info_size, @image_name, @unicode = str.unpack("LLLLLH")
|
91
|
-
when Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
92
|
-
when Wrap32::DebugCodes::RIP
|
91
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
92
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
93
93
|
@rip_error, @rip_type = str.unpack("LL")
|
94
|
-
when Wrap32::DebugCodes::UNLOAD_DLL
|
94
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
95
95
|
@dll_base = str.unpack("L").first
|
96
96
|
else
|
97
97
|
raise WinX.new(:wait_for_debug_event)
|
@@ -99,11 +99,11 @@ class Ragweed::Wrap32::DebugEvent
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def inspect_code(c)
|
102
|
-
Wrap32::DebugCodes.to_key_hash[c].to_s || c.to_i
|
102
|
+
Ragweed::Wrap32::DebugCodes.to_key_hash[c].to_s || c.to_i
|
103
103
|
end
|
104
104
|
|
105
105
|
def inspect_exception_code(c)
|
106
|
-
Wrap32::ExceptionCodes.to_key_hash[c].to_s || c.to_i.to_s(16)
|
106
|
+
Ragweed::Wrap32::ExceptionCodes.to_key_hash[c].to_s || c.to_i.to_s(16)
|
107
107
|
end
|
108
108
|
|
109
109
|
def inspect_parameters(p)
|
@@ -129,7 +129,7 @@ module Ragweed::Wrap32
|
|
129
129
|
buf = "\x00" * 1024
|
130
130
|
r = CALLS["kernel32!WaitForDebugEvent:PL=L"].call(buf, ms)
|
131
131
|
raise WinX.new(:wait_for_debug_event) if r == 0 and get_last_error != 121
|
132
|
-
return Wrap32::DebugEvent.new(buf) if r != 0
|
132
|
+
return Ragweed::Wrap32::DebugEvent.new(buf) if r != 0
|
133
133
|
return nil
|
134
134
|
end
|
135
135
|
|
@@ -3,12 +3,12 @@ module Ragweed
|
|
3
3
|
def initialize(path, options={})
|
4
4
|
@path = path
|
5
5
|
@options = options
|
6
|
-
@h = Wrap32::create_file(@path, :flags => Wrap32::FileAttributes::OVERLAPPED|Wrap32::FileAttributes::NORMAL)
|
6
|
+
@h = Ragweed::Wrap32::create_file(@path, :flags => Ragweed::Wrap32::FileAttributes::OVERLAPPED|Ragweed::Wrap32::FileAttributes::NORMAL)
|
7
7
|
end
|
8
8
|
|
9
9
|
def ioctl(code, inbuf, outbuf)
|
10
10
|
overlap(lambda do |o|
|
11
|
-
Wrap32::device_io_control(@h, code, inbuf, outbuf, o)
|
11
|
+
Ragweed::Wrap32::device_io_control(@h, code, inbuf, outbuf, o)
|
12
12
|
end) do |ret, count|
|
13
13
|
outbuf[0..count]
|
14
14
|
end
|
@@ -16,7 +16,7 @@ module Ragweed
|
|
16
16
|
|
17
17
|
def read(sz)
|
18
18
|
overlap(lambda do |o|
|
19
|
-
Wrap32::read_file(@h, sz, o)
|
19
|
+
Ragweed::Wrap32::read_file(@h, sz, o)
|
20
20
|
end) do |ret, count|
|
21
21
|
ret[0..count]
|
22
22
|
end
|
@@ -24,21 +24,21 @@ module Ragweed
|
|
24
24
|
|
25
25
|
def write(buf)
|
26
26
|
overlap(lambda do |o|
|
27
|
-
Wrap32::write_file(@h, buf, o)
|
27
|
+
Ragweed::Wrap32::write_file(@h, buf, o)
|
28
28
|
end) do |ret, count|
|
29
29
|
count
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
def release
|
34
|
-
Wrap32::close_handle(@h)
|
34
|
+
Ragweed::Wrap32::close_handle(@h)
|
35
35
|
@h = nil
|
36
36
|
end
|
37
37
|
|
38
38
|
private
|
39
39
|
|
40
40
|
def overlap(proc)
|
41
|
-
o = Wrap32::Overlapped.get
|
41
|
+
o = Ragweed::Wrap32::Overlapped.get
|
42
42
|
ret = proc.call(o)
|
43
43
|
count = o.wait(@h)
|
44
44
|
r = yield ret, count
|
data/lib/ragweed/wrap32/event.rb
CHANGED
@@ -27,17 +27,17 @@ class Ragweed::Event
|
|
27
27
|
# Don't return until the event is signalled. Note that you
|
28
28
|
# can't break this with timeouts or CTR-C.
|
29
29
|
def wait
|
30
|
-
Wrap32::wait_for_single_object @h
|
30
|
+
Ragweed::Wrap32::wait_for_single_object @h
|
31
31
|
end
|
32
32
|
|
33
33
|
# Signal the event; anyone waiting on it is now released.
|
34
34
|
def signal
|
35
|
-
Wrap32::set_event(@h)
|
35
|
+
Ragweed::Wrap32::set_event(@h)
|
36
36
|
end
|
37
37
|
|
38
38
|
# Force the event back to unsignalled state.
|
39
39
|
def reset
|
40
|
-
Wrap32::reset_event(@h)
|
40
|
+
Ragweed::Wrap32::reset_event(@h)
|
41
41
|
end
|
42
42
|
|
43
43
|
# A wait loop.
|
@@ -6,7 +6,7 @@ class Ragweed::Process
|
|
6
6
|
include Ragweed
|
7
7
|
|
8
8
|
def self.find_by_regex(name)
|
9
|
-
Wrap32::all_processes do |p|
|
9
|
+
Ragweed::Wrap32::all_processes do |p|
|
10
10
|
if p.szExeFile =~ name
|
11
11
|
return self.new(p.th32ProcessID)
|
12
12
|
end
|
@@ -23,7 +23,7 @@ class Ragweed::Process
|
|
23
23
|
|
24
24
|
# clone a handle from the remote process to here (to here? tf?)
|
25
25
|
def dup_handle(h)
|
26
|
-
Wrap32::duplicate_handle(@h, h)
|
26
|
+
Ragweed::Wrap32::duplicate_handle(@h, h)
|
27
27
|
end
|
28
28
|
|
29
29
|
# look up a process by its name --- but this is in the local process,
|
@@ -31,7 +31,7 @@ class Ragweed::Process
|
|
31
31
|
# but probably never otherwise.
|
32
32
|
def get_proc(name)
|
33
33
|
return Ptr.new(name) if name.kind_of? Numeric or name.kind_of? Ptr
|
34
|
-
ptr(Wrap32::get_proc_address(name))
|
34
|
+
ptr(Ragweed::Wrap32::get_proc_address(name))
|
35
35
|
end
|
36
36
|
|
37
37
|
def get_proc_remote(name)
|
@@ -58,14 +58,14 @@ class Ragweed::Process
|
|
58
58
|
# Just need a PID to get started.
|
59
59
|
def initialize(pid)
|
60
60
|
@pid = pid
|
61
|
-
@h = Wrap32::open_process(pid)
|
61
|
+
@h = Ragweed::Wrap32::open_process(pid)
|
62
62
|
@a = arena()
|
63
63
|
end
|
64
64
|
|
65
65
|
# Return the EXE name of the process.
|
66
66
|
def image
|
67
67
|
buf = "\x00" * 256
|
68
|
-
if Wrap32::nt_query_information_process(@h, 27, buf)
|
68
|
+
if Ragweed::Wrap32::nt_query_information_process(@h, 27, buf)
|
69
69
|
buf = buf.from_utf16
|
70
70
|
buf = buf[(buf.index("\\"))..-1]
|
71
71
|
return buf.asciiz
|
@@ -76,9 +76,9 @@ class Ragweed::Process
|
|
76
76
|
# Return a list of all the threads in the process; relatively
|
77
77
|
# expensive, so cache the result.
|
78
78
|
def threads(full=false, &block)
|
79
|
-
return Wrap32::threads(@pid, &block) if block_given?
|
79
|
+
return Ragweed::Wrap32::threads(@pid, &block) if block_given?
|
80
80
|
ret = []
|
81
|
-
Wrap32::threads(@pid) {|x| ((full) ? ret << x : ret << x.th32ThreadID) }
|
81
|
+
Ragweed::Wrap32::threads(@pid) {|x| ((full) ? ret << x : ret << x.th32ThreadID) }
|
82
82
|
return ret
|
83
83
|
end
|
84
84
|
|
@@ -91,26 +91,26 @@ class Ragweed::Process
|
|
91
91
|
|
92
92
|
# Suspend a thread by tid. Technically, this doesn't need to be
|
93
93
|
# a method; you can suspend a thread anywhere without a process handle.
|
94
|
-
def suspend(tid); Wrap32::open_thread(tid) {|x| Wrap32::suspend_thread(x)}; end
|
94
|
+
def suspend(tid); Ragweed::Wrap32::open_thread(tid) {|x| Ragweed::Wrap32::suspend_thread(x)}; end
|
95
95
|
|
96
96
|
# Resume a thread by tid.
|
97
|
-
def resume(tid); Wrap32::open_thread(tid) {|x| Wrap32::resume_thread(x)}; end
|
97
|
+
def resume(tid); Ragweed::Wrap32::open_thread(tid) {|x| Ragweed::Wrap32::resume_thread(x)}; end
|
98
98
|
|
99
99
|
# List the modules for the process, either yielding a struct for
|
100
100
|
# each to a block, or returning a list.
|
101
101
|
def modules(&block)
|
102
102
|
if block_given?
|
103
|
-
Wrap32::list_modules(@pid, &block)
|
103
|
+
Ragweed::Wrap32::list_modules(@pid, &block)
|
104
104
|
else
|
105
105
|
ret = []
|
106
|
-
Wrap32::list_modules(@pid) {|x| ret << x}
|
106
|
+
Ragweed::Wrap32::list_modules(@pid) {|x| ret << x}
|
107
107
|
return ret
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
# Read/write ranges of data or fixnums to/from the process by address.
|
112
|
-
def read(off, sz=4096); Wrap32::read_process_memory(@h, off, sz); end
|
113
|
-
def write(off, data); Wrap32::write_process_memory(@h, off, data); end
|
112
|
+
def read(off, sz=4096); Ragweed::Wrap32::read_process_memory(@h, off, sz); end
|
113
|
+
def write(off, data); Ragweed::Wrap32::write_process_memory(@h, off, data); end
|
114
114
|
def read32(off); read(off, 4).unpack("L").first; end
|
115
115
|
def read16(off); read(off, 2).unpack("v").first; end
|
116
116
|
def read8(off); read(off, 1)[0]; end
|
@@ -130,11 +130,11 @@ class Ragweed::Process
|
|
130
130
|
end
|
131
131
|
|
132
132
|
# Can I write to this address in the process?
|
133
|
-
def writeable?(off); Wrap32::writeable? @h, off; end
|
133
|
+
def writeable?(off); Ragweed::Wrap32::writeable? @h, off; end
|
134
134
|
|
135
135
|
# Use VirtualAllocEx to grab a block of memory in the process. This
|
136
136
|
# is expensive, the equivalent of mmap()'ing for each allocation.
|
137
|
-
def syscall_alloc(sz); ptr(Wrap32::virtual_alloc_ex(@h, sz)); end
|
137
|
+
def syscall_alloc(sz); ptr(Ragweed::Wrap32::virtual_alloc_ex(@h, sz)); end
|
138
138
|
|
139
139
|
# Use arenas, when possible, to quickly allocate memory. The upside
|
140
140
|
# is this is very fast. The downside is you can't free the memory
|
@@ -150,7 +150,7 @@ class Ragweed::Process
|
|
150
150
|
# Free the return value of syscall_alloc. Do NOT use for the return
|
151
151
|
# value of alloc.
|
152
152
|
def free(off)
|
153
|
-
Wrap32::virtual_free_ex(@h, off)
|
153
|
+
Ragweed::Wrap32::virtual_free_ex(@h, off)
|
154
154
|
end
|
155
155
|
|
156
156
|
# Convert an address to "module+10h" notation, when possible.
|
@@ -199,7 +199,7 @@ class Ragweed::Process
|
|
199
199
|
def list_memory(&block)
|
200
200
|
ret = []
|
201
201
|
i = 0
|
202
|
-
while (mbi = Wrap32::virtual_query_ex(@h, i))
|
202
|
+
while (mbi = Ragweed::Wrap32::virtual_query_ex(@h, i))
|
203
203
|
break if (not ret.empty? and mbi.BaseAddress == 0)
|
204
204
|
if block_given?
|
205
205
|
yield mbi
|
@@ -250,8 +250,8 @@ class Ragweed::Process
|
|
250
250
|
# Dump thread context, returning a struct that contains things like
|
251
251
|
# .Eip and .Eax.
|
252
252
|
def thread_context(tid)
|
253
|
-
Wrap32::open_thread(tid) do |h|
|
254
|
-
Wrap32::get_thread_context(h)
|
253
|
+
Ragweed::Wrap32::open_thread(tid) do |h|
|
254
|
+
Ragweed::Wrap32::get_thread_context(h)
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
@@ -457,7 +457,7 @@ class Ragweed::Process
|
|
457
457
|
# Do something with a thread while its suspended
|
458
458
|
def with_suspended_thread(tid)
|
459
459
|
ret = nil
|
460
|
-
Wrap32::with_suspended_thread(tid) {|x| ret = yield}
|
460
|
+
Ragweed::Wrap32::with_suspended_thread(tid) {|x| ret = yield}
|
461
461
|
return ret
|
462
462
|
end
|
463
463
|
|
@@ -21,7 +21,7 @@ module Ragweed::Wrap32
|
|
21
21
|
end
|
22
22
|
|
23
23
|
class << self
|
24
|
-
def open_process_token(h, access=Wrap32::TokenAccess::ADJUST_PRIVILEGES)
|
24
|
+
def open_process_token(h, access=Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES)
|
25
25
|
outw = "\x00" * 4
|
26
26
|
r = CALLS["advapi32!OpenProcessToken:LLP=L"].call(h, access, outw)
|
27
27
|
raise WinX.new(:open_process_token) if r == 0
|
@@ -48,12 +48,12 @@ end
|
|
48
48
|
|
49
49
|
class Ragweed::Wrap32::ProcessToken
|
50
50
|
def initialize(p=nil)
|
51
|
-
p ||= Wrap32::open_process(Wrap32::get_current_process_id)
|
52
|
-
@h = Wrap32::open_process_token(p)
|
51
|
+
p ||= Ragweed::Wrap32::open_process(Ragweed::Wrap32::get_current_process_id)
|
52
|
+
@h = Ragweed::Wrap32::open_process_token(p)
|
53
53
|
end
|
54
54
|
|
55
55
|
def grant(name)
|
56
|
-
luid = Wrap32::lookup_privilege_value(name)
|
57
|
-
Wrap32::adjust_token_privileges(@h, 0, [luid, Wrap32::PrivilegeAttribute::ENABLED])
|
56
|
+
luid = Ragweed::Wrap32::lookup_privilege_value(name)
|
57
|
+
Ragweed::Wrap32::adjust_token_privileges(@h, 0, [luid, Ragweed::Wrap32::PrivilegeAttribute::ENABLED])
|
58
58
|
end
|
59
59
|
end
|
@@ -81,22 +81,22 @@ class Ragweed::Wrap32::ThreadContext
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.get(h)
|
84
|
-
self.new(Wrap32::get_thread_context_raw(h))
|
84
|
+
self.new(Ragweed::Wrap32::get_thread_context_raw(h))
|
85
85
|
end
|
86
86
|
|
87
87
|
def get(h)
|
88
|
-
refresh(Wrap32::get_thread_context_raw(h))
|
88
|
+
refresh(Ragweed::Wrap32::get_thread_context_raw(h))
|
89
89
|
end
|
90
90
|
|
91
91
|
def set(h)
|
92
|
-
Wrap32::set_thread_context_raw(h, self.to_s)
|
92
|
+
Ragweed::Wrap32::set_thread_context_raw(h, self.to_s)
|
93
93
|
end
|
94
94
|
|
95
95
|
def inspect
|
96
96
|
body = lambda do
|
97
97
|
FIELDS.map do |f|
|
98
98
|
val = send(f[0])
|
99
|
-
"#{f[0]}=#{val.to_s(16) rescue val.to_s}"
|
99
|
+
"#{f[0]}=#{val.to_s(16) rescue val.to_s.hexify}"
|
100
100
|
end.join(", ")
|
101
101
|
end
|
102
102
|
"#<ThreadContext #{body.call}>"
|
@@ -119,15 +119,15 @@ CONTEXT:
|
|
119
119
|
ESI: #{self.esi.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.esi)}
|
120
120
|
EBP: #{self.ebp.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ebp)}
|
121
121
|
ESP: #{self.esp.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.esp)}
|
122
|
-
EFL: #{self.eflags.to_s(2).rjust(32, "0")} #{Wrap32::EFlags.flag_dump(self.eflags)}
|
122
|
+
EFL: #{self.eflags.to_s(2).rjust(32, "0")} #{Ragweed::Wrap32::EFlags.flag_dump(self.eflags)}
|
123
123
|
EOM
|
124
124
|
end
|
125
125
|
|
126
126
|
def single_step(v=true)
|
127
127
|
if v
|
128
|
-
@eflags |= Wrap32::EFlags::TRAP
|
128
|
+
@eflags |= Ragweed::Wrap32::EFlags::TRAP
|
129
129
|
else
|
130
|
-
@eflags &= ~(Wrap32::EFlags::TRAP)
|
130
|
+
@eflags &= ~(Ragweed::Wrap32::EFlags::TRAP)
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -135,7 +135,7 @@ end
|
|
135
135
|
module Ragweed::Wrap32
|
136
136
|
class << self
|
137
137
|
def get_thread_context_raw(h)
|
138
|
-
ctx = [Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
138
|
+
ctx = [Ragweed::Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
139
139
|
ret = CALLS["kernel32!GetThreadContext:LP=L"].call(h, ctx)
|
140
140
|
if ret != 0
|
141
141
|
return ctx
|
@@ -194,7 +194,7 @@ module Ragweed::Wrap32
|
|
194
194
|
# and then resume the thread. Useful (among many other things) to sample
|
195
195
|
# EIP values to see what the code is doing.
|
196
196
|
def get_thread_context(h)
|
197
|
-
ctx = [Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
197
|
+
ctx = [Ragweed::Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
198
198
|
suspend_thread(h)
|
199
199
|
ret = CALLS["kernel32!GetThreadContext:LP=L"].call(h, ctx)
|
200
200
|
resume_thread(h)
|
@@ -302,9 +302,9 @@ module Ragweed::Wrap32
|
|
302
302
|
h = CALLS["kernel32!CreateToolhelp32Snapshot:LL=L"].call(0x8, pid)
|
303
303
|
if h != -1
|
304
304
|
mi = [260+256+(8*4),0,0,0,0,0,0,0,"\x00"*256,"\x00"*260].pack("LLLLLLLLa256a260")
|
305
|
-
if
|
305
|
+
if CALLS["kernel32!Module32First:LP=L"].call(h, mi) != 0
|
306
306
|
yield str2module_info(mi)
|
307
|
-
while
|
307
|
+
while CALLS["kernel32!Module32Next:LP=L"].call(h, mi) != 0
|
308
308
|
yield str2module_info(mi)
|
309
309
|
end
|
310
310
|
end
|
@@ -352,10 +352,10 @@ module Ragweed::Wrap32
|
|
352
352
|
h = CALLS["kernel32!CreateToolhelp32Snapshot:LL=L"].call(0x4, pid)
|
353
353
|
if h != -1
|
354
354
|
mi = [(7*4),0,0,0,0,0,0].pack("LLLLLLL")
|
355
|
-
if
|
355
|
+
if CALLS["kernel32!Thread32First:LP=L"].call(h, mi) != 0
|
356
356
|
ti = str2thread_info(mi)
|
357
357
|
yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
|
358
|
-
while
|
358
|
+
while CALLS["kernel32!Thread32Next:LP=L"].call(h, mi) != 0
|
359
359
|
ti = str2thread_info(mi)
|
360
360
|
yield str2thread_info(mi) if ti.th32OwnerProcessID == pid
|
361
361
|
end
|
data/lib/ragweed/wrap32.rb
CHANGED
@@ -59,7 +59,7 @@ module Ragweed::Wraposx::KernelReturn
|
|
59
59
|
module_function
|
60
60
|
# Much like Signals.list returns a hash of the possible kernel call return values.
|
61
61
|
def list
|
62
|
-
constants.inject({}){|a, c| a.merge! c => const_get(c)}
|
62
|
+
@@list ||= constants.inject({}){|a, c| a.merge! c => const_get(c)}
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -2,7 +2,7 @@ module Ragweed; end
|
|
2
2
|
module Ragweed::Wraposx::ThreadInfo
|
3
3
|
class << self
|
4
4
|
#factory method to get a ThreadInfo variant
|
5
|
-
def
|
5
|
+
def get(flavor,tid)
|
6
6
|
found = false
|
7
7
|
klass = self.constants.detect{|c| con = self.const_get(c); con.kind_of?(Class) && (flavor == con.const_get(:FLAVOR))}
|
8
8
|
if klass.nil?
|
@@ -150,6 +150,22 @@ module Ragweed::Wraposx
|
|
150
150
|
return t.to_a("I", count.to_s(SIZEOFINT).unpack('I_').first)
|
151
151
|
end
|
152
152
|
|
153
|
+
# Decrement the target tasks suspend count
|
154
|
+
# kern_return_t task_resume
|
155
|
+
# (task_t task);
|
156
|
+
def task_resume(task)
|
157
|
+
r = CALLC["libc!task_resume:I=I"].call(task).first
|
158
|
+
raise KernelCallError.new(r) if r != 0
|
159
|
+
end
|
160
|
+
|
161
|
+
# Increment the target tasks suspend count
|
162
|
+
# kern_return_t task_suspend
|
163
|
+
# (task_t task);
|
164
|
+
def task_suspend(task)
|
165
|
+
r = CALLC["libc!task_suspend:I=I"].call(task).first
|
166
|
+
raise KernelCallError.new(r) if r != 0
|
167
|
+
end
|
168
|
+
|
153
169
|
# Sends a signal to a process
|
154
170
|
#
|
155
171
|
# int
|
@@ -237,6 +253,36 @@ module Ragweed::Wraposx
|
|
237
253
|
return nil
|
238
254
|
end
|
239
255
|
|
256
|
+
|
257
|
+
# Allocates a page in the memory space of the target task.
|
258
|
+
#
|
259
|
+
# kern_return_t vm_allocate
|
260
|
+
# (vm_task_t target_task,
|
261
|
+
# vm_address_t address,
|
262
|
+
# vm_size_t size,
|
263
|
+
# boolean_t anywhere);
|
264
|
+
#
|
265
|
+
def vm_allocate(task, address, size, anywhere)
|
266
|
+
addr = int_to_intptr(address)
|
267
|
+
anywhere = anywhere ? 1 : 0
|
268
|
+
r = CALLS["libc!vm_allocate:IPII=I"].call(task,addr,size,anywhere).first
|
269
|
+
raise KernelCallError.new(r) if r != 0
|
270
|
+
addr.ptr
|
271
|
+
end
|
272
|
+
|
273
|
+
# deallocates a page in the memoryspace of target task.
|
274
|
+
#
|
275
|
+
# kern_return_t vm_deallocate
|
276
|
+
# (vm_task_t target_task,
|
277
|
+
# vm_address_t address,
|
278
|
+
# vm_size_t size);
|
279
|
+
#
|
280
|
+
def vm_deallocate(task,address,size)
|
281
|
+
addr = int_to_intptr(address)
|
282
|
+
r = CALLS["libc!vm_deallocate:IPI=I"].call(task, addr, size).first
|
283
|
+
raise KernelCallError.new(r) if r != 0
|
284
|
+
end
|
285
|
+
|
240
286
|
# Resumes a suspended thread by id.
|
241
287
|
#
|
242
288
|
# kern_return_t thread_resume
|
@@ -334,6 +380,12 @@ module Ragweed::Wraposx
|
|
334
380
|
raise SystemCallError.new("sysctl", DL.last_error) if (r != 0 and DL.last_error != Errno::ENOMEM::Errno)
|
335
381
|
return [ret,oldlenp.to_str(SIZEOFINT).unpack("I_").first]
|
336
382
|
end
|
383
|
+
|
384
|
+
# int
|
385
|
+
# nlist(const char *filename, struct nlist *nl)
|
386
|
+
def nlist(filename)
|
387
|
+
|
388
|
+
end
|
337
389
|
|
338
390
|
# Changes execution to file in path with *args as though called from command line.
|
339
391
|
#
|
@@ -348,6 +400,17 @@ module Ragweed::Wraposx
|
|
348
400
|
raise SystemCallError.new("execv", DL.last_error) if r == -1
|
349
401
|
return r
|
350
402
|
end
|
403
|
+
|
404
|
+
def int_to_intptr(i)
|
405
|
+
case i
|
406
|
+
when Integer
|
407
|
+
return [i].pack("I").to_ptr
|
408
|
+
when DL::PtrData
|
409
|
+
return i
|
410
|
+
else
|
411
|
+
raise ArgumentError, "Not an Integer"
|
412
|
+
end
|
413
|
+
end
|
351
414
|
end
|
352
415
|
end
|
353
416
|
|