Land #3181, @dmaloney-r7's fix for metasm

bug/bundler_fix
jvazquez-r7 2014-04-02 16:38:33 -05:00
commit c892da44e8
No known key found for this signature in database
GPG Key ID: 38D99152B9352D83
30 changed files with 660 additions and 97 deletions

View File

@ -36,6 +36,7 @@ module Metasm
'Ia32' => 'cpu/ia32', 'MIPS' => 'cpu/mips', 'PowerPC' => 'cpu/ppc', 'ARM' => 'cpu/arm', 'Ia32' => 'cpu/ia32', 'MIPS' => 'cpu/mips', 'PowerPC' => 'cpu/ppc', 'ARM' => 'cpu/arm',
'X86_64' => 'cpu/x86_64', 'Sh4' => 'cpu/sh4', 'Dalvik' => 'cpu/dalvik', 'ARC' => 'cpu/arc', 'X86_64' => 'cpu/x86_64', 'Sh4' => 'cpu/sh4', 'Dalvik' => 'cpu/dalvik', 'ARC' => 'cpu/arc',
'Python' => 'cpu/python', 'Z80' => 'cpu/z80', 'CY16' => 'cpu/cy16', 'BPF' => 'cpu/bpf', 'Python' => 'cpu/python', 'Z80' => 'cpu/z80', 'CY16' => 'cpu/cy16', 'BPF' => 'cpu/bpf',
'MSP430' => 'cpu/msp430',
'C' => 'compile_c', 'C' => 'compile_c',
'MZ' => 'exe_format/mz', 'PE' => 'exe_format/pe', 'MZ' => 'exe_format/mz', 'PE' => 'exe_format/pe',
'ELF' => 'exe_format/elf', 'COFF' => 'exe_format/coff', 'ELF' => 'exe_format/elf', 'COFF' => 'exe_format/coff',

View File

@ -104,7 +104,7 @@ class ModRM
i = o i = o
s = 1 s = 1
when Expression when Expression
if o.op == :* and (o.rexpr.kind_of? Reg or o.lexpr.kind_of? Reg) if o.op == :* and (o.rexpr.kind_of?(Reg) or o.lexpr.kind_of?(Reg))
# scaled index # scaled index
raise otok, 'mrm: too many indexes' if i raise otok, 'mrm: too many indexes' if i
s = o.lexpr s = o.lexpr
@ -129,7 +129,9 @@ class ModRM
walker[regify[content.reduce]] walker[regify[content.reduce]]
# ensure found immediate is really an immediate # ensure found immediate is really an immediate
raise otok, 'mrm: reg in imm' if imm.kind_of? Expression and not imm.externals.grep(Reg).empty? raise otok, 'mrm: reg in imm' if imm.kind_of?(Expression) and not imm.externals.grep(Reg).empty?
raise otok, 'mrm: bad reg size' if b.kind_of?(Reg) and i.kind_of?(Reg) and b.sz != i.sz
# find default address size # find default address size
adsz = b ? b.sz : i ? i.sz : nil adsz = b ? b.sz : i ? i.sz : nil

View File

@ -0,0 +1,8 @@
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2009 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'metasm/main'
require 'metasm/cpu/msp430/decode'

View File

@ -0,0 +1,247 @@
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2010 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'metasm/cpu/msp430/opcodes'
require 'metasm/decode'
module Metasm
class MSP430
def build_opcode_bin_mask(op)
op.bin_mask = 0
op.fields.each_key { |f|
op.bin_mask |= @fields_mask[f] << @fields_shift[f]
}
op.bin_mask ^= 0xffff
end
def build_bin_lookaside
lookaside = Array.new(256) { [] }
opcode_list.each { |op|
build_opcode_bin_mask op
b = (op.bin >> 8) & 255
msk = (op.bin_mask >> 8) & 255
for i in b..(b | (255^msk))
lookaside[i] << op if i & msk == b & msk
end
}
lookaside
end
def decode_findopcode(edata)
di = DecodedInstruction.new(self)
val = edata.decode_imm(:u16, @endianness)
edata.ptr -= 2
di.opcode = @bin_lookaside[(val >> 8) & 0xff].find { |opcode| (val & opcode.bin_mask) == opcode.bin }
di if di.opcode
end
def decode_instr_op(edata, di)
before_ptr = edata.ptr
op = di.opcode
di.instruction.opname = op.name
val = edata.decode_imm(:u16, @endianness)
field_val = lambda{ |f|
(val >> @fields_shift[f]) & @fields_mask[f]
}
# must decode rs first
vals = {}
([:rs, :rd, :r_pc] & op.args).each { |a|
mod = { :rs => :as, :rd => :ad, :r_pc => :ad }[a]
mod = :as if mod == :ad and not op.fields[mod] # addop_macro1 -> rs + ad
if a == :r_pc
r = Reg.new(0)
else
r = Reg.new(field_val[a])
end
w = op.props[:byte] ? 1 : 2
case field_val[mod]
when 0
if r.i == 3 and a == :rs
vals[a] = Expression[0]
else
vals[a] = r
end
when 1
if r.i == 3 and a == :rs
vals[a] = Expression[1]
else
imm = edata.decode_imm(:u16, @endianness)
r = nil if r.i == 2 # [imm]
vals[a] = Memref.new(r, imm, w)
end
when 2
if r.i == 3
vals[a] = Expression[2]
elsif r.i == 2
vals[a] = Expression[4]
else
vals[a] = Memref.new(r, 0, w)
end
when 3
if r.i == 3
vals[a] = Expression[-1]
elsif r.i == 2
vals[a] = Expression[8]
elsif r.i == 0 # pc++
# XXX order wrt other edata.decode_imm ?
vals[a] = Expression[edata.decode_imm(:u16, @endianness)]
else
vals[a] = Memref.new(r, 0, w, true)
end
end
}
op.args.each { |a|
di.instruction.args << case a
when :joff; Expression[2 * Expression.make_signed(field_val[a], 10)]
when :rs, :rd, :r_pc; vals[a]
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
end
}
di.bin_length += edata.ptr - before_ptr
return if edata.ptr > edata.length
di
end
def decode_instr_interpret(di, addr)
if di.opcode.props[:setip] and di.opcode.name =~ /^j/
delta = di.instruction.args.last.reduce
arg = Expression[[addr, :+, di.bin_length], :+, delta].reduce
di.instruction.args[-1] = Expression[arg]
end
di
end
def backtrace_binding
@backtrace_binding ||= init_backtrace_binding
end
def init_backtrace_binding
@backtrace_binding ||= {}
opcode_list.map { |ol| ol.name }.uniq.each { |op|
@backtrace_binding[op] ||= case op
when 'mov'; lambda { |di, a0, a1| { a0 => Expression[a1] }}
when 'cmp', 'test'; lambda { |di, *a| {} } # TODO
when 'add', 'adc' ; lambda { |di, a0, a1| { a0 => Expression[a0, :+, a1] } }
when 'sub', 'sbc'; lambda { |di, a0, a1| { a0 => Expression[a0, :-, a1] } }
when 'and'; lambda { |di, a0, a1| { a0 => Expression[a0, :&, a1] } }
when 'or'; lambda { |di, a0, a1| { a0 => Expression[a0, :|, a1] } }
when 'xor'; lambda { |di, a0, a1| { a0 => Expression[a0, :^, a1] } }
when 'push'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[a0],
:sp => Expression[:sp, :-, 2] } }
when 'call'; lambda { |di, a0| { Indirection[:sp, 2] => Expression[di.next_addr],
:sp => Expression[:sp, :-, 2] } }
when 'pop'; lambda { |di, a0| { a0 => Expression[Indirection[:sp, 2]],
:sp => Expression[:sp, :+, 2] } }
when 'ret'; lambda { |di| { :sp => Expression[:sp, :+, 2] } }
when 'reti'; lambda { |di| { :sp => Expression[:sp, :+, 4] } }
when /^j/; lambda { |di, a0| {} }
end
}
@backtrace_binding
end
def get_backtrace_binding(di)
a = di.instruction.args.map { |arg|
case arg
when Reg; arg.symbolic
when Memref; arg.symbolic(di.address)
else arg
end
}
if binding = backtrace_binding[di.opcode.basename]
bd = binding[di, *a] || {}
di.instruction.args.grep(Memref).each { |m|
next unless r = m.base and m.postincr
r = m.base.symbolic
bd[r] ||= Expression[r, :+, m.size]
}
bd
else
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
{ :incomplete_binding => Expression[1] }
end
end
def get_xrefs_x(dasm, di)
return [] if not di.opcode.props[:setip]
case di.instruction.opname
when 'ret'
return [Indirection[:sp, 2, di.address]]
when 'reti'
return [Indirection[[:sp, :+, 2], 2, di.address]]
end
# XXX add pc, 42 ?
val = di.instruction.args[0]
case val
when Reg; val = val.symbolic
when Memref; val = val.symbolic(di.address)
end
[Expression[val]]
end
def backtrace_is_function_return(expr, di=nil)
expr = Expression[expr].reduce_rec
expr.kind_of?(Indirection) and expr.len == 2 and expr.target == Expression[:sp]
end
# updates the function backtrace_binding
# if the function is big and no specific register is given, do nothing (the binding will be lazily updated later, on demand)
def backtrace_update_function_binding(dasm, faddr, f, retaddrlist, *wantregs)
b = f.backtrace_binding
bt_val = lambda { |r|
next if not retaddrlist
b[r] = Expression::Unknown
bt = []
retaddrlist.each { |retaddr|
bt |= dasm.backtrace(Expression[r], retaddr, :include_start => true,
:snapshot_addr => faddr, :origin => retaddr)
}
if bt.length != 1
b[r] = Expression::Unknown
else
b[r] = bt.first
end
}
if not wantregs.empty?
wantregs.each(&bt_val)
else
bt_val[:sp]
end
b
end
def replace_instr_arg_immediate(i, old, new)
i.args.map! { |a|
case a
when Expression; a == old ? new : Expression[a.bind(old => new).reduce]
when Memref
a.base = (a.base == old ? new : Expression[a.base.bind(old => new).reduce]) if a.base.kind_of?(Expression)
a
else a
end
}
end
end
end

