ragweed 0.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/History.txt +32 -0
  2. data/README.rdoc +60 -0
  3. data/README.txt +9 -0
  4. data/Rakefile +86 -0
  5. data/VERSION +1 -0
  6. data/examples/hittracertux.rb +45 -0
  7. data/examples/hittracerx.rb +63 -0
  8. data/examples/hook_notepad.rb +9 -0
  9. data/examples/snicker.rb +183 -0
  10. data/examples/tux-example.rb +24 -0
  11. data/lib/ragweed/arena.rb +55 -0
  12. data/lib/ragweed/blocks.rb +128 -0
  13. data/lib/ragweed/debugger32.rb +400 -0
  14. data/lib/ragweed/debuggerosx.rb +456 -0
  15. data/lib/ragweed/debuggertux.rb +502 -0
  16. data/lib/ragweed/detour.rb +223 -0
  17. data/lib/ragweed/ptr.rb +48 -0
  18. data/lib/ragweed/rasm/bblock.rb +73 -0
  19. data/lib/ragweed/rasm/isa.rb +1115 -0
  20. data/lib/ragweed/rasm.rb +59 -0
  21. data/lib/ragweed/sbuf.rb +197 -0
  22. data/lib/ragweed/trampoline.rb +103 -0
  23. data/lib/ragweed/utils.rb +182 -0
  24. data/lib/ragweed/wrap32/debugging.rb +401 -0
  25. data/lib/ragweed/wrap32/device.rb +49 -0
  26. data/lib/ragweed/wrap32/event.rb +50 -0
  27. data/lib/ragweed/wrap32/hooks.rb +39 -0
  28. data/lib/ragweed/wrap32/overlapped.rb +46 -0
  29. data/lib/ragweed/wrap32/process.rb +613 -0
  30. data/lib/ragweed/wrap32/process_token.rb +75 -0
  31. data/lib/ragweed/wrap32/thread_context.rb +142 -0
  32. data/lib/ragweed/wrap32/winx.rb +16 -0
  33. data/lib/ragweed/wrap32/wrap32.rb +583 -0
  34. data/lib/ragweed/wrap32.rb +59 -0
  35. data/lib/ragweed/wraposx/constants.rb +114 -0
  36. data/lib/ragweed/wraposx/kernelerrorx.rb +147 -0
  37. data/lib/ragweed/wraposx/region_info.rb +275 -0
  38. data/lib/ragweed/wraposx/structs.rb +102 -0
  39. data/lib/ragweed/wraposx/thread_context.rb +902 -0
  40. data/lib/ragweed/wraposx/thread_info.rb +160 -0
  41. data/lib/ragweed/wraposx/thread_info.rb.old +121 -0
  42. data/lib/ragweed/wraposx/wraposx.rb +356 -0
  43. data/lib/ragweed/wraposx.rb +60 -0
  44. data/lib/ragweed/wraptux/constants.rb +101 -0
  45. data/lib/ragweed/wraptux/process.rb +35 -0
  46. data/lib/ragweed/wraptux/threads.rb +7 -0
  47. data/lib/ragweed/wraptux/wraptux.rb +72 -0
  48. data/lib/ragweed/wraptux.rb +57 -0
  49. data/lib/ragweed.rb +112 -0
  50. data/ragweed.gemspec +102 -0
  51. data/spec/ragweed_spec.rb +7 -0
  52. data/spec/spec_helper.rb +16 -0
  53. data/test/test_ragweed.rb +0 -0
  54. metadata +121 -0
