iZsh-ragweed 0.1.8

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 (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