ragweed 0.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +32 -0
- data/README.rdoc +60 -0
- data/README.txt +9 -0
- data/Rakefile +86 -0
- data/VERSION +1 -0
- data/examples/hittracertux.rb +45 -0
- data/examples/hittracerx.rb +63 -0
- data/examples/hook_notepad.rb +9 -0
- data/examples/snicker.rb +183 -0
- data/examples/tux-example.rb +24 -0
- data/lib/ragweed/arena.rb +55 -0
- data/lib/ragweed/blocks.rb +128 -0
- data/lib/ragweed/debugger32.rb +400 -0
- data/lib/ragweed/debuggerosx.rb +456 -0
- data/lib/ragweed/debuggertux.rb +502 -0
- data/lib/ragweed/detour.rb +223 -0
- data/lib/ragweed/ptr.rb +48 -0
- data/lib/ragweed/rasm/bblock.rb +73 -0
- data/lib/ragweed/rasm/isa.rb +1115 -0
- data/lib/ragweed/rasm.rb +59 -0
- data/lib/ragweed/sbuf.rb +197 -0
- data/lib/ragweed/trampoline.rb +103 -0
- data/lib/ragweed/utils.rb +182 -0
- data/lib/ragweed/wrap32/debugging.rb +401 -0
- data/lib/ragweed/wrap32/device.rb +49 -0
- data/lib/ragweed/wrap32/event.rb +50 -0
- data/lib/ragweed/wrap32/hooks.rb +39 -0
- data/lib/ragweed/wrap32/overlapped.rb +46 -0
- data/lib/ragweed/wrap32/process.rb +613 -0
- data/lib/ragweed/wrap32/process_token.rb +75 -0
- data/lib/ragweed/wrap32/thread_context.rb +142 -0
- data/lib/ragweed/wrap32/winx.rb +16 -0
- data/lib/ragweed/wrap32/wrap32.rb +583 -0
- data/lib/ragweed/wrap32.rb +59 -0
- data/lib/ragweed/wraposx/constants.rb +114 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +275 -0
- data/lib/ragweed/wraposx/structs.rb +102 -0
- data/lib/ragweed/wraposx/thread_context.rb +902 -0
- data/lib/ragweed/wraposx/thread_info.rb +160 -0
- data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
- data/lib/ragweed/wraposx/wraposx.rb +356 -0
- data/lib/ragweed/wraposx.rb +60 -0
- data/lib/ragweed/wraptux/constants.rb +101 -0
- data/lib/ragweed/wraptux/process.rb +35 -0
- data/lib/ragweed/wraptux/threads.rb +7 -0
- data/lib/ragweed/wraptux/wraptux.rb +72 -0
- data/lib/ragweed/wraptux.rb +57 -0
- data/lib/ragweed.rb +112 -0
- data/ragweed.gemspec +102 -0
- data/spec/ragweed_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/test/test_ragweed.rb +0 -0
- metadata +121 -0
@@ -0,0 +1,401 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Ragweed::Wrap32
|
4
|
+
module DebugCodes
|
5
|
+
CREATE_PROCESS = 3
|
6
|
+
CREATE_THREAD = 2
|
7
|
+
EXCEPTION = 1
|
8
|
+
EXIT_PROCESS = 5
|
9
|
+
EXIT_THREAD = 4
|
10
|
+
LOAD_DLL = 6
|
11
|
+
OUTPUT_DEBUG_STRING = 8
|
12
|
+
RIP = 9
|
13
|
+
UNLOAD_DLL = 7
|
14
|
+
end
|
15
|
+
|
16
|
+
module PagePermissions
|
17
|
+
PAGE_NOACCESS = 0x1
|
18
|
+
PAGE_READONLY = 0x2
|
19
|
+
PAGE_READWRITE = 0x4
|
20
|
+
PAGE_WRITECOPY = 0x8
|
21
|
+
PAGE_EXECUTE = 0x10
|
22
|
+
PAGE_EXECUTE_READ = 0x20
|
23
|
+
PAGE_EXECUTE_READWRITE = 0x40
|
24
|
+
PAGE_EXECUTE_WRITECOPY = 0x80
|
25
|
+
end
|
26
|
+
|
27
|
+
module ExceptionCodes
|
28
|
+
ACCESS_VIOLATION = 0xC0000005
|
29
|
+
GUARD_PAGE = 0x80000001
|
30
|
+
BREAKPOINT = 0x80000003
|
31
|
+
ALIGNMENT = 0x80000002
|
32
|
+
SINGLE_STEP = 0x80000004
|
33
|
+
BOUNDS = 0xC0000008
|
34
|
+
DIVIDE_BY_ZERO = 0xC0000094
|
35
|
+
INT_OVERFLOW = 0xC0000095
|
36
|
+
INVALID_HANDLE = 0xC0000008
|
37
|
+
PRIV_INSTRUCTION = 0xC0000096
|
38
|
+
ILLEGAL_INSTRUCTION = 0xC000001D
|
39
|
+
STACK_OVERFLOW = 0xC00000FD
|
40
|
+
HEAP_CORRUPTION = 0xC0000374
|
41
|
+
BUFFER_OVERRUN = 0xC0000409
|
42
|
+
INVALID_DISPOSITION = 0xC0000026
|
43
|
+
end
|
44
|
+
|
45
|
+
module ExceptionSubTypes
|
46
|
+
ACCESS_VIOLATION_TYPE_READ = 0
|
47
|
+
ACCESS_VIOLATION_TYPE_WRITE = 1
|
48
|
+
ACCESS_VIOLATION_TYPE_DEP = 8
|
49
|
+
end
|
50
|
+
|
51
|
+
module ContinueCodes
|
52
|
+
CONTINUE = 0x10002
|
53
|
+
BREAK = 0x40010008
|
54
|
+
CONTROL_C = 0x40010005
|
55
|
+
UNHANDLED = 0x80010001
|
56
|
+
TERMINATE_THREAD = 0x40010003
|
57
|
+
TERMINATE_PROCESS = 0x40010004
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class Ragweed::Wrap32::StartupInfo < FFI::Struct
|
62
|
+
layout :cb, :ulong,
|
63
|
+
:reserved, :pointer,
|
64
|
+
:desktop, :pointer,
|
65
|
+
:title, :pointer,
|
66
|
+
:x, :ulong,
|
67
|
+
:y, :ulong,
|
68
|
+
:xsize, :ulong,
|
69
|
+
:ysize, :ulong,
|
70
|
+
:xcountchars, :ulong,
|
71
|
+
:ycountchars, :ulong,
|
72
|
+
:fillattr, :ulong,
|
73
|
+
:flags, :ulong,
|
74
|
+
:show_window, :short,
|
75
|
+
:breserved, :uint16,
|
76
|
+
:preserved, :uint8,
|
77
|
+
:std_input, :ulong,
|
78
|
+
:std_output, :ulong,
|
79
|
+
:std_error, :ulong
|
80
|
+
end
|
81
|
+
|
82
|
+
class Ragweed::Wrap32::ProcessInfo < FFI::Struct
|
83
|
+
layout :process_handle, :pointer,
|
84
|
+
:thread_handle, :pointer,
|
85
|
+
:pid, :ulong,
|
86
|
+
:thread_id, :ulong
|
87
|
+
end
|
88
|
+
|
89
|
+
class Ragweed::Wrap32::RipInfo < FFI::Struct
|
90
|
+
include Ragweed::FFIStructInclude
|
91
|
+
layout :error, :ulong,
|
92
|
+
:type, :ulong
|
93
|
+
end
|
94
|
+
|
95
|
+
class Ragweed::Wrap32::OutputDebugStringInfo < FFI::Struct
|
96
|
+
include Ragweed::FFIStructInclude
|
97
|
+
layout :debug_string_data, :ulong, # pointer
|
98
|
+
:unicode, :uint16,
|
99
|
+
:debug_string_length, :uint16
|
100
|
+
end
|
101
|
+
|
102
|
+
class Ragweed::Wrap32::UnloadDLLDebugInfo < FFI::Struct
|
103
|
+
include Ragweed::FFIStructInclude
|
104
|
+
layout :base_of_dll, :ulong
|
105
|
+
end
|
106
|
+
|
107
|
+
class Ragweed::Wrap32::LoadDLLDebugInfo < FFI::Struct
|
108
|
+
include Ragweed::FFIStructInclude
|
109
|
+
layout :file_handle, :ulong,
|
110
|
+
:base_of_dll, :ulong,
|
111
|
+
:debug_info_file_offset, :ulong,
|
112
|
+
:debug_info_size, :ulong,
|
113
|
+
:image_name, :pointer,
|
114
|
+
:unicode, :uint16
|
115
|
+
end
|
116
|
+
|
117
|
+
class Ragweed::Wrap32::ExitProcessDebugInfo < FFI::Struct
|
118
|
+
include Ragweed::FFIStructInclude
|
119
|
+
layout :exit_code, :ulong
|
120
|
+
end
|
121
|
+
|
122
|
+
class Ragweed::Wrap32::ExitThreadDebugInfo < FFI::Struct
|
123
|
+
include Ragweed::FFIStructInclude
|
124
|
+
layout :exit_code, :ulong
|
125
|
+
end
|
126
|
+
|
127
|
+
class Ragweed::Wrap32::CreateProcessDebugInfo < FFI::Struct
|
128
|
+
include Ragweed::FFIStructInclude
|
129
|
+
layout :file_handle, :ulong,
|
130
|
+
:process_handle, :ulong,
|
131
|
+
:thread_handle, :ulong,
|
132
|
+
:base_of_image, :pointer,
|
133
|
+
:debug_info_file_offset, :ulong,
|
134
|
+
:debug_info_size, :ulong,
|
135
|
+
:thread_local_base, :pointer,
|
136
|
+
:start_address, :pointer,
|
137
|
+
:image_name, :pointer,
|
138
|
+
:unicode, :uint16
|
139
|
+
end
|
140
|
+
|
141
|
+
class Ragweed::Wrap32::CreateThreadDebugInfo < FFI::Struct
|
142
|
+
include Ragweed::FFIStructInclude
|
143
|
+
layout :thread_handle, :ulong,
|
144
|
+
:thread_local_base, :ulong,
|
145
|
+
:start_address, :pointer
|
146
|
+
end
|
147
|
+
|
148
|
+
class Ragweed::Wrap32::ExceptionRecord < FFI::Struct
|
149
|
+
include Ragweed::FFIStructInclude
|
150
|
+
layout :exception_code, :ulong,
|
151
|
+
:exception_flags, :ulong,
|
152
|
+
:exception_record, :pointer,
|
153
|
+
:exception_address, :ulong,
|
154
|
+
:number_of_parameters, :ulong,
|
155
|
+
:exception_information, [:uint8, 15] ## EXCEPTION_MAXIMUM_PARAMETERS
|
156
|
+
end
|
157
|
+
|
158
|
+
class Ragweed::Wrap32::ExceptionDebugInfo < FFI::Struct
|
159
|
+
include Ragweed::FFIStructInclude
|
160
|
+
layout :exception_record, Ragweed::Wrap32::ExceptionRecord,
|
161
|
+
:first_chance, :ulong
|
162
|
+
end
|
163
|
+
|
164
|
+
class Ragweed::Wrap32::DebugEventU < FFI::Union
|
165
|
+
include Ragweed::FFIStructInclude
|
166
|
+
layout :exception_debug_info, Ragweed::Wrap32::ExceptionDebugInfo,
|
167
|
+
:create_thread_debug_info, Ragweed::Wrap32::CreateThreadDebugInfo,
|
168
|
+
:create_process_debug_info, Ragweed::Wrap32::CreateProcessDebugInfo,
|
169
|
+
:exit_thread_debug_info, Ragweed::Wrap32::ExitThreadDebugInfo,
|
170
|
+
:exit_process_debug_info, Ragweed::Wrap32::ExitProcessDebugInfo,
|
171
|
+
:load_dll_debug_info, Ragweed::Wrap32::LoadDLLDebugInfo,
|
172
|
+
:unload_dll_debug_info, Ragweed::Wrap32::UnloadDLLDebugInfo,
|
173
|
+
:output_debug_string_info, Ragweed::Wrap32::OutputDebugStringInfo,
|
174
|
+
:rip_info, Ragweed::Wrap32::RipInfo
|
175
|
+
end
|
176
|
+
|
177
|
+
class Ragweed::Wrap32::DebugEvent < FFI::Struct
|
178
|
+
include Ragweed::FFIStructInclude
|
179
|
+
|
180
|
+
layout :DebugEventCode, :ulong,
|
181
|
+
:ProcessId, :ulong,
|
182
|
+
:ThreadId, :ulong,
|
183
|
+
:u, Ragweed::Wrap32::DebugEventU
|
184
|
+
|
185
|
+
# backwards compatability
|
186
|
+
def code; self[:DebugEventCode]; end
|
187
|
+
def code=(cd); self[:DebugEventCode] = cd; end
|
188
|
+
def pid; self[:ProcessId]; end
|
189
|
+
def pid=(pd); self[:ProcessId]= pd; end
|
190
|
+
def tid; self[:ThreadId]; end
|
191
|
+
def tid=(td); self[:ThreadId] = td; end
|
192
|
+
|
193
|
+
# We have rubified this FFI structure by creating a bunch of proxy
|
194
|
+
# methods that are normally only accessible via self.u.x.y which is
|
195
|
+
# a lot to type. You can still use that method however these instance
|
196
|
+
# variables should allow for considerably clearer code
|
197
|
+
if RUBY_VERSION < "1.9"
|
198
|
+
def methods regular=true
|
199
|
+
ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
|
200
|
+
ret += case self[:DebugEventCode]
|
201
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
202
|
+
self[:u][:create_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
203
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
204
|
+
self[:u][:create_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
205
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
206
|
+
self[:u][:exit_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
207
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
208
|
+
self[:u][:exit_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
209
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
210
|
+
self[:u][:load_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
211
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
212
|
+
self[:u][:output_debug_string_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
213
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
214
|
+
self[:u][:rip_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
215
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
216
|
+
self[:u][:unload_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
|
217
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
218
|
+
self[:u][:exception_debug_info].members.map{|x| [x.to_s, x.to_s + "="]} + self[:u][:exception_debug_info][:exception_record].members.map{|x| [x.to_s, x.to_s + "="]}
|
219
|
+
else
|
220
|
+
[]
|
221
|
+
end
|
222
|
+
ret.flatten
|
223
|
+
end
|
224
|
+
else
|
225
|
+
def methods regular=true
|
226
|
+
ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
|
227
|
+
ret += case self[:DebugEventCode]
|
228
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
229
|
+
self[:u][:create_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
230
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
231
|
+
self[:u][:create_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
232
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
233
|
+
self[:u][:exit_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
234
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
235
|
+
self[:u][:exit_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
236
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
237
|
+
self[:u][:load_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
238
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
239
|
+
self[:u][:output_debug_string_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
240
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
241
|
+
self[:u][:rip_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
242
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
243
|
+
self[:u][:unload_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
|
244
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
245
|
+
self[:u][:exception_debug_info].members.map{|x| [x, (x.to_s + "=").intern]} + self[:u][:exception_debug_info][:exception_record].members.map{|x| [x, (x.to_s + "=").intern]}
|
246
|
+
else
|
247
|
+
[]
|
248
|
+
end
|
249
|
+
ret.flatten
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def method_missing meth, *args
|
254
|
+
super unless self.respond_to? meth
|
255
|
+
if meth.to_s =~ /=$/
|
256
|
+
mth = meth.to_s.gsub(/=$/,'').intern
|
257
|
+
if self.members.include? mth
|
258
|
+
# don't proxy
|
259
|
+
self.__send__(:[]=, mth, *args)
|
260
|
+
else
|
261
|
+
case self[:DebugEventCode]
|
262
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
263
|
+
self[:u][:create_process_debug_info].__send__(:[]=, mth, *args)
|
264
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
265
|
+
self[:u][:create_thread_debug_info].__send__(:[]=, mth, *args)
|
266
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
267
|
+
self[:u][:exit_process_debug_info].__send__(:[]=, mth, *args)
|
268
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
269
|
+
self[:u][:exit_thread_debug_info].__send__(:[]=, mth, *args)
|
270
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
271
|
+
self[:u][:load_dll_debug_info].__send__(:[]=, mth, *args)
|
272
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
273
|
+
self[:u][:output_debug_string_info].__send__(:[]=, mth, *args)
|
274
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
275
|
+
self[:u][:rip_info].__send__(:[]=, mth, *args)
|
276
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
277
|
+
self[:u][:unload_dll_debug_info].__send__(:[]=, mth, *args)
|
278
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
279
|
+
case mth
|
280
|
+
when :exception_record, :first_chance
|
281
|
+
self[:u][:exception_debug_info].__send__(:[]=, mth, *args)
|
282
|
+
else # it's in the exception_record -- gross, I know but...
|
283
|
+
self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
else
|
288
|
+
if self.members.include? meth
|
289
|
+
# don't proxy
|
290
|
+
self.__send__(:[], meth, *args)
|
291
|
+
else
|
292
|
+
case self[:DebugEventCode]
|
293
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
|
294
|
+
self[:u][:create_process_debug_info].__send__(:[], meth, *args)
|
295
|
+
when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
|
296
|
+
self[:u][:create_thread_debug_info].__send__(:[], meth, *args)
|
297
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
|
298
|
+
self[:u][:exit_process_debug_info].__send__(:[], meth, *args)
|
299
|
+
when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
|
300
|
+
self[:u][:exit_thread_debug_info].__send__(:[], meth, *args)
|
301
|
+
when Ragweed::Wrap32::DebugCodes::LOAD_DLL
|
302
|
+
self[:u][:load_dll_debug_info].__send__(:[], meth, *args)
|
303
|
+
when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
|
304
|
+
self[:u][:output_debug_string_info].__send__(:[], meth, *args)
|
305
|
+
when Ragweed::Wrap32::DebugCodes::RIP
|
306
|
+
self[:u][:rip_info].__send__(:[], meth, *args)
|
307
|
+
when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
|
308
|
+
self[:u][:unload_dll_debug_info].__send__(:[], meth, *args)
|
309
|
+
when Ragweed::Wrap32::DebugCodes::EXCEPTION
|
310
|
+
case meth
|
311
|
+
when :exception_record, :first_chance
|
312
|
+
self[:u][:exception_debug_info].__send__(:[], meth, *args)
|
313
|
+
else # it's in the exception_record -- gross, I know but...
|
314
|
+
self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def respond_to? meth, include_priv=false
|
322
|
+
# mth = meth.to_s.gsub(/=$/,'')
|
323
|
+
!((self.methods & [meth, meth.to_s]).empty?) || super
|
324
|
+
end
|
325
|
+
|
326
|
+
def inspect_code(c)
|
327
|
+
Ragweed::Wrap32::DebugCodes.to_key_hash[c].to_s || c.to_i
|
328
|
+
end
|
329
|
+
|
330
|
+
def inspect_exception_code(c)
|
331
|
+
Ragweed::Wrap32::ExceptionCodes.to_key_hash[c].to_s || c.to_i.to_s(16)
|
332
|
+
end
|
333
|
+
|
334
|
+
def inspect_parameters(p)
|
335
|
+
"[ " + p.map {|x| x.to_i.to_s}.join(", ") + " ]"
|
336
|
+
end
|
337
|
+
|
338
|
+
def inspect
|
339
|
+
body = lambda do
|
340
|
+
self.members.each_with_index do |m,i|
|
341
|
+
"#{self.values[i].to_s.hexify} #{self.values[i].to_s.hexify}"
|
342
|
+
end.join(", ")
|
343
|
+
end
|
344
|
+
"#<DebugEvent #{body.call}>"
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
## Wrap the Win32 debugging specific APIs
|
349
|
+
module Ragweed::Wrap32
|
350
|
+
module Win
|
351
|
+
extend FFI::Library
|
352
|
+
|
353
|
+
ffi_lib 'kernel32'
|
354
|
+
ffi_convention :stdcall
|
355
|
+
|
356
|
+
attach_function 'WaitForDebugEvent', [ :pointer, :ulong ], :ulong
|
357
|
+
attach_function 'ContinueDebugEvent', [ :ulong, :ulong, :ulong ], :ulong
|
358
|
+
attach_function 'DebugActiveProcess', [ :ulong ], :ulong
|
359
|
+
attach_function 'DebugSetProcessKillOnExit', [ :ulong ], :ulong
|
360
|
+
attach_function 'DebugActiveProcessStop', [ :ulong ], :ulong
|
361
|
+
attach_function 'FlushInstructionCache', [ :ulong, :ulong, :ulong ], :ulong
|
362
|
+
end
|
363
|
+
|
364
|
+
class << self
|
365
|
+
def wait_for_debug_event(ms=1000)
|
366
|
+
# buf = FFI::MemoryPointer.new(Ragweed::Wrap32::DebugEvent, 1)
|
367
|
+
buf = FFI::MemoryPointer.from_string("\x00" * 1024)
|
368
|
+
r = Win.WaitForDebugEvent(buf, ms)
|
369
|
+
raise WinX.new(:wait_for_debug_event) if r == 0 and get_last_error != 121
|
370
|
+
return Ragweed::Wrap32::DebugEvent.new(buf) if r != 0
|
371
|
+
return nil
|
372
|
+
end
|
373
|
+
|
374
|
+
def continue_debug_event(pid, tid, code)
|
375
|
+
r = Win.ContinueDebugEvent(pid, tid, code)
|
376
|
+
raise WinX.new(:continue_debug_event) if r == 0
|
377
|
+
return r
|
378
|
+
end
|
379
|
+
|
380
|
+
def debug_active_process(pid)
|
381
|
+
r = Win.DebugActiveProcess(pid)
|
382
|
+
raise WinX.new(:debug_active_process) if r == 0
|
383
|
+
return r
|
384
|
+
end
|
385
|
+
|
386
|
+
def debug_set_process_kill_on_exit(val=0)
|
387
|
+
r = Win.DebugSetProcessKillOnExit(val)
|
388
|
+
raise WinX.new(:debug_set_process_kill_on_exit) if r == 0
|
389
|
+
return r
|
390
|
+
end
|
391
|
+
|
392
|
+
def debug_active_process_stop(pid)
|
393
|
+
# don't care about failure
|
394
|
+
Win.DebugActiveProcessStop(pid)
|
395
|
+
end
|
396
|
+
|
397
|
+
def flush_instruction_cache(h, v1=0, v2=0)
|
398
|
+
Win.FlushInstructionCache(h, v1, v2)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Ragweed
|
2
|
+
class Device
|
3
|
+
def initialize(path, options={})
|
4
|
+
@path = path
|
5
|
+
@options = options
|
6
|
+
@h = Ragweed::Wrap32::create_file(@path, :flags => Ragweed::Wrap32::FileAttributes::OVERLAPPED|Ragweed::Wrap32::FileAttributes::NORMAL)
|
7
|
+
end
|
8
|
+
|
9
|
+
def ioctl(code, inbuf, outbuf)
|
10
|
+
overlap(lambda do |o|
|
11
|
+
Ragweed::Wrap32::device_io_control(@h, code, inbuf, outbuf, o)
|
12
|
+
end) do |ret, count|
|
13
|
+
outbuf[0..count]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(sz)
|
18
|
+
overlap(lambda do |o|
|
19
|
+
Ragweed::Wrap32::read_file(@h, sz, o)
|
20
|
+
end) do |ret, count|
|
21
|
+
ret[0..count]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(buf)
|
26
|
+
overlap(lambda do |o|
|
27
|
+
Ragweed::Wrap32::write_file(@h, buf, o)
|
28
|
+
end) do |ret, count|
|
29
|
+
count
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def release
|
34
|
+
Ragweed::Wrap32::close_handle(@h)
|
35
|
+
@h = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def overlap(proc)
|
41
|
+
o = Ragweed::Wrap32::Overlapped.get
|
42
|
+
ret = proc.call(o)
|
43
|
+
count = o.wait(@h)
|
44
|
+
r = yield ret, count
|
45
|
+
o.release
|
46
|
+
ret = r if r
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class Ragweed::Event
|
2
|
+
# Quick wrapper around Win32 events. Events are simple thread sync
|
3
|
+
# objects that are cross-process. They are like semaphores that you
|
4
|
+
# can select() on.
|
5
|
+
|
6
|
+
# You can just do WinEvent.new to get a new anonymous handle, and
|
7
|
+
# then call .handle on it to find out what the handle was. Communicate
|
8
|
+
# your pid and the handle value, somehow, to a remote process. That
|
9
|
+
# process can get the same event by passing a WinProcess and the
|
10
|
+
# handle here.
|
11
|
+
#
|
12
|
+
# So, in Process1 (assume pid 668, and handle 300):
|
13
|
+
#
|
14
|
+
# e = WinEvent.new
|
15
|
+
# puts #{ get_current_process_id }: #{ e.handle }"
|
16
|
+
#
|
17
|
+
# And in Process2:
|
18
|
+
#
|
19
|
+
# e = WinEvent.new(WinProcess.new(668), 300)
|
20
|
+
#
|
21
|
+
# Now both processes share an event.
|
22
|
+
def initialize(p=nil, h=nil)
|
23
|
+
@p = p
|
24
|
+
@h = (@p.dup_handle(h) if h) || create_event
|
25
|
+
end
|
26
|
+
|
27
|
+
# Don't return until the event is signalled. Note that you
|
28
|
+
# can't break this with timeouts or CTR-C.
|
29
|
+
def wait
|
30
|
+
Ragweed::Wrap32::wait_for_single_object @h
|
31
|
+
end
|
32
|
+
|
33
|
+
# Signal the event; anyone waiting on it is now released.
|
34
|
+
def signal
|
35
|
+
Ragweed::Wrap32::set_event(@h)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Force the event back to unsignalled state.
|
39
|
+
def reset
|
40
|
+
Ragweed::Wrap32::reset_event(@h)
|
41
|
+
end
|
42
|
+
|
43
|
+
# A wait loop.
|
44
|
+
def on(&block)
|
45
|
+
while 1
|
46
|
+
wait
|
47
|
+
break if not yield
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Ragweed::Debugger32
|
2
|
+
# Hook function calls
|
3
|
+
# nargs is the number of arguments taken by function at ip
|
4
|
+
# callable/block is called with ev, ctx, dir (:enter or :leave), and args Array (see examples/hook_notepad.rb)
|
5
|
+
# default handler prints arguments
|
6
|
+
def hook(ip, nargs, callable=nil, &block)
|
7
|
+
|
8
|
+
callable ||= block || lambda do |ev,ctx,dir,args|
|
9
|
+
#puts args.map{|a| "%08x" % a}.join(',')
|
10
|
+
end
|
11
|
+
|
12
|
+
breakpoint_set(ip) do |ev,ctx|
|
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()
|
36
|
+
callable.call(ev, ctx, :enter, args)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Ragweed::Wrap32::Overlapped
|
2
|
+
attr_accessor :internal
|
3
|
+
attr_accessor :internal_high
|
4
|
+
attr_accessor :offset
|
5
|
+
attr_accessor :offset_high
|
6
|
+
attr_accessor :event
|
7
|
+
attr_accessor :target
|
8
|
+
|
9
|
+
def self.get
|
10
|
+
h = Ragweed::Wrap32::create_event(nil, false, true)
|
11
|
+
r = self.new
|
12
|
+
r.event = h
|
13
|
+
return r
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(str=nil)
|
17
|
+
@buf = "\x00" * 20
|
18
|
+
@internal, @internal_high, @offset, @offset_high, @event = [0,0,0,0,0]
|
19
|
+
init(str) if str
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
buf = [@internal, @internal_high, @offset, @offset_high, @event].pack("LLLLL")
|
24
|
+
@buf.replace(buf)
|
25
|
+
end
|
26
|
+
|
27
|
+
def release
|
28
|
+
Ragweed::Wrap32::close_handle(@event)
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait(h)
|
32
|
+
return if not @event
|
33
|
+
Ragweed::Wrap32::wait_for_single_object(@event)
|
34
|
+
Ragweed::Wrap32::get_overlapped_result(h, self)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def init(str)
|
40
|
+
@internal,
|
41
|
+
@internal_high,
|
42
|
+
@offset,
|
43
|
+
@offset_high,
|
44
|
+
@event = str.unpack("LLLLL")
|
45
|
+
end
|
46
|
+
end
|