Class: Ragweed::Trampoline

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

Instance Method Summary collapse

Constructor Details

#initialize(p, loc, opts = {}) ⇒ Trampoline

Normally called through WinProcess#remote_call, but, for what it’s worth: needs a WinProcess instance and a location, which can be a string module!function or a pointer.



6
7
8
9
10
11
12
13
14
15
16
# File 'lib/ragweed/trampoline.rb', line 6

def initialize(p, loc, opts={})
  @p = p
  @loc = @p.get_proc loc
  @argc = opts[:argc]
  @a = @p.arena
  @mem = @a.alloc(1024)
  @arg_mem = @mem + 512
  @wait = opts[:wait] || true
  @chicken = opts[:chicken] 
  @opts = opts
end

Instance Method Details

#call(*args) ⇒ Object

Call the remote function. Returns the 32 bit EAX return value provided by stdcall.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
# File 'lib/ragweed/trampoline.rb', line 20

def call(*args)
  raise "Insufficient Arguments" if @argc and @argc != args.size
  
  @shim = Ragweed::Blocks::remote_trampoline(args.size, @opts)

  # Won't leak memory.
  @p.arena do |a|
    # 1024 is a SWAG. Divide it in half, one for the trampoline
    # (which is unrolled, because I am lazy and dumb) and the other
    # for the call stack.
    base = @p.ptr(a.alloc(1024))
    
    argm = base + 512
    cur = argm

    # Write the location for the tramp to call
    cur.write(@loc)
    cur += 4

    # Write the function arguments into the call stack.
    (0...args.size).each_backwards do |i|
      if args[i].kind_of? Integer
        val = args[i].to_l32
      elsif args[i].kind_of? String
        stash = a.copy(args[i])
        val = stash.to_l32
      else
        val = args[i].to_s
      end
      cur.write(val)
      cur += 4
    end if args.size.nonzero?

    # Write a placeholder for the return value
    cur.write(0xDEADBEEF.to_l32)

    # Write the tramp
    s = @shim.assemble
    base.write(s)

    th = Ragweed::Wrap32::create_remote_thread(@p.handle, base, argm)
    Ragweed::Wrap32::wait_for_single_object(th) if @wait
    Ragweed::Wrap32::close_handle(th)
    ret = @p.read32(cur)
    if ret == 0xDEADBEEF
      ret = nil
    end
    ret
  end
end