tduehr-ragweed 0.1.5
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 +15 -0
- data/README.rdoc +35 -0
- data/README.txt +9 -0
- data/Rakefile +30 -0
- data/examples/hittracertux.rb +48 -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 +419 -0
- data/lib/ragweed/debuggertux.rb +347 -0
- data/lib/ragweed/detour.rb +223 -0
- data/lib/ragweed/ptr.rb +48 -0
- data/lib/ragweed/rasm/isa.rb +1046 -0
- data/lib/ragweed/rasm/util.rb +26 -0
- data/lib/ragweed/rasm.rb +53 -0
- data/lib/ragweed/sbuf.rb +197 -0
- data/lib/ragweed/trampoline.rb +103 -0
- data/lib/ragweed/utils.rb +87 -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 +53 -0
- data/lib/ragweed/wraposx/constants.rb +101 -0
- data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
- data/lib/ragweed/wraposx/region_info.rb +244 -0
- data/lib/ragweed/wraposx/thread_context.rb +203 -0
- data/lib/ragweed/wraposx/thread_info.rb +213 -0
- data/lib/ragweed/wraposx/wraposx.rb +376 -0
- data/lib/ragweed/wraposx.rb +53 -0
- data/lib/ragweed/wraptux/constants.rb +68 -0
- data/lib/ragweed/wraptux/threads.rb +3 -0
- data/lib/ragweed/wraptux/wraptux.rb +76 -0
- data/lib/ragweed/wraptux.rb +53 -0
- data/lib/ragweed.rb +84 -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 +127 -0
@@ -0,0 +1,1046 @@
|
|
1
|
+
## ------------------------------------------------------------------------
|
2
|
+
|
3
|
+
# Rasm: a half-assed X86 assembler.
|
4
|
+
#
|
5
|
+
# Rasm implements a small subset of the X86 instruction set, and only in
|
6
|
+
# simple encodings.
|
7
|
+
#
|
8
|
+
# However, Rasm implements enough X86 to do interesting things. I wrote it
|
9
|
+
# to inject trampoline functions and detours into remote processes. This
|
10
|
+
# is Ruby code; you'd never use it where performance matters. It's not
|
11
|
+
# enough to write a decent compiler, but it's enough to fuck up programs.
|
12
|
+
module Ragweed::Rasm
|
13
|
+
class NotImp < RuntimeError; end
|
14
|
+
class Insuff < RuntimeError; end
|
15
|
+
class BadArg < RuntimeError; end
|
16
|
+
class TooMan < RuntimeError; end
|
17
|
+
|
18
|
+
## ------------------------------------------------------------------------
|
19
|
+
|
20
|
+
def method_missing(meth, *args)
|
21
|
+
Rasm.const_get(meth).new *args
|
22
|
+
end
|
23
|
+
|
24
|
+
## ------------------------------------------------------------------------
|
25
|
+
|
26
|
+
# A register target encoding, including [EAX+10] disp/indir
|
27
|
+
class Register
|
28
|
+
attr_accessor :code
|
29
|
+
attr_accessor :disp
|
30
|
+
attr_accessor :indir
|
31
|
+
attr_accessor :byte
|
32
|
+
attr_accessor :index
|
33
|
+
attr_accessor :combined
|
34
|
+
attr_accessor :scale
|
35
|
+
|
36
|
+
EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI = [0,1,2,3,4,5,6,7]
|
37
|
+
|
38
|
+
def self.comb(rc1, rc2)
|
39
|
+
(rc1 << 8|rc2)
|
40
|
+
end
|
41
|
+
|
42
|
+
def reg1
|
43
|
+
if combined?
|
44
|
+
self.class.new((code>>8)&0xff)
|
45
|
+
else
|
46
|
+
self
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def reg2
|
51
|
+
self.class.new(code&0xFF)
|
52
|
+
end
|
53
|
+
|
54
|
+
def *(x)
|
55
|
+
if x.kind_of? Numeric
|
56
|
+
ret = clone
|
57
|
+
ret.scale = x
|
58
|
+
return ret
|
59
|
+
end
|
60
|
+
raise BadArg, "bad operand type for *"
|
61
|
+
end
|
62
|
+
|
63
|
+
def +(x)
|
64
|
+
if x.kind_of? Numeric
|
65
|
+
ret = clone
|
66
|
+
ret.disp = x
|
67
|
+
return ret
|
68
|
+
elsif x.kind_of? Register
|
69
|
+
ret = clone
|
70
|
+
ret.combined = true
|
71
|
+
ret.indir = 1
|
72
|
+
ret.scale = x.scale
|
73
|
+
ret.code = self.class.comb(ret.code, x.code)
|
74
|
+
return ret
|
75
|
+
end
|
76
|
+
|
77
|
+
raise BadArg, "bad operand type for +"
|
78
|
+
end
|
79
|
+
|
80
|
+
def -(x)
|
81
|
+
ret = clone
|
82
|
+
ret.disp = -x
|
83
|
+
return ret
|
84
|
+
end
|
85
|
+
|
86
|
+
def regopts(opts={})
|
87
|
+
if (v = opts[:disp])
|
88
|
+
@disp = v
|
89
|
+
end
|
90
|
+
|
91
|
+
if (v = opts[:indir])
|
92
|
+
@indir = v
|
93
|
+
end
|
94
|
+
|
95
|
+
if (v = opts[:byte])
|
96
|
+
@byte = v
|
97
|
+
end
|
98
|
+
|
99
|
+
if (v = opts[:index])
|
100
|
+
@index = v
|
101
|
+
end
|
102
|
+
|
103
|
+
return self
|
104
|
+
end
|
105
|
+
|
106
|
+
def scaled?; @scale and @scale > 0; end
|
107
|
+
def combined?; @combined; end
|
108
|
+
|
109
|
+
def self.eax(opts={}); Eax.clone.regopts opts; end
|
110
|
+
def self.ecx(opts={}); Ecx.clone.regopts opts; end
|
111
|
+
def self.edx(opts={}); Edx.clone.regopts opts; end
|
112
|
+
def self.ebx(opts={}); Ebx.clone.regopts opts; end
|
113
|
+
def self.esp(opts={}); Esp.clone.regopts opts; end
|
114
|
+
def self.ebp(opts={}); Ebp.clone.regopts opts; end
|
115
|
+
def self.esi(opts={}); Esi.clone.regopts opts; end
|
116
|
+
def self.edi(opts={}); Edi.clone.regopts opts; end
|
117
|
+
|
118
|
+
def initialize(code, opts={})
|
119
|
+
@combined = false
|
120
|
+
@code = code
|
121
|
+
@disp = opts[:disp]
|
122
|
+
@indir = opts[:indir]
|
123
|
+
@byte = opts[:byte]
|
124
|
+
@index = nil
|
125
|
+
@scale = nil
|
126
|
+
|
127
|
+
@indir = true if @disp
|
128
|
+
disp = 0 if (@indir and not @disp)
|
129
|
+
end
|
130
|
+
|
131
|
+
def displace(disp)
|
132
|
+
@disp = disp
|
133
|
+
@indir = true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
## ------------------------------------------------------------------------
|
138
|
+
|
139
|
+
# Clone these to get access to the GPRs.
|
140
|
+
# There's a very clean way to do this in Ruby, with like, module_eval
|
141
|
+
# or something, but... time's a wasting.
|
142
|
+
Eax = Register.new(Register::EAX)
|
143
|
+
Ecx = Register.new(Register::ECX)
|
144
|
+
Edx = Register.new(Register::EDX)
|
145
|
+
Ebx = Register.new(Register::EBX)
|
146
|
+
Esp = Register.new(Register::ESP)
|
147
|
+
Ebp = Register.new(Register::EBP)
|
148
|
+
Esi = Register.new(Register::ESI)
|
149
|
+
Edi = Register.new(Register::EDI)
|
150
|
+
def eax(opts={}); Register.eax opts; end
|
151
|
+
def ecx(opts={}); Register.ecx opts; end
|
152
|
+
def edx(opts={}); Register.edx opts; end
|
153
|
+
def ebx(opts={}); Register.ebx opts; end
|
154
|
+
def esp(opts={}); Register.esp opts; end
|
155
|
+
def ebp(opts={}); Register.ebp opts; end
|
156
|
+
def esi(opts={}); Register.esi opts; end
|
157
|
+
def edi(opts={}); Register.edi opts; end
|
158
|
+
module_function :eax
|
159
|
+
module_function :ecx
|
160
|
+
module_function :edx
|
161
|
+
module_function :ebx
|
162
|
+
module_function :esp
|
163
|
+
module_function :ebp
|
164
|
+
module_function :esi
|
165
|
+
module_function :edi
|
166
|
+
|
167
|
+
## ------------------------------------------------------------------------
|
168
|
+
|
169
|
+
# A code fragment. Push instructions into it. You can push Label
|
170
|
+
# objects to create jump targets.
|
171
|
+
class Subprogram < Array
|
172
|
+
|
173
|
+
# Patch code offsets into the instructions to replace abstract
|
174
|
+
# labels. Produces raw instruction stream.
|
175
|
+
def assemble
|
176
|
+
patches = {}
|
177
|
+
buf = Ragweed::Sbuf.new
|
178
|
+
|
179
|
+
each do |i|
|
180
|
+
if i.kind_of? Instruction
|
181
|
+
i.locate(buf.size)
|
182
|
+
buf.straw i.to_s
|
183
|
+
else
|
184
|
+
patches[i] = buf.size
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
select {|i| i.kind_of? Instruction}.each {|i| i.patch(patches)}
|
189
|
+
buf.clear!
|
190
|
+
select {|i| i.kind_of? Instruction}.each {|i|
|
191
|
+
buf.straw(i.to_s)
|
192
|
+
}
|
193
|
+
|
194
|
+
buf.content
|
195
|
+
end
|
196
|
+
|
197
|
+
# Produce an array of insns. This is pretty much broken, because
|
198
|
+
# it doesn't pre-patch the instructions.
|
199
|
+
def disassemble
|
200
|
+
select {|i| i.kind_of? Rasm::Intruction}.map {|i| i.decode}
|
201
|
+
end
|
202
|
+
|
203
|
+
def dump_disassembly
|
204
|
+
disassemble.each do |insn|
|
205
|
+
puts "#{ insn.off.to_x } #{ insn.mnem }"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
## ------------------------------------------------------------------------
|
211
|
+
|
212
|
+
# An immediate value. Basically just a Fixnum with a type wrapper.
|
213
|
+
class Immed
|
214
|
+
attr_reader :val
|
215
|
+
def initialize(i); @val = i; end
|
216
|
+
def method_missing(meth, *args); @val.send meth, *args; end
|
217
|
+
end
|
218
|
+
|
219
|
+
## ------------------------------------------------------------------------
|
220
|
+
|
221
|
+
# A label. Like an Immed with a default value and a different wrapper.
|
222
|
+
class Label < Immed
|
223
|
+
def initialize(i=rand(0x1FFFFFFF)); super i; end
|
224
|
+
end
|
225
|
+
|
226
|
+
## ------------------------------------------------------------------------
|
227
|
+
|
228
|
+
# An X86 instruction. For the most part, you do two things with an
|
229
|
+
# instruction in Rasm: create it, and call to_s to get its raw value.
|
230
|
+
class Instruction
|
231
|
+
attr_accessor :src
|
232
|
+
attr_accessor :dst
|
233
|
+
|
234
|
+
def self.i(*args); self.new *args; end
|
235
|
+
|
236
|
+
# Are the source/dest operands registers?
|
237
|
+
def src_reg?; @src and @src.kind_of? Register; end
|
238
|
+
def dst_reg?; @dst and @dst.kind_of? Register; end
|
239
|
+
|
240
|
+
# Are the source/dest operands immediates?
|
241
|
+
def src_imm?; @src and @src.kind_of? Immed; end
|
242
|
+
def dst_imm?; @dst and @dst.kind_of? Immed; end
|
243
|
+
|
244
|
+
# Are the source/dest operands labels?
|
245
|
+
def src_lab?; @src and @src.kind_of? Label; end
|
246
|
+
def dst_lab?; @dst and @dst.kind_of? Label; end
|
247
|
+
|
248
|
+
def coerce(v)
|
249
|
+
if v
|
250
|
+
v = v.derive
|
251
|
+
v = v.to_i if v.kind_of? Ptr
|
252
|
+
if v.kind_of? Array
|
253
|
+
v = v[0].clone
|
254
|
+
v.indir = true
|
255
|
+
end
|
256
|
+
v = Immed.new(v) if v.number?
|
257
|
+
end
|
258
|
+
v
|
259
|
+
end
|
260
|
+
|
261
|
+
def src=(v); @src = coerce(v); end
|
262
|
+
def dst=(v); @dst = coerce(v); end
|
263
|
+
|
264
|
+
# Never called directly (see subclasses below)
|
265
|
+
def initialize(x=nil, y=nil)
|
266
|
+
@buf = Ragweed::Sbuf.new
|
267
|
+
self.src = y
|
268
|
+
self.dst = x
|
269
|
+
@loc = nil
|
270
|
+
end
|
271
|
+
|
272
|
+
# Disassemble the instruction (mostly for testing)
|
273
|
+
def decode; Frasm::DistormDecoder.new.decode(self.to_s)[0]; end
|
274
|
+
|
275
|
+
# What Subprogram#assemble uses to patch instruction locations.
|
276
|
+
# Not user-servicable
|
277
|
+
def locate(loc); @loc = loc; end
|
278
|
+
# Not user-servicable
|
279
|
+
def patch(patches)
|
280
|
+
if @dst.kind_of? Label
|
281
|
+
raise(BadArg, "need to have location first") if not @loc
|
282
|
+
offset = patches[@dst.val] - @Loc
|
283
|
+
@dst = Immed.new offset
|
284
|
+
if offset < 0
|
285
|
+
offset -= self.to_s
|
286
|
+
@dst = Immed.new offset
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# Calculate ModR/M bits for the instruction; this is
|
292
|
+
# the source/destination operand encoding.
|
293
|
+
def modrm(op1, op2)
|
294
|
+
raise(BadArg, "two indirs") if op1.indir and op2.indir
|
295
|
+
|
296
|
+
if op1.indir or op2.indir
|
297
|
+
base = 0x80
|
298
|
+
(op1.indir) ? (o, alt = [op1,op2]) : (o,alt = [op2,op1])
|
299
|
+
if o.disp and (o.disp < 0x1000)
|
300
|
+
base = 0x40
|
301
|
+
end
|
302
|
+
if (not o.disp) or (o.disp == 0)
|
303
|
+
base = 0x0
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
if op1.indir
|
308
|
+
if op1.combined? or op1.scaled? or (op1.code == Register::EBP)
|
309
|
+
sib(op1, op2, base)
|
310
|
+
else
|
311
|
+
return base + (op2.code << 3) + op1.code
|
312
|
+
end
|
313
|
+
elsif op2.indir
|
314
|
+
if op2.combined? or op2.scaled? or (op2.code == Register::EBP)
|
315
|
+
sib(op2, op1, base)
|
316
|
+
else
|
317
|
+
return base + (op1.code << 3) + op2.code
|
318
|
+
end
|
319
|
+
else
|
320
|
+
return 0xc0 + (op2.code << 3) + op1.code
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def sib(indir, alt, base)
|
325
|
+
modpart = (base+4) + (alt.code << 3)
|
326
|
+
|
327
|
+
if indir.scaled?
|
328
|
+
case indir.scale
|
329
|
+
when 2
|
330
|
+
sbase = 0x40
|
331
|
+
when 4
|
332
|
+
sbase = 0x80
|
333
|
+
when 8
|
334
|
+
sbase = 0xc0
|
335
|
+
else
|
336
|
+
raise BadArg, "scale must be 2, 4, or 8"
|
337
|
+
end
|
338
|
+
else
|
339
|
+
sbase = 0
|
340
|
+
end
|
341
|
+
|
342
|
+
col = indir.reg1.code
|
343
|
+
|
344
|
+
if indir.combined?
|
345
|
+
row = indir.reg2.code
|
346
|
+
else
|
347
|
+
row = 4
|
348
|
+
end
|
349
|
+
|
350
|
+
pp [col,row,sbase]
|
351
|
+
|
352
|
+
sibpart = sbase + (row << 3) + (col)
|
353
|
+
|
354
|
+
return (modpart.chr) + (sibpart.chr)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Add material to the instruction. Not user-servicable.
|
358
|
+
def add(v, immed=false, half=false)
|
359
|
+
return(nil) if not v
|
360
|
+
|
361
|
+
if v.number?
|
362
|
+
if (v < 0x100) and (v > -128) and not immed
|
363
|
+
if v < 0
|
364
|
+
@buf.stl8(v.sx8)
|
365
|
+
else
|
366
|
+
@buf.stl8(v)
|
367
|
+
end
|
368
|
+
else
|
369
|
+
if not half
|
370
|
+
@buf.stl32(v.sx32)
|
371
|
+
else
|
372
|
+
@buf.stl16(v.sx16)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
else
|
376
|
+
@buf.straw v
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Never called directly (see subclasses).
|
381
|
+
def to_s; ret = @buf.content; @buf.clear!; ret; end
|
382
|
+
end
|
383
|
+
|
384
|
+
## ------------------------------------------------------------------------
|
385
|
+
|
386
|
+
# Jump to a relative offset (pos or neg), a register, or an address
|
387
|
+
# in memory. Can take Labels instead of values, let patch figure out
|
388
|
+
# the rest.
|
389
|
+
class Jmp < Instruction
|
390
|
+
# eb rel8
|
391
|
+
# e9 rel
|
392
|
+
# ff r/m
|
393
|
+
# no far yet
|
394
|
+
|
395
|
+
def initialize(x=nil); super x; end
|
396
|
+
|
397
|
+
def to_s
|
398
|
+
raise Insuff if not @dst
|
399
|
+
if dst_imm? or dst_lab?
|
400
|
+
if @dst.val < 0x100 and @dst.val > -127
|
401
|
+
add(0xeb)
|
402
|
+
add(@dst.val)
|
403
|
+
else
|
404
|
+
add(0xe9)
|
405
|
+
add(@dst.val)
|
406
|
+
end
|
407
|
+
else
|
408
|
+
add(0xff)
|
409
|
+
add(modrm(@dst, Esp.clone))
|
410
|
+
add(sx32(@dst.disp)) if @dst.disp
|
411
|
+
end
|
412
|
+
super
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
## ------------------------------------------------------------------------
|
417
|
+
|
418
|
+
# Pop into a register
|
419
|
+
class Pop < Instruction
|
420
|
+
# 8f m32
|
421
|
+
# 58+ # reg
|
422
|
+
|
423
|
+
def initialize(dst=nil); super dst; end
|
424
|
+
|
425
|
+
def to_s
|
426
|
+
raise Insuff if not @dst
|
427
|
+
raise(BadArg, "need register") if not dst_reg?
|
428
|
+
|
429
|
+
if @dst.indir
|
430
|
+
add(0x8f)
|
431
|
+
add(modrm(@dst, Eax.clone))
|
432
|
+
add(@dst.disp)
|
433
|
+
else
|
434
|
+
add(0x58 + @dst.code)
|
435
|
+
end
|
436
|
+
super
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
## ------------------------------------------------------------------------
|
441
|
+
|
442
|
+
# Push a register, register-addressed memory location, or immediate
|
443
|
+
# onto the stack.
|
444
|
+
class Push < Instruction
|
445
|
+
# ff r/m
|
446
|
+
# 50+ r
|
447
|
+
# 6a imm8
|
448
|
+
# 68 imm
|
449
|
+
|
450
|
+
def initialize( dst=nil); super dst; end
|
451
|
+
|
452
|
+
def to_s
|
453
|
+
raise Insuff if not @dst
|
454
|
+
|
455
|
+
if dst_reg?
|
456
|
+
if @dst.indir
|
457
|
+
add(0xff)
|
458
|
+
add(modrm(@dst, Esi.clone))
|
459
|
+
add(@dst.disp)
|
460
|
+
else
|
461
|
+
add(0x50 + @dst.code)
|
462
|
+
end
|
463
|
+
elsif dst_imm?
|
464
|
+
if @dst.val < 0x100
|
465
|
+
add(0x6a)
|
466
|
+
add(@dst.val)
|
467
|
+
else
|
468
|
+
add(0x68)
|
469
|
+
add(@dst.val)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
super
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
## ------------------------------------------------------------------------
|
477
|
+
|
478
|
+
# Call a register/memory location
|
479
|
+
class Call < Instruction
|
480
|
+
# e8 rel
|
481
|
+
# ff/2 r/m
|
482
|
+
# no far yet
|
483
|
+
|
484
|
+
def initialize( dst=nil); super dst; end
|
485
|
+
|
486
|
+
def to_s
|
487
|
+
raise Insuff if not @dst
|
488
|
+
|
489
|
+
if dst_reg?
|
490
|
+
add(0xff)
|
491
|
+
add(modrm(@dst, Edx.clone))
|
492
|
+
else
|
493
|
+
add(0xe8)
|
494
|
+
add(@dst.val, true)
|
495
|
+
end
|
496
|
+
super
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
## ------------------------------------------------------------------------
|
501
|
+
|
502
|
+
# Return; provide immediate for stack adjustment if you want.
|
503
|
+
class Ret < Instruction
|
504
|
+
# c3
|
505
|
+
# c2 imm16
|
506
|
+
|
507
|
+
def initialize( dst=nil); super dst; end
|
508
|
+
|
509
|
+
def to_s
|
510
|
+
if not @dst
|
511
|
+
add(0xc3)
|
512
|
+
elsif dst_imm?
|
513
|
+
add(0xc2)
|
514
|
+
add(@dst.val, true, true)
|
515
|
+
else
|
516
|
+
raise BadArg, "imm16 only"
|
517
|
+
end
|
518
|
+
super
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
class Retn < Ret; end
|
523
|
+
|
524
|
+
## ------------------------------------------------------------------------
|
525
|
+
|
526
|
+
# Wrapper class for arithmatic instructions. Never called directly;
|
527
|
+
# see below.
|
528
|
+
class Arith < Instruction
|
529
|
+
# 05 imm32 to eax
|
530
|
+
# 04 imm8 to al
|
531
|
+
# 80/0 r/m8, imm8
|
532
|
+
# 81/0 r/m, imm
|
533
|
+
# no sign extend yet
|
534
|
+
# 01 r/m, r
|
535
|
+
# 03 r, r/m
|
536
|
+
|
537
|
+
def initialize( dst=nil, src=nil); super dst, src; end
|
538
|
+
|
539
|
+
def to_s
|
540
|
+
if not @dst
|
541
|
+
# fucked up
|
542
|
+
if src_imm?
|
543
|
+
if @src.val < 0x100
|
544
|
+
add(@imp8)
|
545
|
+
add(@src.val)
|
546
|
+
else
|
547
|
+
add(@imp)
|
548
|
+
add(@src.val)
|
549
|
+
end
|
550
|
+
else
|
551
|
+
raise BadArg, "need immed for implicit eax"
|
552
|
+
end
|
553
|
+
else
|
554
|
+
if src_imm?
|
555
|
+
if @src.val < 0x100
|
556
|
+
add(@imm8)
|
557
|
+
add(modrm(@dst, @x))
|
558
|
+
add(@src.val)
|
559
|
+
else
|
560
|
+
add(@imm)
|
561
|
+
add(modrm(@dst, @x))
|
562
|
+
add(@src.val)
|
563
|
+
end
|
564
|
+
else
|
565
|
+
raise(BadArg, "need two r/m") if not src_reg? or not dst_reg?
|
566
|
+
raise(BadArg, "can't both be indir") if @src.indir and @dst.indir
|
567
|
+
if @src.indir
|
568
|
+
add(@rm)
|
569
|
+
add(modrm(@dst, @src))
|
570
|
+
else
|
571
|
+
add(@mr)
|
572
|
+
add(modrm(@dst, @src))
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
super
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
## ------------------------------------------------------------------------
|
581
|
+
|
582
|
+
# ADD
|
583
|
+
class Add < Arith
|
584
|
+
def initialize(*args)
|
585
|
+
super *args
|
586
|
+
@imp8, @imp, @imm8, @imm, @rm, @mr = [0x04, 0x05, 0x83, 0x81, 0x03, 0x01]
|
587
|
+
@x = Eax.clone
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
## ------------------------------------------------------------------------
|
592
|
+
|
593
|
+
# SUB
|
594
|
+
class Sub < Arith
|
595
|
+
def initialize(*args)
|
596
|
+
super *args
|
597
|
+
@imp8, @imp, @imm8, @imm, @rm, @mr = [0x2c, 0x2d, 0x83, 0x81, 0x2b, 0x29]
|
598
|
+
@x = Ebp.clone
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
## ------------------------------------------------------------------------
|
603
|
+
|
604
|
+
# XOR
|
605
|
+
class Xor < Arith
|
606
|
+
def initialize(*args)
|
607
|
+
super *args
|
608
|
+
@imp8, @imp, @imm8, @imm, @rm, @mr = [0x34, 0x35, 0x83, 0x81, 0x33, 0x31]
|
609
|
+
@x = Esi.clone
|
610
|
+
end
|
611
|
+
end
|
612
|
+
## ------------------------------------------------------------------------
|
613
|
+
|
614
|
+
# AND
|
615
|
+
class And < Arith
|
616
|
+
def initialize(*args)
|
617
|
+
super *args
|
618
|
+
@imp8, @imp, @imm8, @imm, @rm, @mr = [0x24, 0x25, 0x83, 0x81, 0x23, 0x21]
|
619
|
+
@x = Esp.clone
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
## ------------------------------------------------------------------------
|
624
|
+
|
625
|
+
# OR
|
626
|
+
class Or < Arith
|
627
|
+
def initialize(*args)
|
628
|
+
super *args
|
629
|
+
@imp8, @imp, @imm8, @imm, @rm, @mr = [0x0c, 0x0d, 0x83, 0x81, 0x0b, 0x09]
|
630
|
+
@x = Ecx.clone
|
631
|
+
end
|
632
|
+
end
|
633
|
+
|
634
|
+
## ------------------------------------------------------------------------
|
635
|
+
|
636
|
+
# Test is AND + condition code
|
637
|
+
class Test < Instruction
|
638
|
+
# a8 imm8
|
639
|
+
# a9 imm
|
640
|
+
# f7/0, r/m
|
641
|
+
# 85 r/m, r
|
642
|
+
|
643
|
+
def initialize( dst=nil, src=nil); super(dst,src); end
|
644
|
+
|
645
|
+
def to_s
|
646
|
+
if not @dst
|
647
|
+
raise(BadArg, "need imm for implied ax") if not src_imm?
|
648
|
+
if @src.val < 0x100
|
649
|
+
add(0xa8)
|
650
|
+
add(@src.val)
|
651
|
+
else
|
652
|
+
add(0xa9)
|
653
|
+
add(@src.val)
|
654
|
+
end
|
655
|
+
else
|
656
|
+
if src_imm?
|
657
|
+
add(0xf7)
|
658
|
+
add(modrm(@dst.val, Eax.clone))
|
659
|
+
add(@src.val)
|
660
|
+
else
|
661
|
+
add(0x85)
|
662
|
+
add(modrm(@dst.val, @src))
|
663
|
+
end
|
664
|
+
end
|
665
|
+
super
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
## ------------------------------------------------------------------------
|
670
|
+
|
671
|
+
# CMP is SUB + condition code
|
672
|
+
class Cmp < Instruction
|
673
|
+
# 3c imm8
|
674
|
+
# 3d imm
|
675
|
+
# 80/7 r/m8, imm8
|
676
|
+
# 81/7 r/m, imm
|
677
|
+
# 83/7 r/m, imm8
|
678
|
+
# 38 r/m8, r8
|
679
|
+
# 39 r/m, r
|
680
|
+
# 3a r8, r/m8
|
681
|
+
# 3b r, r/m
|
682
|
+
|
683
|
+
def initialize( dst=nil, src=nil); super dst, src; end
|
684
|
+
|
685
|
+
def to_s
|
686
|
+
if not @dst
|
687
|
+
raise(BadArg, "need immed for implicit ax") if not src_imm?
|
688
|
+
if @src.val < 0x100
|
689
|
+
add(0x3c)
|
690
|
+
add(@src.val)
|
691
|
+
else
|
692
|
+
add(0x3d)
|
693
|
+
add(@src.val)
|
694
|
+
end
|
695
|
+
else
|
696
|
+
raise(BadArg, "need reg dst") if not dst_reg?
|
697
|
+
if src_imm?
|
698
|
+
raise NotImp if @dst.byte
|
699
|
+
if @src.val < 0x100
|
700
|
+
add(0x83)
|
701
|
+
add(modrm(@dst, Edi.clone))
|
702
|
+
add(@src.val)
|
703
|
+
else
|
704
|
+
add(0x81)
|
705
|
+
add(modrm(@dst, Edi.clone))
|
706
|
+
add(@src.val)
|
707
|
+
end
|
708
|
+
else
|
709
|
+
if @dst.indir
|
710
|
+
add(0x39)
|
711
|
+
add(modrm(@src, @dst))
|
712
|
+
add(@dst.disp)
|
713
|
+
else
|
714
|
+
add(0x3b)
|
715
|
+
add(modrm(@src, @dst))
|
716
|
+
add(@dst.disp)
|
717
|
+
end
|
718
|
+
end
|
719
|
+
end
|
720
|
+
super
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
## ------------------------------------------------------------------------
|
725
|
+
|
726
|
+
# Wrapper for INC and DEC, not called directly.
|
727
|
+
class IncDec < Instruction
|
728
|
+
# fe/0 r/m8
|
729
|
+
# ff/0 r/m
|
730
|
+
# 40+ (reg)
|
731
|
+
|
732
|
+
def initialize( dst=nil); super dst; end
|
733
|
+
|
734
|
+
def to_s
|
735
|
+
raise Insuff if not @dst
|
736
|
+
raise(BadArg, "need a register") if not dst_reg?
|
737
|
+
|
738
|
+
if @dst.indir
|
739
|
+
add(0xff)
|
740
|
+
add(modrm(@dst, @var))
|
741
|
+
else
|
742
|
+
add(@bas + @dst.code)
|
743
|
+
end
|
744
|
+
super
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
748
|
+
## ------------------------------------------------------------------------
|
749
|
+
|
750
|
+
# INC memory or register
|
751
|
+
class Inc < IncDec
|
752
|
+
def initialize(*args)
|
753
|
+
super *args
|
754
|
+
@var = Eax.clone
|
755
|
+
@bas = 0x40
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
## ------------------------------------------------------------------------
|
760
|
+
|
761
|
+
# DEC memory or register
|
762
|
+
class Dec < IncDec
|
763
|
+
def initialize(*args)
|
764
|
+
super *args
|
765
|
+
@var = Ecx.clone
|
766
|
+
@bas = 0x48
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
770
|
+
## ------------------------------------------------------------------------
|
771
|
+
|
772
|
+
# MOV, from reg to mem or v/v, or imm to reg, v/v
|
773
|
+
class Mov < Instruction
|
774
|
+
# 89 r/m, r
|
775
|
+
# 8b r, r/m
|
776
|
+
# b8+ r, imm
|
777
|
+
# c7+ r/m, imm
|
778
|
+
def to_s
|
779
|
+
raise Insuff if not @src or not @dst
|
780
|
+
raise NotImp if (src_reg? and @src.index) or (dst_reg? and @dst.index)
|
781
|
+
|
782
|
+
if src_imm?
|
783
|
+
if @dst.indir
|
784
|
+
add(0xc7)
|
785
|
+
add(@dst.code)
|
786
|
+
add(@src.val)
|
787
|
+
else
|
788
|
+
add(0xb8 + @dst.code)
|
789
|
+
add(@src.val, true)
|
790
|
+
end
|
791
|
+
elsif dst_imm?
|
792
|
+
raise BadArg, "mov to immed"
|
793
|
+
else
|
794
|
+
raise(BadArg, "two r/m") if @src.indir and @dst.indir
|
795
|
+
if not @src.indir and not @dst.indir
|
796
|
+
add(0x89)
|
797
|
+
add(modrm(@dst, @src))
|
798
|
+
elsif @src.indir # ie, ld
|
799
|
+
add(0x8b)
|
800
|
+
add(modrm(@dst, @src))
|
801
|
+
add(@src.disp)
|
802
|
+
elsif @dst.indir # ie, st
|
803
|
+
add(0x89)
|
804
|
+
add(modrm(@dst, @src))
|
805
|
+
add(@dst.disp)
|
806
|
+
end
|
807
|
+
end
|
808
|
+
super
|
809
|
+
end
|
810
|
+
|
811
|
+
def initialize( x=nil, y=nil); super x, y; end
|
812
|
+
end
|
813
|
+
|
814
|
+
## ------------------------------------------------------------------------
|
815
|
+
|
816
|
+
# Wrapper for the shift operations below.
|
817
|
+
class Shift < Instruction
|
818
|
+
once = nil
|
819
|
+
bycl = nil
|
820
|
+
imm = nil
|
821
|
+
x = nil
|
822
|
+
|
823
|
+
def initialize( dst=nil, src=nil); super dst, src; end
|
824
|
+
|
825
|
+
def to_s
|
826
|
+
raise Insuff if not @dst
|
827
|
+
raise(BadArg, "need reg dst") if not dst_reg?
|
828
|
+
|
829
|
+
if not @src
|
830
|
+
add(@once)
|
831
|
+
add(modrm(@dst, @x))
|
832
|
+
else
|
833
|
+
if src_imm?
|
834
|
+
add(@imm)
|
835
|
+
add(modrm(@dst, @x))
|
836
|
+
add(@src.val)
|
837
|
+
else
|
838
|
+
add(@bycl)
|
839
|
+
add(modrm(@dst, @x))
|
840
|
+
end
|
841
|
+
end
|
842
|
+
super
|
843
|
+
end
|
844
|
+
|
845
|
+
def magic(x, y, z, r); @once, @bycl, @imm, @x = [x,y,z,r.clone]; end
|
846
|
+
end
|
847
|
+
|
848
|
+
# XXX looks wrong
|
849
|
+
|
850
|
+
# Left arith shift
|
851
|
+
class Sal < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Esp; end; end
|
852
|
+
|
853
|
+
# Right arith shift
|
854
|
+
class Sar < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Edi; end; end
|
855
|
+
|
856
|
+
# Left logic shift
|
857
|
+
class Shl < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Esp; end; end
|
858
|
+
|
859
|
+
# Right logic shift
|
860
|
+
class Shr < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Ebp; end; end
|
861
|
+
|
862
|
+
## ------------------------------------------------------------------------
|
863
|
+
|
864
|
+
# NOP
|
865
|
+
class Nop < Instruction
|
866
|
+
# 90
|
867
|
+
def initialize; super; end
|
868
|
+
|
869
|
+
def to_s
|
870
|
+
add(0x90)
|
871
|
+
super
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
## ------------------------------------------------------------------------
|
876
|
+
|
877
|
+
# NOT a register
|
878
|
+
class Not < Instruction
|
879
|
+
# f7/2 r/m
|
880
|
+
|
881
|
+
def initialize( dst=nil); super dst; end
|
882
|
+
|
883
|
+
def to_s
|
884
|
+
raise Insuff if not @dst
|
885
|
+
raise(BadArg, "need reg for not") if not dst_reg?
|
886
|
+
|
887
|
+
add(0xf7)
|
888
|
+
add(modrm(@dst, Edx.clone))
|
889
|
+
super
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
893
|
+
## ------------------------------------------------------------------------
|
894
|
+
|
895
|
+
# Load a memory address from a register into another register;
|
896
|
+
# uses memory notation, but is a pure arith insn
|
897
|
+
class Lea < Instruction
|
898
|
+
# 8d r, m
|
899
|
+
|
900
|
+
def initialize( dst=nil, src=nil); super dst, src; end
|
901
|
+
|
902
|
+
def to_s
|
903
|
+
raise Insuff if not @src or not @dst
|
904
|
+
raise(BadArg, "need reg src") if not src_reg?
|
905
|
+
raise(BadArg, "need indirected src") if not @src.indir
|
906
|
+
|
907
|
+
add(0x8d)
|
908
|
+
add(modrm(@dst, @src))
|
909
|
+
add(@src.disp)
|
910
|
+
super
|
911
|
+
end
|
912
|
+
end
|
913
|
+
|
914
|
+
## ------------------------------------------------------------------------
|
915
|
+
|
916
|
+
# Wrapper for conditional jumps, see below
|
917
|
+
class Jcc < Instruction
|
918
|
+
|
919
|
+
def m; [nil,nil]; end
|
920
|
+
def initialize( dst)
|
921
|
+
super dst
|
922
|
+
@short, @near = m()
|
923
|
+
end
|
924
|
+
|
925
|
+
def to_s
|
926
|
+
raise Insuff if not @dst
|
927
|
+
raise(BadArg, "need immed") if not dst_imm? and not dst_lab?
|
928
|
+
|
929
|
+
if @dst.val < 0
|
930
|
+
if @dst.val.abs & 0x80
|
931
|
+
add(0x0f)
|
932
|
+
add(@near)
|
933
|
+
add(@dst.sx32)
|
934
|
+
else
|
935
|
+
add(@short)
|
936
|
+
add(@dst.sx8)
|
937
|
+
end
|
938
|
+
else
|
939
|
+
if @dst.val < 0x100
|
940
|
+
add(@short)
|
941
|
+
add(@dst.val)
|
942
|
+
else
|
943
|
+
add(0x0f)
|
944
|
+
add(@near)
|
945
|
+
add(@dst.val, true)
|
946
|
+
end
|
947
|
+
end
|
948
|
+
super
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
# Somewhere in the SDM there's a table of what condition codes
|
953
|
+
# each of these check.
|
954
|
+
|
955
|
+
# Above
|
956
|
+
class Ja < Jcc; def m; [0x77, 0x87]; end; end
|
957
|
+
# Above/eq
|
958
|
+
class Jae <Jcc; def m; [0x73, 0x83]; end; end
|
959
|
+
# Below
|
960
|
+
class Jb < Jcc; def m; [0x72, 0x82]; end; end
|
961
|
+
# Below/eq
|
962
|
+
class Jbe < Jcc; def m; [0x76, 0x86]; end; end
|
963
|
+
# Carry
|
964
|
+
class Jc < Jcc; def m; [0x72, 0x82]; end; end
|
965
|
+
# Equal
|
966
|
+
class Je < Jcc; def m; [0x74, 0x84]; end; end
|
967
|
+
# Greater (SIGNED)
|
968
|
+
class Jg < Jcc; def m; [0x7f, 0x8f]; end; end
|
969
|
+
# Greater/eq (SIGNED)
|
970
|
+
class Jge < Jcc; def m; [0x7d, 0x8d]; end; end
|
971
|
+
# Less (SIGNED)
|
972
|
+
class Jl < Jcc; def m; [0x7c, 0x8c]; end; end
|
973
|
+
# Less/eq (SIGNED)
|
974
|
+
class Jle < Jcc; def m; [0x7e, 0x8e]; end; end
|
975
|
+
# Not above
|
976
|
+
class Jna < Jcc; def m; [0x76, 0x86]; end; end
|
977
|
+
# Not above/eq
|
978
|
+
class Jnae < Jcc; def m; [0x72, 0x82]; end; end
|
979
|
+
# Not below
|
980
|
+
class Jnb < Jcc; def m; [0x73, 0x83]; end; end
|
981
|
+
# Not below/eq
|
982
|
+
class Jnbe < Jcc; def m; [0x77, 0x87]; end; end
|
983
|
+
# Not carry
|
984
|
+
class Jnc < Jcc; def m; [0x73, 0x83]; end; end
|
985
|
+
# Not equal
|
986
|
+
class Jne < Jcc; def m; [0x75, 0x85]; end; end
|
987
|
+
# Not greater (SIGNED)
|
988
|
+
class Jng < Jcc; def m; [0x7e, 0x8e]; end; end
|
989
|
+
# Not greater/eq (SIGNED)
|
990
|
+
class Jnge < Jcc; def m; [0x7c, 0x8c]; end; end
|
991
|
+
# Not less (SIGNED)
|
992
|
+
class Jnl < Jcc; def m; [0x7d, 0x8d]; end; end
|
993
|
+
# Not less/eq (SIGNED)
|
994
|
+
class Jnle < Jcc; def m; [0x7f, 0x8f]; end; end
|
995
|
+
# Not overflow
|
996
|
+
class Jno < Jcc; def m; [0x71, 0x81]; end; end
|
997
|
+
# Not parity
|
998
|
+
class Jnp < Jcc; def m; [0x7b, 0x8b]; end; end
|
999
|
+
# Not sign
|
1000
|
+
class Jns < Jcc; def m; [0x79, 0x89]; end; end
|
1001
|
+
# Not zero
|
1002
|
+
class Jnz < Jcc; def m; [0x75, 0x85]; end; end
|
1003
|
+
# Overflow
|
1004
|
+
class Jo < Jcc; def m; [0x70, 0x80]; end; end
|
1005
|
+
# Parity
|
1006
|
+
class Jp < Jcc; def m; [0x7a, 0x8a]; end; end
|
1007
|
+
# Parity/eq
|
1008
|
+
class Jpe < Jcc; def m; [0x7a, 0x8a]; end; end
|
1009
|
+
# Parity/overflow
|
1010
|
+
class Jpo < Jcc; def m; [0x7b, 0x8b]; end; end
|
1011
|
+
# Signed
|
1012
|
+
class Js < Jcc; def m; [0x78, 0x88]; end; end
|
1013
|
+
# Zero
|
1014
|
+
class Jz < Jcc; def m; [0x74, 0x84]; end; end
|
1015
|
+
|
1016
|
+
## ------------------------------------------------------------------------
|
1017
|
+
|
1018
|
+
# INT 3, mostly, but will do INT X
|
1019
|
+
class Int < Instruction
|
1020
|
+
## cc int 3
|
1021
|
+
## cd imm int n
|
1022
|
+
## ce int 4 notimp
|
1023
|
+
|
1024
|
+
def initialize(dst=nil); super dst; end
|
1025
|
+
|
1026
|
+
def to_s
|
1027
|
+
raise(TooMan, "too many arguments for int") if @src
|
1028
|
+
raise(BadArg, "int takes immed") if @dst and not dst_imm?
|
1029
|
+
|
1030
|
+
if @dst
|
1031
|
+
raise(BadArg, "need 8 bit immed") if @dst.val >= 0x100
|
1032
|
+
if @dst.val == 3
|
1033
|
+
add(0xcc)
|
1034
|
+
elsif @dst.val == 4
|
1035
|
+
add(0xce)
|
1036
|
+
else
|
1037
|
+
add(0xcd)
|
1038
|
+
add(@dst.val)
|
1039
|
+
end
|
1040
|
+
else
|
1041
|
+
add(0xcc)
|
1042
|
+
end
|
1043
|
+
super
|
1044
|
+
end
|
1045
|
+
end
|
1046
|
+
end
|