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,3 +1,5 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
1
3
|
module Ragweed::Wrap32
|
2
4
|
module DebugCodes
|
3
5
|
CREATE_PROCESS = 3
|
@@ -35,64 +37,169 @@ module Ragweed::Wrap32
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
|
-
class Ragweed::Wrap32::
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
40
|
+
class Ragweed::Wrap32::RipInfo < FFI::Struct
|
41
|
+
include Ragweed::FFIStructInclude
|
42
|
+
layout :error, :ulong,
|
43
|
+
:type, :ulong
|
44
|
+
end
|
45
|
+
|
46
|
+
class Ragweed::Wrap32::OutputDebugStringInfo < FFI::Struct
|
47
|
+
include Ragweed::FFIStructInclude
|
48
|
+
layout :debug_string_data, :ulong, # pointer
|
49
|
+
:unicode, :uint16,
|
50
|
+
:debug_string_length, :uint16
|
51
|
+
end
|
52
|
+
|
53
|
+
class Ragweed::Wrap32::UnloadDLLDebugInfo < FFI::Struct
|
54
|
+
include Ragweed::FFIStructInclude
|
55
|
+
layout :base_of_dll, :ulong
|
56
|
+
end
|
57
|
+
|
58
|
+
class Ragweed::Wrap32::LoadDLLDebugInfo < FFI::Struct
|
59
|
+
include Ragweed::FFIStructInclude
|
60
|
+
layout :file_handle, :ulong,
|
61
|
+
:base_of_dll, :ulong,
|
62
|
+
:debug_info_file_offset, :ulong,
|
63
|
+
:debug_info_size, :ulong,
|
64
|
+
:image_name, :pointer,
|
65
|
+
:unicode, :uint16
|
66
|
+
end
|
67
|
+
|
68
|
+
class Ragweed::Wrap32::ExitProcessDebugInfo < FFI::Struct
|
69
|
+
include Ragweed::FFIStructInclude
|
70
|
+
layout :exit_code, :ulong
|
71
|
+
end
|
72
|
+
|
73
|
+
class Ragweed::Wrap32::ExitThreadDebugInfo < FFI::Struct
|
74
|
+
include Ragweed::FFIStructInclude
|
75
|
+
layout :exit_code, :ulong
|
76
|
+
end
|
77
|
+
|
78
|
+
class Ragweed::Wrap32::CreateProcessDebugInfo < FFI::Struct
|
79
|
+
include Ragweed::FFIStructInclude
|
80
|
+
layout :file_handle, :ulong,
|
81
|
+
:process_handle, :ulong,
|
82
|
+
:thread_handle, :ulong,
|
83
|
+
:base_of_image, :pointer,
|
84
|
+
:debug_info_file_offset, :ulong,
|
85
|
+
:debug_info_size, :ulong,
|
86
|
+
:thread_local_base, :pointer,
|
87
|
+
:start_address, :pointer,
|
88
|
+
:image_name, :pointer,
|
89
|
+
:unicode, :uint16
|
90
|
+
end
|
91
|
+
|
92
|
+
class Ragweed::Wrap32::CreateThreadDebugInfo < FFI::Struct
|
93
|
+
include Ragweed::FFIStructInclude
|
94
|
+
layout :thread_handle, :ulong,
|
95
|
+
:thread_local_base, :ulong,
|
96
|
+
:start_address, :pointer
|
97
|
+
end
|
98
|
+
|
99
|
+
class Ragweed::Wrap32::ExceptionRecord < FFI::Struct
|
100
|
+
include Ragweed::FFIStructInclude
|
101
|
+
layout :exception_code, :ulong,
|
102
|
+
:exception_flags, :ulong,
|
103
|
+
:exception_record, :pointer,
|
104
|
+
:exception_address, :ulong,
|
105
|
+
:number_of_parameters, :ulong,
|
106
|
+
:exception_information, [:uint8, 15] ## EXCEPTION_MAXIMUM_PARAMETERS
|
107
|
+
end
|
108
|
+
|
109
|
+
class Ragweed::Wrap32::ExceptionDebugInfo < FFI::Struct
|
110
|
+
include Ragweed::FFIStructInclude
|
111
|
+
layout :exception_record, Ragweed::Wrap32::ExceptionRecord,
|
112
|
+
:first_chance, :ulong
|
113
|
+
end
|
114
|
+
|
115
|
+
class Ragweed::Wrap32::DebugEventU < FFI::Union
|
116
|
+
include Ragweed::FFIStructInclude
|
117
|
+
layout :exception_debug_info, Ragweed::Wrap32::ExceptionDebugInfo,
|
118
|
+
:create_thread_debug_info, Ragweed::Wrap32::CreateThreadDebugInfo,
|
119
|
+
:create_process_debug_info, Ragweed::Wrap32::CreateProcessDebugInfo,
|
120
|
+
:exit_thread_debug_info, Ragweed::Wrap32::ExitThreadDebugInfo,
|
121
|
+
:exit_process_debug_info, Ragweed::Wrap32::ExitProcessDebugInfo,
|
122
|
+
:load_dll_debug_info, Ragweed::Wrap32::LoadDLLDebugInfo,
|
123
|
+
:unload_dll_debug_info, Ragweed::Wrap32::UnloadDLLDebugInfo,
|
124
|
+
:output_debug_string_info, Ragweed::Wrap32::OutputDebugStringInfo,
|
125
|
+
:rip_info, Ragweed::Wrap32::RipInfo
|
126
|
+
end
|
127
|
+
|
128
|
+
class Ragweed::Wrap32::DebugEvent < FFI::Struct
|
129
|
+
include Ragweed::FFIStructInclude
|
130
|
+
|
131
|
+
layout :code, :ulong,
|
132
|
+
:pid, :ulong,
|
133
|
+
:tid, :ulong,
|
134
|
+
:u, Ragweed::Wrap32::DebugEventU
|
135
|
+
|
136
|
+
## We have rubified this FFI structure by creating a bunch of instance
|
137
|
+
## variables that are normally only accessible via self.u.x.y which is
|
138
|
+
## a lot to type. You can still use that method however these instance
|
139
|
+
## variables should allow for considerably clearer code
|
140
|
+
attr_accessor :base_of_dll, :base_of_image, :debug_info_file_offset, :debug_info_size, :exception_address, :exception_code,
|
141
|
+
:exception_flags, :exception_record, :exit_code, :file_handle, :image_name, :number_of_parameters, :parameters,
|
142
|
+
:process_handle, :rip_error, :rip_type, :start_address, :thread_local_base, :thread_handle, :thread_local_base,
|
143
|
+
:unicode
|
144
|
+
|
145
|
+
def initialize(buf)
|
146
|
+
super buf
|
147
|
+
|
148
|
+
case self.code
|
66
149
|
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
67
|
-
@file_handle
|
68
|
-
@
|
69
|
-
@
|
70
|
-
@
|
150
|
+
@file_handle = self.u.create_process_debug_info.file_handle
|
151
|
+
@process_handle = self.u.create_process_debug_info.process_handle
|
152
|
+
@thread_handle = self.u.create_process_debug_info.thread_handle
|
153
|
+
@base_of_image = self.u.create_process_debug_info.base_of_image
|
154
|
+
@debug_info_file_offset = self.u.create_process_debug_info.debug_info_file_offset
|
155
|
+
@debug_info_size = self.u.create_process_debug_info.debug_info_size
|
156
|
+
@thread_local_base = self.u.create_process_debug_info.thread_local_base
|
157
|
+
@start_address = self.u.create_process_debug_info.start_address
|
158
|
+
@image_name = self.u.create_process_debug_info.image_name
|
159
|
+
@unicode = self.u.create_process_debug_info.unicode
|
160
|
+
|
71
161
|
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
72
|
-
@thread_handle
|
73
|
-
|
74
|
-
@
|
75
|
-
|
76
|
-
|
162
|
+
@thread_handle = self.u.create_thread_debug_info.thread_handle
|
163
|
+
@thread_local_base = self.u.create_thread_debug_info.thread_local_base
|
164
|
+
@start_address = self.u.create_thread_debug_info.start_address
|
165
|
+
|
166
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
167
|
+
@exception_code = self.u.exception_debug_info.exception_record.exception_code
|
168
|
+
@exception_flags = self.u.exception_debug_info.exception_record.exception_flags
|
169
|
+
@exception_record = self.u.exception_debug_info.exception_record.exception_record
|
170
|
+
@exception_address = self.u.exception_debug_info.exception_record.exception_address
|
171
|
+
@number_of_parameters = self.u.exception_debug_info.exception_record.number_of_parameters
|
172
|
+
|
77
173
|
@parameters = []
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
str = str[4..-1]
|
82
|
-
rescue;end
|
174
|
+
|
175
|
+
self.number_of_parameters.times do |i|
|
176
|
+
@parameters << self.u.exception_debug_info.exception_record.exception_information[i]
|
83
177
|
end
|
178
|
+
|
84
179
|
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
85
|
-
|
180
|
+
@exit_code = self.u.exit_process_debug_info.exit_code
|
181
|
+
|
86
182
|
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
183
|
+
@exit_code = self.u.exit_thread_debug_info.exit_code
|
184
|
+
|
185
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
186
|
+
@file_handle = self.u.load_dll_debug_info.file_handle
|
187
|
+
@base_of_dll = self.u.load_dll_debug_info.base_of_dll
|
188
|
+
@debug_info_file_offset = self.u.load_dll_debug_info.debug_info_file_offset
|
189
|
+
@debug_info_size = self.u.load_dll_debug_info.debug_info_size
|
190
|
+
@image_name = self.u.load_dll_debug_info.image_name
|
191
|
+
@unicode = self.u.load_dll_debug_info.unicode
|
192
|
+
|
91
193
|
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
194
|
+
##
|
195
|
+
|
92
196
|
when Ragweed::Wrap32::DebugCodes::RIP
|
93
|
-
|
197
|
+
@rip_error = self.u.rip_info.rip_error
|
198
|
+
@rip_type = self.u.rip_info.rip_type
|
199
|
+
|
94
200
|
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
95
|
-
|
201
|
+
@base_of_dll = self.u.unload_dll_debug_info.base_of_dll
|
202
|
+
|
96
203
|
else
|
97
204
|
raise WinX.new(:wait_for_debug_event)
|
98
205
|
end
|
@@ -111,53 +218,66 @@ class Ragweed::Wrap32::DebugEvent
|
|
111
218
|
end
|
112
219
|
|
113
220
|
def inspect
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end.compact.join(" ")
|
120
|
-
end
|
121
|
-
|
221
|
+
body = lambda do
|
222
|
+
self.members.each_with_index do |m,i|
|
223
|
+
"#{self.values[i].to_s.hexify} #{self.values[i].to_s.hexify}"
|
224
|
+
end.join(", ")
|
225
|
+
end
|
122
226
|
"#<DebugEvent #{body.call}>"
|
123
227
|
end
|
124
228
|
end
|
125
229
|
|
230
|
+
## Wrap the Win32 debugging specific APIs
|
126
231
|
module Ragweed::Wrap32
|
232
|
+
module Win
|
233
|
+
extend FFI::Library
|
234
|
+
|
235
|
+
ffi_lib 'kernel32'
|
236
|
+
ffi_convention :stdcall
|
237
|
+
|
238
|
+
attach_function 'WaitForDebugEvent', [ :pointer, :ulong ], :ulong
|
239
|
+
attach_function 'ContinueDebugEvent', [ :ulong, :ulong, :ulong ], :ulong
|
240
|
+
attach_function 'DebugActiveProcess', [ :ulong ], :ulong
|
241
|
+
attach_function 'DebugSetProcessKillOnExit', [ :ulong ], :ulong
|
242
|
+
attach_function 'DebugActiveProcessStop', [ :ulong ], :ulong
|
243
|
+
attach_function 'FlushInstructionCache', [ :ulong, :ulong, :ulong ], :ulong
|
244
|
+
end
|
245
|
+
|
127
246
|
class << self
|
128
247
|
def wait_for_debug_event(ms=1000)
|
129
|
-
buf =
|
130
|
-
|
248
|
+
# buf = FFI::MemoryPointer.new(Ragweed::Wrap32::DebugEvent, 1)
|
249
|
+
buf = FFI::MemoryPointer.from_string("\x00" * 1024)
|
250
|
+
r = Win.WaitForDebugEvent(buf, ms)
|
131
251
|
raise WinX.new(:wait_for_debug_event) if r == 0 and get_last_error != 121
|
132
252
|
return Ragweed::Wrap32::DebugEvent.new(buf) if r != 0
|
133
253
|
return nil
|
134
254
|
end
|
135
255
|
|
136
256
|
def continue_debug_event(pid, tid, code)
|
137
|
-
r =
|
257
|
+
r = Win.ContinueDebugEvent(pid, tid, code)
|
138
258
|
raise WinX.new(:continue_debug_event) if r == 0
|
139
259
|
return r
|
140
260
|
end
|
141
261
|
|
142
262
|
def debug_active_process(pid)
|
143
|
-
r =
|
263
|
+
r = Win.DebugActiveProcess(pid)
|
144
264
|
raise WinX.new(:debug_active_process) if r == 0
|
145
265
|
return r
|
146
266
|
end
|
147
267
|
|
148
268
|
def debug_set_process_kill_on_exit(val=0)
|
149
|
-
r =
|
269
|
+
r = Win.DebugSetProcessKillOnExit(val)
|
150
270
|
raise WinX.new(:debug_set_process_kill_on_exit) if r == 0
|
151
271
|
return r
|
152
272
|
end
|
153
273
|
|
154
274
|
def debug_active_process_stop(pid)
|
155
275
|
# don't care about failure
|
156
|
-
|
276
|
+
Win.DebugActiveProcessStop(pid)
|
157
277
|
end
|
158
278
|
|
159
279
|
def flush_instruction_cache(h, v1=0, v2=0)
|
160
|
-
|
280
|
+
Win.FlushInstructionCache(h, v1, v2)
|
161
281
|
end
|
162
282
|
end
|
163
283
|
end
|
data/lib/ragweed/wrap32/hooks.rb
CHANGED
@@ -4,20 +4,36 @@ class Ragweed::Debugger32
|
|
4
4
|
# callable/block is called with ev, ctx, dir (:enter or :leave), and args Array (see examples/hook_notepad.rb)
|
5
5
|
# default handler prints arguments
|
6
6
|
def hook(ip, nargs, callable=nil, &block)
|
7
|
-
|
8
|
-
|
9
|
-
puts args.map{|a| "%08x" % a}.join(',')
|
7
|
+
|
8
|
+
callable ||= block || lambda do |ev,ctx,dir,args|
|
9
|
+
#puts args.map{|a| "%08x" % a}.join(',')
|
10
10
|
end
|
11
11
|
|
12
12
|
breakpoint_set(ip) do |ev,ctx|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
esp = process.read32(ctx.esp)
|
14
|
+
nargs = nargs.to_i
|
15
|
+
|
16
|
+
if nargs >= 1
|
17
|
+
args = (1..nargs).map {|i| process.read32(ctx.esp + 4*i)}
|
18
|
+
end
|
19
|
+
|
20
|
+
## set exit bpoint
|
21
|
+
## We cant always set a leave bp due to
|
22
|
+
## calling conventions but we can avoid
|
23
|
+
## a crash by setting a breakpoint on
|
24
|
+
## the wrong address. So we attempt to
|
25
|
+
## get an idea of where the instruction
|
26
|
+
## is mapped.
|
27
|
+
eip = ctx.eip
|
28
|
+
if esp != 0 and esp > (eip & 0xf0000000)
|
29
|
+
breakpoint_set(esp) do |ev,ctx|
|
30
|
+
callable.call(ev, ctx, :leave, args)
|
31
|
+
breakpoint_clear(esp)
|
32
|
+
end.install
|
33
|
+
end
|
34
|
+
|
35
|
+
## Call the block sent to hook()
|
20
36
|
callable.call(ev, ctx, :enter, args)
|
21
37
|
end
|
22
38
|
end
|
23
|
-
end
|
39
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# TODO - PORT ME!!
|
2
|
-
|
3
1
|
class Ragweed::Process
|
4
2
|
def handle; @h; end
|
5
3
|
attr_reader :pid
|
@@ -34,16 +32,125 @@ class Ragweed::Process
|
|
34
32
|
ptr(Ragweed::Wrap32::get_proc_address(name))
|
35
33
|
end
|
36
34
|
|
35
|
+
def is_hex(s)
|
36
|
+
s = s.strip
|
37
|
+
|
38
|
+
## Strip leading 0s and 0x prefix
|
39
|
+
while s[0..1] == '0x' or s[0..1] == '00'
|
40
|
+
s = s[2..-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
o = s
|
44
|
+
|
45
|
+
if s.hex.to_s(16) == o
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
## This only gets called for breakpoints in modules
|
52
|
+
## that have just been loaded and detected by a LOAD_DLL
|
53
|
+
## event. It is called from on_load_dll() -> deferred_install()
|
54
|
+
def get_deferred_proc_remote(name, handle, base_of_dll)
|
55
|
+
if !name.kind_of?String
|
56
|
+
return name
|
57
|
+
end
|
58
|
+
|
59
|
+
mod, meth = name.split "!"
|
60
|
+
|
61
|
+
if mod.nil? or meth.nil?
|
62
|
+
raise "can not set this breakpoint: #{name}"
|
63
|
+
end
|
64
|
+
|
65
|
+
modh = handle
|
66
|
+
|
67
|
+
## Location is an offset
|
68
|
+
if is_hex(meth)
|
69
|
+
baseaddr = 0
|
70
|
+
modules.each do |m|
|
71
|
+
if m.szModule == mod
|
72
|
+
break
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
ret = base_of_dll + meth.hex
|
77
|
+
else
|
78
|
+
## Location is a symbolic name
|
79
|
+
## Win32 should have successfully loaded the DLL
|
80
|
+
ret = remote_call "kernel32!GetProcAddress", modh, meth
|
81
|
+
end
|
82
|
+
ret
|
83
|
+
end
|
84
|
+
|
85
|
+
## This only gets called for breakpoints
|
86
|
+
## in modules that are already loaded
|
37
87
|
def get_proc_remote(name)
|
88
|
+
if !name.kind_of?String
|
89
|
+
return name
|
90
|
+
end
|
91
|
+
|
38
92
|
mod, meth = name.split "!"
|
39
|
-
|
93
|
+
|
94
|
+
if mod.nil? or meth.nil?
|
95
|
+
raise "can not set this breakpoint: #{name}"
|
96
|
+
end
|
97
|
+
|
98
|
+
# modh = remote_call "kernel32!GetModuleHandleW", mod.to_utf16
|
99
|
+
modh = remote_call "kernel32!GetModuleHandleA", mod
|
40
100
|
raise "no such module #{ mod }" if not modh
|
41
|
-
|
101
|
+
|
102
|
+
## Location is an offset
|
103
|
+
if is_hex(meth)
|
104
|
+
baseaddr = 0
|
105
|
+
modules.each do |m|
|
106
|
+
if m.szModule == mod
|
107
|
+
baseaddr = m.modBaseAddr
|
108
|
+
break
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
## Somehow the module does not appear to be
|
113
|
+
## loaded. This should have been caught by
|
114
|
+
## Process::is_breakpoint_deferred either way
|
115
|
+
## Process::initialize should catch this return
|
116
|
+
if baseaddr == 0 or baseaddr == -1
|
117
|
+
return name
|
118
|
+
end
|
119
|
+
|
120
|
+
ret = baseaddr + meth.hex
|
121
|
+
else
|
122
|
+
## Location is a symbolic name
|
123
|
+
ret = remote_call "kernel32!GetProcAddress", modh, meth
|
124
|
+
end
|
42
125
|
ret
|
43
126
|
end
|
44
127
|
|
45
|
-
|
46
|
-
|
128
|
+
## Check if breakpoint location is deferred
|
129
|
+
## This method expects a string 'module!function'
|
130
|
+
## true is the module is not yet loaded
|
131
|
+
## false is the module is loaded
|
132
|
+
def is_breakpoint_deferred(ip)
|
133
|
+
if !ip.kind_of? String
|
134
|
+
return false
|
135
|
+
end
|
136
|
+
|
137
|
+
m,f = ip.split('!')
|
138
|
+
|
139
|
+
if f.nil? or m.nil?
|
140
|
+
return true
|
141
|
+
end
|
142
|
+
|
143
|
+
modules.each do |d|
|
144
|
+
if d.szModule.to_s.match(/#{m}/)
|
145
|
+
return false
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
|
152
|
+
## Look up a process by name or regex, returning an array of all
|
153
|
+
## matching processes, as objects.
|
47
154
|
def self.by_name(n)
|
48
155
|
n = Regexp.new(n) if not n.kind_of? Regexp
|
49
156
|
p = []
|
@@ -126,7 +233,7 @@ class Ragweed::Process
|
|
126
233
|
loc = Ragweed::Ptr.new loc
|
127
234
|
raise "bad proc name" if loc.null?
|
128
235
|
t = Trampoline.new(self, loc)
|
129
|
-
t.call *args
|
236
|
+
t.call *args
|
130
237
|
end
|
131
238
|
|
132
239
|
# Can I write to this address in the process?
|
@@ -20,28 +20,44 @@ module Ragweed::Wrap32
|
|
20
20
|
USED_FOR_ACCESS = 0x80000000
|
21
21
|
end
|
22
22
|
|
23
|
+
module Win
|
24
|
+
extend FFI::Library
|
25
|
+
|
26
|
+
ffi_lib 'kernel32','Advapi32'
|
27
|
+
ffi_convention :stdcall
|
28
|
+
attach_function 'OpenProcess', [ :long, :long, :long ], :long
|
29
|
+
attach_function 'OpenProcessToken', [:long, :long, :pointer ], :long
|
30
|
+
|
31
|
+
# ffi_lib 'advapi32'
|
32
|
+
# ffi_convention :stdcall
|
33
|
+
attach_function 'AdjustTokenPrivileges', [ :long, :long, :pointer, :long, :pointer, :pointer ], :long
|
34
|
+
attach_function 'LookupPrivilegeValueA', [ :pointer, :pointer, :pointer ] ,:long
|
35
|
+
end
|
36
|
+
|
23
37
|
class << self
|
38
|
+
|
24
39
|
def open_process_token(h, access=Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES)
|
25
40
|
outw = "\x00" * 4
|
26
|
-
r =
|
41
|
+
r = Win.OpenProcessToken(h, access, outw)
|
27
42
|
raise WinX.new(:open_process_token) if r == 0
|
28
43
|
return outw.unpack("L").first
|
29
44
|
end
|
30
45
|
|
31
46
|
def adjust_token_privileges(t, disable, *args)
|
32
|
-
buf = [args.size].pack("L") + (args.map {|tup| tup.pack("QL") }.join(""))
|
47
|
+
buf = FFI::MemoryPointer.from_string( [args.size].pack("L") + (args.map {|tup| tup.pack("QL") }.join("")) )
|
33
48
|
|
34
|
-
r =
|
35
|
-
call(t, disable, buf, buf.size, NULL, NULL)
|
49
|
+
r = Win.AdjustTokenPrivileges(t, disable, buf, buf.size, nil, nil)
|
36
50
|
|
37
51
|
raise WinX.new(:adjust_token_privileges) if r == 0
|
38
52
|
end
|
39
53
|
|
40
54
|
def lookup_privilege_value(name)
|
41
|
-
|
42
|
-
|
55
|
+
namep = FFI::MemoryPointer.from_string(name)
|
56
|
+
outw = FFI::MemoryPointer.new(:int64, 1)
|
57
|
+
r = Win.LookupPrivilegeValueA(nil, namep, outw)
|
58
|
+
r = Win.LookupPrivilegeValueA(nil, name, outw)
|
43
59
|
raise WinX.new(:lookup_privilege_value) if r == 0
|
44
|
-
|
60
|
+
outw.read_long_long
|
45
61
|
end
|
46
62
|
end
|
47
63
|
end
|