ragweed 0.2.0-java

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