Skip to content

Instantly share code, notes, and snippets.

@daeken
Created December 16, 2009 04:12
Show Gist options
  • Save daeken/257581 to your computer and use it in GitHub Desktop.
Save daeken/257581 to your computer and use it in GitHub Desktop.
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