Class: Ragweed::Detour::Detour

Inherits:
Object
  • Object
show all
Defined in:
lib/ragweed/detour.rb

Overview

“Ghetto Detours”, as Scott Stender might say. Patch subprograms in to running programs as a hooking mechanism.

Direct Known Subclasses

Dbreak

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(p, opts = {}) ⇒ Detour

Easiest way to do this is just to ask WinProcess#detour. Wants “p” to be a pointer into the process, presumable returned from WinProcess#get_proc.

In theory, “p” should be OK anywhere as long as there are 5 bytes of instructions before the end of the basic block its in. In practice, this only really stands a chance of working if “p” points to a function prologue.



17
18
19
20
21
22
23
24
# File 'lib/ragweed/detour.rb', line 17

def initialize(p, opts={})      
  @p = p.p
  @dpoint = p
  @opts = opts
  @a = @opts[:arena] || @p.arena
  @stack = @a.alloc(2048)
  @snarfed = snarf_prologue
end

Instance Attribute Details

#dpointObject (readonly)

Returns the value of attribute dpoint.



6
7
8
# File 'lib/ragweed/detour.rb', line 6

def dpoint
  @dpoint
end

#snarfedObject (readonly)

Returns the value of attribute snarfed.



5
6
7
# File 'lib/ragweed/detour.rb', line 5

def snarfed
  @snarfed
end

#stackObject (readonly)

Returns the value of attribute stack.



7
8
9
# File 'lib/ragweed/detour.rb', line 7

def stack
  @stack
end

Instance Method Details

#callObject

Patch the target function. There is a 70% chance this will totally fuck your process.

You would be wise to have the threads in the process suspended while you do this, but I’m not going to do it for you.



38
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
66
67
68
69
70
71
# File 'lib/ragweed/detour.rb', line 38

def call
  # a Detours-style trampoline --- the location we patch the
  # target function to jump to --- consists of:
  #
  # - A stack switch (to push/pop w/o fucking the program)
  # - A context save
  # - The Detour code
  # - A context restore
  # - A stack restore
  # - The code we patched out of the target
  # - A jump back to the target function (after the prologue)

  # Do this now to make room for the (probably 5 byte) jump. 
  # We don't know what the address will be until we allocate.
  jumpback = (Jmp 0xDEADBEEF) # patch back later

  # Build the trampoline
  tramp = trampoline(@stack).assemble

  # Figure out how big the whole mess will be, allocate it
  tsz = tramp.size + @snarfed.size + jumpback.to_s.size
  tbuf = @a.alloc(tsz + 10)
  
  # assume trampoline is ahead of the patched program text;
  # jump to [dpoint+patch]
  jumpback.dst = (@dpoint.to_i + @snarfed.size) - (tbuf + tsz)
  
  # Write it into memory. It's not "live" yet because we haven't
  # patched the target function.
  @p.write(tbuf, tramp + @snarfed + jumpback.to_s)

  # But now it is. =)
  @p.write(@dpoint, injection(tbuf).assemRASble)
end

#inner_blockObject

Hook function. Override this in subclasses to provide different behavior.



75
76
77
78
# File 'lib/ragweed/detour.rb', line 75

def inner_block
  i = Ragweed::Rasm::Subprogram.new
  i.<< Int(3)
end

#releaseObject

Release the detour and its associated memory, unpatch the target function.



28
29
30
31
# File 'lib/ragweed/detour.rb', line 28

def release
  @dpoint.write(@snarfed)
  @a.release if not @opts[:arena]
end