@@ -0,0 +1,1115 @@
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; end
13
+ module Ragweed::Rasm
14
+ class NotImp < RuntimeError; end
15
+ class Insuff < RuntimeError; end
16
+ class BadArg < RuntimeError; end
17
+ class TooMan < RuntimeError; end
18
+
19
+ ## ------------------------------------------------------------------------
20
+
21
+ def method_missing(meth, *args)
22
+ Ragweed::Rasm.const_get(meth).new *args
23
+ end
24
+
25
+ ## ------------------------------------------------------------------------
26
+
27
+ # A register target encoding, including [EAX+10] disp/indir
28
+ class Register
29
+ attr_accessor :code
30
+ attr_accessor :disp
31
+ attr_accessor :indir
32
+ attr_accessor :byte
33
+ attr_accessor :index
34
+ attr_accessor :combined
35
+ attr_accessor :scale
36
+
37
+ EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI = [0,1,2,3,4,5,6,7]
38
+
39
+ def self.comb(rc1, rc2)
40
+ (rc1 << 8|rc2)
41
+ end
42
+
43
+ def scaled?; @scale and @scale > 0; end
44
+ def combined?; @combined; end
45
+ def reg1
46
+ if combined?
47
+ self.class.new((code>>8)&0xff)
48
+ else
49
+ self
50
+ end
51
+ end
52
+
53
+ def reg2
54
+ self.class.new(code&0xFF)
55
+ end
56
+
57
+ def *(x)
58
+ if x.kind_of? Numeric
59
+ ret = clone
60
+ ret.scale = x
61
+ return ret
62
+ end
63
+ raise BadArg, "bad operand type for *"
64
+ end
65
+
66
+ def +(x)
67
+ if x.kind_of? Numeric
68
+ ret = clone
69
+ ret.disp = x
70
+ return ret
71
+ elsif x.kind_of? Register
72
+ ret = clone
73
+ ret.combined = true
74
+ ret.indir = 1
75
+ ret.scale = x.scale
76
+ ret.code = self.class.comb(ret.code, x.code)
77
+ return ret
78
+ end
79
+
80
+ raise BadArg, "bad operand type for +"
81
+ end
82
+
83
+ def -(x)
84
+ ret = clone
85
+ ret.disp = -x
86
+ return ret
87
+ end
88
+
89
+ def regopts(opts={})
90
+ if (v = opts[:disp])
91
+ @disp = v
92
+ end
93
+
94
+ if (v = opts[:indir])
95
+ @indir = v
96
+ end
97
+
98
+ if (v = opts[:byte])
99
+ @byte = v
100
+ end
101
+
102
+ if (v = opts[:index])
103
+ @index = v
104
+ end
105
+
106
+ return self
107
+ 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? Ragweed::Rasm::Instruction}.map {|i| i.decode}
201
+ end
202
+
203
+ def dump_disassembly
204
+ disassemble.each_with_index do |insn, i|
205
+ puts "#{ i } #{ 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? Ragweed::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
+ # Push the registers onto the stack
479
+ # not valid for 64bit mode
480
+ class Pushad < Instruction
481
+ def to_s
482
+ add(0x60)
483
+ super
484
+ end
485
+ end
486
+
487
+ ## ------------------------------------------------------------------------
488
+
489
+ # Pop the registers off the stack
490
+ class Popad < Instruction
491
+ def to_s
492
+ add(0x61)
493
+ super
494
+ end
495
+ end
496
+
497
+ ## ------------------------------------------------------------------------
498
+
499
+ # Call a register/memory location
500
+ class Call < Instruction
501
+ # e8 rel
502
+ # ff/2 r/m
503
+ # no far yet
504
+
505
+ def initialize( dst=nil); super dst; end
506
+
507
+ def to_s
508
+ raise Insuff if not @dst
509
+
510
+ if dst_reg?
511
+ add(0xff)
512
+ add(modrm(@dst, Edx.clone))
513
+ else
514
+ add(0xe8)
515
+ add(@dst.val, true)
516
+ end
517
+ super
518
+ end
519
+ end
520
+
521
+ ## ------------------------------------------------------------------------
522
+
523
+ # Return; provide immediate for stack adjustment if you want.
524
+ class Ret < Instruction
525
+ # c3
526
+ # c2 imm16
527
+
528
+ def initialize( dst=nil); super dst; end
529
+
530
+ def to_s
531
+ if not @dst
532
+ add(0xc3)
533
+ elsif dst_imm?
534
+ add(0xc2)
535
+ add(@dst.val, true, true)
536
+ else
537
+ raise BadArg, "imm16 only"
538
+ end
539
+ super
540
+ end
541
+ end
542
+
543
+ class Retn < Ret; end
544
+
545
+ ## ------------------------------------------------------------------------
546
+
547
+ # Leave
548
+ class Leave < Instruction
549
+ # c9
550
+
551
+ def to_s
552
+ add(0xc9)
553
+ end
554
+ end
555
+
556
+ ## ------------------------------------------------------------------------
557
+
558
+ # Wrapper class for arithmatic instructions. Never called directly;
559
+ # see below.
560
+ class Arith < Instruction
561
+ # 05 imm32 to eax
562
+ # 04 imm8 to al
563
+ # 80/0 r/m8, imm8
564
+ # 81/0 r/m, imm
565
+ # no sign extend yet
566
+ # 01 r/m, r
567
+ # 03 r, r/m
568
+
569
+ def initialize( dst=nil, src=nil); super dst, src; end
570
+
571
+ def to_s
572
+ if not @dst
573
+ # fucked up
574
+ if src_imm?
575
+ if @src.val < 0x100
576
+ add(@imp8)
577
+ add(@src.val)
578
+ else
579
+ add(@imp)
580
+ add(@src.val)
581
+ end
582
+ else
583
+ raise BadArg, "need immed for implicit eax"
584
+ end
585
+ else
586
+ if src_imm?
587
+ if @src.val < 0x100
588
+ add(@imm8)
589
+ add(modrm(@dst, @x))
590
+ add(@src.val)
591
+ else
592
+ add(@imm)
593
+ add(modrm(@dst, @x))
594
+ add(@src.val)
595
+ end
596
+ else
597
+ raise(BadArg, "need two r/m") if not src_reg? or not dst_reg?
598
+ raise(BadArg, "can't both be indir") if @src.indir and @dst.indir
599
+ if @src.indir
600
+ add(@rm)
601
+ add(modrm(@dst, @src))
602
+ else
603
+ add(@mr)
604
+ add(modrm(@dst, @src))
605
+ end
606
+ end
607
+ end
608
+ super
609
+ end
610
+ end
611
+
612
+ ## ------------------------------------------------------------------------
613
+
614
+ # ADD
615
+ class Add < Arith
616
+ def initialize(*args)
617
+ super *args
618
+ @imp8, @imp, @imm8, @imm, @rm, @mr = [0x04, 0x05, 0x83, 0x81, 0x03, 0x01]
619
+ @x = Eax.clone
620
+ end
621
+ end
622
+ Addl = Add
623
+
624
+ ## ------------------------------------------------------------------------
625
+
626
+ # SUB
627
+ class Sub < Arith
628
+ def initialize(*args)
629
+ super *args
630
+ @imp8, @imp, @imm8, @imm, @rm, @mr = [0x2c, 0x2d, 0x83, 0x81, 0x2b, 0x29]
631
+ @x = Ebp.clone
632
+ end
633
+ end
634
+ Subl = Sub
635
+
636
+ ## ------------------------------------------------------------------------
637
+
638
+ # XOR
639
+ class Xor < Arith
640
+ def initialize(*args)
641
+ super *args
642
+ @imp8, @imp, @imm8, @imm, @rm, @mr = [0x34, 0x35, 0x83, 0x81, 0x33, 0x31]
643
+ @x = Esi.clone
644
+ end
645
+ end
646
+ ## ------------------------------------------------------------------------
647
+
648
+ # AND
649
+ class And < Arith
650
+ def initialize(*args)
651
+ super *args
652
+ @imp8, @imp, @imm8, @imm, @rm, @mr = [0x24, 0x25, 0x83, 0x81, 0x23, 0x21]
653
+ @x = Esp.clone
654
+ end
655
+ end
656
+
657
+ ## ------------------------------------------------------------------------
658
+
659
+ # OR
660
+ class Or < Arith
661
+ def initialize(*args)
662
+ super *args
663
+ @imp8, @imp, @imm8, @imm, @rm, @mr = [0x0c, 0x0d, 0x83, 0x81, 0x0b, 0x09]
664
+ @x = Ecx.clone
665
+ end
666
+ end
667
+
668
+ ## ------------------------------------------------------------------------
669
+
670
+ # Test is AND + condition code
671
+ class Test < Instruction
672
+ # a8 imm8
673
+ # a9 imm
674
+ # f7/0, r/m
675
+ # 85 r/m, r
676
+
677
+ def initialize( dst=nil, src=nil); super(dst,src); end
678
+
679
+ def to_s
680
+ if not @dst
681
+ raise(BadArg, "need imm for implied ax") if not src_imm?
682
+ if @src.val < 0x100
683
+ add(0xa8)
684
+ add(@src.val)
685
+ else
686
+ add(0xa9)
687
+ add(@src.val)
688
+ end
689
+ else
690
+ if src_imm?
691
+ add(0xf7)
692
+ add(modrm(@dst.val, Eax.clone))
693
+ add(@src.val)
694
+ else
695
+ add(0x85)
696
+ add(modrm(@dst.val, @src))
697
+ end
698
+ end
699
+ super
700
+ end
701
+ end
702
+
703
+ ## ------------------------------------------------------------------------
704
+
705
+ # CMP is SUB + condition code
706
+ class Cmp < Instruction
707
+ # 3c imm8
708
+ # 3d imm
709
+ # 80/7 r/m8, imm8
710
+ # 81/7 r/m, imm
711
+ # 83/7 r/m, imm8
712
+ # 38 r/m8, r8
713
+ # 39 r/m, r
714
+ # 3a r8, r/m8
715
+ # 3b r, r/m
716
+
717
+ def initialize( dst=nil, src=nil); super dst, src; end
718
+
719
+ def to_s
720
+ if not @dst
721
+ raise(BadArg, "need immed for implicit ax") if not src_imm?
722
+ if @src.val < 0x100
723
+ add(0x3c)
724
+ add(@src.val)
725
+ else
726
+ add(0x3d)
727
+ add(@src.val)
728
+ end
729
+ else
730
+ raise(BadArg, "need reg dst") if not dst_reg?
731
+ if src_imm?
732
+ raise NotImp if @dst.byte
733
+ if @src.val < 0x100
734
+ add(0x83)
735
+ add(modrm(@dst, Edi.clone))
736
+ add(@src.val)
737
+ else
738
+ add(0x81)
739
+ add(modrm(@dst, Edi.clone))
740
+ add(@src.val)
741
+ end
742
+ else
743
+ if @dst.indir
744
+ add(0x39)
745
+ add(modrm(@src, @dst))
746
+ add(@dst.disp)
747
+ else
748
+ add(0x3b)
749
+ add(modrm(@src, @dst))
750
+ add(@dst.disp)
751
+ end
752
+ end
753
+ end
754
+ super
755
+ end
756
+ end
757
+
758
+ ## ------------------------------------------------------------------------
759
+
760
+ # Wrapper for INC and DEC, not called directly.
761
+ class IncDec < Instruction
762
+ # fe/0 r/m8
763
+ # ff/0 r/m
764
+ # 40+ (reg)
765
+
766
+ def initialize( dst=nil); super dst; end
767
+
768
+ def to_s
769
+ raise Insuff if not @dst
770
+ raise(BadArg, "need a register") if not dst_reg?
771
+
772
+ if @dst.indir
773
+ add(0xff)
774
+ add(modrm(@dst, @var))
775
+ else
776
+ add(@bas + @dst.code)
777
+ end
778
+ super
779
+ end
780
+ end
781
+
782
+ ## ------------------------------------------------------------------------
783
+
784
+ # INC memory or register
785
+ class Inc < IncDec
786
+ def initialize(*args)
787
+ super *args
788
+ @var = Eax.clone
789
+ @bas = 0x40
790
+ end
791
+ end
792
+
793
+ ## ------------------------------------------------------------------------
794
+
795
+ # DEC memory or register
796
+ class Dec < IncDec
797
+ def initialize(*args)
798
+ super *args
799
+ @var = Ecx.clone
800
+ @bas = 0x48
801
+ end
802
+ end
803
+
804
+ ## ------------------------------------------------------------------------
805
+
806
+ # MOV, from reg to mem or v/v, or imm to reg, v/v
807
+ class Mov < Instruction
808
+ # 89 r/m, r
809
+ # 8b r, r/m
810
+ # b8+ r, imm
811
+ # c7+ r/m, imm
812
+ def to_s
813
+ raise Insuff if not @src or not @dst
814
+ raise NotImp if (src_reg? and @src.index) or (dst_reg? and @dst.index)
815
+
816
+ if src_imm?
817
+ if @dst.indir
818
+ add(0xc7)
819
+ add(@dst.code)
820
+ add(@src.val)
821
+ else
822
+ add(0xb8 + @dst.code)
823
+ add(@src.val, true)
824
+ end
825
+ elsif dst_imm?
826
+ raise BadArg, "mov to immed"
827
+ else
828
+ raise(BadArg, "two r/m") if @src.indir and @dst.indir
829
+ if not @src.indir and not @dst.indir
830
+ add(0x89)
831
+ add(modrm(@dst, @src))
832
+ elsif @src.indir # ie, ld
833
+ add(0x8b)
834
+ add(modrm(@dst, @src))
835
+ add(@src.disp)
836
+ elsif @dst.indir # ie, st
837
+ add(0x89)
838
+ add(modrm(@dst, @src))
839
+ add(@dst.disp)
840
+ end
841
+ end
842
+ super
843
+ end
844
+
845
+ def initialize( x=nil, y=nil); super x, y; end
846
+ end
847
+
848
+ ## ------------------------------------------------------------------------
849
+
850
+ # Wrapper for the shift operations below.
851
+ class Shift < Instruction
852
+ once = nil
853
+ bycl = nil
854
+ imm = nil
855
+ x = nil
856
+
857
+ def initialize( dst=nil, src=nil); super dst, src; end
858
+
859
+ def to_s
860
+ raise Insuff if not @dst
861
+ raise(BadArg, "need reg dst") if not dst_reg?
862
+
863
+ if not @src
864
+ add(@once)
865
+ add(modrm(@dst, @x))
866
+ else
867
+ if src_imm?
868
+ add(@imm)
869
+ add(modrm(@dst, @x))
870
+ add(@src.val)
871
+ else
872
+ add(@bycl)
873
+ add(modrm(@dst, @x))
874
+ end
875
+ end
876
+ super
877
+ end
878
+
879
+ def magic(x, y, z, r); @once, @bycl, @imm, @x = [x,y,z,r.clone]; end
880
+ end
881
+
882
+ # TODO looks wrong
883
+
884
+ # Left arith shift
885
+ class Sal < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Esp; end; end
886
+
887
+ # Right arith shift
888
+ class Sar < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Edi; end; end
889
+
890
+ # Left logic shift
891
+ class Shl < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Esp; end; end
892
+
893
+ # Right logic shift
894
+ class Shr < Shift; def initialize(*args); super *args; magic 0xd1, 0xd3, 0xc1, Ebp; end; end
895
+
896
+ ## ------------------------------------------------------------------------
897
+
898
+ # NOP
899
+ class Nop < Instruction
900
+ # 90
901
+ def initialize; super; end
902
+
903
+ def to_s
904
+ add(0x90)
905
+ super
906
+ end
907
+ end
908
+
909
+ ## ------------------------------------------------------------------------
910
+
911
+ # NOT a register
912
+ class Not < Instruction
913
+ # f7/2 r/m
914
+
915
+ def initialize( dst=nil); super dst; end
916
+
917
+ def to_s
918
+ raise Insuff if not @dst
919
+ raise(BadArg, "need reg for not") if not dst_reg?
920
+
921
+ add(0xf7)
922
+ add(modrm(@dst, Edx.clone))
923
+ super
924
+ end
925
+ end
926
+
927
+ ## ------------------------------------------------------------------------
928
+
929
+ # Load a memory address from a register into another register;
930
+ # uses memory notation, but is a pure arith insn
931
+ class Lea < Instruction
932
+ # 8d r, m
933
+
934
+ def initialize( dst=nil, src=nil); super dst, src; end
935
+
936
+ def to_s
937
+ raise Insuff if not @src or not @dst
938
+ raise(BadArg, "need reg src") if not src_reg?
939
+ raise(BadArg, "need indirected src") if not @src.indir
940
+
941
+ add(0x8d)
942
+ add(modrm(@dst, @src))
943
+ add(@src.disp)
944
+ super
945
+ end
946
+ end
947
+
948
+ ## ------------------------------------------------------------------------
949
+
950
+ # Wrapper for conditional jumps, see below
951
+ class Jcc < Instruction
952
+
953
+ def m; [nil,nil]; end
954
+ def initialize( dst)
955
+ super dst
956
+ @short, @near = m()
957
+ end
958
+
959
+ def to_s
960
+ raise Insuff if not @dst
961
+ raise(BadArg, "need immed") if not dst_imm? and not dst_lab?
962
+
963
+ if @dst.val < 0
964
+ if @dst.val.abs & 0x80
965
+ add(0x0f)
966
+ add(@near)
967
+ add(@dst.sx32)
968
+ else
969
+ add(@short)
970
+ add(@dst.sx8)
971
+ end
972
+ else
973
+ if @dst.val < 0x100
974
+ add(@short)
975
+ add(@dst.val)
976
+ else
977
+ add(0x0f)
978
+ add(@near)
979
+ add(@dst.val, true)
980
+ end
981
+ end
982
+ super
983
+ end
984
+ end
985
+
986
+ # Somewhere in the SDM there's a table of what condition codes
987
+ # each of these check.
988
+
989
+ # Above
990
+ class Ja < Jcc; def m; [0x77, 0x87]; end; end
991
+ # Above/eq
992
+ class Jae <Jcc; def m; [0x73, 0x83]; end; end
993
+ # Below
994
+ class Jb < Jcc; def m; [0x72, 0x82]; end; end
995
+ # Below/eq
996
+ class Jbe < Jcc; def m; [0x76, 0x86]; end; end
997
+ # Carry
998
+ class Jc < Jcc; def m; [0x72, 0x82]; end; end
999
+ # Equal
1000
+ class Je < Jcc; def m; [0x74, 0x84]; end; end
1001
+ # Greater (SIGNED)
1002
+ class Jg < Jcc; def m; [0x7f, 0x8f]; end; end
1003
+ # Greater/eq (SIGNED)
1004
+ class Jge < Jcc; def m; [0x7d, 0x8d]; end; end
1005
+ # Less (SIGNED)
1006
+ class Jl < Jcc; def m; [0x7c, 0x8c]; end; end
1007
+ # Less/eq (SIGNED)
1008
+ class Jle < Jcc; def m; [0x7e, 0x8e]; end; end
1009
+ # Not above
1010
+ class Jna < Jcc; def m; [0x76, 0x86]; end; end
1011
+ # Not above/eq
1012
+ class Jnae < Jcc; def m; [0x72, 0x82]; end; end
1013
+ # Not below
1014
+ class Jnb < Jcc; def m; [0x73, 0x83]; end; end
1015
+ # Not below/eq
1016
+ class Jnbe < Jcc; def m; [0x77, 0x87]; end; end
1017
+ # Not carry
1018
+ class Jnc < Jcc; def m; [0x73, 0x83]; end; end
1019
+ # Not equal
1020
+ class Jne < Jcc; def m; [0x75, 0x85]; end; end
1021
+ # Not greater (SIGNED)
1022
+ class Jng < Jcc; def m; [0x7e, 0x8e]; end; end
1023
+ # Not greater/eq (SIGNED)
1024
+ class Jnge < Jcc; def m; [0x7c, 0x8c]; end; end
1025
+ # Not less (SIGNED)
1026
+ class Jnl < Jcc; def m; [0x7d, 0x8d]; end; end
1027
+ # Not less/eq (SIGNED)
1028
+ class Jnle < Jcc; def m; [0x7f, 0x8f]; end; end
1029
+ # Not overflow
1030
+ class Jno < Jcc; def m; [0x71, 0x81]; end; end
1031
+ # Not parity
1032
+ class Jnp < Jcc; def m; [0x7b, 0x8b]; end; end
1033
+ # Not sign
1034
+ class Jns < Jcc; def m; [0x79, 0x89]; end; end
1035
+ # Not zero
1036
+ class Jnz < Jcc; def m; [0x75, 0x85]; end; end
1037
+ # Overflow
1038
+ class Jo < Jcc; def m; [0x70, 0x80]; end; end
1039
+ # Parity
1040
+ class Jp < Jcc; def m; [0x7a, 0x8a]; end; end
1041
+ # Parity/eq
1042
+ class Jpe < Jcc; def m; [0x7a, 0x8a]; end; end
1043
+ # Parity/overflow
1044
+ class Jpo < Jcc; def m; [0x7b, 0x8b]; end; end
1045
+ # Signed
1046
+ class Js < Jcc; def m; [0x78, 0x88]; end; end
1047
+ # Zero
1048
+ class Jz < Jcc; def m; [0x74, 0x84]; end; end
1049
+
1050
+ ## ------------------------------------------------------------------------
1051
+
1052
+ class Pushf < Instruction
1053
+ # 9c pushfd
1054
+
1055
+ # def initialize; end
1056
+ def to_s
1057
+ raise(TooMan, "too many arguments") if @src or @dst
1058
+ add(0x9c)
1059
+ super
1060
+ end
1061
+ end
1062
+
1063
+ ## ------------------------------------------------------------------------
1064
+
1065
+ class Popf < Instruction
1066
+ # 9d popfd
1067
+
1068
+ # def initialize; end
1069
+ def to_s
1070
+ raise(TooMan, "too many arguments") if @src or @dst
1071
+ add(0x9d)
1072
+ super
1073
+ end
1074
+ end
1075
+
1076
+ ## ------------------------------------------------------------------------
1077
+
1078
+ class Iret < Instruction
1079
+ def to_s
1080
+ add(0xcf)
1081
+ super
1082
+ end
1083
+ end
1084
+
1085
+ ## ------------------------------------------------------------------------
1086
+
1087
+ # INT 3, mostly, but will do INT X
1088
+ class Int < Instruction
1089
+ ## cc int 3
1090
+ ## cd imm int n
1091
+ ## ce int 4 notimp
1092
+
1093
+ def initialize(dst=nil); super dst; end
1094
+
1095
+ def to_s
1096
+ raise(TooMan, "too many arguments for int") if @src
1097
+ raise(BadArg, "int takes immed") if @dst and not dst_imm?
1098
+
1099
+ if @dst
1100
+ raise(BadArg, "need 8 bit immed") if @dst.val >= 0x100
1101
+ if @dst.val == 3
1102
+ add(0xcc)
1103
+ elsif @dst.val == 4
1104
+ add(0xce)
1105
+ else
1106
+ add(0xcd)
1107
+ add(@dst.val)
1108
+ end
1109
+ else
1110
+ add(0xcc)
1111
+ end
1112
+ super
1113
+ end
1114
+ end
1115
+ end