View File

@ -0,0 +1,62 @@
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2010 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'metasm/main'
module Metasm
class MSP430 < CPU
def initialize(e = :little)
super()
@endianness = e
@size = 16
end
class Reg
include Renderable
Sym = (4..15).inject(0 => :pc, 1 => :sp, 2 => :flags, 3 => :rzero) { |h, i| h.update i => "r#{i}".to_sym }
attr_accessor :i
def initialize(i) ; @i = i end
def symbolic ; Sym[@i] end
def render ; [Sym[@i].to_s] end
def ==(o) ; o.class == self.class and o.i == @i end
end
class Memref
attr_accessor :base, :offset, :size, :postincr
def initialize(base, offset = 0, size = nil, postincr = false)
@base = base
@offset = Expression[offset]
@size = size
@postincr = postincr
end
def symbolic(orig=nil)
r = @base.symbolic if @base
e = Expression[r, :+, @offset].reduce
Indirection[e, (@size || 1), orig]
end
include Renderable
def render
b = @base
b = @base.to_s + '++' if @base and @postincr
p = Expression[b, :+, @offset].reduce
Indirection[p, @size].render
end
end
def init_opcode_list
init
end
def dbg_register_list
@dbg_register_list ||= Reg::Sym.sort.transpose.last
end
end
end

View File

@ -0,0 +1,101 @@
# This file is part of Metasm, the Ruby assembly manipulation suite
# Copyright (C) 2006-2010 Yoann GUILLOT
#
# Licence is LGPL, see LICENCE in the top-level directory
require 'metasm/cpu/msp430/main'
module Metasm
class MSP430
def addop(name, bin, *args)
o = Opcode.new name, bin
args.each { |a|
o.args << a if @valid_args[a]
o.props[a] = true if @valid_props[a]
o.fields[a] = [@fields_mask[a], @fields_shift[a]] if @fields_mask[a]
}
@opcode_list << o
end
def init
@opcode_list = []
@fields_mask = {
:as => 3, # adressing mode
:ad => 1, # adressing mode
:rd => 0xf,
:rs => 0xf,
:joff => 0x3ff, # signed offset for jumps
}
@fields_shift = {
:as => 4,
:ad => 7,
:rd => 0,
:rs => 8,
:joff => 0,
}
@valid_args = { :r_pc => true, :rd => true, :rs => true, :joff => true }
@valid_props = { :setip => true, :stopexec => true, :saveip => true, :byte => true }
# https://en.wikipedia.org/wiki/TI_MSP430
addop_macro1 'rrc', 0, :byte
addop_macro1 'swpb', 1
addop_macro1 'rra', 2, :byte
addop_macro1 'sxt', 3
addop_macro1 'push', 4, :byte
addop_macro1 'call', 5, :setip, :stopexec, :saveip
addop 'reti', 0b000100_110_0000000
addop_macro2 'jnz', 0
addop_macro2 'jz', 1
addop_macro2 'jnc', 2
addop_macro2 'jc', 3
addop_macro2 'jb', 4 # 'jn' jump if negative => jl unsigned ?
addop_macro2 'jge', 5
addop_macro2 'jl', 6
addop_macro2 'jmp', 7, :stopexec
addop 'ret', 0x4130, :setip, :stopexec # mov pc, [sp++]
addop 'pop', 0x4130, :rd, :ad # mov rd, [sp++]
addop_macro3 'mov', 4
addop_macro3 'add', 5
addop_macro3 'adc', 6 # 'addc'
addop_macro3 'sbc', 7
addop_macro3 'sub', 8
addop_macro3 'cmp', 9
addop_macro3 'dadd',10 # decimal add with carry
addop_macro3 'test',11 # 'bit'
addop_macro3 'andn',12 # 'bic'
addop_macro3 'or', 13 # 'bis'
addop_macro3 'xor', 14
addop_macro3 'and', 15
end
def addop_macro1(name, bin, *props)
if props.delete :byte
addop_byte name, (0b000100 << 10) | (bin << 7), :as, :rd, *props
else
addop name, (0b000100 << 10) | (bin << 7), :as, :rd, *props
end
end
def addop_macro2(name, bin, *props)
addop name, (0b001 << 13) | (bin << 10), :joff, :setip, *props
end
def addop_macro3(name, bin, *props)
addop_byte name, (bin << 12), :r_pc, :ad, :as, :rs, :setip, :stopexec # dst == pc
addop_byte name, (bin << 12), :rd, :ad, :as, :rs
end
def addop_byte(name, bin, *props)
addop name, bin, *props
addop name + '.b', bin | (1 << 6), :byte, *props
end
end
end

View File

@ -39,6 +39,8 @@ class Sh4
end end
def decode_findopcode(edata) def decode_findopcode(edata)
return if edata.ptr >= edata.length
di = DecodedInstruction.new(self) di = DecodedInstruction.new(self)
val = edata.decode_imm(:u16, @endianness) val = edata.decode_imm(:u16, @endianness)
edata.ptr -= 2 edata.ptr -= 2

View File

