ragweed 0.2.0-java
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 +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
|