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.
Files changed (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -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,60 @@
1
+ == Ragweed
2
+ by tduehr, crohlf, and tqbf
3
+ http://chargen.matasano.com
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
+ == Supported Platforms
13
+
14
+ Ragweed is supported and has been tested on the following platforms (32bit intel only):
15
+
16
+ Windows 7
17
+ Windows XP
18
+ Linux Ubuntu 10.4
19
+ Linux Ubuntu 9.10
20
+ Mac OS X 10.6
21
+ Mac OS X 10.5
22
+
23
+ At this time only Ruby 1.8.x has been tested. We are actively investigating both 64 bit
24
+ support for each platform and support for Ruby 1.9.x. Unfortunately, both of these things
25
+ require significant changes to Ragweed.
26
+
27
+ * We are currently moving to FFI from ruby/dl. This will likely result in some incompatibilities if you are using the low level functions calls directly. It will also add ffi as a dependency. This move is to facilitate 1.9 and 64bit support.
28
+
29
+ == FEATURES/PROBLEMS:
30
+
31
+ * This suite is currently fairly piecemeal. Each OS has it's own set of tools.
32
+ The most complete set is for Win32.
33
+
34
+ * Work is ongoing to complete and unify the OSX and Linux portions.
35
+
36
+ * The FFI move is mostly complete. There may be a few changes to some structures to come, but everything should mostly match the C APIs.
37
+
38
+ * The move to FFI should give us free support for jRuby. This is, however, untested at this time.
39
+
40
+ * Struct's Nerve[http://github.com/struct/Nerve] is an example of the API we are heading toward
41
+
42
+ == SYNOPSIS:
43
+
44
+ require 'debuggerosx'
45
+ d = Debuggerosx.new(514) # pid of process to trace
46
+
47
+ Please see the examples directory for more. There are hit tracers for each platform.
48
+
49
+ == REQUIREMENTS:
50
+
51
+ * FFI - This was required to get around the limitations of Ruby/DL. If you're using Ragweed from jRuby, this should be free.
52
+
53
+ == INSTALL:
54
+
55
+ sudo gem install ragweed
56
+ # relax with a tasty beverage, you're done
57
+
58
+ == LICENSE:
59
+
60
+ Copyright 2009/2010 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,86 @@
1
+
2
+ # begin
3
+ # require 'bones'
4
+ # rescue LoadError
5
+ # abort '### Please install the "bones" gem ###'
6
+ # end
7
+ #
8
+ # ensure_in_path 'lib'
9
+ # require 'ragweed'
10
+ #
11
+ # task :default => 'test:run'
12
+ # task 'gem:release' => 'test:run'
13
+ #
14
+ # Bones {
15
+ # name 'ragweed'
16
+ # ignore_file '.gitignore'
17
+ # authors 'tduehr, tqbf, struct'
18
+ # email 'td@matasano.com'
19
+ # description 'General debugging tool written in Ruby for OSX/Win32/Linux'
20
+ # summary 'Scriptable debugger'
21
+ # exclude << %w(old$)
22
+ # url 'http://github.com/tduehr/ragweed/tree/master'
23
+ # version Ragweed::VERSION
24
+ # rdoc.opts << "--inline-source"
25
+ # rdoc.opts << "--line-numbers"
26
+ # spec.opts << '--color'
27
+ # }
28
+ # # EOF
29
+
30
+ require 'rubygems'
31
+ require 'rake'
32
+
33
+ begin
34
+ require 'jeweler'
35
+ Jeweler::Tasks.new do |gem|
36
+ gem.name = "ragweed"
37
+ gem.summary = %Q{Scriptable debugger}
38
+ gem.description = %Q{General debugging tool written in Ruby for OSX/Win32/Linux}
39
+ gem.email = "td@matasano.com"
40
+ gem.homepage = "http://github.com/tduehr/ragweed"
41
+ gem.authors = ["tduehr", "struct", "tqbf"]
42
+ gem.rdoc_options = ["--inline-source", "--line-numbers", "--main", "README.rdoc"]
43
+ gem.platform = "java" if Gem::Platform.local.os == "java"
44
+ gem.add_dependency "ffi", "~> 1.0" if Gem::Platform.local.os != "java"
45
+ # gem.exclude = [%w(old)]
46
+ # gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
47
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
48
+ end
49
+ Jeweler::GemcutterTasks.new
50
+ rescue LoadError
51
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
52
+ end
53
+
54
+ require 'rake/testtask'
55
+ Rake::TestTask.new(:test) do |test|
56
+ test.libs << 'lib' << 'test'
57
+ test.pattern = 'test/**/test_*.rb'
58
+ test.verbose = true
59
+ end
60
+
61
+ begin
62
+ require 'rcov/rcovtask'
63
+ Rcov::RcovTask.new do |test|
64
+ test.libs << 'test'
65
+ test.pattern = 'test/**/test_*.rb'
66
+ test.verbose = true
67
+ end
68
+ rescue LoadError
69
+ task :rcov do
70
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
71
+ end
72
+ end
73
+
74
+ task :test => :check_dependencies
75
+
76
+ task :default => :test
77
+
78
+ require 'rake/rdoctask'
79
+ Rake::RDocTask.new do |rdoc|
80
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
81
+
82
+ rdoc.rdoc_dir = 'rdoc'
83
+ rdoc.title = "ragweed #{version}"
84
+ rdoc.rdoc_files.include('README*')
85
+ rdoc.rdoc_files.include('lib/**/*.rb')
86
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ragweed'
4
+
5
+ filename = ARGV[0]
6
+ pid = ARGV[1].to_i
7
+
8
+ raise "hittracertux.rb FILE PID" if (ARGV.size < 2 or pid <= 0)
9
+
10
+ opts = {}
11
+ d = Ragweed::Debuggertux.new(pid, opts)
12
+ d.attach
13
+
14
+ File.open(filename, "r") do |fd|
15
+ lines = fd.readlines
16
+ lines.map {|x| x.chomp}
17
+ lines.each do |tl|
18
+ fn, addr = tl.split(",", 2)
19
+ d.breakpoint_set(addr.to_i(16), fn, (bpl = lambda do puts "hit - #{fn} #{addr}\n"; end))
20
+ end
21
+ end
22
+
23
+ d.install_bps
24
+ d.continue
25
+ catch(:throw) { d.loop }
26
+
27
+ # An IDC script for generating the text file this hit tracer requires
28
+ =begin
29
+ #include <idc.idc>
30
+
31
+ static main()
32
+ {
33
+ auto entry, fname, outf, fd;
34
+ outf = AskFile(1, "*.txt", "Please select an output file");
35
+ fd = fopen(outf,"w");
36
+
37
+ for(entry=NextFunction(0); entry != BADADDR; entry=NextFunction(entry) )
38
+ {
39
+ fname = GetFunctionName(entry);
40
+ fprintf(fd, "%s,0x%x\n", fname, entry);
41
+ }
42
+
43
+ fclose(fd);
44
+ }
45
+ =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 = Debugger32.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
@@ -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,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ## Simple example of attaching to a process and letting it run
4
+
5
+ require 'ragweed'
6
+
7
+ pid = Ragweed::Debuggertux.find_by_regex(/gcalctool/)
8
+
9
+ begin
10
+ t = Ragweed::Debuggertux.threads(pid)
11
+ puts "Available pid/tdpids\n"
12
+ t.each do |h| puts h end
13
+ puts "Which thread do you want to attach to?"
14
+ pid = STDIN.gets.chomp.to_i
15
+
16
+ opts = {}
17
+ opts[:fork] = true ## This flag tells ragweed to trace any forked child processes
18
+ d = Ragweed::Debuggertux.new(pid, opts)
19
+ d.attach
20
+ d.continue
21
+ catch(:throw) { d.loop }
22
+ rescue
23
+ puts "Maybe your PID is wrong?"
24
+ 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 Ragweed::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 = Ragweed::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 = Ragweed::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