Created
December 16, 2009 04:12
-
-
Save daeken/257581 to your computer and use it in GitHub Desktop.
This file contains 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
require 'pp' | |
require 'stringio' | |
class Architecture | |
class << self | |
def opcodes(&block) | |
@@opcodes = {} | |
@@operandCount = {} | |
@@disassembly = {} | |
@@semantics = {} | |
class_eval &block | |
end | |
def opcode(opcd, mnem, *form) | |
@@opcodes[opcd] = mnem, form | |
@@operandCount[mnem] = form.size | |
end | |
def instruction(mnem, &block) | |
@@mnem = mnem | |
@@disassembly[mnem] = mnem, (0...@@operandCount[mnem]).to_a | |
block.call 0, 1, 2, 3, 4, 5, 6, 7 | |
end | |
def disassemble(mnem, *operands) | |
@@mnem = mnem | |
@@disassembly[mnem] = mnem, operands | |
end | |
def semantics(&block) | |
@@semantics[@@mnem] = block | |
end | |
def emit(exp) | |
@@exps[@@exps.size] = exp | |
end | |
end | |
def disassemble(code, base, off) | |
if code.is_a? File | |
fp = code | |
else | |
fp = StringIO.new code | |
end | |
fp.pos = off | |
insts = [] | |
while not fp.eof? | |
inst = disassemble_one fp, base + (fp.pos - off) | |
@@exps = [] | |
@@semantics[inst[0]].call(*(inst[1...inst.size])) | |
insts[insts.size] = inst, @@exps | |
end | |
pp insts | |
insts | |
end | |
end | |
class IAMeta < Architecture | |
opcodes do | |
opcode 0x00, :add, :Eb, :Gb | |
opcode 0x01, :add, :Ev, :Gv | |
opcode 0x02, :add, :Gb, :Eb | |
opcode 0x03, :add, :Gv, :Ev | |
opcode 0x04, :add, :al, :Ib | |
opcode 0x55, :push, :ebp | |
opcode 0x8B, :mov, :Gv, :Ev | |
end | |
instruction :add do |dest, src| | |
disassemble :add, dest, dest, src | |
semantics do |dest, a, b| | |
emit [:set, dest, [:+, a, b]] | |
emit [:set, :zf, [:==, dest, 0]] | |
end | |
end | |
instruction :push do |value| | |
semantics do |value| | |
emit [:sub, :esp, 4] # XXX: value.sizeof | |
emit [:set, [:deref, :esp], value] | |
end | |
end | |
instruction :mov do |dest, src| | |
semantics do |dest, src| | |
emit [:set, dest, src] | |
end | |
end | |
def decode_field(field, fp) | |
case field | |
when 0 then :eax | |
when 1 then :ecx | |
when 2 then :edx | |
when 3 then :ebx | |
when 4 | |
sib = fp.read(1).ord | |
scale, index, base = sib >> 6, (sib >> 3) & 7, sib & 7 | |
index = decode_field field, fp | |
base = decode_field field, fp | |
#case scale | |
#when | |
#end | |
when 5 then fp.read(4).unpack('i') | |
when 6 then :esi | |
when 7 then :edi | |
end | |
end | |
def modrm(fp) | |
return @modrm if @modrm != nil | |
byte = fp.read(1).ord | |
mod, rm, reg = byte >> 6, byte & 7, (byte >> 3) & 7 | |
rm = decode_field rm, fp | |
reg = decode_field reg, fp | |
#case mod | |
# when 0 | |
# | |
#end | |
end | |
def disassemble_one(fp, address) | |
opcd = fp.read(1).ord | |
if opcd == 0xFF | |
opcd = 0xFF00 | fp.read(1).ord | |
end | |
if @@opcodes.has_key? opcd | |
mnem, form = @@opcodes[opcd] | |
operands = form.map { |sub| | |
if sub[0] == sub[0].downcase then sub | |
else | |
@modrm = nil | |
case sub[0] | |
#when 'G' | |
# | |
when 'I' | |
case sub[1] | |
when 'b' then fp.read(1).ord | |
when 'w' then fp.read(2).unpack('S') | |
when 'd' | 'v' | 'z' then fp.read(4).unpack('I') | |
end | |
end | |
end | |
} | |
dispmnem, layout = @@disassembly[mnem] | |
layout.map! { |i| operands[i] } | |
[dispmnem] + layout | |
else | |
throw "Unknown opcode: #{opcd.to_s 16}" | |
end | |
end | |
end | |
puts 'Disassembling/decoding \x04\xFF' | |
IAMeta.new.disassemble("\x04\xFF\x55", 0, 0) | |
puts 'Disassembling/decoding Test.dll' | |
IAMeta.new.disassemble(File.open('Test\\Debug\\Test.dll'), 0x100111E0, 0x5E0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment