ragweed 0.2.0.pre2 → 0.2.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0.pre2
1
+ 0.2.0.pre3
@@ -305,6 +305,7 @@ class Ragweed::Debugger32
305
305
  def on_heap_corruption(ev) end
306
306
  def on_buffer_overrun(ev) end
307
307
  def on_invalid_disposition(ev) end
308
+ def on_attach() end
308
309
 
309
310
  ## Read through me to see all the random events
310
311
  ## you can hook in a subclass.
@@ -382,6 +383,7 @@ class Ragweed::Debugger32
382
383
  Ragweed::Wrap32::debug_active_process(@p.pid)
383
384
  Ragweed::Wrap32::debug_set_process_kill_on_exit
384
385
  @attached = true
386
+ try(:on_attach)
385
387
  @breakpoints.each_pair do |k, bp|
386
388
  bp.install
387
389
  end
@@ -13,7 +13,7 @@ module Ragweed; end
13
13
  ## that Debuggertux already handles, call "super", too.
14
14
  class Ragweed::Debuggertux
15
15
  attr_reader :pid, :status, :exited, :signal
16
- attr_accessor :breakpoints, :mapped_regions
16
+ attr_accessor :breakpoints, :mapped_regions, :process
17
17
 
18
18
  ## Class to handle installing/uninstalling breakpoints
19
19
  class Breakpoint
@@ -78,6 +78,8 @@ class Ragweed::Debuggertux
78
78
  @mapped_regions = Hash.new
79
79
  @breakpoints = Hash.new
80
80
  @opts.each { |k, v| try(k) if v }
81
+
82
+ @process = Ragweed::Process.new(@pid)
81
83
  end
82
84
 
83
85
  def self.find_by_regex(rx)
@@ -462,6 +464,7 @@ class Ragweed::Debuggertux
462
464
  def print_registers
463
465
  regs = get_registers
464
466
  puts "eip %08x" % regs.eip
467
+ puts "ebp %08x" % regs.ebp
465
468
  puts "esi %08x" % regs.esi
466
469
  puts "edi %08x" % regs.edi
467
470
  puts "esp %08x" % regs.esp
@@ -13,6 +13,10 @@ module Ragweed::Wrap32
13
13
  UNLOAD_DLL = 7
14
14
  end
15
15
 
16
+ module PagePermissions
17
+ PAGE_EXECUTE_READWRITE = 0x40
18
+ end
19
+
16
20
  module ExceptionCodes
17
21
  ACCESS_VIOLATION = 0xC0000005
18
22
  GUARD_PAGE = 0x80000001
@@ -136,85 +140,154 @@ class Ragweed::Wrap32::DebugEventU < FFI::Union
136
140
  end
137
141
 
138
142
  class Ragweed::Wrap32::DebugEvent < FFI::Struct
