Last active
October 13, 2015 02:08
-
-
Save emonti/4122904 to your computer and use it in GitHub Desktop.
Multi-arch bytecode disassembler using libLLVM
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# author eric monti ~ nov 20, 2012 | |
# license: DWTFYW | |
require 'rubygems' | |
require 'ffi' | |
class LLVMDisassembler | |
module C | |
extend FFI::Library | |
ffi_lib ['LLVM', 'LLVM-3.2svn', 'LLVM-3.1', 'LLVM-3.0'] | |
# not currently used | |
callback :op_info_callback, [:ulong_long, :ulong_long, :ulong_long, :int, :pointer], :pointer | |
callback :symbol_lookup_callback, [:ulong_long, :pointer, :ulong_long, :pointer], :pointer | |
attach_function :create_disasm, :LLVMCreateDisasm, [:string, :pointer, :int, :op_info_callback, :symbol_lookup_callback], :pointer | |
attach_function :disasm_dispose, :LLVMDisasmDispose, [:pointer], :void | |
attach_function :disasm_instruction, :LLVMDisasmInstruction, [:pointer, :pointer, :ulong_long, :ulong_long, :pointer, :ulong], :ulong | |
end | |
def self.open(triple, &block) | |
new(triple) do |dis| | |
return block.call(dis) | |
end | |
end | |
def initialize(triple) | |
@dis = C.create_disasm(triple, nil, 0, nil, nil) | |
if block_given? | |
yield(self) | |
dispose() | |
end | |
end | |
def dispose | |
C.disasm_dispose(_dis) | |
@dis=nil | |
end | |
def get_instruction(bytes, pc=0) | |
insize = bytes.size | |
FFI::MemoryPointer.new(insize) do |bytes_ptr| | |
bytes_ptr.write_string_length(bytes, insize) | |
FFI::MemoryPointer.new(255) do |out_string| | |
retlen=C.disasm_instruction(_dis, bytes_ptr, insize, pc, out_string, 255) | |
if retlen > 0 | |
return [out_string.read_string, bytes_ptr.read_array_of_uint8(retlen), retlen] | |
end | |
end | |
end | |
return nil | |
end | |
def get_instructions(bytes, pc=0) | |
off=0 | |
insize = bytes.size | |
FFI::MemoryPointer.new(insize) do |bytes_ptr| | |
bytes_ptr.write_string_length(bytes, insize) | |
FFI::MemoryPointer.new(255) do |out_string| | |
while (off < insize) | |
offp = bytes_ptr+off | |
retlen=C.disasm_instruction(_dis, offp, insize-off, pc, out_string, 255) | |
if retlen > 0 | |
yield(out_string.read_string, offp.read_array_of_uint8(retlen), retlen) | |
off+=retlen | |
else | |
break | |
end | |
end | |
end | |
end | |
return nil | |
end | |
private | |
def _dis | |
@dis || raise(FFI::NullPointerError, "This Disassembler has been disposed of and can no longer be used") | |
end | |
end | |
if __FILE__ == $0 | |
arch = ARGV.shift || "i386" | |
off=0 | |
LLVMDisassembler.open(arch) do |dis| | |
dis.get_instructions(STDIN.read) do |ins, byt, bytsz| | |
raw = byt.map{|b| b.to_s(16).rjust(2,'0') }.join(' ') | |
puts "#{off.to_s(16).rjust(8,'0')} #{raw.ljust(16)} #{ins}" | |
off+=bytsz | |
end | |
end | |
puts off.to_s(16).rjust(8,'0') | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment