metasm/exe_format/pe.rb in metasm-1.0.3 vs metasm/exe_format/pe.rb in metasm-1.0.4
- old
+ new
@@ -9,12 +9,13 @@
require 'metasm/exe_format/coff'
module Metasm
class PE < COFF
MAGIC = "PE\0\0" # 0x50450000
+ MAGIC.force_encoding('BINARY') if MAGIC.respond_to?(:force_encoding)
- attr_accessor :coff_offset, :signature, :mz
+ attr_accessor :coff_offset, :signature, :mz, :productid
def initialize(*a)
super(*a)
cpu = a.grep(CPU).first
@mz = MZ.new(cpu).share_namespace(self)
@@ -24,11 +25,18 @@
# simply sets the offset to the PE pointer before decoding the COFF header
# also checks the PE signature
def decode_header
@cursection ||= self
@encoded.ptr = 0x3c
- @encoded.ptr = decode_word(@encoded)
+ lfanew = decode_word(@encoded)
+
+ try_rich_sz = [0x400, lfanew].min
+ rich_ary = []
+ rich_ary << decode_word(@encoded) while @encoded.ptr < try_rich_sz
+ @productid = decode_productid(rich_ary)
+
+ @encoded.ptr = lfanew
@signature = @encoded.read(4)
raise InvalidExeFormat, "Invalid PE signature #{@signature.inspect}" if @signature != MAGIC
@coff_offset = @encoded.ptr
if @mz.encoded.empty?
@mz.encoded << @encoded[0, @coff_offset-4]
@@ -36,10 +44,24 @@
@mz.decode_header
end
super()
end
+ RICH_MAGIC = 0x68636952 # "Rich"
+ def decode_productid(ary)
+ return unless idx = ary.index(RICH_MAGIC) and xorkey = ary[idx+1]
+ ary = ary[0, idx-1].map { |dw| dw ^ xorkey }
+ return unless idx = ary.rindex(0x536E6144) # "DanS"
+ ary = ary[idx+2..-1]
+ out = []
+ until ary.empty?
+ ar1 = ary.shift
+ out << { :id => ar1 >> 16, :ver => ar1 & 0xffff, :count => ary.shift.to_i }
+ end
+ out
+ end
+
# creates a default MZ file to be used in the PE header
# this one is specially crafted to fit in the 0x3c bytes before the signature
def encode_default_mz_header
# XXX use single-quoted source, to avoid ruby interpretation of \r\n
@mz.cpu = Ia32.new(386, 16)
@@ -224,10 +246,10 @@
a = dasm.backtrace(sehptr, di.address, :include_start => true, :origin => di.address, :type => :x, :detached => true)
puts "backtrace seh from #{di} => #{a.map { |addr| Expression[addr] }.join(', ')}" if $VERBOSE
a.each { |aa|
next if aa == Expression::Unknown
dasm.auto_label_at(aa, 'seh', 'loc', 'sub')
- dasm.addrs_todo << [aa]
+ dasm.addrs_todo << { :addr => aa }
}
super(dasm, di)
else
super(dasm, di)
end