Land #3181, @dmaloney-r7's fix for metasm
commit
c892da44e8
|
@ -36,6 +36,7 @@ module Metasm
|
|||
'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',
|
||||
'Python' => 'cpu/python', 'Z80' => 'cpu/z80', 'CY16' => 'cpu/cy16', 'BPF' => 'cpu/bpf',
|
||||
'MSP430' => 'cpu/msp430',
|
||||
'C' => 'compile_c',
|
||||
'MZ' => 'exe_format/mz', 'PE' => 'exe_format/pe',
|
||||
'ELF' => 'exe_format/elf', 'COFF' => 'exe_format/coff',
|
||||
|
|
|
@ -104,7 +104,7 @@ class ModRM
|
|||
i = o
|
||||
s = 1
|
||||
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
|
||||
raise otok, 'mrm: too many indexes' if i
|
||||
s = o.lexpr
|
||||
|
@ -129,7 +129,9 @@ class ModRM
|
|||
walker[regify[content.reduce]]
|
||||
|
||||
# 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
|
||||
adsz = b ? b.sz : i ? i.sz : nil
|
||||
|
|
|
@ -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'
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -39,6 +39,8 @@ class Sh4
|
|||
end
|
||||
|
||||
def decode_findopcode(edata)
|
||||
return if edata.ptr >= edata.length
|
||||
|
||||
di = DecodedInstruction.new(self)
|
||||
val = edata.decode_imm(:u16, @endianness)
|
||||
edata.ptr -= 2
|
||||
|
|
|
@ -594,6 +594,7 @@ class CCompiler < C::Compiler
|
|||
l = c_cexpr_inner(expr.lexpr)
|
||||
l = make_volatile(l, expr.type)
|
||||
r = c_cexpr_inner(expr.rexpr)
|
||||
r = make_volatile(r, expr.type) if r.kind_of?(ModRM) and r.sz != l.sz
|
||||
unuse r
|
||||
if expr.lexpr.type.integral? or expr.lexpr.type.pointer?
|
||||
instr 'cmp', l, i_to_i32(r)
|
||||
|
@ -790,6 +791,7 @@ class CCompiler < C::Compiler
|
|||
end
|
||||
instr 'mov', l, ll
|
||||
else
|
||||
r = make_volatile(r, type) if r.kind_of?(ModRM) and r.sz != l.sz
|
||||
instr 'imul', l, r
|
||||
end
|
||||
unuse r
|
||||
|
@ -876,6 +878,8 @@ class CCompiler < C::Compiler
|
|||
l = c_cexpr_inner(expr.lexpr)
|
||||
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 r.sz != l.sz
|
||||
l = make_volatile(l, expr.type) if l.kind_of?(ModRM)
|
||||
if l.kind_of? Expression
|
||||
o = { :< => :>, :> => :<, :>= => :<=, :<= => :>= }[o] || o
|
||||
l, r = r, l
|
||||
|
|
|
@ -93,6 +93,9 @@ class AOut < ExeFormat
|
|||
def encode_byte(w) Expression[w].encode(:u8 , @endianness) end
|
||||
def encode_half(w) Expression[w].encode(:u16, @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)
|
||||
@endianness = cpu ? cpu.endianness : :little
|
||||
|
|
|
@ -57,6 +57,7 @@ class Bflt < ExeFormat
|
|||
|
||||
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
|
||||
def encode_word(w) Expression[w].encode(:u32, @endianness) end
|
||||
def sizeof_word ; 4 ; end
|
||||
|
||||
attr_accessor :endianness
|
||||
def initialize(cpu = nil)
|
||||
|
|
|
@ -140,7 +140,7 @@ class COFF < ExeFormat
|
|||
bytes :link_ver_maj, :link_ver_min
|
||||
words :code_size, :data_size, :udata_size, :entrypoint, :base_of_code
|
||||
# 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
|
||||
xword :image_base
|
||||
words :sect_align, :file_align
|
||||
|
@ -413,6 +413,11 @@ class COFF < ExeFormat
|
|||
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
|
||||
|
||||
# the COFF archive file format
|
||||
|
@ -448,6 +453,9 @@ class COFFArchive < ExeFormat
|
|||
def member(name)
|
||||
@members.find { |m| m.name == name }
|
||||
end
|
||||
|
||||
def sizeof_half ; 2 ; end
|
||||
def sizeof_word ; 4 ; end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -847,6 +847,7 @@ class COFFArchive
|
|||
ar.encoded.ptr += 1 if @size & 1 == 1
|
||||
end
|
||||
|
||||
# TODO XXX are those actually used ?
|
||||
def decode_half ; @encoded.decode_imm(:u16, :big) end
|
||||
def decode_word ; @encoded.decode_imm(:u32, :big) end
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ class DEX < ExeFormat
|
|||
|
||||
|
||||
class SerialStruct < Metasm::SerialStruct
|
||||
# TODO move uleb/sleb to new_field for sizeof
|
||||
new_int_field :u2, :u4, :uleb, :sleb
|
||||
end
|
||||
|
||||
|
@ -328,6 +329,8 @@ class DEX < ExeFormat
|
|||
def encode_u4(val) Expression[val].encode(:u32, @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 sizeof_u2 ; 2 ; end
|
||||
def sizeof_u4 ; 4 ; end
|
||||
def decode_uleb(ed = @encoded, signed=false)
|
||||
v = s = 0
|
||||
while s < 5*7
|
||||
|
|
|
@ -26,6 +26,7 @@ class Dol < ExeFormat
|
|||
|
||||
def decode_word(edata = @encoded) edata.decode_imm(:u32, @endianness) end
|
||||
def encode_word(w) Expression[w].encode(:u32, @endianness) end
|
||||
def sizeof_word ; 4 ; end
|
||||
|
||||
def initialize(cpu = nil)
|
||||
@endianness = :big
|
||||
|
|
|
@ -21,29 +21,52 @@ class ELF < ExeFormat
|
|||
TYPE_HIPROC = 0xffff
|
||||
|
||||
MACHINE = {
|
||||
0 => 'NONE', 1 => 'M32', 2 => 'SPARC', 3 => '386',
|
||||
4 => '68K', 5 => '88K', 6 => '486', 7 => '860',
|
||||
8 => 'MIPS', 9 => 'S370', 10 => 'MIPS_RS3_LE',
|
||||
15 => 'PARISC',
|
||||
17 => 'VPP500',18 => 'SPARC32PLUS', 19 => '960',
|
||||
20 => 'PPC', 21 => 'PPC64', 22 => 'S390',
|
||||
36 => 'V800', 37 => 'FR20', 38 => 'RH32', 39 => 'MCORE',
|
||||
40 => 'ARM', 41 => 'ALPHA_STD', 42 => 'SH', 43 => 'SPARCV9',
|
||||
44 => 'TRICORE', 45 => 'ARC', 46 => 'H8_300', 47 => 'H8_300H',
|
||||
48 => 'H8S', 49 => 'H8_500', 50 => 'IA_64', 51 => 'MIPS_X',
|
||||
0 => 'NONE', 1 => 'M32', 2 => 'SPARC', 3 => '386',
|
||||
4 => '68K', 5 => '88K', 6 => '486', 7 => '860',
|
||||
8 => 'MIPS', 9 => 'S370', 10 => 'MIPS_RS3_LE',
|
||||
15 => 'PARISC', 17 => 'VPP500', 18 => 'SPARC32PLUS', 19 => '960',
|
||||
20 => 'PPC', 21 => 'PPC64', 22 => 'S390', 23 => 'SPU',
|
||||
36 => 'V800', 37 => 'FR20', 38 => 'RH32', 39 => 'MCORE',
|
||||
40 => 'ARM', 41 => 'ALPHA', 42 => 'SH', 43 => 'SPARCV9',
|
||||
44 => 'TRICORE', 45 => 'ARC', 46 => 'H8_300', 47 => 'H8_300H',
|
||||
48 => 'H8S', 49 => 'H8_500', 50 => 'IA_64', 51 => 'MIPS_X',
|
||||
52 => 'COLDFIRE', 53 => '68HC12', 54 => 'MMA', 55 => 'PCP',
|
||||
56 => 'NCPU', 57 => 'NDR1', 58 => 'STARCORE', 59 => 'ME16',
|
||||
60 => 'ST100', 61 => 'TINYJ', 62 => 'X86_64', 63 => 'PDSP',
|
||||
66 => 'FX66', 67 => 'ST9PLUS',
|
||||
68 => 'ST7', 69 => '68HC16', 70 => '68HC11', 71 => '68HC08',
|
||||
72 => '68HC05',73 => 'SVX', 74 => 'ST19', 75 => 'VAX',
|
||||
76 => 'CRIS', 77 => 'JAVELIN',78 => 'FIREPATH', 79 => 'ZSP',
|
||||
80 => 'MMIX', 81 => 'HUANY', 82 => 'PRISM', 83 => 'AVR',
|
||||
84 => 'FR30', 85 => 'D10V', 86 => 'D30V', 87 => 'V850',
|
||||
88 => 'M32R', 89 => 'MN10300',90 => 'MN10200',91 => 'PJ',
|
||||
92 => 'OPENRISC', 93 => 'ARC_A5', 94 => 'XTENSA',
|
||||
99 => 'PJ',
|
||||
0x9026 => 'ALPHA'
|
||||
56 => 'NCPU', 57 => 'NDR1', 58 => 'STARCORE', 59 => 'ME16',
|
||||
60 => 'ST100', 61 => 'TINYJ', 62 => 'X86_64', 63 => 'PDSP',
|
||||
64 => 'PDP10', 65 => 'PDP11', 66 => 'FX66', 67 => 'ST9PLUS',
|
||||
68 => 'ST7', 69 => '68HC16', 70 => '68HC11', 71 => '68HC08',
|
||||
72 => '68HC05',73 => 'SVX', 74 => 'ST19', 75 => 'VAX',
|
||||
76 => 'CRIS', 77 => 'JAVELIN',78 => 'FIREPATH', 79 => 'ZSP',
|
||||
80 => 'MMIX', 81 => 'HUANY', 82 => 'PRISM', 83 => 'AVR',
|
||||
84 => 'FR30', 85 => 'D10V', 86 => 'D30V', 87 => 'V850',
|
||||
88 => 'M32R', 89 => 'MN10300',90 => 'MN10200',91 => 'PJ',
|
||||
92 => 'OPENRISC', 93 => 'ARC_A5', 94 => 'XTENSA', 95 => 'VIDEOCORE',
|
||||
96 => 'TMM_GPP', 97 => 'NS32K', 98 => 'TPC', 99 => 'SNP1K',
|
||||
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 = {
|
||||
|
@ -394,11 +417,6 @@ class ELF < ExeFormat
|
|||
word :flags
|
||||
fld_bits(:flags) { |elf, hdr| FLAGS[hdr.machine] || {} }
|
||||
halfs :ehsize, :phentsize, :phnum, :shentsize, :shnum, :shstrndx
|
||||
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
40 + 3*x
|
||||
end
|
||||
end
|
||||
|
||||
class Segment < SerialStruct
|
||||
|
@ -412,11 +430,6 @@ class ELF < ExeFormat
|
|||
else Segment64
|
||||
end
|
||||
end
|
||||
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
8 + 6*x
|
||||
end
|
||||
end
|
||||
|
||||
class Segment32 < Segment
|
||||
|
@ -453,11 +466,6 @@ class ELF < ExeFormat
|
|||
xword :entsize
|
||||
|
||||
attr_accessor :name, :encoded
|
||||
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
16 + 6*x
|
||||
end
|
||||
end
|
||||
|
||||
class Symbol < SerialStruct
|
||||
|
@ -471,11 +479,6 @@ class ELF < ExeFormat
|
|||
|
||||
attr_accessor :name_p, :value, :size, :bind, :type, :other, :shndx
|
||||
attr_accessor :name, :thunk
|
||||
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
8 + 2*x
|
||||
end
|
||||
end
|
||||
|
||||
class Symbol32 < Symbol
|
||||
|
@ -510,12 +513,6 @@ class ELF < ExeFormat
|
|||
end
|
||||
|
||||
def addend ; end
|
||||
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
2*x
|
||||
end
|
||||
|
||||
end
|
||||
class Relocation32 < Relocation
|
||||
addr :offset
|
||||
|
@ -538,11 +535,6 @@ class ELF < ExeFormat
|
|||
else RelocationAddend64
|
||||
end
|
||||
end
|
||||
def self.size elf
|
||||
x = elf.bitsize >> 3
|
||||
3*x
|
||||
end
|
||||
|
||||
end
|
||||
class RelocationAddend32 < RelocationAddend
|
||||
addr :offset
|
||||
|
@ -669,6 +661,15 @@ class ELF < ExeFormat
|
|||
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
|
||||
|
||||
class LoadedELF < ELF
|
||||
|
@ -721,6 +722,9 @@ class FatELF < ExeFormat
|
|||
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @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 sizeof_byte ; 1 ; end
|
||||
def sizeof_word ; 2 ; end
|
||||
def sizeof_qword ; 8 ; end
|
||||
|
||||
attr_accessor :header, :list
|
||||
def initialize
|
||||
|
|
|
@ -106,7 +106,7 @@ class ELF
|
|||
def decode_header(off = 0, decode_phdr=true, decode_shdr=true)
|
||||
@encoded.ptr = off
|
||||
@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
|
||||
decode_program_header(@header.phoff+off)
|
||||
end
|
||||
|
@ -118,7 +118,7 @@ class ELF
|
|||
# decodes the section header
|
||||
# section names are read from shstrndx if possible
|
||||
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.ptr = off
|
||||
@sections = []
|
||||
|
@ -137,7 +137,7 @@ class ELF
|
|||
# decodes the program header table
|
||||
# marks the elf entrypoint as an export of +self.encoded+
|
||||
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.ptr = off
|
||||
@segments = []
|
||||
|
@ -232,13 +232,13 @@ class ELF
|
|||
# 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..
|
||||
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']
|
||||
while @encoded.ptr < p_end
|
||||
rels << Relocation.decode(self)
|
||||
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']
|
||||
while @encoded.ptr < p_end
|
||||
rels << RelocationAddend.decode(self)
|
||||
|
@ -392,7 +392,7 @@ class ELF
|
|||
def decode_segments_symbols
|
||||
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
|
||||
if @tag['HASH']
|
||||
|
@ -427,7 +427,7 @@ class ELF
|
|||
@encoded.ptr = sec.offset
|
||||
syms = []
|
||||
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'
|
||||
alreadysyms = @symbols.inject({}) { |h, s| h.update s.name => true } if alreadysegs
|
||||
syms.each { |s|
|
||||
|
@ -480,7 +480,7 @@ class ELF
|
|||
def decode_segments_relocs
|
||||
@relocations.clear
|
||||
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']
|
||||
while @encoded.ptr < p_end
|
||||
@relocations << Relocation.decode(self)
|
||||
|
@ -488,7 +488,7 @@ class ELF
|
|||
end
|
||||
|
||||
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']
|
||||
while @encoded.ptr < p_end
|
||||
@relocations << RelocationAddend.decode(self)
|
||||
|
@ -935,6 +935,8 @@ class ELF
|
|||
when 'PPC'; PPC.new
|
||||
when 'ARM'; ARM.new
|
||||
when 'SH'; Sh4.new
|
||||
when 'ARC_COMPACT'; ARC.new
|
||||
when 'MSP430'; MSP430.new
|
||||
else raise "unsupported cpu #{@header.machine}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,10 +20,10 @@ class ELF
|
|||
@phoff ||= elf.segments.empty? ? 0 : elf.new_label('phdr')
|
||||
@shoff ||= elf.sections.length <= 1 ? 0 : elf.new_label('shdr')
|
||||
@flags ||= []
|
||||
@ehsize ||= Header.size(elf)
|
||||
@phentsize ||= Segment.size(elf)
|
||||
@ehsize ||= Header.sizeof(elf)
|
||||
@phentsize ||= Segment.sizeof(elf)
|
||||
@phnum ||= elf.segments.length
|
||||
@shentsize ||= Section.size(elf)
|
||||
@shentsize ||= Section.sizeof(elf)
|
||||
@shnum ||= elf.sections.length
|
||||
|
||||
super(elf)
|
||||
|
@ -247,7 +247,7 @@ class ELF
|
|||
dynsym = Section.new
|
||||
dynsym.name = '.dynsym'
|
||||
dynsym.type = 'DYNSYM'
|
||||
dynsym.entsize = Symbol.size(self)
|
||||
dynsym.entsize = Symbol.sizeof(self)
|
||||
dynsym.addralign = 4
|
||||
dynsym.flags = ['ALLOC']
|
||||
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
|
||||
|
||||
@tag['SYMTAB'] = label_at(dynsym.encoded, 0)
|
||||
@tag['SYMENT'] = Symbol.size(self)
|
||||
@tag['SYMENT'] = Symbol.sizeof(self)
|
||||
|
||||
encode_check_section_size dynsym
|
||||
|
||||
|
@ -294,7 +294,7 @@ class ELF
|
|||
@tag['JMPREL'] = label_at(relplt.encoded, 0)
|
||||
@tag['PLTRELSZ'] = relplt.encoded.virtsize
|
||||
@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
|
||||
end
|
||||
|
||||
|
@ -312,13 +312,13 @@ class ELF
|
|||
rel.name = '.rel.dyn'
|
||||
rel.type = 'REL'
|
||||
rel.flags = ['ALLOC']
|
||||
rel.entsize = rel.addralign = Relocation.size(self)
|
||||
rel.entsize = rel.addralign = Relocation.sizeof(self)
|
||||
encode_add_section rel
|
||||
end
|
||||
rel.encoded = EncodedData.new
|
||||
list.each { |r| rel.encoded << r.encode(self) }
|
||||
@tag['REL'] = label_at(rel.encoded, 0)
|
||||
@tag['RELENT'] = Relocation.size(self)
|
||||
@tag['RELENT'] = Relocation.sizeof(self)
|
||||
@tag['RELSZ'] = rel.encoded.virtsize
|
||||
encode_check_section_size rel
|
||||
end
|
||||
|
@ -330,13 +330,13 @@ class ELF
|
|||
rela.name = '.rela.dyn'
|
||||
rela.type = 'RELA'
|
||||
rela.flags = ['ALLOC']
|
||||
rela.entsize = rela.addralign = RelocationAddend.size(self)
|
||||
rela.entsize = rela.addralign = RelocationAddend.sizeof(self)
|
||||
encode_add_section rela
|
||||
end
|
||||
rela.encoded = EncodedData.new
|
||||
list.each { |r| rela.encoded << r.encode(self) }
|
||||
@tag['RELA'] = label_at(rela.encoded, 0)
|
||||
@tag['RELAENT'] = RelocationAddend.size(self)
|
||||
@tag['RELAENT'] = RelocationAddend.sizeof(self)
|
||||
@tag['RELASZ'] = rela.encoded.virtsize
|
||||
encode_check_section_size rela
|
||||
end
|
||||
|
@ -457,7 +457,7 @@ class ELF
|
|||
plt.encoded << shellcode["jmp [#{base} + #{gotplt.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 *= Relocation.size(self) if @bitsize == 32
|
||||
reloffset *= Relocation.sizeof(self) if @bitsize == 32
|
||||
plt.encoded << shellcode["push #{reloffset}\njmp metasm_plt_start"]
|
||||
|
||||
# transform the reloc PC32 => JMP_SLOT
|
||||
|
|
|
@ -30,6 +30,7 @@ class GameBoyRom < ExeFormat
|
|||
|
||||
def encode_byte(val) Expression[val].encode(:u8, @endianness) end
|
||||
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @endianness) end
|
||||
def sizeof_byte ; 1 ; end
|
||||
|
||||
|
||||
attr_accessor :header
|
||||
|
|
|
@ -292,6 +292,9 @@ class JavaClass < ExeFormat
|
|||
def decode_u1(edata = @encoded) edata.decode_imm(:u8, @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 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
|
||||
|
||||
|
|
|
@ -511,6 +511,10 @@ class MachO < ExeFormat
|
|||
def decode_half(edata = @encoded) edata.decode_imm(:u16, @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 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
|
||||
|
@ -978,6 +982,7 @@ class UniversalBinary < ExeFormat
|
|||
|
||||
def encode_word(val) Expression[val].encode(: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
|
||||
def initialize
|
||||
|
|
|
@ -51,6 +51,7 @@ class MZ < ExeFormat
|
|||
def encode_word(val) Expression[val].encode(:u16, @endianness) end
|
||||
# decodes a 16bits word from self.encoded
|
||||
def decode_word(edata = @encoded) edata.decode_imm(:u16, @endianness) end
|
||||
def sizeof_word ; 2 ; end
|
||||
|
||||
|
||||
attr_accessor :endianness, :header, :source
|
||||
|
|
|
@ -70,6 +70,9 @@ class NDS < ExeFormat
|
|||
def decode_byte(edata = @encoded) edata.decode_imm(:u8, @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 sizeof_byte ; 1 ; end
|
||||
def sizeof_half ; 2 ; end
|
||||
def sizeof_word ; 4 ; end
|
||||
|
||||
|
||||
attr_accessor :header, :icon, :arm9, :arm7
|
||||
|
|
|
@ -297,6 +297,35 @@ EOS
|
|||
} if export
|
||||
syms
|
||||
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
|
||||
|
||||
# an instance of a PE file, loaded in memory
|
||||
|
@ -436,5 +465,9 @@ class LoadedPE < PE
|
|||
dump.imports.last.imports << i
|
||||
end
|
||||
end
|
||||
|
||||
def pehash(digest)
|
||||
raise "cannot compute a PEhash from memory image"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,6 +27,9 @@ class PYC < ExeFormat
|
|||
def decode_half(edata=@encoded) edata.decode_imm(:u16, @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 sizeof_half ; 2 ; end
|
||||
def sizeof_word ; 4 ; end
|
||||
def sizeof_long ; 4 ; end
|
||||
|
||||
# file header
|
||||
attr_accessor :header
|
||||
|
|
|
@ -13,19 +13,20 @@ class SerialStruct
|
|||
NAME=0
|
||||
DECODE=1
|
||||
ENCODE=2
|
||||
DEFVAL=3
|
||||
ENUM=4
|
||||
BITS=5
|
||||
SIZEOF=3
|
||||
DEFVAL=4
|
||||
ENUM=5
|
||||
BITS=6
|
||||
|
||||
class << self
|
||||
# defines a new field
|
||||
# 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
|
||||
attr_accessor name
|
||||
name = "@#{name}".to_sym
|
||||
end
|
||||
(@@fields[self] ||= []) << [name, decode, encode, defval, enum, bits]
|
||||
(@@fields[self] ||= []) << [name, decode, encode, sizeof, defval, enum, bits]
|
||||
end
|
||||
|
||||
# creates a field constructor for a simple integer
|
||||
|
@ -34,7 +35,7 @@ class << self
|
|||
recv = class << self ; self ; end
|
||||
types.each { |type|
|
||||
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
|
||||
|
@ -49,19 +50,20 @@ class << self
|
|||
# virtual field, handled explicitly in a custom encode/decode
|
||||
def virtual(*a)
|
||||
a.each { |f|
|
||||
new_field(f, nil, nil, nil)
|
||||
new_field(f, nil, nil, nil, nil)
|
||||
}
|
||||
end
|
||||
|
||||
# a fixed-size memory chunk
|
||||
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
|
||||
# a fixed-size string, 0-padded
|
||||
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 }
|
||||
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
|
||||
# 0-terminated string
|
||||
def strz(name, defval='')
|
||||
|
@ -70,7 +72,8 @@ class << self
|
|||
ed.read(ed.data.index(?\0, ed.ptr)-ed.ptr+1).chop
|
||||
}
|
||||
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
|
||||
|
||||
# field access
|
||||
|
@ -100,7 +103,7 @@ class << self
|
|||
d = lambda { |exe, me| @bitfield_val = exe.send("decode_#{inttype}") }
|
||||
# reset a temp var
|
||||
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.length.times { |i|
|
||||
|
@ -114,7 +117,7 @@ class << self
|
|||
d = lambda { |exe, me| (@bitfield_val >> off) & mask }
|
||||
# update the temp var with the field value, return 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
|
||||
|
@ -125,7 +128,8 @@ class << self
|
|||
@bitfield_val = nil
|
||||
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
|
||||
|
||||
# inject a hook to be run during the decoding process
|
||||
|
@ -217,6 +221,39 @@ end # class methods
|
|||
ed
|
||||
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
|
||||
def self.decode(*a)
|
||||
s = new
|
||||
|
@ -224,6 +261,14 @@ end # class methods
|
|||
s
|
||||
end
|
||||
|
||||
def self.sizeof(exe)
|
||||
new.sizeof(exe)
|
||||
end
|
||||
|
||||
def self.offsetof(exe, fld)
|
||||
new.offsetof(exe, fld)
|
||||
end
|
||||
|
||||
def dump(e, a)
|
||||
case e
|
||||
when Integer; e >= 0x100 ? '0x%X'%e : e
|
||||
|
|
|
@ -164,6 +164,11 @@ class SWF < ExeFormat
|
|||
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_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
|
||||
def initialize(cpu = nil)
|
||||
|
|
|
@ -51,7 +51,7 @@ class XCoff < ExeFormat
|
|||
@nsec ||= xcoff.sections.size
|
||||
@symptr ||= xcoff.symbols ? xcoff.new_label('symptr') : 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)
|
||||
end
|
||||
end
|
||||
|
@ -61,13 +61,9 @@ class XCoff < ExeFormat
|
|||
xwords :tsize, :dsize, :bsize, :entry, :text_start, :data_start, :toc
|
||||
halfs :snentry, :sntext, :sndata, :sntoc, :snloader, :snbss, :aligntext, :aligndata, :modtype, :cpu
|
||||
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)
|
||||
@vstamp ||= 1
|
||||
@snentry ||= 1
|
||||
|
@ -99,12 +95,16 @@ class XCoff < ExeFormat
|
|||
# basic immediates decoding functions
|
||||
def decode_half( edata = @encoded) edata.decode_imm(:u16, @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 encode_half(w) Expression[w].encode(:u16, @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_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
|
||||
|
|
|
@ -211,6 +211,8 @@ class ZIP < ExeFormat
|
|||
def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end
|
||||
def encode_half(w) Expression[w].encode(:u16, @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
|
||||
|
||||
|
|
|
@ -1423,6 +1423,11 @@ class WinOS < OS
|
|||
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
|
||||
# call only when the thread is suspended
|
||||
def update
|
||||
|
|
|
@ -92,4 +92,11 @@ class TestX86_64 < Test::Unit::TestCase
|
|||
assert_equal("\x87\xc0", assemble('xchg eax, eax'))
|
||||
assert_equal('xchg r8, rax', disassemble("\x49\x90").decoded[0].instruction.to_s)
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue