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.
Files changed (62) hide show
  1. data/History.txt +15 -0
  2. data/README.rdoc +35 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +30 -0
  5. data/examples/hittracertux.rb +48 -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/arena.rb +55 -0
  11. data/lib/ragweed/blocks.rb +128 -0
  12. data/lib/ragweed/debugger32.rb +338 -0
  13. data/lib/ragweed/debuggerosx.rb +419 -0
  14. data/lib/ragweed/debuggertux.rb +347 -0
  15. data/lib/ragweed/detour.rb +223 -0
  16. data/lib/ragweed/ptr.rb +48 -0
  17. data/lib/ragweed/rasm/isa.rb +1046 -0
  18. data/lib/ragweed/rasm/util.rb +26 -0
  19. data/lib/ragweed/rasm.rb +53 -0
  20. data/lib/ragweed/sbuf.rb +197 -0
  21. data/lib/ragweed/trampoline.rb +103 -0
  22. data/lib/ragweed/utils.rb +87 -0
  23. data/lib/ragweed/wrap32/debugging.rb +163 -0
  24. data/lib/ragweed/wrap32/device.rb +49 -0
  25. data/lib/ragweed/wrap32/event.rb +50 -0
  26. data/lib/ragweed/wrap32/hooks.rb +23 -0
  27. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  28. data/lib/ragweed/wrap32/process.rb +506 -0
  29. data/lib/ragweed/wrap32/process_token.rb +59 -0
  30. data/lib/ragweed/wrap32/thread_context.rb +208 -0
  31. data/lib/ragweed/wrap32/winx.rb +16 -0
  32. data/lib/ragweed/wrap32/wrap32.rb +526 -0
  33. data/lib/ragweed/wrap32.rb +53 -0
  34. data/lib/ragweed/wraposx/constants.rb +101 -0
  35. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  36. data/lib/ragweed/wraposx/region_info.rb +244 -0
  37. data/lib/ragweed/wraposx/thread_context.rb +203 -0
  38. data/lib/ragweed/wraposx/thread_info.rb +213 -0
  39. data/lib/ragweed/wraposx/wraposx.rb +376 -0
  40. data/lib/ragweed/wraposx.rb +53 -0
  41. data/lib/ragweed/wraptux/constants.rb +68 -0
  42. data/lib/ragweed/wraptux/threads.rb +3 -0
  43. data/lib/ragweed/wraptux/wraptux.rb +76 -0
  44. data/lib/ragweed/wraptux.rb +53 -0
  45. data/lib/ragweed.rb +84 -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,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