ragweed 0.1.7.2
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 +35 -0
- data/README.txt +9 -0
- data/Rakefile +34 -0
- data/examples/hittracertux.rb +49 -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 +23 -0
- data/lib/ragweed/arena.rb +55 -0
- data/lib/ragweed/blocks.rb +128 -0
- data/lib/ragweed/debugger32.rb +338 -0
- data/lib/ragweed/debuggerosx.rb +427 -0
- data/lib/ragweed/debuggertux.rb +346 -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 +156 -0
- data/lib/ragweed/wrap32/debugging.rb +163 -0
- data/lib/ragweed/wrap32/device.rb +49 -0
- data/lib/ragweed/wrap32/event.rb +50 -0
- data/lib/ragweed/wrap32/hooks.rb +23 -0
- data/lib/ragweed/wrap32/overlapped.rb +46 -0
- data/lib/ragweed/wrap32/process.rb +506 -0
- data/lib/ragweed/wrap32/process_token.rb +59 -0
- data/lib/ragweed/wrap32/thread_context.rb +208 -0
- data/lib/ragweed/wrap32/winx.rb +16 -0
- data/lib/ragweed/wrap32/wrap32.rb +526 -0
- data/lib/ragweed/wrap32.rb +59 -0
- data/lib/ragweed/wraposx/constants.rb +122 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +254 -0
- data/lib/ragweed/wraposx/thread_context.rb +203 -0
- data/lib/ragweed/wraposx/thread_info.rb +227 -0
- data/lib/ragweed/wraposx/wraposx.rb +433 -0
- data/lib/ragweed/wraposx.rb +59 -0
- data/lib/ragweed/wraptux/constants.rb +68 -0
- data/lib/ragweed/wraptux/threads.rb +7 -0
- data/lib/ragweed/wraptux/wraptux.rb +76 -0
- data/lib/ragweed/wraptux.rb +59 -0
- data/lib/ragweed.rb +84 -0
- data/ragweed.gemspec +34 -0
- data/spec/ragweed_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test_ragweed.rb +0 -0
- metadata +132 -0
data/History.txt
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
== 0.1.7.2 / 2009-09-21
|
2
|
+
|
3
|
+
* fixed Sub and Add in Rasm correctly. added Leave instruction
|
4
|
+
|
5
|
+
== 0.1.7.1 / 2009-09-20
|
6
|
+
|
7
|
+
* added Rasm::Subl to avoid conflict in Bblock with Kernel#sub
|
8
|
+
* setup for call trampolines in osx
|
9
|
+
|
10
|
+
== 0.1.7 / 2009-08-03
|
11
|
+
|
12
|
+
* bug fixes (Wraposx#RegionInfo should now fully work)
|
13
|
+
|
14
|
+
== 0.1.6 / 2009-07-13
|
15
|
+
|
16
|
+
* bug fixes and API work
|
17
|
+
|
18
|
+
== 0.1.5 / 2009-06-18
|
19
|
+
|
20
|
+
* more bug fixes
|
21
|
+
|
22
|
+
== 0.1.1 / 2009-06-02
|
23
|
+
|
24
|
+
* bug fixen and namespace changes
|
25
|
+
|
26
|
+
== 0.1.0 / 2009-05-31
|
27
|
+
|
28
|
+
* initial release
|
29
|
+
|
30
|
+
== 0.0.1 / 2009-05-13
|
31
|
+
|
32
|
+
* initial pull from svn
|
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
Ragweed
|
2
|
+
by tduehr, struct, and tqbf
|
3
|
+
http://matasano.com/log
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
* Ragweed is a set of scriptable debugging tools written mostly in native ruby.
|
8
|
+
|
9
|
+
* Where required the Ruby/DL and Win32API libraries are used to interface the machine
|
10
|
+
and OS native system calls.
|
11
|
+
|
12
|
+
== FEATURES/PROBLEMS:
|
13
|
+
|
14
|
+
* This suite is currently fairly piecemeal. Each OS has it's own set of tools.
|
15
|
+
The most complete set is for Win32.
|
16
|
+
|
17
|
+
* Work is ongoing to complete and unify the OSX and Linux portions.
|
18
|
+
|
19
|
+
== SYNOPSIS:
|
20
|
+
|
21
|
+
require 'debuggerosx'
|
22
|
+
d = Debuggerosx.new(514) # pid of process to trace
|
23
|
+
|
24
|
+
== REQUIREMENTS:
|
25
|
+
|
26
|
+
* NONE - no really, this is pure native ruby hooking system libraries. There are no other dependencies, none.
|
27
|
+
|
28
|
+
== INSTALL:
|
29
|
+
|
30
|
+
gem sources -a http://gems.github.com
|
31
|
+
sudo gem install tduehr-ragweed
|
32
|
+
|
33
|
+
== LICENSE:
|
34
|
+
|
35
|
+
Copyright 2009 Matasano Security, LLC All Rights Reserved
|
data/README.txt
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Ragweed is a set of scriptable debugging tools written mostly in native ruby.
|
2
|
+
|
3
|
+
Where required the Ruby/DL and Win32API libraries are used to interface the machine
|
4
|
+
and OS native system calls.
|
5
|
+
|
6
|
+
This suite is currently fairly piecemeal. Each OS has it's own set of tools.
|
7
|
+
The most complete set is for Win32.
|
8
|
+
|
9
|
+
Work is ongoing to complete and unify the OSX and Linux portions.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
Bones.setup
|
8
|
+
rescue LoadError
|
9
|
+
begin
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
rescue LoadError
|
12
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ensure_in_path 'lib'
|
17
|
+
require 'ragweed'
|
18
|
+
|
19
|
+
task :default => 'spec:run'
|
20
|
+
|
21
|
+
PROJ.name = 'ragweed'
|
22
|
+
PROJ.ignore_file = '.gitignore'
|
23
|
+
PROJ.authors = 'tduehr, tqbf, struct'
|
24
|
+
PROJ.email = 'td@matasano.com'
|
25
|
+
PROJ.description = 'General debugging tool written in Ruby for OSX/Win32/Linux'
|
26
|
+
PROJ.summary = 'Scriptable debugger'
|
27
|
+
PROJ.exclude << %w(old$)
|
28
|
+
PROJ.url = 'http://github.com/tduehr/ragweed/tree/master'
|
29
|
+
PROJ.version = Ragweed::VERSION
|
30
|
+
PROJ.rdoc.opts << "--inline-source"
|
31
|
+
PROJ.rdoc.opts << "--line-numbers"
|
32
|
+
PROJ.spec.opts << '--color'
|
33
|
+
|
34
|
+
# EOF
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ragweed'
|
4
|
+
require 'debuggertux'
|
5
|
+
require 'pp'
|
6
|
+
require 'irb'
|
7
|
+
#include Ragweed
|
8
|
+
|
9
|
+
filename = ARGV[0]
|
10
|
+
pid = ARGV[1].to_i
|
11
|
+
|
12
|
+
raise "hittracertux.rb FILE PID" if (ARGV.size < 2 or pid <= 0)
|
13
|
+
|
14
|
+
d = Debuggertux.new(pid)
|
15
|
+
d.attach
|
16
|
+
|
17
|
+
File.open(filename, "r") do |fd|
|
18
|
+
lines = fd.readlines
|
19
|
+
lines.map {|x| x.chomp}
|
20
|
+
lines.each do |tl|
|
21
|
+
fn, addr = tl.split(",", 2)
|
22
|
+
d.breakpoint_set(addr.to_i(16), fn, (bpl = lambda do puts "hit - #{fn} #{addr}\n"; end))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
d.install_bps
|
27
|
+
d.continue
|
28
|
+
catch(:throw) { d.loop }
|
29
|
+
|
30
|
+
|
31
|
+
# An IDC script for generating the text file this hit tracer requires
|
32
|
+
=begin
|
33
|
+
#include <idc.idc>
|
34
|
+
|
35
|
+
static main()
|
36
|
+
{
|
37
|
+
auto entry, fname, outf, fd;
|
38
|
+
outf = AskFile(1, "*.txt", "Please select an output file");
|
39
|
+
fd = fopen(outf,"w");
|
40
|
+
|
41
|
+
for(entry=NextFunction(0); entry != BADADDR; entry=NextFunction(entry) )
|
42
|
+
{
|
43
|
+
fname = GetFunctionName(entry);
|
44
|
+
fprintf(fd, "%s,0x%x\n", fname, entry);
|
45
|
+
}
|
46
|
+
|
47
|
+
fclose(fd);
|
48
|
+
}
|
49
|
+
=end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# A simple hittracer to debug and test Debuggerosx.
|
4
|
+
# FILE is CSV file,address
|
5
|
+
# PID is the proces id to attach to.
|
6
|
+
|
7
|
+
require 'debuggerosx'
|
8
|
+
require 'pp'
|
9
|
+
require 'irb'
|
10
|
+
include Ragweed
|
11
|
+
|
12
|
+
filename = ARGV[0]
|
13
|
+
pid = ARGV[1].to_i
|
14
|
+
|
15
|
+
raise "hittracerosx.rb FILE PID" if (ARGV.size < 2 or pid <= 0)
|
16
|
+
|
17
|
+
class Debuggerosx
|
18
|
+
def on_exit
|
19
|
+
exit(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_single_step
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_segv(thread)
|
26
|
+
pp self.get_registers(thread)
|
27
|
+
pp self.threads
|
28
|
+
self.threads.each {|thread| puts Wraposx::ThreadContext.get(thread).dump}
|
29
|
+
self.threads.each {|thread| puts Wraposx::ThreadInfo.get(thread).dump}
|
30
|
+
throw(:break)
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_bus(thread)
|
34
|
+
throw(:break)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
d = Debuggerosx.new(pid)
|
39
|
+
d.attach
|
40
|
+
|
41
|
+
File.open(filename, "r") do |fd|
|
42
|
+
lines = fd.readlines
|
43
|
+
lines.map {|x| x.chomp}
|
44
|
+
lines.each do |tl|
|
45
|
+
fn, addr = tl.split(",", 2)
|
46
|
+
d.breakpoint_set(addr.to_i(16), fn, (bpl = lambda do | t, r, s | puts "#{ s.breakpoints[r.eip].first.function } hit in thread #{ t }\n"; end))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
d.install_bps
|
51
|
+
d.continue
|
52
|
+
catch(:throw) { d.loop }
|
53
|
+
pp d.wait 1
|
54
|
+
pp d.threads
|
55
|
+
|
56
|
+
d.threads.each do |t|
|
57
|
+
r = Wraposx::ThreadContext.get(t)
|
58
|
+
i = Wraposx::ThreadInfo.get(t)
|
59
|
+
pp r
|
60
|
+
puts r.dump
|
61
|
+
pp i
|
62
|
+
puts i.dump
|
63
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "ragweed"
|
2
|
+
include Ragweed
|
3
|
+
|
4
|
+
dbg = Debugger.find_by_regex /notepad/i
|
5
|
+
raise "notepad not running" if dbg.nil?
|
6
|
+
|
7
|
+
dbg.hook('kernel32!CreateFileW', 7) {|e,c,d,a| puts "#{d} CreateFileW for #{dbg.process.read(a[0],512).from_utf16_buffer}"}
|
8
|
+
dbg.loop
|
9
|
+
dbg.release
|
data/examples/snicker.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This is a slightly more complex hit tracer implementation of
|
4
|
+
# Debuggerosx. It does fork/exec and attempts, in a manner resembling
|
5
|
+
# rocket surgery with a steamroller, to skip any call to ptrace.
|
6
|
+
|
7
|
+
# This was last setup to debug the race condition in Debuggerosx#on_breakpoint
|
8
|
+
# using ftp as the child.
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'ragweed'
|
12
|
+
require 'pp'
|
13
|
+
require 'ruby-debug'
|
14
|
+
Debugger.start
|
15
|
+
|
16
|
+
filename = ARGV[0]
|
17
|
+
pid = ARGV[1].to_i
|
18
|
+
ptraceloc = 0
|
19
|
+
rd, wr = nil, nil
|
20
|
+
|
21
|
+
class Snicker < Ragweed::Debuggerosx
|
22
|
+
attr_accessor :attached
|
23
|
+
|
24
|
+
def on_exit(status)
|
25
|
+
pp "Exited with status #{ status }"
|
26
|
+
@hooked = false
|
27
|
+
@attached = false
|
28
|
+
@exited = true
|
29
|
+
throw(:break)
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_single_step
|
33
|
+
end
|
34
|
+
|
35
|
+
def on_sigsegv
|
36
|
+
pp "SEGV"
|
37
|
+
pp self.threads
|
38
|
+
self.threads.each do |t|
|
39
|
+
pp self.get_registers(t)
|
40
|
+
pp Ragweed::Wraposx::ThreadInfo.get(t)
|
41
|
+
end
|
42
|
+
debugger
|
43
|
+
@exited = true
|
44
|
+
throw(:break)
|
45
|
+
end
|
46
|
+
|
47
|
+
def on_sigbus
|
48
|
+
pp "sigbus"
|
49
|
+
# pp Ragweed::Wraposx::vm_read(@task,0x420f,169)
|
50
|
+
# # Kernel.debugger
|
51
|
+
# # Debugger.breakpoint
|
52
|
+
# # Debugger.catchpoint
|
53
|
+
# debugger
|
54
|
+
throw(:break)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if pid == 0
|
59
|
+
rd, wr = IO.pipe
|
60
|
+
pid = fork
|
61
|
+
end
|
62
|
+
|
63
|
+
if pid.nil?
|
64
|
+
ptraceloc = Ragweed::Wraposx::LIBS['/usr/lib/libc.dylib'].sym("ptrace", "IIIII").to_ptr.ref.to_s(Ragweed::Wraposx::SIZEOFINT).unpack("I_").first
|
65
|
+
|
66
|
+
pp ptraceloc.to_s(16)
|
67
|
+
rd.close
|
68
|
+
wr.puts ptraceloc
|
69
|
+
|
70
|
+
Ragweed::Wraposx::ptrace(Ragweed::Wraposx::Ptrace::TRACE_ME, 0, 0, 0)
|
71
|
+
puts "Traced!"
|
72
|
+
# sleep(1)
|
73
|
+
|
74
|
+
puts "Execing #{ARGV[1]}"
|
75
|
+
exec(ARGV[1])
|
76
|
+
puts "it left"
|
77
|
+
else
|
78
|
+
d = Snicker.new(pid)
|
79
|
+
|
80
|
+
if rd
|
81
|
+
wr.close
|
82
|
+
# d.attached = true
|
83
|
+
ptraceloc = rd.gets.chomp.to_i(0)
|
84
|
+
|
85
|
+
pp ptraceloc.to_s(16)
|
86
|
+
pp d
|
87
|
+
pp d.threads
|
88
|
+
|
89
|
+
raise "Fail!" if ptraceloc == 0
|
90
|
+
|
91
|
+
d.breakpoint_set(ptraceloc,"Ptrace",(bpl = lambda do |t, r, s|
|
92
|
+
puts "#{ s.breakpoints[r.eip].first.function } hit in thread #{ t }\n"
|
93
|
+
pp r
|
94
|
+
if Ragweed::Wraposx::vm_read(s.task,r.esp + 4,4).unpack("I").first == Ragweed::Wraposx::Ptrace::DENY_ATTACH
|
95
|
+
pp Ragweed::Wraposx::vm_read(s.task,r.esp-28,32).unpack("I_*").map{|x| x.to_s(16)}
|
96
|
+
pp Ragweed::Wraposx::vm_read(s.task,r.esp,32).unpack("I_*").map{|x| x.to_s(16)}
|
97
|
+
r.eax = 0
|
98
|
+
# r.esp = r.ebp
|
99
|
+
# r.ebp = Ragweed::Wraposx::vm_read(s.task,r.esp,4).unpack("I_").first
|
100
|
+
r.eip = Ragweed::Wraposx::vm_read(s.task,r.esp,4).unpack("V").first
|
101
|
+
# r.esp = Ragweed::Wraposx::vm_read(s.task,r.ebp,4).unpack("I_").first
|
102
|
+
# r.ebp +=4
|
103
|
+
# r.eip = Ragweed::Wraposx::vm_read(s.task,r.esp,4).unpack("I_").first
|
104
|
+
# r.esp+=4
|
105
|
+
pp "bounced"
|
106
|
+
return false
|
107
|
+
else
|
108
|
+
pp Ragweed::Wraposx::vm_read(s.task,r.esp-28,32).unpack("I_*").map{|x| x.to_s(16)}
|
109
|
+
pp Ragweed::Wraposx::vm_read(s.task,r.esp,32).unpack("I_*").map{|x| x.to_s(16)}
|
110
|
+
# pp Ragweed::Wraposx::dl_bignum_to_ulong(r.esp).ptr.to_s(4).unpack("I").first.to_s(16)
|
111
|
+
# pp Ragweed::Wraposx::dl_bignum_to_ulong(r.esp - 15*4).to_s(4*16).unpack("I*").map{|x| x.to_s(16)}
|
112
|
+
# pp Ragweed::Wraposx::dl_bignum_to_ulong(r.esp).to_s(15*4).unpack("I*").map{|x| x.to_s(16)}
|
113
|
+
return true
|
114
|
+
end
|
115
|
+
end))
|
116
|
+
|
117
|
+
d.install_bps
|
118
|
+
|
119
|
+
class Snicker < Ragweed::Debuggerosx
|
120
|
+
def on_sigtrap
|
121
|
+
if not @first
|
122
|
+
@first = true
|
123
|
+
self.install_bps
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def on_stop(signal)
|
128
|
+
pp "#Stopped with signal #{ signal } (on_stop)"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
else
|
133
|
+
d.attach
|
134
|
+
|
135
|
+
class Snicker < Ragweed::Debuggerosx
|
136
|
+
def on_sigstop
|
137
|
+
if not @first
|
138
|
+
@first = true
|
139
|
+
self.install_bps
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def on_stop(signal)
|
144
|
+
pp "#Stopped with signal #{ signal } (on_stop)"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# File.open(filename, "r") do |fd|
|
150
|
+
# lines = fd.readlines
|
151
|
+
# lines.map {|x| x.chomp!}
|
152
|
+
# lines.each do |tl|
|
153
|
+
# pp tl
|
154
|
+
# fn, addr = tl.split(",", 2)
|
155
|
+
# pp [fn, addr.to_i(16)]
|
156
|
+
# if (not addr.nil? and addr.to_i(16) > 0)
|
157
|
+
# d.breakpoint_set(addr.to_i(16), fn, (bpl = lambda do | t, r, s |
|
158
|
+
# puts "#{ s.breakpoints[r.eip].first.function } hit in thread #{ t }\n"
|
159
|
+
# # pp r
|
160
|
+
# # debugger
|
161
|
+
# end))
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# blpwd = Wraposx::vm_read(d.task,0x420f,16)
|
167
|
+
# bbus = Wraposx::vm_read(d.task,0x4220,32)
|
168
|
+
|
169
|
+
catch(:break) { d.loop() }
|
170
|
+
|
171
|
+
if not d.exited
|
172
|
+
pp d.threads
|
173
|
+
|
174
|
+
d.threads.each do |t|
|
175
|
+
r = Ragweed::Wraposx::ThreadContext.get(t)
|
176
|
+
i = Ragweed::Wraposx::ThreadInfo.get(t)
|
177
|
+
pp r
|
178
|
+
puts r.dump
|
179
|
+
pp i
|
180
|
+
puts i.dump
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
## Simple example of attaching to a process and letting it run
|
4
|
+
|
5
|
+
require 'rubygems' # Yah I know its bad
|
6
|
+
require 'ragweed'
|
7
|
+
|
8
|
+
pid = Ragweed::Debuggertux.find_by_regex(/gcalctool/)
|
9
|
+
|
10
|
+
begin
|
11
|
+
t = Ragweed::Debuggertux.threads(pid)
|
12
|
+
puts "Available pid/tdpids\n"
|
13
|
+
t.each do |h| puts h end
|
14
|
+
puts "Which thread do you want to attach to?"
|
15
|
+
pid = STDIN.gets.chomp.to_i
|
16
|
+
|
17
|
+
d = Ragweed::Debuggertux.new(pid)
|
18
|
+
d.attach
|
19
|
+
d.continue
|
20
|
+
catch(:throw) { d.loop }
|
21
|
+
rescue
|
22
|
+
puts "Maybe your PID is wrong?"
|
23
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Ragweed::Arena
|
2
|
+
# I want 3 lambdas:
|
3
|
+
# * "get" should take no arguments and result in the address of a fresh
|
4
|
+
# 4k page.
|
5
|
+
# * "free" should free any 4k page returned by "get"
|
6
|
+
# * "copy" should implement memcpy, copying a string into a 4k page.
|
7
|
+
def initialize(get, free, copy)
|
8
|
+
@get = get
|
9
|
+
@free = free
|
10
|
+
@copy = copy
|
11
|
+
@pages = []
|
12
|
+
@avail = 0
|
13
|
+
@off = 0
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get
|
19
|
+
p = @get.call
|
20
|
+
@pages << p
|
21
|
+
@cur = p
|
22
|
+
@avail = 4096
|
23
|
+
@off = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
public
|
27
|
+
|
28
|
+
# Allocate any size less than 4090 from the arena.
|
29
|
+
def alloc(sz)
|
30
|
+
raise "can't handle > page size now" if sz > 4090
|
31
|
+
get if sz > @avail
|
32
|
+
ret = @off
|
33
|
+
@off += sz
|
34
|
+
round = 4 - (@off % 4)
|
35
|
+
if (@off + round) > 4096
|
36
|
+
@avail = 0
|
37
|
+
@off = 4096
|
38
|
+
else
|
39
|
+
@off += round
|
40
|
+
@avail -= (sz + round)
|
41
|
+
end
|
42
|
+
|
43
|
+
return Ptr.new(@cur + ret)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Copy a buffer into the arena and return its new address.
|
47
|
+
def copy(buf)
|
48
|
+
ret = alloc(buf.size)
|
49
|
+
@copy.call(ret, buf)
|
50
|
+
return ret
|
51
|
+
end
|
52
|
+
|
53
|
+
# Release the whole arena all at once.
|
54
|
+
def release; @pages.each {|p| @free.call(p)}; end
|
55
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require ::File.join(::File.dirname(__FILE__),'rasm')
|
2
|
+
|
3
|
+
pushv = $VERBOSE
|
4
|
+
$VERBOSE = nil
|
5
|
+
|
6
|
+
module Ragweed::Blocks
|
7
|
+
include Ragweed::Rasm
|
8
|
+
extend Ragweed::Rasm
|
9
|
+
|
10
|
+
def remote_trampoline(argc, opts={})
|
11
|
+
i = Rasm::Subprogram.new
|
12
|
+
|
13
|
+
# drop directly to debugger
|
14
|
+
i << Int(3) if opts[:debug]
|
15
|
+
|
16
|
+
# psuedo-frame-pointer
|
17
|
+
i.<< Push(esi)
|
18
|
+
i.<< Mov(esi, esp)
|
19
|
+
|
20
|
+
# get the thread arg
|
21
|
+
i.<< Add(esi, 8)
|
22
|
+
|
23
|
+
# load it
|
24
|
+
i.<< Mov(esi, [esi])
|
25
|
+
i.<< Push(ebx)
|
26
|
+
i.<< Mov(ebx, [esi])
|
27
|
+
i.<< Push(ecx)
|
28
|
+
|
29
|
+
# harvest arguments out of the argument buffer
|
30
|
+
(0...argc).each do |n|
|
31
|
+
i.<< Mov(ecx, [esi+(4+(n*4))])
|
32
|
+
i.<< Push(ecx)
|
33
|
+
end
|
34
|
+
|
35
|
+
i.<< Call(ebx)
|
36
|
+
|
37
|
+
# stuff return value after args
|
38
|
+
i.<< Mov([esi + (4+(argc*4))], eax)
|
39
|
+
|
40
|
+
# epilogue
|
41
|
+
i.<< Pop(ecx)
|
42
|
+
i.<< Pop(ebx)
|
43
|
+
i.<< Pop(esi)
|
44
|
+
i.<< Ret() # i think this is an artifact of my IRB, TODO clean up
|
45
|
+
end
|
46
|
+
module_function :remote_trampoline
|
47
|
+
|
48
|
+
def event_pair_stub(opts={})
|
49
|
+
i = Rasm::Subprogram.new
|
50
|
+
|
51
|
+
i << Int(3) if opts[:debug]
|
52
|
+
|
53
|
+
i.<< Push(ebp)
|
54
|
+
i.<< Mov(ebp, esp)
|
55
|
+
i.<< Sub(esp, 12)
|
56
|
+
|
57
|
+
i.<< Push(esi)
|
58
|
+
i.<< Mov(esi, [ebp+8])
|
59
|
+
|
60
|
+
i.<< Push(eax)
|
61
|
+
i.<< Push(ebx)
|
62
|
+
i.<< Push(edx)
|
63
|
+
|
64
|
+
# OpenProcess
|
65
|
+
i.<< Mov(ebx, [esi]) # function ptr
|
66
|
+
i.<< Mov(eax, [esi+24])
|
67
|
+
i.<< Push(eax)
|
68
|
+
i.<< Xor(eax, eax)
|
69
|
+
i.<< Push(eax)
|
70
|
+
i.<< Or(eax, 0x1F0FFF)
|
71
|
+
i.<< Push(eax)
|
72
|
+
i.<< Call(ebx)
|
73
|
+
i.<< Mov([ebp-4], eax)
|
74
|
+
|
75
|
+
# DuplicateHandle
|
76
|
+
i.<< Mov(ebx, [esi+4]) # function ptr
|
77
|
+
(1..2).each do |which|
|
78
|
+
i.<< Push(2) # flags
|
79
|
+
i.<< Push(0) # dunno
|
80
|
+
i.<< Push(0) # dunno
|
81
|
+
i.<< Mov(edx, ebp) # my LEA encoding is broken
|
82
|
+
i.<< Sub(edx, 8+(4*(which-1)))
|
83
|
+
i.<< Lea(eax, [edx])
|
84
|
+
i.<< Push(eax) # handle out-arg
|
85
|
+
i.<< Xor(eax, eax)
|
86
|
+
i.<< Not(eax)
|
87
|
+
i.<< Push(eax) # target process
|
88
|
+
i.<< Mov(ecx, esi)
|
89
|
+
i.<< Add(ecx, (20 + (4 * which)))
|
90
|
+
i.<< Push([ecx])
|
91
|
+
i.<< Push([ebp-4]) # target process handle
|
92
|
+
i.<< Call(ebx)
|
93
|
+
end
|
94
|
+
|
95
|
+
# ResetHandle
|
96
|
+
i.<< Mov(ebx, [esi+8]) # function ptr
|
97
|
+
(0..1).each do |which|
|
98
|
+
i.<< Push([ebp-(8+(4*which))])
|
99
|
+
i.<< Call(ebx)
|
100
|
+
end
|
101
|
+
|
102
|
+
# SignalHandle
|
103
|
+
i.<< Mov(ebx, [esi+12]) # function ptr
|
104
|
+
i.<< Push([ebp-8])
|
105
|
+
i.<< Call(ebx)
|
106
|
+
|
107
|
+
# WaitForSingleObject
|
108
|
+
i.<< Mov(ebx, [esi+16])
|
109
|
+
i.<< Xor(eax, eax)
|
110
|
+
i.<< Not(eax)
|
111
|
+
i.<< Push(eax)
|
112
|
+
i.<< Push([ebp-12])
|
113
|
+
i.<< Call(ebx)
|
114
|
+
|
115
|
+
# All done!
|
116
|
+
|
117
|
+
i.<< Pop(edx)
|
118
|
+
i.<< Pop(ebx)
|
119
|
+
i.<< Pop(eax)
|
120
|
+
i.<< Pop(ecx)
|
121
|
+
i.<< Pop(esi)
|
122
|
+
i.<< Add(esp, 12)
|
123
|
+
i.<< Pop(ebp)
|
124
|
+
i.<< Ret()
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
$VERBOSE = pushv
|