@ -594,6 +594,7 @@ class CCompiler < C::Compiler
l = c_cexpr_inner(expr.lexpr) l = c_cexpr_inner(expr.lexpr)
l = make_volatile(l, expr.type) l = make_volatile(l, expr.type)
r = c_cexpr_inner(expr.rexpr) r = c_cexpr_inner(expr.rexpr)
r = make_volatile(r, expr.type) if r.kind_of?(ModRM) and r.sz != l.sz
unuse r unuse r
if expr.lexpr.type.integral? or expr.lexpr.type.pointer? if expr.lexpr.type.integral? or expr.lexpr.type.pointer?
instr 'cmp', l, i_to_i32(r) instr 'cmp', l, i_to_i32(r)
@ -790,6 +791,7 @@ class CCompiler < C::Compiler
end end
instr 'mov', l, ll instr 'mov', l, ll
else else
r = make_volatile(r, type) if r.kind_of?(ModRM) and r.sz != l.sz
instr 'imul', l, r instr 'imul', l, r
end end
unuse r unuse r
@ -876,6 +878,8 @@ class CCompiler < C::Compiler
l = c_cexpr_inner(expr.lexpr) l = c_cexpr_inner(expr.lexpr)
r = c_cexpr_inner(expr.rexpr) r = c_cexpr_inner(expr.rexpr)
r = make_volatile(r, expr.type) if r.kind_of? ModRM and l.kind_of? ModRM r = make_volatile(r, expr.type) if r.kind_of? ModRM and l.kind_of? ModRM
r = make_volatile(r, expr.type) if r.kind_of?(ModRM) and r.sz != l.sz
l = make_volatile(l, expr.type) if l.kind_of?(ModRM)
if l.kind_of? Expression if l.kind_of? Expression
o = { :< => :>, :> => :<, :>= => :<=, :<= => :>= }[o] || o o = { :< => :>, :> => :<, :>= => :<=, :<= => :>= }[o] || o
l, r = r, l l, r = r, l

View File

@ -93,6 +93,9 @@ class AOut < ExeFormat
def encode_byte(w) Expression[w].encode(:u8 , @endianness) end def encode_byte(w) Expression[w].encode(:u8 , @endianness) end
def encode_half(w) Expression[w].encode(:u16, @endianness) end def encode_half(w) Expression[w].encode(:u16, @endianness) end
def encode_word(w) Expression[w].encode(:u32, @endianness) end def encode_word(w) Expression[w].encode(:u32, @endianness) end
def sizeof_byte ; 1 ; end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def initialize(cpu = nil) def initialize(cpu = nil)
@endianness = cpu ? cpu.endianness : :little @endianness = cpu ? cpu.endianness : :little

View File

@ -57,6 +57,7 @@ class Bflt < ExeFormat
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def encode_word(w) Expression[w].encode(:u32, @endianness) end def encode_word(w) Expression[w].encode(:u32, @endianness) end
def sizeof_word ; 4 ; end
attr_accessor :endianness attr_accessor :endianness
def initialize(cpu = nil) def initialize(cpu = nil)

View File

@ -140,7 +140,7 @@ class COFF < ExeFormat
bytes :link_ver_maj, :link_ver_min bytes :link_ver_maj, :link_ver_min
words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code
# base_of_data does not exist in 64-bit # base_of_data does not exist in 64-bit
new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, 0) new_field(:base_of_data, lambda { |exe, hdr| exe.decode_word if exe.bitsize != 64 }, lambda { |exe, hdr, val| exe.encode_word(val) if exe.bitsize != 64 }, lambda { |exe, hdr| exe.bitsize != 64 ? 4 : 0 }, 0)
# NT-specific fields # NT-specific fields
xword :image_base xword :image_base
words :sect_align, :file_align words :sect_align, :file_align
@ -413,6 +413,11 @@ class COFF < ExeFormat
end end
def shortname; 'coff'; end def shortname; 'coff'; end
def sizeof_byte ; 1 ; end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def sizeof_xword ; @bitsize == 32 ? 4 : 8 ; end
end end
# the COFF archive file format # the COFF archive file format
@ -448,6 +453,9 @@ class COFFArchive < ExeFormat
def member(name) def member(name)
@members.find { |m| m.name == name } @members.find { |m| m.name == name }
end end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
end end
end end

View File

@ -847,6 +847,7 @@ class COFFArchive
ar.encoded.ptr += 1 if @size & 1 == 1 ar.encoded.ptr += 1 if @size & 1 == 1
end end
# TODO XXX are those actually used ?
def decode_half ; @encoded.decode_imm(:u16, :big) end def decode_half ; @encoded.decode_imm(:u16, :big) end
def decode_word ; @encoded.decode_imm(:u32, :big) end def decode_word ; @encoded.decode_imm(:u32, :big) end

View File

@ -43,6 +43,7 @@ class DEX < ExeFormat
class SerialStruct < Metasm::SerialStruct class SerialStruct < Metasm::SerialStruct
# TODO move uleb/sleb to new_field for sizeof
new_int_field :u2, :u4, :uleb, :sleb new_int_field :u2, :u4, :uleb, :sleb
end end
@ -328,6 +329,8 @@ class DEX < ExeFormat
def encode_u4(val) Expression[val].encode(:u32, @endianness) end def encode_u4(val) Expression[val].encode(:u32, @endianness) end
def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def sizeof_u2 ; 2 ; end
def sizeof_u4 ; 4 ; end
def decode_uleb(ed = @encoded, signed=false) def decode_uleb(ed = @encoded, signed=false)
v = s = 0 v = s = 0
while s < 5*7 while s < 5*7

View File

@ -26,6 +26,7 @@ class Dol < ExeFormat
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def encode_word(w) Expression[w].encode(:u32, @endianness) end def encode_word(w) Expression[w].encode(:u32, @endianness) end
def sizeof_word ; 4 ; end
def initialize(cpu = nil) def initialize(cpu = nil)
@endianness = :big @endianness = :big

View File

