iZsh-ragweed 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/History.txt +29 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +30 -0
  5. data/examples/hittracertux.rb +49 -0
  6. data/examples/hittracerx.rb +63 -0
  7. data/examples/hook_notepad.rb +9 -0
  8. data/examples/snicker.rb +183 -0
  9. data/examples/tux-example.rb +23 -0
  10. data/lib/ragweed.rb +84 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +338 -0
  14. data/lib/ragweed/debuggerosx.rb +419 -0
  15. data/lib/ragweed/debuggertux.rb +345 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm.rb +53 -0
  19. data/lib/ragweed/rasm/isa.rb +1046 -0
  20. data/lib/ragweed/rasm/util.rb +26 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +88 -0
  24. data/lib/ragweed/wrap32.rb +53 -0
  25. data/lib/ragweed/wrap32/debugging.rb +163 -0
  26. data/lib/ragweed/wrap32/device.rb +49 -0
  27. data/lib/ragweed/wrap32/event.rb +50 -0
  28. data/lib/ragweed/wrap32/hooks.rb +23 -0
  29. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  30. data/lib/ragweed/wrap32/process.rb +506 -0
  31. data/lib/ragweed/wrap32/process_token.rb +59 -0
  32. data/lib/ragweed/wrap32/thread_context.rb +208 -0
  33. data/lib/ragweed/wrap32/winx.rb +16 -0
  34. data/lib/ragweed/wrap32/wrap32.rb +526 -0
  35. data/lib/ragweed/wraposx.rb +53 -0
  36. data/lib/ragweed/wraposx/constants.rb +112 -0
  37. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  38. data/lib/ragweed/wraposx/region_info.rb +250 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +225 -0
  41. data/lib/ragweed/wraposx/wraposx.rb +376 -0
  42. data/lib/ragweed/wraptux.rb +53 -0
  43. data/lib/ragweed/wraptux/constants.rb +68 -0
  44. data/lib/ragweed/wraptux/threads.rb +7 -0
  45. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  46. data/spec/ragweed_spec.rb +7 -0
  47. data/spec/spec_helper.rb +16 -0
  48. data/tasks/ann.rake +80 -0
  49. data/tasks/bones.rake +20 -0
  50. data/tasks/gem.rake +201 -0
  51. data/tasks/git.rake +40 -0
  52. data/tasks/notes.rake +27 -0
  53. data/tasks/post_load.rake +34 -0
  54. data/tasks/rdoc.rake +51 -0
  55. data/tasks/rubyforge.rake +55 -0
  56. data/tasks/setup.rb +292 -0
  57. data/tasks/spec.rake +54 -0
  58. data/tasks/svn.rake +47 -0
  59. data/tasks/test.rake +40 -0
  60. data/tasks/zentest.rake +36 -0
  61. data/test/test_ragweed.rb +0 -0
  62. metadata +127 -0
