ffi-udis86 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,563 @@
1
+ require 'udis86/types'
2
+ require 'udis86/operand'
3
+ require 'udis86/ffi'
4
+
5
+ require 'ffi'
6
+
7
+ module FFI
8
+ module UDis86
9
+ class UD < FFI::Struct
10
+
11
+ include Enumerable
12
+
13
+ layout :inp_hook, :ud_input_callback,
14
+ :inp_curr, :uint8,
15
+ :inp_fill, :uint8,
16
+ :inp_file, :pointer,
17
+ :inp_ctr, :uint8,
18
+ :inp_buff, :pointer,
19
+ :inp_buff_end, :pointer,
20
+ :inp_end, :uint8,
21
+ :translator, :ud_translator_callback,
22
+ :insn_offset, :uint64,
23
+ :insn_hexcode, [:char, 32],
24
+ :insn_buffer, [:char, 64],
25
+ :insn_fill, :uint,
26
+ :dis_mode, :uint8,
27
+ :pc, :uint64,
28
+ :vendor, :uint8,
29
+ :mapen, :pointer,
30
+ :mnemonic, :ud_mnemonic_code,
31
+ :operand, [Operand, 3],
32
+ :error, :uint8,
33
+ :pfx_rex, :uint8,
34
+ :pfx_seg, :uint8,
35
+ :pfx_opr, :uint8,
36
+ :pfx_adr, :uint8,
37
+ :pfx_lock, :uint8,
38
+ :pfx_rep, :uint8,
39
+ :pfx_repe, :uint8,
40
+ :pfx_repne, :uint8,
41
+ :pfx_insn, :uint8,
42
+ :default64, :uint8,
43
+ :opr_mode, :uint8,
44
+ :adr_mode, :uint8,
45
+ :br_far, :uint8,
46
+ :br_near, :uint8,
47
+ :implicit_addr, :uint8,
48
+ :c1, :uint8,
49
+ :c2, :uint8,
50
+ :c3, :uint8,
51
+ :inp_cache, [NativeType::UINT8, 256],
52
+ :inp_sess, [NativeType::UINT8, 64],
53
+ :itab_entry, :pointer
54
+
55
+ #
56
+ # Creates a new disassembler object.
57
+ #
58
+ # @param [Hash] options
59
+ # Additional options.
60
+ #
61
+ # @option options [Integer] :mode (32)
62
+ # The mode of disassembly, can either 16, 32 or 64.
63
+ #
64
+ # @option options [Integer] :syntax (:intel)
65
+ # The assembly syntax the disassembler will emit, can be either
66
+ # `:att` or `:intel`.
67
+ #
68
+ # @option options [String] :buffer
69
+ # A buffer to disassemble.
70
+ #
71
+ # @option options [Symbol] :vendor
72
+ # Sets the vendor of whose instructions to choose from. Can be
73
+ # either `:amd` or `:intel`.
74
+ #
75
+ # @option options [Integer] :pc
76
+ # Initial value of the Program Counter (PC).
77
+ #
78
+ # @yield [ud]
79
+ # If a block is given, it will be used as an input callback to
80
+ # return the next byte to disassemble. When the block returns
81
+ # -1, the disassembler will stop processing input.
82
+ #
83
+ # @yieldparam [UD] ud
84
+ # The disassembler.
85
+ #
86
+ # @return [UD]
87
+ # The newly created disassembler.
88
+ #
89
+ def self.create(options={},&block)
90
+ ud = self.new
91
+ ud.init
92
+
93
+ ud.mode = (options[:mode] || 32)
94
+
95
+ if options[:buffer]
96
+ ud.input_buffer = options[:buffer]
97
+ end
98
+
99
+ ud.syntax = (options[:syntax] || :intel)
100
+
101
+ if options[:vendor]
102
+ ud.vendor = options[:vendor]
103
+ end
104
+
105
+ if options[:pc]
106
+ ud.pc = options[:pc]
107
+ end
108
+
109
+ ud.input_callback(&block) if block
110
+
111
+ return ud
112
+ end
113
+
114
+ #
115
+ # Opens a file and disassembles it.
116
+ #
117
+ # @param [String] path
118
+ # The path to the file.
119
+ #
120
+ # @param [Hash] options
121
+ # Additional dissaembly options.
122
+ #
123
+ # @option options [Integer] :mode (32)
124
+ # The mode of disassembly, can either 16, 32 or 64.
125
+ #
126
+ # @option options [Integer] :syntax (:intel)
127
+ # The assembly syntax the disassembler will emit, can be either
128
+ # `:att` or `:intel`.
129
+ #
130
+ # @option options [String] :buffer
131
+ # A buffer to disassemble.
132
+ #
133
+ # @option options [Symbol] :vendor
134
+ # Sets the vendor of whose instructions to choose from. Can be
135
+ # either `:amd` or `:intel`.
136
+ #
137
+ # @option options [Integer] :pc
138
+ # Initial value of the Program Counter (PC).
139
+ #
140
+ # @yield [ud]
141
+ # If a block is given, it will be passed the newly created
142
+ # UD object, configured to disassembler the file.
143
+ #
144
+ # @yieldparam [UD] ud
145
+ # The newly created disassembler.
146
+ #
147
+ def self.open(path,options={},&block)
148
+ File.open(path,'rb') do |file|
149
+ ud = self.create(options) do |ud|
150
+ if (b = file.getc)
151
+ b.ord
152
+ else
153
+ -1
154
+ end
155
+ end
156
+
157
+ block.call(ud) if block
158
+ end
159
+
160
+ return nil
161
+ end
162
+
163
+ #
164
+ # Initializes the disassembler.
165
+ #
166
+ # @return [UD]
167
+ # The initialized disassembler.
168
+ #
169
+ def init
170
+ UDis86.ud_init(self)
171
+ return self
172
+ end
173
+
174
+ #
175
+ # Returns the input buffer used by the disassembler.
176
+ #
177
+ # @return [String]
178
+ # The current contents of the input buffer.
179
+ #
180
+ def input_buffer
181
+ if @input_buffer
182
+ @input_buffer.get_bytes(0,@input_buffer.total)
183
+ else
184
+ ''
185
+ end
186
+ end
187
+
188
+ #
189
+ # Sets the contents of the input buffer for the disassembler.
190
+ #
191
+ # @param [Array<Integer>, String] data
192
+ # The new contents to use for the input buffer.
193
+ #
194
+ # @return [String]
195
+ # The new contents of the input buffer.
196
+ #
197
+ # @raise [RuntimeError]
198
+ # The given input buffer was neigther a String or an Array of bytes.
199
+ #
200
+ def input_buffer=(data)
201
+ data = data.to_s
202
+
203
+ @input_buffer = FFI::MemoryPointer.new(data.length)
204
+
205
+ if data.kind_of?(Array)
206
+ @input_buffer.put_array_of_uint8(0,data)
207
+ elsif data.kind_of?(String)
208
+ @input_buffer.put_bytes(0,data)
209
+ else
210
+ raise(RuntimeError,"input buffer must be either a String or an Array of bytes",caller)
211
+ end
212
+
213
+ UDis86.ud_set_input_buffer(self,@input_buffer,@input_buffer.total)
214
+ return data
215
+ end
216
+
217
+ #
218
+ # Sets the input callback for the disassembler.
219
+ #
220
+ # @yield [ud]
221
+ # If a block is given, it will be used to get the next byte of
222
+ # input to disassemble. When the block returns -1, the disassembler
223
+ # will stop processing input.
224
+ #
225
+ # @yieldparam [UD]
226
+ # The disassembler.
227
+ #
228
+ def input_callback(&block)
229
+ if block
230
+ @input_callback = Proc.new { |ptr| block.call(self) }
231
+
232
+ UDis86.ud_set_input_hook(self,@input_callback)
233
+ end
234
+
235
+ return @input_callback
236
+ end
237
+
238
+ #
239
+ # Returns the mode the disassembler is running in.
240
+ #
241
+ # @return [Integer]
242
+ # Returns either 16, 32 or 64.
243
+ #
244
+ def mode
245
+ self[:dis_mode]
246
+ end
247
+
248
+ #
249
+ # Sets the mode the disassembler will run in.
250
+ #
251
+ # @param [Integer] new_mode
252
+ # The mode the disassembler will run in. Can be either 16, 32 or 64.
253
+ #
254
+ # @return [Integer]
255
+ # The new mode of the disassembler.
256
+ #
257
+ def mode=(new_mode)
258
+ unless MODES.include?(new_mode)
259
+ raise(RuntimeError,"invalid disassembly mode #{new_mode}",caller)
260
+ end
261
+
262
+ UDis86.ud_set_mode(self,new_mode)
263
+ return new_mode
264
+ end
265
+
266
+ #
267
+ # Sets the assembly syntax that the disassembler will emit.
268
+ #
269
+ # @param [Symbol, String] new_syntax
270
+ # The new assembler syntax the disassembler will emit. Can be
271
+ # either `:att` or `:intel`.
272
+ #
273
+ # @return [Symbol]
274
+ # The new assembly syntax being used.
275
+ #
276
+ def syntax=(new_syntax)
277
+ new_syntax = new_syntax.to_s.downcase.to_sym
278
+ func_name = UDis86::SYNTAX[new_syntax]
279
+
280
+ unless func_name
281
+ raise(ArgumentError,"unknown syntax name #{new_syntax}",caller)
282
+ end
283
+
284
+ UDis86.ud_set_syntax(self,UDis86.method(func_name))
285
+ return new_syntax
286
+ end
287
+
288
+ #
289
+ # The vendor of whose instructions are to be choosen from during
290
+ # disassembly.
291
+ #
292
+ # @return [Symbol]
293
+ # The vendor name, may be either `:amd` or `:intel`.
294
+ #
295
+ def vendor
296
+ VENDORS[self[:vendor]]
297
+ end
298
+
299
+ #
300
+ # Sets the vendor, of whose instructions are to be choosen from
301
+ # during disassembly.
302
+ #
303
+ # @param [Symbol] new_vendor
304
+ # The new vendor to use, can be either `:amd` or `:intel`.
305
+ #
306
+ # @return [Symbol]
307
+ # The new vendor to use.
308
+ #
309
+ def vendor=(new_vendor)
310
+ UDis86.ud_set_vendor(self,VENDORS.index(new_vendor))
311
+ return new_vendor
312
+ end
313
+
314
+ #
315
+ # Returns the current value of the Program Counter (PC).
316
+ #
317
+ # @return [Integer]
318
+ # The value of the PC.
319
+ #
320
+ def pc
321
+ self[:pc]
322
+ end
323
+
324
+ #
325
+ # Sets the value of the Program Counter (PC).
326
+ #
327
+ # @param [Integer] new_pc
328
+ # The new value to use for the PC.
329
+ #
330
+ # @return [Integer]
331
+ # The new value of the PC.
332
+ #
333
+ def pc=(new_pc)
334
+ UDis86.ud_set_pc(self,new_pc)
335
+ return new_pc
336
+ end
337
+
338
+ #
339
+ # Causes the disassembler to skip a certain number of bytes in the
340
+ # input stream.
341
+ #
342
+ # @param [Integer] n
343
+ # The number of bytes to skip.
344
+ #
345
+ # @return [UD]
346
+ # The disassembler.
347
+ #
348
+ def skip(n)
349
+ UDis86.ud_input_skip(self,n)
350
+ return self
351
+ end
352
+
353
+ #
354
+ # The mnemonic code of the last disassembled instruction.
355
+ #
356
+ # @return [Symbol]
357
+ # The mnemonic code.
358
+ #
359
+ def mnemonic_code
360
+ self[:mnemonic]
361
+ end
362
+
363
+ #
364
+ # The mnemonic string of the last disassembled instruction.
365
+ #
366
+ # @return [Symbol]
367
+ # The mnemonic string.
368
+ #
369
+ def mnemonic
370
+ UDis86.ud_lookup_mnemonic(self[:mnemonic]).to_sym
371
+ end
372
+
373
+ #
374
+ # The 64-bit mode REX prefix of the last disassembled instruction.
375
+ #
376
+ # @return [Integer]
377
+ # The 64-bit REX prefix.
378
+ #
379
+ def rex_prefix
380
+ self[:pfx_rex]
381
+ end
382
+
383
+ #
384
+ # The segment register prefix of the last disassembled instruction.
385
+ #
386
+ # @return [Integer]
387
+ # The segment register prefix.
388
+ #
389
+ def segment_prefix
390
+ self[:pfx_seg]
391
+ end
392
+
393
+ #
394
+ # The operand-size prefix (66h) of the last disassembled instruction.
395
+ #
396
+ # @return [Integer]
397
+ # The operand-size prefix.
398
+ #
399
+ def operand_prefix
400
+ self[:pfx_opr]
401
+ end
402
+
403
+ #
404
+ # The address-size prefix (67h) of the last disassembled instruction.
405
+ #
406
+ # @return [Integer]
407
+ # The address-size prefix.
408
+ #
409
+ def address_prefix
410
+ self[:pfx_adr]
411
+ end
412
+
413
+ #
414
+ # The lock prefix of the last disassembled instruction.
415
+ #
416
+ # @return [Integer]
417
+ # The lock prefix.
418
+ #
419
+ def lock_prefix
420
+ self[:pfx_lock]
421
+ end
422
+
423
+ #
424
+ # The rep prefix of the last disassembled instruction.
425
+ #
426
+ # @return [Integer]
427
+ # The rep prefix.
428
+ #
429
+ def rep_prefix
430
+ self[:pfx_rep]
431
+ end
432
+
433
+ #
434
+ # The repe prefix of the last disassembled instruction.
435
+ #
436
+ # @return [Integer]
437
+ # The repe prefix.
438
+ #
439
+ def repe_prefix
440
+ self[:pfx_repe]
441
+ end
442
+
443
+ #
444
+ # The repne prefix of the last disassembled instruction.
445
+ #
446
+ # @return [Integer]
447
+ # The repne prefix.
448
+ #
449
+ def repne_prefix
450
+ self[:pfx_repne]
451
+ end
452
+
453
+ #
454
+ # Returns the assembly syntax for the last disassembled instruction.
455
+ #
456
+ # @return [String]
457
+ # The assembly syntax for the instruction.
458
+ #
459
+ def to_asm
460
+ UDis86.ud_insn_asm(self)
461
+ end
462
+
463
+ #
464
+ # Returns the hexadecimal representation of the disassembled
465
+ # instruction.
466
+ #
467
+ # @return [String]
468
+ # The hexadecimal form of the disassembled instruction.
469
+ #
470
+ def to_hex
471
+ UDis86.ud_insn_hex(self)
472
+ end
473
+
474
+ alias :to_s :to_asm
475
+
476
+ #
477
+ # Returns the operands for the last disassembled instruction.
478
+ #
479
+ # @return [Array<Operand>]
480
+ # The operands of the instruction.
481
+ #
482
+ def operands
483
+ self[:operand].entries.select do |operand|
484
+ [
485
+ :ud_op_reg,
486
+ :ud_op_mem,
487
+ :ud_op_ptr,
488
+ :ud_op_imm,
489
+ :ud_op_jimm,
490
+ :ud_op_const
491
+ ].include?(operand.type)
492
+ end
493
+ end
494
+
495
+ #
496
+ # Disassembles the next instruction in the input stream.
497
+ #
498
+ # @return [UD]
499
+ # The disassembler.
500
+ #
501
+ def next_insn
502
+ UDis86.ud_disassemble(self)
503
+ end
504
+
505
+ #
506
+ # Returns the number of bytes that were disassembled.
507
+ #
508
+ # @return [Integer]
509
+ # The number of bytes disassembled.
510
+ #
511
+ def insn_length
512
+ UDis86.ud_insn_len(self)
513
+ end
514
+
515
+ #
516
+ # Returns the starting offset of the disassembled instruction
517
+ # relative to the initial value of the Program Counter (PC).
518
+ #
519
+ # @return [Integer]
520
+ # The offset of the instruction.
521
+ #
522
+ def insn_offset
523
+ UDis86.ud_insn_off(self)
524
+ end
525
+
526
+ #
527
+ # Returns the pointer to the buffer holding the disassembled
528
+ # instruction bytes.
529
+ #
530
+ # @return [FFI::Pointer]
531
+ # The pointer to the instruction buffer.
532
+ #
533
+ def insn_ptr
534
+ UDis86.ud_insn_ptr(self)
535
+ end
536
+
537
+ #
538
+ # Reads each byte, disassembling each instruction.
539
+ #
540
+ # @yield [ud]
541
+ # If a block is given, it will be passed the disassembler after
542
+ # each instruction has been disassembled.
543
+ #
544
+ # @yieldparam [UD] ud
545
+ # The disassembler.
546
+ #
547
+ # @return [UD]
548
+ # The disassembler.
549
+ #
550
+ def disassemble(&block)
551
+ until UDis86.ud_disassemble(self) == 0
552
+ block.call(self) if block
553
+ end
554
+
555
+ return self
556
+ end
557
+
558
+ alias :disas :disassemble
559
+ alias :each :disassemble
560
+
561
+ end
562
+ end
563
+ end