139
- include Ragweed::FFIStructInclude
140
-
141
- layout :code, :ulong,
142
- :pid, :ulong,
143
- :tid, :ulong,
144
- :u, Ragweed::Wrap32::DebugEventU
145
-
146
- ## We have rubified this FFI structure by creating a bunch of instance
147
- ## variables that are normally only accessible via self.u.x.y which is
148
- ## a lot to type. You can still use that method however these instance
149
- ## variables should allow for considerably clearer code
150
- attr_accessor :base_of_dll, :base_of_image, :debug_info_file_offset, :debug_info_size, :exception_address, :exception_code,
151
- :exception_flags, :exception_record, :exit_code, :file_handle, :image_name, :number_of_parameters, :parameters,
152
- :process_handle, :rip_error, :rip_type, :start_address, :thread_local_base, :thread_handle, :thread_local_base,
153
- :unicode
154
-
155
- def initialize(buf)
156
- super buf
157
-
158
- case self.code
159
- when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
160
- @file_handle = self.u.create_process_debug_info.file_handle
161
- @process_handle = self.u.create_process_debug_info.process_handle
162
- @thread_handle = self.u.create_process_debug_info.thread_handle
163
- @base_of_image = self.u.create_process_debug_info.base_of_image
164
- @debug_info_file_offset = self.u.create_process_debug_info.debug_info_file_offset
165
- @debug_info_size = self.u.create_process_debug_info.debug_info_size
166
- @thread_local_base = self.u.create_process_debug_info.thread_local_base
167
- @start_address = self.u.create_process_debug_info.start_address
168
- @image_name = self.u.create_process_debug_info.image_name
169
- @unicode = self.u.create_process_debug_info.unicode
170
-
171
- when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
172
- @thread_handle = self.u.create_thread_debug_info.thread_handle
173
- @thread_local_base = self.u.create_thread_debug_info.thread_local_base
174
- @start_address = self.u.create_thread_debug_info.start_address
175
-
176
- when Ragweed::Wrap32::DebugCodes::EXCEPTION
177
- @exception_code = self.u.exception_debug_info.exception_record.exception_code
178
- @exception_flags = self.u.exception_debug_info.exception_record.exception_flags
179
- @exception_record = self.u.exception_debug_info.exception_record.exception_record
180
- @exception_address = self.u.exception_debug_info.exception_record.exception_address
181
- @number_of_parameters = self.u.exception_debug_info.exception_record.number_of_parameters
182
-
183
- @parameters = []
184
-
185
- self.number_of_parameters.times do |i|
186
- @parameters << self.u.exception_debug_info.exception_record.exception_information[i]
143
+ include Ragweed::FFIStructInclude
144
+
145
+ layout :DebugEventCode, :ulong,
146
+ :ProcessId, :ulong,
147
+ :ThreadId, :ulong,
148
+ :u, Ragweed::Wrap32::DebugEventU
149
+
150
+ # backwards compatability
151
+ def code; self[:DebugEventCode]; end
152
+ def code=(cd); self[:DebugEventCode] = cd; end
153
+ def pid; self[:ProcessId]; end
154
+ def pid=(pd); self[:ProcessId]= pd; end
155
+ def tid; self[:ThreadId]; end
156
+ def tid=(td); self[:ThreadId] = td; end
157
+
158
+ # We have rubified this FFI structure by creating a bunch of proxy
159
+ # methods that are normally only accessible via self.u.x.y which is
160
+ # a lot to type. You can still use that method however these instance
161
+ # variables should allow for considerably clearer code
162
+ if RUBY_VERSION < "1.9"
163
+ def methods regular=true
164
+ ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
165
+ ret += case self[:DebugEventCode]
166
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
167
+ self[:u][:create_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
168
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
169
+ self[:u][:create_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
170
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
171
+ self[:u][:exit_process_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
172
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
173
+ self[:u][:exit_thread_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
174
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
175
+ self[:u][:load_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
176
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
177
+ self[:u][:output_debug_string_info].members.map{|x| [x.to_s, x.to_s + "="]}
178
+ when Ragweed::Wrap32::DebugCodes::RIP
179
+ self[:u][:rip_info].members.map{|x| [x.to_s, x.to_s + "="]}
180
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
181
+ self[:u][:unload_dll_debug_info].members.map{|x| [x.to_s, x.to_s + "="]}
182
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
183
+ 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 + "="]}
184
+ else
185
+ []
187
186
  end
187
+ ret.flatten
188
+ end
189
+ else
190
+ def methods regular=true
191
+ ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
192
+ ret += case self[:DebugEventCode]
193
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
194
+ self[:u][:create_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
195
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
196
+ self[:u][:create_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
197
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
198
+ self[:u][:exit_process_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
199
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
200
+ self[:u][:exit_thread_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
201
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
202
+ self[:u][:load_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
203
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
204
+ self[:u][:output_debug_string_info].members.map{|x| [x, (x.to_s + "=").intern]}
205
+ when Ragweed::Wrap32::DebugCodes::RIP
206
+ self[:u][:rip_info].members.map{|x| [x, (x.to_s + "=").intern]}
207
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
208
+ self[:u][:unload_dll_debug_info].members.map{|x| [x, (x.to_s + "=").intern]}
209
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
210
+ 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]}
211
+ else
212
+ []
213
+ end
214
+ ret.flatten
215
+ end
216
+ end
188
217
 
189
- when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
190
- @exit_code = self.u.exit_process_debug_info.exit_code
191
-
192
- when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
193
- @exit_code = self.u.exit_thread_debug_info.exit_code
194
-
195
- when Ragweed::Wrap32::DebugCodes::LOAD_DLL
196
- @file_handle = self.u.load_dll_debug_info.file_handle
197
- @base_of_dll = self.u.load_dll_debug_info.base_of_dll
198
- @debug_info_file_offset = self.u.load_dll_debug_info.debug_info_file_offset
199
- @debug_info_size = self.u.load_dll_debug_info.debug_info_size
200
- @image_name = self.u.load_dll_debug_info.image_name
201
- @unicode = self.u.load_dll_debug_info.unicode
202
-
203
- when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
204
- ##
205
-
206
- when Ragweed::Wrap32::DebugCodes::RIP
207
- @rip_error = self.u.rip_info.rip_error
208
- @rip_type = self.u.rip_info.rip_type
209
-
210
- when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
211
- @base_of_dll = self.u.unload_dll_debug_info.base_of_dll
212
-
218
+ def method_missing meth, *args
219
+ super unless self.respond_to? meth
220
+ if meth.to_s =~ /=$/
221
+ mth = meth.to_s.gsub(/=$/,'').intern
222
+ if self.members.include? mth
223
+ # don't proxy
224
+ self.__send__(:[]=, mth, *args)
225
+ else
226
+ case self[:DebugEventCode]
227
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
228
+ self[:u][:create_process_debug_info].__send__(:[]=, mth, *args)
229
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
230
+ self[:u][:create_thread_debug_info].__send__(:[]=, mth, *args)
231
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
232
+ self[:u][:exit_process_debug_info].__send__(:[]=, mth, *args)
233
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
234
+ self[:u][:exit_thread_debug_info].__send__(:[]=, mth, *args)
235
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
236
+ self[:u][:load_dll_debug_info].__send__(:[]=, mth, *args)
237
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
238
+ self[:u][:output_debug_string_info].__send__(:[]=, mth, *args)
239
+ when Ragweed::Wrap32::DebugCodes::RIP
240
+ self[:u][:rip_info].__send__(:[]=, mth, *args)
241
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
242
+ self[:u][:unload_dll_debug_info].__send__(:[]=, mth, *args)
243
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
244
+ case mth
245
+ when :exception_record, :first_chance
246
+ self[:u][:exception_debug_info].__send__(:[]=, mth, *args)
247
+ else # it's in the exception_record -- gross, I know but...
248
+ self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
249
+ end
250
+ end
251
+ end
213
252
  else
214
- raise WinX.new(:wait_for_debug_event)
253
+ if self.members.include? meth
254
+ # don't proxy
255
+ self.__send__(:[], meth, *args)
256
+ else
257
+ case self[:DebugEventCode]
258
+ when Ragweed::Wrap32::DebugCodes::CREATE_PROCESS
259
+ self[:u][:create_process_debug_info].__send__(:[], meth, *args)
260
+ when Ragweed::Wrap32::DebugCodes::CREATE_THREAD
261
+ self[:u][:create_thread_debug_info].__send__(:[], meth, *args)
262
+ when Ragweed::Wrap32::DebugCodes::EXIT_PROCESS
263
+ self[:u][:exit_process_debug_info].__send__(:[], meth, *args)
264
+ when Ragweed::Wrap32::DebugCodes::EXIT_THREAD
265
+ self[:u][:exit_thread_debug_info].__send__(:[], meth, *args)
266
+ when Ragweed::Wrap32::DebugCodes::LOAD_DLL
267
+ self[:u][:load_dll_debug_info].__send__(:[], meth, *args)
268
+ when Ragweed::Wrap32::DebugCodes::OUTPUT_DEBUG_STRING
269
+ self[:u][:output_debug_string_info].__send__(:[], meth, *args)
270
+ when Ragweed::Wrap32::DebugCodes::RIP
271
+ self[:u][:rip_info].__send__(:[], meth, *args)
272
+ when Ragweed::Wrap32::DebugCodes::UNLOAD_DLL
273
+ self[:u][:unload_dll_debug_info].__send__(:[], meth, *args)
274
+ when Ragweed::Wrap32::DebugCodes::EXCEPTION
275
+ case meth
276
+ when :exception_record, :first_chance
277
+ self[:u][:exception_debug_info].__send__(:[], meth, *args)
278
+ else # it's in the exception_record -- gross, I know but...
279
+ self[:u][:exception_debug_info][:exception_record].__send__(meth, *args)
280
+ end
281
+ end
282
+ end
215
283
  end
216
284
  end
217
285
 
286
+ def respond_to? meth, include_priv=false
287
+ # mth = meth.to_s.gsub(/=$/,'')
288
+ !((self.methods & [meth, meth.to_s]).empty?) || super
289
+ end
290
+
218
291
  def inspect_code(c)
219
292
  Ragweed::Wrap32::DebugCodes.to_key_hash[c].to_s || c.to_i
220
293
  end
@@ -25,7 +25,7 @@ class Ragweed::Debugger32
25
25
  ## get an idea of where the instruction
26
26
  ## is mapped.
27
27
  eip = ctx.eip
28
- if esp != 0 and esp > (eip & 0xf0000000)
28
+ if esp != 0 #and esp > (eip & 0xf0000000)
29
29
  breakpoint_set(esp) do |ev,ctx|
30
30
  callable.call(ev, ctx, :leave, args)
31
31
  breakpoint_clear(esp)
@@ -117,6 +117,8 @@ module Ragweed::Wrap32
117
117
  attach_function 'DeviceIoControl', [ :long, :long, :pointer, :long, :pointer, :long, :pointer, :pointer ], :long
118
118
  attach_function 'GetOverlappedResult', [ :long, :pointer, :pointer, :long ], :long
119
119
  attach_function 'WaitForMultipleObjects', [ :long, :pointer, :long, :long ], :long
120
+ attach_function 'CreateProcessA', [ :pointer, :pointer, :pointer, :pointer, :long, :long, :pointer, :pointer, :pointer, :pointer ], :long
121
+ attach_function 'CreateProcessW', [ :pointer, :pointer, :pointer, :pointer, :long, :long, :pointer, :pointer, :pointer, :pointer ], :long
120
122
 
121
123
  ffi_lib 'ntdll'
122
124
  ffi_convention :stdcall
@@ -255,6 +255,80 @@ EOM
255
255
  FLAVOR = 7
256
256
  layout :tsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
257
257
  :uts, Ragweed::Wraposx::ThreadContext::UnionThreadState
258
+
259
+ # We have rubified this FFI structure by creating a bunch of proxy
260
+ # methods that are normally only accessible via self.v.x.y which is
261
+ # a lot to type. You can still use that method however these proxy
262
+ # methods should allow for considerably clearer code
263
+ if RUBY_VERSION < "1.9"
264
+ def methods regular=true
265
+ ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
266
+ ret += self[:tsh].members.map{|x| [x.to_s, x.to_s + "="]}
267
+ ret + case self[:tsh][:flavor]
268
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
269
+ self[:uts].ts32.members.map{|x| [x.to_s, x.to_s + "="]}
270
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
271
+ self[:uts].ts64.members.map{|x| [x.to_s, x.to_s + "="]}
272
+ else
273
+ []
274
+ end
275
+ ret.flatten
276
+ end
277
+ else
278
+ def methods regular=true
279
+ ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
280
+ ret += self[:tsh].members.map{|x| [x, (x.to_s + "=").intern]}
281
+ ret + case self[:tsh][:flavor]
282
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
283
+ self[:uts].ts32.members.map{|x| [x, (x.to_s + "=").intern]}
284
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
285
+ self[:uts].ts64.members.map{|x| [x, (x.to_s + "=").intern]}
286
+ else
287
+ []
288
+ end
289
+ ret.flatten
290
+ end
291
+ end
292
+
293
+ def method_missing meth, *args
294
+ super unless self.respond_to? meth
295
+ if meth.to_s =~ /=$/
296
+ mth = meth.to_s.gsub(/=$/,'').intern
297
+ if self.members.include? mth
298
+ # don't proxy
299
+ self.__send__(:[]=, mth, *args)
300
+ elsif self[:tsh].members.include? meth
301
+ self[:tsh].__send__(:[]=, mth, *args)
302
+ else
303
+ case self[:tsh][:flavor]
304
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
305
+ self[:uts].ts32.__send__(:[]=, mth, *args)
306
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
307
+ self[:uts].ts64.__send__(:[]=, mth, *args)
308
+ end
309
+ end
310
+ else
311
+ if self.members.include? meth
312
+ # don't proxy
313
+ self.__send__(:[], meth, *args)
314
+ elsif self[:tsh].members.include? meth
315
+ self[:tsh].__send__(:[], meth, *args)
316
+ else
317
+ case self[:tsh][:flavor]
318
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE32
319
+ self[:uts].ts32.__send__(:[], meth, *args)
320
+ when Ragweed::Wraposx::ThreadContext::X86_THREAD_STATE64
321
+ self[:uts].ts64.__send__(:[], meth, *args)
322
+ end
323
+ end
324
+ end
325
+ end
326
+
327
+ def respond_to? meth, include_priv=false
328
+ mth = meth.to_s.gsub(/=$/,'') # may not be needed anymore
329
+ self.methods.include? mth || super
330
+ end
331
+
258
332
  end
259
333
 
260
334
  # _STRUCT_X86_DEBUG_STATE32
@@ -352,6 +426,79 @@ EOM
352
426
  FLAVOR = 12
353
427
  layout :dsh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
354
428
  :uds, Ragweed::Wraposx::ThreadContext::UnionDebugState
429
+
430
+ # We have rubified this FFI structure by creating a bunch of proxy
431
+ # methods that are normally only accessible via self.v.x.y which is
432
+ # a lot to type. You can still use that method however these proxy
433
+ # methods should allow for considerably clearer code
434
+ if RUBY_VERSION < "1.9"
435
+ def methods regular=true
436
+ ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
437
+ ret += self[:dsh].members.map{|x| [x.to_s, x.to_s + "="]}
438
+ ret + case self[:dsh][:flavor]
439
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
440
+ self[:uds].ds32.members.map{|x| [x.to_s, x.to_s + "="]}
441
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
442
+ self[:uds].ds64.members.map{|x| [x.to_s, x.to_s + "="]}
443
+ else
444
+ []
445
+ end
446
+ ret.flatten
447
+ end
448
+ else
449
+ def methods regular=true
450
+ ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
451
+ ret += self[:dsh].members.map{|x| [x, (x.to_s + "=").intern]}
452
+ ret + case self[:dsh][:flavor]
453
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
454
+ self[:uds].ds32.members.map{|x| [x, (x.to_s + "=").intern]}
455
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
456
+ self[:uds].ds64.members.map{|x| [x, (x.to_s + "=").intern]}
457
+ else
458
+ []
459
+ end
460
+ ret.flatten
461
+ end
462
+ end
463
+
464
+ def method_missing meth, *args
465
+ super unless self.respond_to? meth
466
+ if meth.to_s =~ /=$/
467
+ mth = meth.to_s.gsub(/=$/,'').intern
468
+ if self.members.include? mth
469
+ # don't proxy
470
+ self.__send__(:[]=, mth, *args)
471
+ elsif self[:dsh].members.include? meth
472
+ self[:dsh].__send__(:[]=, mth, *args)
473
+ else
474
+ case self[:dsh][:flavor]
475
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
476
+ self[:uds].ds32.__send__(:[]=, mth, *args)
477
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
478
+ self[:uds].ds64.__send__(:[]=, mth, *args)
479
+ end
480
+ end
481
+ else
482
+ if self.members.include? meth
483
+ # don't proxy
484
+ self.__send__(:[], meth, *args)
485
+ elsif self[:dsh].members.include? meth
486
+ self[:dsh].__send__(:[], meth, *args)
487
+ else
488
+ case self[:dsh][:flavor]
489
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE32
490
+ self[:uds].ds32.__send__(:[], meth, *args)
491
+ when Ragweed::Wraposx::ThreadContext::X86_DEBUG_STATE64
492
+ self[:uds].ds64.__send__(:[], meth, *args)
493
+ end
494
+ end
495
+ end
496
+ end
497
+
498
+ def respond_to? meth, include_priv=false
499
+ mth = meth.to_s.gsub(/=$/,'') # may not be needed anymore
500
+ self.methods.include? mth || super
501
+ end
355
502
  end
356
503
 
357
504
  # _STRUCT_X86_EXCEPTION_STATE32
@@ -419,6 +566,81 @@ EOM
419
566
  FLAVOR = 9
420
567
  layout :esh, Ragweed::Wraposx::ThreadContext::X86StateHdr,
421
568
  :ues, Ragweed::Wraposx::ThreadContext::UnionExceptionState
569
+
570
+ #comment
571
+ # We have rubified this FFI structure by creating a bunch of proxy
572
+ # methods that are normally only accessible via self.v.x.y which is
573
+ # a lot to type. You can still use that method however these proxy
574
+ # methods should allow for considerably clearer code
575
+ if RUBY_VERSION < "1.9"
576
+ def methods regular=true
577
+ ret = super + self.members.map{|x| [x.to_s, x.to_s + "="]}
578
+ ret += self[:esh].members.map{|x| [x.to_s, x.to_s + "="]}
579
+ ret + case self[:esh][:flavor]
580
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
581
+ self[:ues].es32.members.map{|x| [x.to_s, x.to_s + "="]}
582
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
583
+ self[:ues].es64.members.map{|x| [x.to_s, x.to_s + "="]}
584
+ else
585
+ []
586
+ end
587
+ ret.flatten
588
+ end
589
+ else
590
+ def methods regular=true
591
+ ret = super + self.members.map{|x| [x, (x.to_s + "=").intern]}
592
+ ret += self[:esh].members.map{|x| [x, (x.to_s + "=").intern]}
593
+ ret + case self[:esh][:flavor]
594
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
595
+ self[:ues].es32.members.map{|x| [x, (x.to_s + "=").intern]}
596
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
597
+ self[:ues].es64.members.map{|x| [x, (x.to_s + "=").intern]}
598
+ else
599
+ []
600
+ end
601
+ ret.flatten
602
+ end
603
+ end
604
+
605
+ def method_missing meth, *args
606
+ super unless self.respond_to? meth
607
+ if meth.to_s =~ /=$/
608
+ mth = meth.to_s.gsub(/=$/,'').intern
609
+ if self.members.include? mth
610
+ # don't proxy
611
+ self.__send__(:[]=, mth, *args)
612
+ elsif self[:esh].members.include? meth
613
+ self[:esh].__send__(:[]=, mth, *args)
614
+ else
615
+ case self[:esh][:flavor]
616
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
617
+ self[:ues].es32.__send__(:[]=, mth, *args)
618
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
619
+ self[:ues].es64.__send__(:[]=, mth, *args)
620
+ end
621
+ end
622
+ else
623
+ if self.members.include? meth
624
+ # don't proxy
625
+ self.__send__(:[], meth, *args)
626
+ elsif self[:esh].members.include? meth
627
+ self[:esh].__send__(:[], meth, *args)
628
+ else
629
+ case self[:esh][:flavor]
630
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE32
631
+ self[:ues].es32.__send__(:[], meth, *args)
632
+ when Ragweed::Wraposx::ThreadContext::X86_EXCEPTION_STATE64
633
+ self[:ues].es64.__send__(:[], meth, *args)
634
+ end
635
+ end
636
+ end
637
+ end
638
+
639
+ def respond_to? meth, include_priv=false
640
+ mth = meth.to_s.gsub(/=$/,'') # may not be needed anymore
641
+ self.methods.include? mth || super
642
+ end
643
+
422
644
  end
423
645
 
424
646
  # _STRUCT_X86_FLOAT_STATE32
@@ -90,3 +90,9 @@ module Ragweed::Wraptux::Wait
90
90
  CONTINUED = 10
91
91
  NOWWAIT = 20
92
92
  end
93
+
94
+ module Ragweed::Wraptux::PagePermissions
95
+ PROT_READ = 0x1
96
+ PROT_WRITE = 0x2
97
+ PROT_EXEC = 0x4
98
+ end
@@ -0,0 +1,35 @@
1
+ class Ragweed::Process
2
+
3
+ include Ragweed
4
+ attr_reader :pid
5
+
6
+ def initialize(pid); @pid = pid; end
7
+
8
+ ## Read/write ranges of data or fixnums to/from the process by address.
9
+ def read(off, sz=4096)
10
+ a = []
11
+ while off < off+sz
12
+ a.push(Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::PEEK_TEXT, @pid, off, 0))
13
+ return a.pack('L*') if a.last == -1 and FFI.errno != 0
14
+ off+=4
15
+ end
16
+ a.pack('L*')
17
+ end
18
+
19
+ ## ptrace sucks, writing 8 or 16 bytes will probably
20
+ ## result in failure unless you PTRACE_POKE first and
21
+ ## get the rest of the original value at the address
22
+ def write(off, data)
23
+ while off < data.size
24
+ Ragweed::Wraptux::ptrace(Ragweed::Wraptux::Ptrace::POKE_TEXT, @pid, off, data[off,4].unpack('L').first)
25
+ off += 4
26
+ end
27
+ end
28
+
29
+ def read32(off); read(off, 4).unpack("L").first; end
30
+ def read16(off); read(off, 2).unpack("v").first; end
31
+ def read8(off); read(off, 1)[0]; end
32
+ def write32(off, v); write(off, [v].pack("L")); end
33
+ def write16(off, v); write(off, [v].pack("v")); end
34
+ def write8(off, v); write(off, v.chr); end
35
+ end
data/lib/ragweed.rb CHANGED
@@ -75,11 +75,11 @@ end # module Ragweed
75
75
  module Ragweed::FFIStructInclude
76
76
  if RUBY_VERSION < "1.9"
77
77
  def methods regular=true
78
- super + self.offsets.map{|x| x.first.to_s}
78
+ (super + self.members.map{|x| [x.to_s, x.to_s+"="]}).flatten
79
79
  end
80
80
  else
81
81
  def methods regular=true
82
- super + self.offsets.map{|x| x.first}
82
+ (super + self.members.map{|x| [x, (x.to_s+"=").intern]}).flatten
83
83
  end
84
84
  end
85
85
 
@@ -93,8 +93,8 @@ module Ragweed::FFIStructInclude
93
93
  end
94
94
 
95
95
  def respond_to? meth, include_priv=false
96
- mth = meth.to_s.gsub(/=$/,'')
97
- self.offsets.map{|x| x.first.to_s}.include? mth || super
96
+ # mth = meth.to_s.gsub(/=$/,'')
97
+ !((self.methods & [meth, meth.to_s]).empty?) || super
98
98
  end
99
99
  end
100
100
 
data/ragweed.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ragweed}
8
- s.version = "0.2.0.pre2"
8
+ s.version = "0.2.0.pre3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["tduehr", "struct", "tqbf"]
12
- s.date = %q{2011-02-14}
12
+ s.date = %q{2011-03-09}
13
13
  s.description = %q{General debugging tool written in Ruby for OSX/Win32/Linux}
14
14
  s.email = %q{td@matasano.com}
15
15
  s.extra_rdoc_files = [
@@ -64,7 +64,7 @@ Gem::Specification.new do |s|
64
64
  "lib/ragweed/wraposx/wraposx.rb",
65
65
  "lib/ragweed/wraptux.rb",
66
66
  "lib/ragweed/wraptux/constants.rb",
67
- "lib/ragweed/wraptux/struct_helpers.rb",
67
+ "lib/ragweed/wraptux/process.rb",
68
68
  "lib/ragweed/wraptux/threads.rb",
69
69
  "lib/ragweed/wraptux/wraptux.rb",
70
70
  "ragweed.gemspec",
@@ -75,7 +75,7 @@ Gem::Specification.new do |s|
75
75
  s.homepage = %q{http://github.com/tduehr/ragweed}
76
76
  s.rdoc_options = ["--inline-source", "--line-numbers", "--main", "README.rdoc"]
77
77
  s.require_paths = ["lib"]
78
- s.rubygems_version = %q{1.3.7}
78
+ s.rubygems_version = %q{1.5.2}
79
79
  s.summary = %q{Scriptable debugger}
80
80
  s.test_files = [
81
81
  "examples/hittracertux.rb",
@@ -89,7 +89,6 @@ Gem::Specification.new do |s|
89
89
  ]
90
90
 
91
91
  if s.respond_to? :specification_version then
92
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
93
92
  s.specification_version = 3
94
93
 
95
94
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ragweed
3
3
  version: !ruby/object:Gem::Version
4
- hash: -1876988175
5
- prerelease: true
4
+ hash: 1923831951
5
+ prerelease: 6
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
9
  - 0
10
- - pre2
11
- version: 0.2.0.pre2
10
+ - pre
11
+ - 3
12
+ version: 0.2.0.pre3
12
13
  platform: ruby
13
14
  authors:
14
15
  - tduehr
@@ -18,7 +19,7 @@ autorequire:
18
19
  bindir: bin
19
20
  cert_chain: []
20
21
 
21
- date: 2011-02-14 00:00:00 -06:00
22
+ date: 2011-03-09 00:00:00 -06:00
22
23
  default_executable:
23
24
  dependencies:
24
25
  - !ruby/object:Gem::Dependency
@@ -93,7 +94,7 @@ files:
93
94
  - lib/ragweed/wraposx/wraposx.rb
94
95
  - lib/ragweed/wraptux.rb
95
96
  - lib/ragweed/wraptux/constants.rb
96
- - lib/ragweed/wraptux/struct_helpers.rb
97
+ - lib/ragweed/wraptux/process.rb
97
98
  - lib/ragweed/wraptux/threads.rb
98
99
  - lib/ragweed/wraptux/wraptux.rb
99
100
  - ragweed.gemspec
@@ -135,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
136
  requirements: []
136
137
 
137
138
  rubyforge_project:
138
- rubygems_version: 1.3.7
139
+ rubygems_version: 1.5.2
139
140
  signing_key:
140
141
  specification_version: 3
141
142
  summary: Scriptable debugger
@@ -1,25 +0,0 @@
1
- module Ragweed::FFIStructInclude
2
- if RUBY_VERSION < "1.9"
3
- def methods regular=true
4
- super + self.offsets.map{|x| x.first.to_s}
5
- end
6
- else
7
- def methods regular=true
8
- super + self.offsets.map{|x| x.first}
9
- end
10
- end
11
-
12
- def method_missing meth, *args
13
- super unless self.respond_to? meth
14
- if meth.to_s =~ /=$/
15
- self.__send__(:[]=, meth.to_s.gsub(/=$/,'').intern, *args)
16
- else
17
- self.__send__(:[], meth, *args)
18
- end
19
- end
20
-
21
- def respond_to? meth, include_priv=false
22
- mth = meth.to_s.gsub(/=$/,'')
23
- self.offsets.map{|x| x.first.to_s}.include? mth || super
24
- end
25
- end