@@ -0,0 +1,26 @@
1
+ # Cheating; monkeypatching Object is evil.
2
+ class Object
3
+ # self-evident
4
+ def callable?; respond_to? :call; end
5
+ def number?; kind_of? Numeric; end
6
+
7
+ # while X remains callable, keep calling it to get its value
8
+ def derive
9
+ x = self
10
+ while x.callable?
11
+ x = x()
12
+ end
13
+ return x
14
+ end
15
+ end
16
+
17
+ # class String
18
+ # # this is just horrible
19
+ # def distorm
20
+ # Frasm::DistormDecoder.new.decode(self)
21
+ # end
22
+ #
23
+ # def disasm
24
+ # distorm.each {|i| puts i.mnem}
25
+ # end
26
+ # end
@@ -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=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 = Wrap32::create_remote_thread(@p.handle, base, argm)
61
+ Wrap32::wait_for_single_object(th) if @wait
62
+ 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 = [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
+ Wrap32::create_remote_thread(@p.handle, base, data)
100
+ @ev1.wait
101
+ @ev2
102
+ end
103
+ end
@@ -0,0 +1,88 @@
1
+ # These should probably be extensions to Module since that's the location of instance_eval and friends.
2
+ class Object
3
+ module ObjectExtensions
4
+ # Every object has a "singleton" class, which you can think
5
+ # of as the class (ie, 1.metaclass =~ Fixnum) --- but that you
6
+ # can modify and extend without fucking up the actual class.
7
+ def metaclass; class << self; self; end; end
8
+ def meta_eval(&blk) metaclass.instance_eval &blk; end
9
+ def meta_def(name, &blk) meta_eval { define_method name, &blk }; end
10
+ def try(meth, *args); send(meth, *args) if respond_to? meth; end
11
+
12
+ def through(meth, *args)
13
+ if respond_to? meth
14
+ send(meth, *args)
15
+ else
16
+ self
17
+ end
18
+ end
19
+
20
+ ## This is from Topher Cyll's Stupd IRB tricks
21
+ def mymethods
22
+ (self.methods - self.class.superclass.methods).sort
23
+ end
24
+ end
25
+ include ObjectExtensions
26
+ end
27
+
28
+ class String
29
+ def to_l32; unpack("L").first; end
30
+ def to_b32; unpack("N").first; end
31
+ def to_l16; unpack("v").first; end
32
+ def to_b16; unpack("n").first; end
33
+ def to_u8; self[0]; end
34
+ def shift_l32; shift(4).to_l32; end
35
+ def shift_b32; shift(4).to_b32; end
36
+ def shift_l16; shift(2).to_l16; end
37
+ def shift_b16; shift(2).to_b16; end
38
+ def shift_u8; shift(1).to_u8; end
39
+
40
+ def shift(count=1)
41
+ return self if count == 0
42
+ slice! 0..(count-1)
43
+ end
44
+ end
45
+
46
+ class Integer
47
+ module IntegerExtensions
48
+ # Convert integers to binary strings
49
+ def to_l32; [self].pack "L"; end
50
+ def to_b32; [self].pack "N"; end
51
+ def to_l16; [self].pack "v"; end
52
+ def to_b16; [self].pack "n"; end
53
+ def to_u8; [self].pack "C"; end
54
+ def ffs
55
+ i = 0
56
+ v = self
57
+ while((v >>= 1) != 0)
58
+ i += 1
59
+ end
60
+ return i
61
+ end
62
+ end
63
+ include IntegerExtensions
64
+ end
65
+
66
+ class Module
67
+ def flag_dump(i)
68
+ @bit_map ||= constants.map do |k|
69
+ [k, const_get(k.intern).ffs]
70
+ end.sort {|x, y| x[1] <=> y[1]}
71
+
72
+ last = 0
73
+ r = ""
74
+ @bit_map.each do |tup|
75
+ if((v = (tup[1] - last)) > 1)
76
+ r << ("." * (v-1))
77
+ end
78
+
79
+ if((i & (1 << tup[1])) != 0)
80
+ r << tup[0][0].chr
81
+ else
82
+ r << tup[0][0].chr.downcase
83
+ end
84
+ last = tup[1]
85
+ end
86
+ return r.reverse
87
+ end
88
+ end
@@ -0,0 +1,53 @@
1
+ # Dir[File.expand_path("#{File.dirname(__FILE__)}/wrap32/*.rb")].each do |file|
2
+ # require file
3
+ # end
4
+ module Ragweed; end
5
+ module Ragweed::Wrap32
6
+
7
+ # :stopdoc:
8
+ VERSION = '0.1.6'
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 method used to require all files ending in .rb that lie in the
36
+ # directory below this file that has the same name as the filename passed
37
+ # in. Optionally, a specific _directory_ name can be passed in such that
38
+ # the _filename_ does not have to be equivalent to the directory.
39
+ #
40
+ def self.require_all_libs_relative_to( fname, dir = nil )
41
+ dir ||= ::File.basename(fname, '.*')
42
+ search_me = ::File.expand_path(
43
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
44
+
45
+ Dir.glob(search_me).sort.each {|rb| require rb}
46
+ # require File.dirname(File.basename(__FILE__)) + "/#{x}"
47
+
48
+ end
49
+ end # module Ragweed::Wrap32
50
+
51
+ Ragweed::Wrap32.require_all_libs_relative_to(__FILE__)
52
+
53
+ # EOF