@ -21,29 +21,52 @@ class ELF < ExeFormat
TYPE_HIPROC = 0xffff TYPE_HIPROC = 0xffff
MACHINE = { MACHINE = {
0 => 'NONE', 1 => 'M32', 2 => 'SPARC', 3 => '386', 0 => 'NONE', 1 => 'M32', 2 => 'SPARC', 3 => '386',
4 => '68K', 5 => '88K', 6 => '486', 7 => '860', 4 => '68K', 5 => '88K', 6 => '486', 7 => '860',
8 => 'MIPS', 9 => 'S370', 10 => 'MIPS_RS3_LE', 8 => 'MIPS', 9 => 'S370', 10 => 'MIPS_RS3_LE',
15 => 'PARISC', 15 => 'PARISC', 17 => 'VPP500', 18 => 'SPARC32PLUS', 19 => '960',
17 => 'VPP500',18 => 'SPARC32PLUS', 19 => '960', 20 => 'PPC', 21 => 'PPC64', 22 => 'S390', 23 => 'SPU',
20 => 'PPC', 21 => 'PPC64', 22 => 'S390', 36 => 'V800', 37 => 'FR20', 38 => 'RH32', 39 => 'MCORE',
36 => 'V800', 37 => 'FR20', 38 => 'RH32', 39 => 'MCORE', 40 => 'ARM', 41 => 'ALPHA', 42 => 'SH', 43 => 'SPARCV9',
40 => 'ARM', 41 => 'ALPHA_STD', 42 => 'SH', 43 => 'SPARCV9', 44 => 'TRICORE', 45 => 'ARC', 46 => 'H8_300', 47 => 'H8_300H',
44 => 'TRICORE', 45 => 'ARC', 46 => 'H8_300', 47 => 'H8_300H', 48 => 'H8S', 49 => 'H8_500', 50 => 'IA_64', 51 => 'MIPS_X',
48 => 'H8S', 49 => 'H8_500', 50 => 'IA_64', 51 => 'MIPS_X',
52 => 'COLDFIRE', 53 => '68HC12', 54 => 'MMA', 55 => 'PCP', 52 => 'COLDFIRE', 53 => '68HC12', 54 => 'MMA', 55 => 'PCP',
56 => 'NCPU', 57 => 'NDR1', 58 => 'STARCORE', 59 => 'ME16', 56 => 'NCPU', 57 => 'NDR1', 58 => 'STARCORE', 59 => 'ME16',
60 => 'ST100', 61 => 'TINYJ', 62 => 'X86_64', 63 => 'PDSP', 60 => 'ST100', 61 => 'TINYJ', 62 => 'X86_64', 63 => 'PDSP',
66 => 'FX66', 67 => 'ST9PLUS', 64 => 'PDP10', 65 => 'PDP11', 66 => 'FX66', 67 => 'ST9PLUS',
68 => 'ST7', 69 => '68HC16', 70 => '68HC11', 71 => '68HC08', 68 => 'ST7', 69 => '68HC16', 70 => '68HC11', 71 => '68HC08',
72 => '68HC05',73 => 'SVX', 74 => 'ST19', 75 => 'VAX', 72 => '68HC05',73 => 'SVX', 74 => 'ST19', 75 => 'VAX',
76 => 'CRIS', 77 => 'JAVELIN',78 => 'FIREPATH', 79 => 'ZSP', 76 => 'CRIS', 77 => 'JAVELIN',78 => 'FIREPATH', 79 => 'ZSP',
80 => 'MMIX', 81 => 'HUANY', 82 => 'PRISM', 83 => 'AVR', 80 => 'MMIX', 81 => 'HUANY', 82 => 'PRISM', 83 => 'AVR',
84 => 'FR30', 85 => 'D10V', 86 => 'D30V', 87 => 'V850', 84 => 'FR30', 85 => 'D10V', 86 => 'D30V', 87 => 'V850',
88 => 'M32R', 89 => 'MN10300',90 => 'MN10200',91 => 'PJ', 88 => 'M32R', 89 => 'MN10300',90 => 'MN10200',91 => 'PJ',
92 => 'OPENRISC', 93 => 'ARC_A5', 94 => 'XTENSA', 92 => 'OPENRISC', 93 => 'ARC_A5', 94 => 'XTENSA', 95 => 'VIDEOCORE',
99 => 'PJ', 96 => 'TMM_GPP', 97 => 'NS32K', 98 => 'TPC', 99 => 'SNP1K',
0x9026 => 'ALPHA' 100 => 'ST200', 101 => 'IP2K', 102 => 'MAX', 103 => 'CR',
104 => 'F2MC16', 105 => 'MSP430', 106 => 'BLACKFIN', 107 => 'SE_C33',
108 => 'SEP', 109 => 'ARCA', 110 => 'UNICORE', 111 => 'EXCESS',
112 => 'DXP', 113 => 'ALTERA_NIOS2', 114 => 'CRX', 115 => 'XGATE',
116 => 'C166', 117 => 'M16C', 118 => 'DSPIC30F', 119 => 'CE',
120 => 'M32C',
131 => 'TSK3000', 132 => 'RS08', 133 => 'SHARC',
134 => 'ECOG2', 135 => 'SCORE7', 136 => 'DSP24', 137 => 'VIDEOCORE3',
138 => 'LATTICEMICO32', 139 => 'SE_C17', 140 => 'TI_C6000', 141 => 'TI_C2000',
142 => 'TI_C5500',
160 => 'MMDSP_PLUS', 161 => 'CYPRESS_M8C', 162 => 'R32C', 163 => 'TRIMEDIA',
164 => 'QDSP6', 165 => '8051', 166 => 'STXP7X', 167 => 'NDS32',
168 => 'ECOG1', 169 => 'MAXQ30', 170 => 'XIMO16', 171 => 'MANIK',
172 => 'CRAYNV2', 173 => 'RX', 174 => 'METAG', 175 => 'MCST_ELBRUS',
176 => 'ECOG16', 177 => 'CR16', 178 => 'ETPU', 179 => 'SLE9X',
180 => 'L10M', 181 => 'K10M', 182 => 'INTEL_RESV', 183 => 'AARCH64',
184 => 'ARM_RESV', 185 => 'AVR32', 186 => 'STM8', 187 => 'TILE64',
188 => 'TILEPRO', 189 => 'MICROBLAZE', 190 => 'CUDA', 191 => 'TILEGX',
192 => 'CLOUDSHIELD', 193 => 'COREA_1ST', 194 => 'COREA_2ND', 195 => 'ARC_COMPACT2',
196 => 'OPEN8', 197 => 'RL78', 198 => 'VIDEOCORE5', 199 => '78KOR',
200 => '56800EX', 201 => 'BA1', 202 => 'BA2', 203 => 'XCORE',
204 => 'MCHP_PIC', 205 => 'INTEL205', 206 => 'INTEL206', 207 => 'INTEL207',
208 => 'INTEL208', 209 => 'INTEL209', 210 => 'KM32', 211 => 'KMX32',
212 => 'KMX16', 213 => 'KMX8', 214 => 'KVARC', 215 => 'CDP',
216 => 'COGE', 217 => 'COOL', 218 => 'NORC',
} }
FLAGS = { FLAGS = {
@ -394,11 +417,6 @@ class ELF < ExeFormat
word :flags word :flags
fld_bits(:flags) { |elf, hdr| FLAGS[hdr.machine] || {} } fld_bits(:flags) { |elf, hdr| FLAGS[hdr.machine] || {} }
halfs :ehsize, :phentsize, :phnum, :shentsize, :shnum, :shstrndx halfs :ehsize, :phentsize, :phnum, :shentsize, :shnum, :shstrndx
def self.size elf
x = elf.bitsize >> 3
40 + 3*x
end
end end
class Segment < SerialStruct class Segment < SerialStruct
@ -412,11 +430,6 @@ class ELF < ExeFormat
else Segment64 else Segment64
end end
end end
def self.size elf
x = elf.bitsize >> 3
8 + 6*x
end
end end
class Segment32 < Segment class Segment32 < Segment
@ -453,11 +466,6 @@ class ELF < ExeFormat
xword :entsize xword :entsize
attr_accessor :name, :encoded attr_accessor :name, :encoded
def self.size elf
x = elf.bitsize >> 3
16 + 6*x
end
end end
class Symbol < SerialStruct class Symbol < SerialStruct
@ -471,11 +479,6 @@ class ELF < ExeFormat
attr_accessor :name_p, :value, :size, :bind, :type, :other, :shndx attr_accessor :name_p, :value, :size, :bind, :type, :other, :shndx
attr_accessor :name, :thunk attr_accessor :name, :thunk
def self.size elf
x = elf.bitsize >> 3
8 + 2*x
end
end end
class Symbol32 < Symbol class Symbol32 < Symbol
@ -510,12 +513,6 @@ class ELF < ExeFormat
end end
def addend ; end def addend ; end
def self.size elf
x = elf.bitsize >> 3
2*x
end
end end
class Relocation32 < Relocation class Relocation32 < Relocation
addr :offset addr :offset
@ -538,11 +535,6 @@ class ELF < ExeFormat
else RelocationAddend64 else RelocationAddend64
end end
end end
def self.size elf
x = elf.bitsize >> 3
3*x
end
end end
class RelocationAddend32 < RelocationAddend class RelocationAddend32 < RelocationAddend
addr :offset addr :offset
@ -669,6 +661,15 @@ class ELF < ExeFormat
end end
def shortname; 'elf'; end def shortname; 'elf'; end
def sizeof_byte ; 1 ; end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def sizeof_sword ; 4 ; end
def sizeof_xword ; @bitsize == 32 ? 4 : 8 ; end
alias sizeof_sxword sizeof_xword
alias sizeof_addr sizeof_xword
alias sizeof_off sizeof_xword
end end
class LoadedELF < ELF class LoadedELF < ELF
@ -721,6 +722,9 @@ class FatELF < ExeFormat
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end
def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_qword(edata = @encoded) edata.decode_imm(:u64, @endianness) end def decode_qword(edata = @encoded) edata.decode_imm(:u64, @endianness) end
def sizeof_byte ; 1 ; end
def sizeof_word ; 2 ; end
def sizeof_qword ; 8 ; end
attr_accessor :header, :list attr_accessor :header, :list
def initialize def initialize

View File

@ -106,7 +106,7 @@ class ELF
def decode_header(off = 0, decode_phdr=true, decode_shdr=true) def decode_header(off = 0, decode_phdr=true, decode_shdr=true)
@encoded.ptr = off @encoded.ptr = off
@header.decode self @header.decode self
raise InvalidExeFormat, "Invalid elf header size: #{@header.ehsize}" if Header.size(self) != @header.ehsize raise InvalidExeFormat, "Invalid elf header size: #{@header.ehsize}" if Header.sizeof(self) != @header.ehsize
if decode_phdr and @header.phoff != 0 if decode_phdr and @header.phoff != 0
decode_program_header(@header.phoff+off) decode_program_header(@header.phoff+off)
end end
@ -118,7 +118,7 @@ class ELF
# decodes the section header # decodes the section header
# section names are read from shstrndx if possible # section names are read from shstrndx if possible
def decode_section_header(off = @header.shoff) def decode_section_header(off = @header.shoff)
raise InvalidExeFormat, "Invalid elf section header size: #{@header.shentsize}" if Section.size(self) != @header.shentsize raise InvalidExeFormat, "Invalid elf section header size: #{@header.shentsize}" if Section.sizeof(self) != @header.shentsize
@encoded.add_export new_label('section_header'), off @encoded.add_export new_label('section_header'), off
@encoded.ptr = off @encoded.ptr = off
@sections = [] @sections = []
@ -137,7 +137,7 @@ class ELF
# decodes the program header table # decodes the program header table
# marks the elf entrypoint as an export of +self.encoded+ # marks the elf entrypoint as an export of +self.encoded+
def decode_program_header(off = @header.phoff) def decode_program_header(off = @header.phoff)
raise InvalidExeFormat, "Invalid elf program header size: #{@header.phentsize}" if Segment.size(self) != @header.phentsize raise InvalidExeFormat, "Invalid elf program header size: #{@header.phentsize}" if Segment.sizeof(self) != @header.phentsize
@encoded.add_export new_label('program_header'), off @encoded.add_export new_label('program_header'), off
@encoded.ptr = off @encoded.ptr = off
@segments = [] @segments = []
@ -232,13 +232,13 @@ class ELF
# no way to get the number of non-exported symbols from what we have here # no way to get the number of non-exported symbols from what we have here
# so we'll decode all relocs and use the largest index we see.. # so we'll decode all relocs and use the largest index we see..
rels = [] rels = []
if @encoded.ptr = @tag['REL'] and @tag['RELENT'] == Relocation.size(self) if @encoded.ptr = @tag['REL'] and @tag['RELENT'] == Relocation.sizeof(self)
p_end = @encoded.ptr + @tag['RELSZ'] p_end = @encoded.ptr + @tag['RELSZ']
while @encoded.ptr < p_end while @encoded.ptr < p_end
rels << Relocation.decode(self) rels << Relocation.decode(self)
end end
end end
if @encoded.ptr = @tag['RELA'] and @tag['RELAENT'] == RelocationAddend.size(self) if @encoded.ptr = @tag['RELA'] and @tag['RELAENT'] == RelocationAddend.sizeof(self)
p_end = @encoded.ptr + @tag['RELASZ'] p_end = @encoded.ptr + @tag['RELASZ']
while @encoded.ptr < p_end while @encoded.ptr < p_end
rels << RelocationAddend.decode(self) rels << RelocationAddend.decode(self)
@ -392,7 +392,7 @@ class ELF
def decode_segments_symbols def decode_segments_symbols
return unless @tag['STRTAB'] and @tag['STRSZ'] and @tag['SYMTAB'] and (@tag['HASH'] or @tag['GNU_HASH']) return unless @tag['STRTAB'] and @tag['STRSZ'] and @tag['SYMTAB'] and (@tag['HASH'] or @tag['GNU_HASH'])
raise "E: ELF: unsupported symbol entry size: #{@tag['SYMENT']}" if @tag['SYMENT'] != Symbol.size(self) raise "E: ELF: unsupported symbol entry size: #{@tag['SYMENT']}" if @tag['SYMENT'] != Symbol.sizeof(self)
# find number of symbols # find number of symbols
if @tag['HASH'] if @tag['HASH']
@ -427,7 +427,7 @@ class ELF
@encoded.ptr = sec.offset @encoded.ptr = sec.offset
syms = [] syms = []
raise 'Invalid symbol table' if sec.size > @encoded.length raise 'Invalid symbol table' if sec.size > @encoded.length
(sec.size / Symbol.size(self)).times { syms << Symbol.decode(self, strtab) } (sec.size / Symbol.sizeof(self)).times { syms << Symbol.decode(self, strtab) }
alreadysegs = true if @header.type == 'DYN' or @header.type == 'EXEC' alreadysegs = true if @header.type == 'DYN' or @header.type == 'EXEC'
alreadysyms = @symbols.inject({}) { |h, s| h.update s.name => true } if alreadysegs alreadysyms = @symbols.inject({}) { |h, s| h.update s.name => true } if alreadysegs
syms.each { |s| syms.each { |s|
@ -480,7 +480,7 @@ class ELF
def decode_segments_relocs def decode_segments_relocs
@relocations.clear @relocations.clear
if @encoded.ptr = @tag['REL'] if @encoded.ptr = @tag['REL']
raise "E: ELF: unsupported rel entry size #{@tag['RELENT']}" if @tag['RELENT'] != Relocation.size(self) raise "E: ELF: unsupported rel entry size #{@tag['RELENT']}" if @tag['RELENT'] != Relocation.sizeof(self)
p_end = @encoded.ptr + @tag['RELSZ'] p_end = @encoded.ptr + @tag['RELSZ']
while @encoded.ptr < p_end while @encoded.ptr < p_end
@relocations << Relocation.decode(self) @relocations << Relocation.decode(self)
@ -488,7 +488,7 @@ class ELF
end end
if @encoded.ptr = @tag['RELA'] if @encoded.ptr = @tag['RELA']
raise "E: ELF: unsupported rela entry size #{@tag['RELAENT'].inspect}" if @tag['RELAENT'] != RelocationAddend.size(self) raise "E: ELF: unsupported rela entry size #{@tag['RELAENT'].inspect}" if @tag['RELAENT'] != RelocationAddend.sizeof(self)
p_end = @encoded.ptr + @tag['RELASZ'] p_end = @encoded.ptr + @tag['RELASZ']
while @encoded.ptr < p_end while @encoded.ptr < p_end
@relocations << RelocationAddend.decode(self) @relocations << RelocationAddend.decode(self)
@ -935,6 +935,8 @@ class ELF
when 'PPC'; PPC.new when 'PPC'; PPC.new
when 'ARM'; ARM.new when 'ARM'; ARM.new
when 'SH'; Sh4.new when 'SH'; Sh4.new
when 'ARC_COMPACT'; ARC.new
when 'MSP430'; MSP430.new
else raise "unsupported cpu #{@header.machine}" else raise "unsupported cpu #{@header.machine}"
end end
end end

View File

@ -20,10 +20,10 @@ class ELF
@phoff ||= elf.segments.empty? ? 0 : elf.new_label('phdr') @phoff ||= elf.segments.empty? ? 0 : elf.new_label('phdr')
@shoff ||= elf.sections.length <= 1 ? 0 : elf.new_label('shdr') @shoff ||= elf.sections.length <= 1 ? 0 : elf.new_label('shdr')
@flags ||= [] @flags ||= []
@ehsize ||= Header.size(elf) @ehsize ||= Header.sizeof(elf)
@phentsize ||= Segment.size(elf) @phentsize ||= Segment.sizeof(elf)
@phnum ||= elf.segments.length @phnum ||= elf.segments.length
@shentsize ||= Section.size(elf) @shentsize ||= Section.sizeof(elf)
@shnum ||= elf.sections.length @shnum ||= elf.sections.length
super(elf) super(elf)
@ -247,7 +247,7 @@ class ELF
dynsym = Section.new dynsym = Section.new
dynsym.name = '.dynsym' dynsym.name = '.dynsym'
dynsym.type = 'DYNSYM' dynsym.type = 'DYNSYM'
dynsym.entsize = Symbol.size(self) dynsym.entsize = Symbol.sizeof(self)
dynsym.addralign = 4 dynsym.addralign = 4
dynsym.flags = ['ALLOC'] dynsym.flags = ['ALLOC']
dynsym.info = @symbols[1..-1].find_all { |s| s.bind == 'LOCAL' }.length + 1 dynsym.info = @symbols[1..-1].find_all { |s| s.bind == 'LOCAL' }.length + 1
@ -258,7 +258,7 @@ class ELF
@symbols.each { |s| dynsym.encoded << s.encode(self, strtab.encoded) } # needs all section indexes, as will be in the final section header @symbols.each { |s| dynsym.encoded << s.encode(self, strtab.encoded) } # needs all section indexes, as will be in the final section header
@tag['SYMTAB'] = label_at(dynsym.encoded, 0) @tag['SYMTAB'] = label_at(dynsym.encoded, 0)
@tag['SYMENT'] = Symbol.size(self) @tag['SYMENT'] = Symbol.sizeof(self)
encode_check_section_size dynsym encode_check_section_size dynsym
@ -294,7 +294,7 @@ class ELF
@tag['JMPREL'] = label_at(relplt.encoded, 0) @tag['JMPREL'] = label_at(relplt.encoded, 0)
@tag['PLTRELSZ'] = relplt.encoded.virtsize @tag['PLTRELSZ'] = relplt.encoded.virtsize
@tag['PLTREL'] = relplt.type = stype @tag['PLTREL'] = relplt.type = stype
@tag[stype + 'ENT'] = relplt.entsize = relplt.addralign = (stype == 'REL' ? Relocation.size(self) : RelocationAddend.size(self)) @tag[stype + 'ENT'] = relplt.entsize = relplt.addralign = (stype == 'REL' ? Relocation.sizeof(self) : RelocationAddend.sizeof(self))
encode_check_section_size relplt encode_check_section_size relplt
end end
@ -312,13 +312,13 @@ class ELF
rel.name = '.rel.dyn' rel.name = '.rel.dyn'
rel.type = 'REL' rel.type = 'REL'
rel.flags = ['ALLOC'] rel.flags = ['ALLOC']
rel.entsize = rel.addralign = Relocation.size(self) rel.entsize = rel.addralign = Relocation.sizeof(self)
encode_add_section rel encode_add_section rel
end end
rel.encoded = EncodedData.new rel.encoded = EncodedData.new
list.each { |r| rel.encoded << r.encode(self) } list.each { |r| rel.encoded << r.encode(self) }
@tag['REL'] = label_at(rel.encoded, 0) @tag['REL'] = label_at(rel.encoded, 0)
@tag['RELENT'] = Relocation.size(self) @tag['RELENT'] = Relocation.sizeof(self)
@tag['RELSZ'] = rel.encoded.virtsize @tag['RELSZ'] = rel.encoded.virtsize
encode_check_section_size rel encode_check_section_size rel
end end
@ -330,13 +330,13 @@ class ELF
rela.name = '.rela.dyn' rela.name = '.rela.dyn'
rela.type = 'RELA' rela.type = 'RELA'
rela.flags = ['ALLOC'] rela.flags = ['ALLOC']
rela.entsize = rela.addralign = RelocationAddend.size(self) rela.entsize = rela.addralign = RelocationAddend.sizeof(self)
encode_add_section rela encode_add_section rela
end end
rela.encoded = EncodedData.new rela.encoded = EncodedData.new
list.each { |r| rela.encoded << r.encode(self) } list.each { |r| rela.encoded << r.encode(self) }
@tag['RELA'] = label_at(rela.encoded, 0) @tag['RELA'] = label_at(rela.encoded, 0)
@tag['RELAENT'] = RelocationAddend.size(self) @tag['RELAENT'] = RelocationAddend.sizeof(self)
@tag['RELASZ'] = rela.encoded.virtsize @tag['RELASZ'] = rela.encoded.virtsize
encode_check_section_size rela encode_check_section_size rela
end end
@ -457,7 +457,7 @@ class ELF
plt.encoded << shellcode["jmp [#{base} + #{gotplt.encoded.length}]"] plt.encoded << shellcode["jmp [#{base} + #{gotplt.encoded.length}]"]
plt.encoded.add_export r.symbol.name+'_plt_default', plt.encoded.length plt.encoded.add_export r.symbol.name+'_plt_default', plt.encoded.length
reloffset = @relocations.find_all { |rr| rr.type == 'JMP_SLOT' }.length reloffset = @relocations.find_all { |rr| rr.type == 'JMP_SLOT' }.length
reloffset *= Relocation.size(self) if @bitsize == 32 reloffset *= Relocation.sizeof(self) if @bitsize == 32
plt.encoded << shellcode["push #{reloffset}\njmp metasm_plt_start"] plt.encoded << shellcode["push #{reloffset}\njmp metasm_plt_start"]
# transform the reloc PC32 => JMP_SLOT # transform the reloc PC32 => JMP_SLOT

View File

@ -30,6 +30,7 @@ class GameBoyRom < ExeFormat
def encode_byte(val) Expression[val].encode(:u8, @endianness) end def encode_byte(val) Expression[val].encode(:u8, @endianness) end
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end
def sizeof_byte ; 1 ; end
attr_accessor :header attr_accessor :header

View File

@ -292,6 +292,9 @@ class JavaClass < ExeFormat
def decode_u1(edata = @encoded) edata.decode_imm(:u8, @endianness) end def decode_u1(edata = @encoded) edata.decode_imm(:u8, @endianness) end
def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_u2(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_u4(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def sizeof_u1 ; 1 ; end
def sizeof_u2 ; 2 ; end
def sizeof_u4 ; 4 ; end
attr_accessor :header, :constant_pool, :class_info, :interfaces, :fields, :methods, :attributes attr_accessor :header, :constant_pool, :class_info, :interfaces, :fields, :methods, :attributes

View File

@ -511,6 +511,10 @@ class MachO < ExeFormat
def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def decode_xword(edata= @encoded) edata.decode_imm((@size == 32 ? :u32 : :u64), @endianness) end def decode_xword(edata= @encoded) edata.decode_imm((@size == 32 ? :u32 : :u64), @endianness) end
def sizeof_byte ; 1 ; end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def sizeof_xword ; @size == 32 ? 4 : 8 ; end
attr_accessor :endianness, :size attr_accessor :endianness, :size
@ -978,6 +982,7 @@ class UniversalBinary < ExeFormat
def encode_word(val) Expression[val].encode(:u32, @endianness) end def encode_word(val) Expression[val].encode(:u32, @endianness) end
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def sizeof_word ; 4 ; end
attr_accessor :endianness, :encoded, :header, :archive attr_accessor :endianness, :encoded, :header, :archive
def initialize def initialize

View File

@ -51,6 +51,7 @@ class MZ < ExeFormat
def encode_word(val) Expression[val].encode(:u16, @endianness) end def encode_word(val) Expression[val].encode(:u16, @endianness) end
# decodes a 16bits word from self.encoded # decodes a 16bits word from self.encoded
def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def sizeof_word ; 2 ; end
attr_accessor :endianness, :header, :source attr_accessor :endianness, :header, :source

View File

@ -70,6 +70,9 @@ class NDS < ExeFormat
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end
def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_half(edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
def sizeof_byte ; 1 ; end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
attr_accessor :header, :icon, :arm9, :arm7 attr_accessor :header, :icon, :arm9, :arm7

View File

@ -297,6 +297,35 @@ EOS
} if export } if export
syms syms
end end
# compute the pe-sha1 or pe-sha256 of the binary
# argument should be a Digest::SHA1 (from digest/sha1) or a Digest::SHA256 (from digest/sha2)
# returns the hex checksum
def pehash(digest)
off0 = 0
off1 = @coff_offset + @header.sizeof(self) + @optheader.offsetof(self, :checksum)
dir_ct_idx = DIRECTORIES.index('certificate_table')
if @optheader.numrva > dir_ct_idx
off2 = @coff_offset + @header.sizeof(self) + @optheader.sizeof(self) + 8*dir_ct_idx
ct_size = @encoded.data[off2, 8].unpack('V*')[1]
off3 = @encoded.length - ct_size
else
off4 = @encoded.length
end
digest << @encoded.data[off0 ... off1].to_str
digest << @encoded.data[off1+4 ... off2].to_str if off2
digest << @encoded.data[off2+8 ... off3].to_str if off2 and off3 > off2+8
digest << @encoded.data[off1+4 ... off4].to_str if off4
digest << ("\0" * (8 - (@encoded.length & 7))) if @encoded.length & 7 != 0
digest.hexdigest
end
def self.pehash(path, digest)
decode_file_header(path).pehash(digest)
end
end end
# an instance of a PE file, loaded in memory # an instance of a PE file, loaded in memory
@ -436,5 +465,9 @@ class LoadedPE < PE
dump.imports.last.imports << i dump.imports.last.imports << i
end end
end end
def pehash(digest)
raise "cannot compute a PEhash from memory image"
end
end end
end end

View File

@ -27,6 +27,9 @@ class PYC < ExeFormat
def decode_half(edata=@encoded) edata.decode_imm(:u16, @endianness) end def decode_half(edata=@encoded) edata.decode_imm(:u16, @endianness) end
def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end
def decode_long(edata=@encoded) edata.decode_imm(:i32, @endianness) end def decode_long(edata=@encoded) edata.decode_imm(:i32, @endianness) end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def sizeof_long ; 4 ; end
# file header # file header
attr_accessor :header attr_accessor :header

View File

@ -13,19 +13,20 @@ class SerialStruct
NAME=0 NAME=0
DECODE=1 DECODE=1
ENCODE=2 ENCODE=2
DEFVAL=3 SIZEOF=3
ENUM=4 DEFVAL=4
BITS=5 ENUM=5
BITS=6
class << self class << self
# defines a new field # defines a new field
# adds an accessor # adds an accessor
def new_field(name, decode, encode, defval, enum=nil, bits=nil) def new_field(name, decode, encode, sizeof, defval, enum=nil, bits=nil)
if name if name
attr_accessor name attr_accessor name
name = "@#{name}".to_sym name = "@#{name}".to_sym
end end
(@@fields[self] ||= []) << [name, decode, encode, defval, enum, bits] (@@fields[self] ||= []) << [name, decode, encode, sizeof, defval, enum, bits]
end end
# creates a field constructor for a simple integer # creates a field constructor for a simple integer
@ -34,7 +35,7 @@ class << self
recv = class << self ; self ; end recv = class << self ; self ; end
types.each { |type| types.each { |type|
recv.send(:define_method, type) { |name, *args| recv.send(:define_method, type) { |name, *args|
new_field(name, "decode_#{type}".to_sym, "encode_#{type}".to_sym, args[0] || 0, args[1]) new_field(name, "decode_#{type}".to_sym, "encode_#{type}".to_sym, "sizeof_#{type}".to_sym, args[0] || 0, args[1])
} }
# shortcut to define multiple fields of this type with default values # shortcut to define multiple fields of this type with default values
@ -49,19 +50,20 @@ class << self
# virtual field, handled explicitly in a custom encode/decode # virtual field, handled explicitly in a custom encode/decode
def virtual(*a) def virtual(*a)
a.each { |f| a.each { |f|
new_field(f, nil, nil, nil) new_field(f, nil, nil, nil, nil)
} }
end end
# a fixed-size memory chunk # a fixed-size memory chunk
def mem(name, len, defval='') def mem(name, len, defval='')
new_field(name, lambda { |exe, me| exe.curencoded.read(len) }, lambda { |exe, me, val| val[0, len].ljust(len, 0.chr) }, defval) new_field(name, lambda { |exe, me| exe.curencoded.read(len) }, lambda { |exe, me, val| val[0, len].ljust(len, 0.chr) }, lambda { |exe, me| len }, defval)
end end
# a fixed-size string, 0-padded # a fixed-size string, 0-padded
def str(name, len, defval='') def str(name, len, defval='')
e = lambda { |exe, me, val| val[0, len].ljust(len, 0.chr) }
d = lambda { |exe, me| v = exe.curencoded.read(len) ; v = v[0, v.index(?\0)] if v.index(?\0) ; v } d = lambda { |exe, me| v = exe.curencoded.read(len) ; v = v[0, v.index(?\0)] if v.index(?\0) ; v }
new_field(name, d, e, defval) e = lambda { |exe, me, val| val[0, len].ljust(len, 0.chr) }
s = lambda { |exe, me| len }
new_field(name, d, e, s, defval)
end end
# 0-terminated string # 0-terminated string
def strz(name, defval='') def strz(name, defval='')
@ -70,7 +72,8 @@ class << self
ed.read(ed.data.index(?\0, ed.ptr)-ed.ptr+1).chop ed.read(ed.data.index(?\0, ed.ptr)-ed.ptr+1).chop
} }
e = lambda { |exe, me, val| val + 0.chr } e = lambda { |exe, me, val| val + 0.chr }
new_field(name, d, e, defval) s = lambda { |exe, val| val.length + 1 }
new_field(name, d, e, s, defval)
end end
# field access # field access
@ -100,7 +103,7 @@ class << self
d = lambda { |exe, me| @bitfield_val = exe.send("decode_#{inttype}") } d = lambda { |exe, me| @bitfield_val = exe.send("decode_#{inttype}") }
# reset a temp var # reset a temp var
e = lambda { |exe, me, val| @bitfield_val = 0 ; nil } e = lambda { |exe, me, val| @bitfield_val = 0 ; nil }
new_field(nil, d, e, nil) new_field(nil, d, e, 0, nil)
h = h.sort h = h.sort
h.length.times { |i| h.length.times { |i|
@ -114,7 +117,7 @@ class << self
d = lambda { |exe, me| (@bitfield_val >> off) & mask } d = lambda { |exe, me| (@bitfield_val >> off) & mask }
# update the temp var with the field value, return nil # update the temp var with the field value, return nil
e = lambda { |exe, me, val| @bitfield_val |= (val & mask) << off ; nil } e = lambda { |exe, me, val| @bitfield_val |= (val & mask) << off ; nil }
new_field(name, d, e, 0) new_field(name, d, e, 0, 0)
} }
# free the temp var # free the temp var
@ -125,7 +128,8 @@ class << self
@bitfield_val = nil @bitfield_val = nil
exe.send("encode_#{inttype}", val) exe.send("encode_#{inttype}", val)
} }
new_field(nil, d, e, nil) s = lambda { |exe, me| exe.send("sizeof_#{inttype}") }
new_field(nil, d, e, s, nil)
end end
# inject a hook to be run during the decoding process # inject a hook to be run during the decoding process
@ -217,6 +221,39 @@ end # class methods
ed ed
end end
# size of the structure = fields.sum { size of field }
def sizeof(exe)
struct_fields(exe).inject(0) { |off, f|
case sz = f[SIZEOF]
when Proc; sz = sz[exe, self]
when Symbol; sz = exe.send(sz)
when Array; sz = exe.send(*sz)
when nil; sz = 0
end
off + sz
}
end
# offset (in bytes) of the structure member
# for bitfields, return the byte offset of the whole bitfield
def offsetof(exe, fld)
fld2 = fld
fld2 = "@#{fld}".to_sym if fld.to_s[0] != ?@
off = 0
struct_fields(exe).each { |f|
return off if f[NAME] == fld or f[NAME] == fld2
case sz = f[SIZEOF]
when Proc; sz = sz[exe, self]
when Symbol; sz = exe.send(sz)
when Array; sz = exe.send(*sz)
when nil; sz = 0
end
off += sz
}
raise 'unknown field'
end
# shortcut to create a new instance and decode it # shortcut to create a new instance and decode it
def self.decode(*a) def self.decode(*a)
s = new s = new
@ -224,6 +261,14 @@ end # class methods
s s
end end
def self.sizeof(exe)
new.sizeof(exe)
end
def self.offsetof(exe, fld)
new.offsetof(exe, fld)
end
def dump(e, a) def dump(e, a)
case e case e
when Integer; e >= 0x100 ? '0x%X'%e : e when Integer; e >= 0x100 ? '0x%X'%e : e

View File

@ -164,6 +164,11 @@ class SWF < ExeFormat
def encode_u32(w) Expression[w].encode(:u32, @endianness) end def encode_u32(w) Expression[w].encode(:u32, @endianness) end
def encode_f16(w) Expression[(w*256).to_i].encode(:u16, @endianness) end def encode_f16(w) Expression[(w*256).to_i].encode(:u16, @endianness) end
def encode_f32(w) Expression[(w*65536).to_i].encode(:u32, @endianness) end def encode_f32(w) Expression[(w*65536).to_i].encode(:u32, @endianness) end
def sizeof_u8 ; 1 ; end
def sizeof_u16 ; 2 ; end
def sizeof_u32 ; 4 ; end
def sizeof_f16 ; 2 ; end
def sizeof_f32 ; 4 ; end
attr_accessor :endianness attr_accessor :endianness
def initialize(cpu = nil) def initialize(cpu = nil)

View File

@ -51,7 +51,7 @@ class XCoff < ExeFormat
@nsec ||= xcoff.sections.size @nsec ||= xcoff.sections.size
@symptr ||= xcoff.symbols ? xcoff.new_label('symptr') : 0 @symptr ||= xcoff.symbols ? xcoff.new_label('symptr') : 0
@nsym ||= xcoff.symbols ? xcoff.symbols.length : 0 @nsym ||= xcoff.symbols ? xcoff.symbols.length : 0
@opthdr ||= xcoff.optheader ? OptHeader.size(xcoff) : 0 @opthdr ||= xcoff.optheader ? xcoff.optheader.sizeof(xcoff) : 0
super(xcoff) super(xcoff)
end end
end end
@ -61,13 +61,9 @@ class XCoff < ExeFormat
xwords :tsize, :dsize, :bsize, :entry, :text_start, :data_start, :toc xwords :tsize, :dsize, :bsize, :entry, :text_start, :data_start, :toc
halfs :snentry, :sntext, :sndata, :sntoc, :snloader, :snbss, :aligntext, :aligndata, :modtype, :cpu halfs :snentry, :sntext, :sndata, :sntoc, :snloader, :snbss, :aligntext, :aligndata, :modtype, :cpu
xwords :maxstack, :maxdata xwords :maxstack, :maxdata
new_field(:res, lambda { |exe, me| exe.encoded.read(exe.intsize == 32 ? 8 : 120) }, lambda { |exe, me, val| val }, '') new_field(:res, lambda { |exe, me| exe.encoded.read(exe.intsize == 32 ? 8 : 120) }, lambda { |exe, me, val| val }, lambda { |exe, me| exe.intsize == 32 ? 8 : 120 }, '')
def self.size(xcoff)
xcoff.intsize == 32 ? 2*2+7*4+10*2+2*4+2+8 : 2*2+7*8+10*2+2*8+2+120
end
def set_default_values(xcoff) def set_default_values(xcoff)
@vstamp ||= 1 @vstamp ||= 1
@snentry ||= 1 @snentry ||= 1
@ -99,12 +95,16 @@ class XCoff < ExeFormat
# basic immediates decoding functions # basic immediates decoding functions
def decode_half( edata = @encoded) edata.decode_imm(:u16, @endianness) end def decode_half( edata = @encoded) edata.decode_imm(:u16, @endianness) end
def decode_word( edata = @encoded) edata.decode_imm(:u32, @endianness) end def decode_word( edata = @encoded) edata.decode_imm(:u32, @endianness) end
def decode_xhalf(edata = @encoded) edata.edoced_imm((@intsize == 32 ? :u16 : :u32), @endianness) end def decode_xhalf(edata = @encoded) edata.decode_imm((@intsize == 32 ? :u16 : :u32), @endianness) end
def decode_xword(edata = @encoded) edata.decode_imm((@intsize == 32 ? :u32 : :u64), @endianness) end def decode_xword(edata = @encoded) edata.decode_imm((@intsize == 32 ? :u32 : :u64), @endianness) end
def encode_half(w) Expression[w].encode(:u16, @endianness) end def encode_half(w) Expression[w].encode(:u16, @endianness) end
def encode_word(w) Expression[w].encode(:u32, @endianness) end def encode_word(w) Expression[w].encode(:u32, @endianness) end
def encode_xhalf(w) Expression[w].encode((@intsize == 32 ? :u16 : :u32), @endianness) end def encode_xhalf(w) Expression[w].encode((@intsize == 32 ? :u16 : :u32), @endianness) end
def encode_xword(w) Expression[w].encode((@intsize == 32 ? :u32 : :u64), @endianness) end def encode_xword(w) Expression[w].encode((@intsize == 32 ? :u32 : :u64), @endianness) end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
def sizeof_xhalf ; @intsize == 32 ? 2 : 4 ; end
def sizeof_xword ; @intsize == 32 ? 4 : 8 ; end
attr_accessor :header, :segments, :relocs, :intsize, :endianness attr_accessor :header, :segments, :relocs, :intsize, :endianness

View File

@ -211,6 +211,8 @@ class ZIP < ExeFormat
def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end
def encode_half(w) Expression[w].encode(:u16, @endianness) end def encode_half(w) Expression[w].encode(:u16, @endianness) end
def encode_word(w) Expression[w].encode(:u32, @endianness) end def encode_word(w) Expression[w].encode(:u32, @endianness) end
def sizeof_half ; 2 ; end
def sizeof_word ; 4 ; end
attr_accessor :files, :header attr_accessor :files, :header

View File

@ -1423,6 +1423,11 @@ class WinOS < OS
end end
end end
# retrieve the actual context structure (so we can pass to API's like StackWalk64)
def c_struct
@context
end
# update the context to reflect the current thread reg values # update the context to reflect the current thread reg values
# call only when the thread is suspended # call only when the thread is suspended
def update def update

View File

@ -92,4 +92,11 @@ class TestX86_64 < Test::Unit::TestCase
assert_equal("\x87\xc0", assemble('xchg eax, eax')) assert_equal("\x87\xc0", assemble('xchg eax, eax'))
assert_equal('xchg r8, rax', disassemble("\x49\x90").decoded[0].instruction.to_s) assert_equal('xchg r8, rax', disassemble("\x49\x90").decoded[0].instruction.to_s)
end end
def test_C_size
assert_nothing_raised {
Metasm::Shellcode.compile_c(@@cpu, "void main(void) { int i=5670, j=8907 ; i = i*j; }").encode_string
}
end
end end