ragweed 0.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,59 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/rasm/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Rasm
6
+
7
+ # :stopdoc:
8
+ VERSION = File.read(File.join(File.dirname(__FILE__),"..","..","VERSION")).strip
9
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
10
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
11
+ # :startdoc:
12
+
13
+ # Returns the version string for the library.
14
+ #
15
+ def self.version
16
+ VERSION
17
+ end
18
+
19
+ # Returns the library path for the module. If any arguments are given,
20
+ # they will be joined to the end of the libray path using
21
+ # <tt>File.join</tt>.
22
+ #
23
+ def self.libpath( *args )
24
+ args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ end
34
+
35
+ # Utility function to load utility classes and extensions
36
+ def self.require_utils
37
+ %w{utils sbuf}.each{|r| require self.libpath(r)+'.rb'}
38
+ end
39
+
40
+ # Utility method used to require all files ending in .rb that lie in the
41
+ # directory below this file that has the same name as the filename passed
42
+ # in. Optionally, a specific _directory_ name can be passed in such that
43
+ # the _filename_ does not have to be equivalent to the directory.
44
+ #
45
+ def self.require_all_libs_relative_to( fname, dir = nil )
46
+ self.require_utils
47
+ dir ||= ::File.basename(fname, '.*')
48
+ search_me = ::File.expand_path(
49
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
50
+
51
+ Dir.glob(search_me).sort.each {|rb| require rb}
52
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
53
+
54
+ end
55
+ end # module Ragweed::Rasm
56
+
57
+ Ragweed::Rasm.require_all_libs_relative_to(__FILE__)
58
+
59
+ # EOF
@@ -0,0 +1,197 @@
1
+ # Stolen (mostly) from Net::SSH
2
+
3
+ # a* string a10 string 10 bytes A* string trimmed
4
+ # C uchar
5
+ # L native u32, l signed
6
+ # N BE u32, n 16
7
+ # Qq quad
8
+ # Ss native u16
9
+ # Vv LE u32
10
+
11
+ # Encapsulate a buffer of data with structured data accessors
12
+ class Ragweed::Sbuf
13
+ attr_reader :content
14
+ attr_accessor :position
15
+
16
+ def self.from(*args)
17
+ raise ArgumentError, "odd argument count" if args.length.odd?
18
+
19
+ b = self.new
20
+ while not args.empty?
21
+ t = args.shift; v = args.shift
22
+ if t == :raw
23
+ b.straw(v)
24
+ elsif v.kind_of? Array
25
+ b.st t, *v
26
+ else
27
+ b.st t, v
28
+ end
29
+ end
30
+
31
+ return b
32
+ end
33
+
34
+ def st(t, *args)
35
+ send "st#{ t }", *args
36
+ end
37
+
38
+ def straw(*args)
39
+ args.each do |raw|
40
+ @content << raw.to_s
41
+ end
42
+ self
43
+ end
44
+
45
+ def initialize(opts={})
46
+ @content = opts[:content] || ""
47
+ @position = 0
48
+ end
49
+
50
+ def consume!(n=position)
51
+ if(n >= length); clear!
52
+ elsif n > 0
53
+ @content = remainder(n)
54
+ @position -= n
55
+ @position = 0 if @position < 0
56
+ end
57
+ self
58
+ end
59
+
60
+ def ldraw(n=length)
61
+ n = ((self.length) - position) if(position + n > length)
62
+ @position += n
63
+ @content[position-n, n]
64
+ end
65
+
66
+ def ld(t, *args)
67
+ return ldraw(t) if t.kind_of? Numeric
68
+
69
+ begin
70
+ send "ld#{ t }", *args
71
+ rescue => e
72
+ case t.to_s
73
+ when /^strz(\d+)?/
74
+ n = $1.to_i if not $1.empty?
75
+ n ||= 0
76
+ ldsz(n)
77
+ when /^strs(\d+)?/
78
+ n = $1.to_i if not $1.empty?
79
+ n ||= 0
80
+ ldss(n)
81
+ else
82
+ raise e
83
+ end
84
+ end
85
+ end
86
+
87
+ def sz(t, *args); self.class.sz(t, *args); end
88
+ def self.sz(t, *args)
89
+ begin
90
+ send "sz#{ t }", *args
91
+ rescue => e
92
+ case t.to_s
93
+ when /^strz(\d+)/
94
+ $1.to_i
95
+ when /^strs(\d+)/
96
+ $1.to_i
97
+ when /^str.*/
98
+ raise Exception, "can't take size of unbounded string"
99
+ else
100
+ raise e
101
+ end
102
+ end
103
+ end
104
+
105
+ def shraw(n=length)
106
+ ret = ldraw(n)
107
+ consume!
108
+ return ret
109
+ end
110
+
111
+ def sh(t, *args)
112
+ return shraw(t) if t.kind_of? Numeric
113
+ ret = send "ld#{ t }", *args
114
+ consume!
115
+ return ret
116
+ end
117
+
118
+ def ldsz(n=0)
119
+ n = @content.size - @position if n == 0
120
+ ld(n).unpack("a#{ n }").first
121
+ end
122
+
123
+ def ldss(n=0)
124
+ n = @content.size - @position if n == 0
125
+ ld(n).unpack("A#{ n }").first
126
+ end
127
+
128
+ def length; @content.length; end
129
+ def size; @content.size; end
130
+ def empty?; @content.empty?; end
131
+
132
+ def available; length - position; end
133
+ alias_method :remaining, :available
134
+
135
+ def to_s; @content.dup; end
136
+ def ==(b); to_s == b.to_s; end
137
+ def reset; @position = 0; end
138
+ def eof?; @position >= length; end
139
+ def clear!; @content = "" and reset; end
140
+ def remainder(n = position); @content[n..-1] || ""; end
141
+ def remainder_as_buffer(t=Ragweed::Sbuf); t.new(:content => remainder); end
142
+
143
+ def self.szl64; 8; end
144
+ def self.szb64; 8; end
145
+ def self.szn64; 8; end
146
+
147
+ def ldl64; ld(8).unpack("Q").first; end
148
+ def ldb64; ld(8).reverse.unpack("Q").first; end
149
+ alias_method :ldn64, :ldb64
150
+
151
+ def stl64(v); straw([v].pack("Q")); end
152
+ def stb64(v); straw([v].pack("Q").reverse); end
153
+ alias_method :stn64, :stb64
154
+
155
+ def self.szl32; 4; end
156
+ def self.szb32; 4; end
157
+ def self.szn32; 4; end
158
+
159
+ def ldl32; ld(4).unpack("L").first; end
160
+ def ldb32; ld(4).unpack("N").first; end
161
+ alias_method :ldn32, :ldb32
162
+
163
+ def stl32(v); straw([v].pack("L")); end
164
+ def stb32(v); straw([v].pack("N")); end
165
+ alias_method :stn32, :stb32
166
+
167
+ def self.szl16; 2; end
168
+ def self.szb16; 2; end
169
+ def self.szn16; 2; end
170
+
171
+ def ldl16; ld(2).unpack("v").first; end
172
+ def ldb16; ld(2).unpack("n").first; end
173
+ alias_method :ldn16, :ldb16
174
+
175
+ def stl16(v); straw([v].pack("v")); end
176
+ def stb16(v); straw([v].pack("n")); end
177
+ alias_method :stn16, :stb16
178
+
179
+ def self.szl8; 1; end;
180
+ def self.szb8; 1; end;
181
+ def self.szn8; 1; end;
182
+
183
+ def ldl8; ld(1)[0]; end
184
+ def ldb8; ldl8; end
185
+ alias_method :ldn8, :ldb8
186
+
187
+ def stl8(v)
188
+ if v.kind_of? String
189
+ straw(v[0].chr)
190
+ else
191
+ straw([v].pack("c"))
192
+ end
193
+ end
194
+
195
+ def stb8(v); stl8(v); end
196
+ alias_method :stn8, :stb8
197
+ end
@@ -0,0 +1,103 @@
1
+ class Ragweed::Trampoline
2
+
3
+ # Normally called through WinProcess#remote_call, but, for
4
+ # what it's worth: needs a WinProcess instance and a location,
5
+ # which can be a string module!function or a pointer.
6
+ def initialize(p, loc, opts={})
7
+ @p = p
8
+ @loc = @p.get_proc loc
9
+ @argc = opts[:argc]
10
+ @a = @p.arena
11
+ @mem = @a.alloc(1024)
12
+ @arg_mem = @mem + 512
13
+ @wait = opts[:wait] || true
14
+ @chicken = opts[:chicken]
15
+ @opts = opts
16
+ end
17
+
18
+ # Call the remote function. Returns the 32 bit EAX return value provided
19
+ # by stdcall.
20
+ def call(*args)
21
+ raise "Insufficient Arguments" if @argc and @argc != args.size
22
+
23
+ @shim = Ragweed::Blocks::remote_trampoline(args.size, @opts)
24
+
25
+ # Won't leak memory.
26
+ @p.arena do |a|
27
+ # 1024 is a SWAG. Divide it in half, one for the trampoline
28
+ # (which is unrolled, because I am lazy and dumb) and the other
29
+ # for the call stack.
30
+ base = @p.ptr(a.alloc(1024))
31
+
32
+ argm = base + 512
33
+ cur = argm
34
+
35
+ # Write the location for the tramp to call
36
+ cur.write(@loc)
37
+ cur += 4
38
+
39
+ # Write the function arguments into the call stack.
40
+ (0...args.size).each_backwards do |i|
41
+ if args[i].kind_of? Integer
42
+ val = args[i].to_l32
43
+ elsif args[i].kind_of? String
44
+ stash = a.copy(args[i])
45
+ val = stash.to_l32
46
+ else
47
+ val = args[i].to_s
48
+ end
49
+ cur.write(val)
50
+ cur += 4
51
+ end if args.size.nonzero?
52
+
53
+ # Write a placeholder for the return value
54
+ cur.write(0xDEADBEEF.to_l32)
55
+
56
+ # Write the tramp
57
+ s = @shim.assemble
58
+ base.write(s)
59
+
60
+ th = Ragweed::Wrap32::create_remote_thread(@p.handle, base, argm)
61
+ Ragweed::Wrap32::wait_for_single_object(th) if @wait
62
+ Ragweed::Wrap32::close_handle(th)
63
+ ret = @p.read32(cur)
64
+ if ret == 0xDEADBEEF
65
+ ret = nil
66
+ end
67
+ ret
68
+ end
69
+ end
70
+ end
71
+
72
+ class Trevil
73
+ def initialize(p)
74
+ @p = p
75
+ @ev1, @ev2 = [WinEvent.new, WinEvent.new]
76
+ @a = @p.arena
77
+ end
78
+
79
+ def clear!
80
+ @a.release
81
+ end
82
+
83
+ def go
84
+ mem = @a.alloc(1024)
85
+ base = @p.ptr(mem)
86
+ data = base + 512
87
+ swch = ["OpenProcess",
88
+ "DuplicateHandle",
89
+ "ResetEvent",
90
+ "SetEvent",
91
+ "WaitForSingleObject"].
92
+ map {|x| @p.get_proc("kernel32!#{x}").to_i}.
93
+ pack("LLLLL")
94
+ state = [Ragweed::Wrap32::get_current_process_id, @ev1.handle, @ev2.handle].
95
+ pack("LLL")
96
+
97
+ data.write(swch + state)
98
+ base.write(event_pair_stub(:debug => false).assemble)
99
+ Ragweed::Wrap32::create_remote_thread(@p.handle, base, data)
100
+ @ev1.wait
101
+ @ev2
102
+ end
103
+ end
@@ -0,0 +1,182 @@
1
+ require 'iconv'
2
+
3
+ #do not rely on this extension to range. it'll be removed at some point.
4
+ class Range
5
+ module RangeExtensions
6
+ def each_backwards
7
+ max.to_i.downto(min) {|i| yield i}
8
+ end
9
+ end
10
+ include RangeExtensions
11
+ end
12
+
13
+ class Array
14
+ module ArrayExtensions
15
+ # Convert to hash
16
+ ##
17
+ def to_hash
18
+ # too clever.
19
+ # Hash[*self.flatten]
20
+
21
+ h = Hash.new
22
+ each do |k,v|
23
+ h[k] = v
24
+ end
25
+ h
26
+ end
27
+ end
28
+ include ArrayExtensions
29
+ end
30
+
31
+ # These should probably be extensions to Module since that's the location of instance_eval and friends.
32
+ class Object
33
+ module ObjectExtensions
34
+ # Every object has a "singleton" class, which you can think
35
+ # of as the class (ie, 1.metaclass =~ Fixnum) --- but that you
36
+ # can modify and extend without fucking up the actual class.
37
+ def metaclass; class << self; self; end; end
38
+ def meta_eval(&blk) metaclass.instance_eval &blk; end
39
+ def meta_def(name, &blk) meta_eval { define_method name, &blk }; end
40
+ def try(meth, *args); send(meth, *args) if respond_to? meth; end
41
+
42
+ def through(meth, *args)
43
+ if respond_to? meth
44
+ send(meth, *args)
45
+ else
46
+ self
47
+ end
48
+ end
49
+
50
+ ## This is from Topher Cyll's Stupd IRB tricks
51
+ def mymethods
52
+ (self.methods - self.class.superclass.methods).sort
53
+ end
54
+ # self-evident
55
+ def callable?; respond_to? :call; end
56
+ def number?; kind_of? Numeric; end
57
+
58
+ # while X remains callable, keep calling it to get its value
59
+ def derive
60
+ # also, don't drink and derive
61
+ x = self
62
+ while x.callable?
63
+ x = x()
64
+ end
65
+ return x
66
+ end
67
+ end
68
+ include ObjectExtensions
69
+ end
70
+
71
+ class String
72
+ def to_l32; unpack("L").first; end
73
+ def to_b32; unpack("N").first; end
74
+ def to_l16; unpack("v").first; end
75
+ def to_b16; unpack("n").first; end
76
+ def to_u8; self[0]; end
77
+ def shift_l32; shift(4).to_l32; end
78
+ def shift_b32; shift(4).to_b32; end
79
+ def shift_l16; shift(2).to_l16; end
80
+ def shift_b16; shift(2).to_b16; end
81
+ def shift_u8; shift(1).to_u8; end
82
+ def to_utf16
83
+ Iconv.iconv("utf-16LE", "utf-8", self).first + "\x00\x00"
84
+ end
85
+ def from_utf16
86
+ ret = Iconv.iconv("utf-8", "utf-16le", self).first
87
+ if ret[-1] == 0
88
+ ret = ret[0..-2]
89
+ end
90
+ end
91
+ alias_method :to_utf8, :from_utf16
92
+ alias_method :to_ascii, :from_utf16
93
+ def from_utf16_buffer
94
+ self[0..index("\0\0\0")+2].from_utf16
95
+ end
96
+
97
+ def shift(count=1)
98
+ return self if count == 0
99
+ slice! 0..(count-1)
100
+ end
101
+
102
+ # Sometimes string buffers passed through Win32 interfaces come with
103
+ # garbage after the trailing NUL; this method gets rid of that, like
104
+ # String#trim
105
+ def asciiz
106
+ begin
107
+ self[0..self.index("\x00")-1]
108
+ rescue
109
+ self
110
+ end
111
+ end
112
+
113
+ def asciiz!; replace asciiz; end
114
+
115
+ # Convert a string into hex characters
116
+ def hexify
117
+ self.unpack("H*").first
118
+ end
119
+
120
+ # Convert a string of raw hex characters (no %'s or anything) into binary
121
+ def dehexify
122
+ [self].pack("H*")
123
+ end
124
+ end
125
+
126
+ class Integer
127
+ module IntegerExtensions
128
+ # Convert integers to binary strings
129
+ def to_l32; [self].pack "L"; end
130
+ def to_b32; [self].pack "N"; end
131
+ def to_l16; [self].pack "v"; end
132
+ def to_b16; [self].pack "n"; end
133
+ def to_u8; [self].pack "C"; end
134
+
135
+ # sign extend
136
+ def sx8; ([self].pack "c").unpack("C").first; end
137
+ def sx16; ([self].pack "s").unpack("S").first; end
138
+ def sx32; ([self].pack "l").unpack("L").first; end
139
+
140
+ def ffs
141
+ i = 0
142
+ v = self
143
+ while((v >>= 1) != 0)
144
+ i += 1
145
+ end
146
+ return i
147
+ end
148
+ end
149
+ include IntegerExtensions
150
+ end
151
+
152
+ class Module
153
+ def to_name_hash
154
+ @name_hash ||= constants.map {|k| [k.intern, const_get(k.intern)]}.to_hash
155
+ end
156
+
157
+ def to_key_hash
158
+ @key_hash ||= constants.map {|k| [const_get(k.intern), k.intern]}.to_hash
159
+ end
160
+
161
+ def flag_dump(i)
162
+ @bit_map ||= constants.map do |k|
163
+ [k, const_get(k.intern).ffs]
164
+ end.sort {|x, y| x[1] <=> y[1]}
165
+
166
+ last = 0
167
+ r = ""
168
+ @bit_map.each do |tup|
169
+ if((v = (tup[1] - last)) > 1)
170
+ r << ("." * (v-1))
171
+ end
172
+
173
+ if((i & (1 << tup[1])) != 0)
174
+ r << tup[0][0].chr
175
+ else
176
+ r << tup[0][0].chr.downcase
177
+ end
178
+ last = tup[1]
179
+ end
180
+ return r.reverse
181
+ end
182
+ end