ragweed 0.1.7.2
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.
- 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
@@ -0,0 +1,59 @@
|
|
1
|
+
module Ragweed::Wrap32
|
2
|
+
module TokenAccess
|
3
|
+
ADJUST_DEFAULT = 128
|
4
|
+
ADJUST_GROUPS = 64
|
5
|
+
ADJUST_PRIVILEGES = 32
|
6
|
+
ALL_ACCESS = 0xf00ff
|
7
|
+
ASSIGN_PRIMARY = 1
|
8
|
+
DUPLICATE = 2
|
9
|
+
EXECUTE = 0x20000
|
10
|
+
IMPERSONATE = 4
|
11
|
+
QUERY = 8
|
12
|
+
QUERY_SOURCE = 16
|
13
|
+
READ = 0x20008
|
14
|
+
WRITE = 0x200e0
|
15
|
+
end
|
16
|
+
|
17
|
+
module PrivilegeAttribute
|
18
|
+
ENABLED = 0x2
|
19
|
+
ENABLED_BY_DEFAULT = 0x1
|
20
|
+
USED_FOR_ACCESS = 0x80000000
|
21
|
+
end
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def open_process_token(h, access=Ragweed::Wrap32::TokenAccess::ADJUST_PRIVILEGES)
|
25
|
+
outw = "\x00" * 4
|
26
|
+
r = CALLS["advapi32!OpenProcessToken:LLP=L"].call(h, access, outw)
|
27
|
+
raise WinX.new(:open_process_token) if r == 0
|
28
|
+
return outw.unpack("L").first
|
29
|
+
end
|
30
|
+
|
31
|
+
def adjust_token_privileges(t, disable, *args)
|
32
|
+
buf = [args.size].pack("L") + (args.map {|tup| tup.pack("QL") }.join(""))
|
33
|
+
|
34
|
+
r = CALLS["advapi32!AdjustTokenPrivileges:LLPLPP=L"].
|
35
|
+
call(t, disable, buf, buf.size, NULL, NULL)
|
36
|
+
|
37
|
+
raise WinX.new(:adjust_token_privileges) if r == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def lookup_privilege_value(name)
|
41
|
+
outw = "\x00" * 8
|
42
|
+
r = CALLS["advapi32!LookupPrivilegeValueA:PPP=L"].call(NULL, name, outw)
|
43
|
+
raise WinX.new(:lookup_privilege_value) if r == 0
|
44
|
+
return outw.unpack("Q").first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Ragweed::Wrap32::ProcessToken
|
50
|
+
def initialize(p=nil)
|
51
|
+
p ||= Ragweed::Wrap32::open_process(Ragweed::Wrap32::get_current_process_id)
|
52
|
+
@h = Ragweed::Wrap32::open_process_token(p)
|
53
|
+
end
|
54
|
+
|
55
|
+
def grant(name)
|
56
|
+
luid = Ragweed::Wrap32::lookup_privilege_value(name)
|
57
|
+
Ragweed::Wrap32::adjust_token_privileges(@h, 0, [luid, Ragweed::Wrap32::PrivilegeAttribute::ENABLED])
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
module Ragweed::Wrap32
|
2
|
+
module EFlags
|
3
|
+
CARRY = (1<< 0)
|
4
|
+
X0 = (1<< 1)
|
5
|
+
PARITY = (1<< 2)
|
6
|
+
X1 = (1<< 3)
|
7
|
+
ADJUST = (1<< 4)
|
8
|
+
X2 = (1<< 5)
|
9
|
+
ZERO = (1<< 6)
|
10
|
+
SIGN = (1<< 7)
|
11
|
+
TRAP = (1<< 8)
|
12
|
+
INTERRUPT = (1<< 9)
|
13
|
+
DIRECTION = (1<< 10)
|
14
|
+
OVERFLOW = (1<< 11)
|
15
|
+
IOPL1 = (1<< 12)
|
16
|
+
IOPL2 = (1<< 13)
|
17
|
+
NESTEDTASK = (1<< 14)
|
18
|
+
X3 = (1<< 15)
|
19
|
+
RESUME = (1<< 16)
|
20
|
+
V86MODE = (1<< 17)
|
21
|
+
ALIGNCHECK = (1<< 18)
|
22
|
+
VINT = (1<< 19)
|
23
|
+
VINTPENDING = (1<< 20)
|
24
|
+
CPUID = (1<< 21)
|
25
|
+
end
|
26
|
+
|
27
|
+
module ContextFlags
|
28
|
+
I386 = 0x10000
|
29
|
+
CONTROL = 1
|
30
|
+
INTEGER = 2
|
31
|
+
SEGMENTS = 4
|
32
|
+
FLOATING_POINT = 8
|
33
|
+
DEBUG_REGISTERS = 0x10
|
34
|
+
|
35
|
+
FULL = (I386|CONTROL|INTEGER|SEGMENTS)
|
36
|
+
DEBUG = (FULL|DEBUG_REGISTERS)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Ragweed::Wrap32::ThreadContext
|
41
|
+
(FIELDS = [ [:context_flags, "L"],
|
42
|
+
[:dr0, "L"],
|
43
|
+
[:dr1, "L"],
|
44
|
+
[:dr2, "L"],
|
45
|
+
[:dr3, "L"],
|
46
|
+
[:dr6, "L"],
|
47
|
+
[:dr7, "L"],
|
48
|
+
[:floating_save, "a112"],
|
49
|
+
[:seg_gs, "L"],
|
50
|
+
[:seg_gs, "L"],
|
51
|
+
[:seg_es, "L"],
|
52
|
+
[:seg_ds, "L"],
|
53
|
+
[:edi, "L"],
|
54
|
+
[:esi, "L"],
|
55
|
+
[:ebx, "L"],
|
56
|
+
[:edx, "L"],
|
57
|
+
[:ecx, "L"],
|
58
|
+
[:eax, "L"],
|
59
|
+
[:ebp, "L"],
|
60
|
+
[:eip, "L"],
|
61
|
+
[:seg_cs, "L"],
|
62
|
+
[:eflags, "L"],
|
63
|
+
[:esp, "L"],
|
64
|
+
[:seg_ss, "L"],
|
65
|
+
[:spill, "a1024"]]).each {|x| attr_accessor x[0]}
|
66
|
+
|
67
|
+
def initialize(str=nil)
|
68
|
+
refresh(str) if str
|
69
|
+
end
|
70
|
+
|
71
|
+
def refresh(str)
|
72
|
+
if str
|
73
|
+
str.unpack(FIELDS.map {|x| x[1]}.join("")).each_with_index do |val, i|
|
74
|
+
instance_variable_set "@#{ FIELDS[i][0] }".intern, val
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def to_s
|
80
|
+
FIELDS.map {|f| send(f[0])}.pack(FIELDS.map {|x| x[1]}.join(""))
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.get(h)
|
84
|
+
self.new(Ragweed::Wrap32::get_thread_context_raw(h))
|
85
|
+
end
|
86
|
+
|
87
|
+
def get(h)
|
88
|
+
refresh(Ragweed::Wrap32::get_thread_context_raw(h))
|
89
|
+
end
|
90
|
+
|
91
|
+
def set(h)
|
92
|
+
Ragweed::Wrap32::set_thread_context_raw(h, self.to_s)
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect
|
96
|
+
body = lambda do
|
97
|
+
FIELDS.map do |f|
|
98
|
+
val = send(f[0])
|
99
|
+
"#{f[0]}=#{val.to_s(16) rescue val.to_s.hexify}"
|
100
|
+
end.join(", ")
|
101
|
+
end
|
102
|
+
"#<ThreadContext #{body.call}>"
|
103
|
+
end
|
104
|
+
|
105
|
+
def dump(&block)
|
106
|
+
maybe_hex = lambda {|a| begin; "\n" + (" " * 9) + block.call(a, 16).hexdump(true)[10..-2]; rescue; ""; end }
|
107
|
+
maybe_dis = lambda {|a| begin; "\n" + block.call(a, 16).distorm.map {|i| " " + i.mnem}.join("\n"); rescue; ""; end }
|
108
|
+
|
109
|
+
string =<<EOM
|
110
|
+
-----------------------------------------------------------------------
|
111
|
+
CONTEXT:
|
112
|
+
EIP: #{self.eip.to_s(16).rjust(8, "0")} #{maybe_dis.call(self.eip)}
|
113
|
+
|
114
|
+
EAX: #{self.eax.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.eax)}
|
115
|
+
EBX: #{self.ebx.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ebx)}
|
116
|
+
ECX: #{self.ecx.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ecx)}
|
117
|
+
EDX: #{self.edx.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.edx)}
|
118
|
+
EDI: #{self.edi.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.edi)}
|
119
|
+
ESI: #{self.esi.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.esi)}
|
120
|
+
EBP: #{self.ebp.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.ebp)}
|
121
|
+
ESP: #{self.esp.to_s(16).rjust(8, "0")} #{maybe_hex.call(self.esp)}
|
122
|
+
EFL: #{self.eflags.to_s(2).rjust(32, "0")} #{Ragweed::Wrap32::EFlags.flag_dump(self.eflags)}
|
123
|
+
EOM
|
124
|
+
end
|
125
|
+
|
126
|
+
def single_step(v=true)
|
127
|
+
if v
|
128
|
+
@eflags |= Ragweed::Wrap32::EFlags::TRAP
|
129
|
+
else
|
130
|
+
@eflags &= ~(Ragweed::Wrap32::EFlags::TRAP)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
module Ragweed::Wrap32
|
136
|
+
class << self
|
137
|
+
def get_thread_context_raw(h)
|
138
|
+
ctx = [Ragweed::Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
139
|
+
ret = CALLS["kernel32!GetThreadContext:LP=L"].call(h, ctx)
|
140
|
+
if ret != 0
|
141
|
+
return ctx
|
142
|
+
else
|
143
|
+
raise WinX.new(:get_thread_context)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def set_thread_context_raw(h, c)
|
148
|
+
buf = c.to_s
|
149
|
+
ret = CALLS["kernel32!SetThreadContext:LP=L"].call(h, buf)
|
150
|
+
raise WinX.new(:set_thread_context) if ret == 0
|
151
|
+
return ret
|
152
|
+
end
|
153
|
+
|
154
|
+
def str2context(str)
|
155
|
+
ret = OpenStruct.new
|
156
|
+
ret.ContextFlags,
|
157
|
+
ret.Dr0,
|
158
|
+
ret.Dr1,
|
159
|
+
ret.Dr2,
|
160
|
+
ret.Dr3,
|
161
|
+
ret.Dr6,
|
162
|
+
ret.Dr7,
|
163
|
+
ret.FloatControlWord,
|
164
|
+
ret.FloatStatusWord,
|
165
|
+
ret.FloatTagWord,
|
166
|
+
ret.FloatErrorOffset,
|
167
|
+
ret.FloatErrorSelector,
|
168
|
+
ret.FloatDataOffset,
|
169
|
+
ret.FloatDataSelector,
|
170
|
+
ret.FloatRegisterArea,
|
171
|
+
ret.FloatCr0NpxState,
|
172
|
+
ret.SegGs,
|
173
|
+
ret.SegFs,
|
174
|
+
ret.SegEs,
|
175
|
+
ret.SegDs,
|
176
|
+
ret.Edi,
|
177
|
+
ret.Esi,
|
178
|
+
ret.Ebx,
|
179
|
+
ret.Edx,
|
180
|
+
ret.Ecx,
|
181
|
+
ret.Eax,
|
182
|
+
ret.Ebp,
|
183
|
+
ret.Eip,
|
184
|
+
ret.SegCs,
|
185
|
+
ret.EFlags,
|
186
|
+
ret.Esp,
|
187
|
+
ret.SegSs,
|
188
|
+
ret.Spill = str.unpack("LLLLLLLLLLLLLLA80LLLLLLLLLLLLLLLLLA1024")
|
189
|
+
return ret
|
190
|
+
end
|
191
|
+
|
192
|
+
# Retrieve the running context of a thread given its handle, returning a
|
193
|
+
# struct that mostly contains register values. Note that this will suspend
|
194
|
+
# and then resume the thread. Useful (among many other things) to sample
|
195
|
+
# EIP values to see what the code is doing.
|
196
|
+
def get_thread_context(h)
|
197
|
+
ctx = [Ragweed::Wrap32::ContextFlags::DEBUG,0,0,0,0,0,0,"\x00"*112,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"\x00"*1024].pack("LLLLLLLa112LLLLLLLLLLLLLLLLa1024")
|
198
|
+
suspend_thread(h)
|
199
|
+
ret = CALLS["kernel32!GetThreadContext:LP=L"].call(h, ctx)
|
200
|
+
resume_thread(h)
|
201
|
+
if ret != 0
|
202
|
+
return str2context(ctx)
|
203
|
+
else
|
204
|
+
raise WinX.new(:get_thread_context)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%w[ostruct Win32API pp].each {|x| require x}
|
2
|
+
|
3
|
+
module Ragweed;end
|
4
|
+
module Ragweed::Wrap32
|
5
|
+
class WinX < StandardError
|
6
|
+
attr_reader :code
|
7
|
+
attr_reader :msg
|
8
|
+
attr_reader :call
|
9
|
+
def initialize(sym=nil)
|
10
|
+
@call = sym
|
11
|
+
@code = Ragweed::Wrap32::get_last_error()
|
12
|
+
@msg = "#{(@call ? @call.to_s + ": " : "")}(#{@code}) #{ Ragweed::Wrap32::format_message(@code) }"
|
13
|
+
super @msg
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|