class Metasm::PYC

Python preparsed module (.pyc)

Constants

MAGICS

1 magic per python version… file = MAGIC(u16) r n timestamp(u32) data

Attributes

all_code[RW]

list of all code objects

header[RW]

file header

root[RW]

the marshalled object

Public Class Methods

new() click to toggle source
Calls superclass method Metasm::ExeFormat.new
# File metasm/exe_format/pyc.rb, line 41
def initialize()
        @endianness = :little
        @encoded = EncodedData.new
        super()
end

Public Instance Methods

code_at_off(off) click to toggle source

return the :code part which contains off

# File metasm/exe_format/pyc.rb, line 163
def code_at_off(off)
        @all_code.find { |c| c[:fileoff] <= off and c[:fileoff] + c[:code].length > off }
end
cpu_from_headers() click to toggle source
# File metasm/exe_format/pyc.rb, line 146
def cpu_from_headers
        Python.new(self)
end
decode() click to toggle source
# File metasm/exe_format/pyc.rb, line 138
def decode
        decode_header
        @all_code = []
        @references = []
        @root = decode_pymarshal
        @references = nil
end
decode_half(edata=@encoded) click to toggle source
# File metasm/exe_format/pyc.rb, line 27
def decode_half(edata=@encoded) edata.decode_imm(:u16, @endianness) end
decode_header() click to toggle source
# File metasm/exe_format/pyc.rb, line 47
def decode_header
        @header = Header.decode(self)
end
decode_long(edata=@encoded) click to toggle source
# File metasm/exe_format/pyc.rb, line 29
def decode_long(edata=@encoded) edata.decode_imm(:i32, @endianness) end
decode_pymarshal() click to toggle source
# File metasm/exe_format/pyc.rb, line 51
def decode_pymarshal
        case c = @encoded.read(1)
        when '0' # NULL
                :null
        when 'N' # None
                nil
        when 'F' # False
                false
        when 'T' # True
                true
        #when 'S' # stopiter TODO
        #when '.' # ellipsis TODO
        when 'i' # long (i32)
                decode_long
        when 'I' # long (i64)
                decode_word | (decode_long << 32)
        when 'f' # float (ascii)
                @encoded.read(@encoded.read(1).unpack('C').first).to_f
        when 'g' # float (binary)
                @encoded.read(8).unpack('d').first   # XXX check
        when 'x' # complex (f f)
                { :type => :complex,
                  :real => @encoded.read(@encoded.read(1).unpack('C').first).to_f,
                  :imag => @encoded.read(@encoded.read(1).unpack('C').first).to_f }
        when 'y' # complex (g g)
                { :type => :complex,
                  :real => @encoded.read(8).unpack('d').first,
                  :imag => @encoded.read(8).unpack('d').first }
        when 'l' # long (i32?)
                decode_long
        when 's' # string: len (long), data
                @encoded.read(decode_long)
        when 't' # 'interned': string with possible backreference later
                s = @encoded.read(decode_long)
                @references << s
                s
        when 'R' # stringref (see 't')
                @references[decode_long]
        when '(' # tuple (frozen Array): length l*objs
                obj = []
                decode_long.times { obj << decode_pymarshal }
                obj
        when '[' # list (Array)
                obj = []
                decode_long.times { obj << decode_pymarshal }
                obj
        when '{' # dict (Hash)
                obj = {}
                loop do
                        k = decode_pymarshal
                        break if k == :null
                        obj[k] = decode_pymarshal
                end
                { :type => hash, :hash => obj }      # XXX to avoid confusion with code, etc
        when 'c' # code
                # XXX format varies with version (header.signature)
                obj = {}
                obj[:type] = :code
                obj[:argcount] = decode_long
                #obj[:kwonly_argcount] = decode_long # not in py2.7
                obj[:nlocals] = decode_long
                obj[:stacksize] = decode_long
                obj[:flags] = decode_long    # TODO bit-decode this one

                obj[:fileoff] = @encoded.ptr + 5     # XXX assume :code is a 's'
                obj[:code] = decode_pymarshal
                obj[:consts] = decode_pymarshal
                obj[:names] = decode_pymarshal
                obj[:varnames] = decode_pymarshal
                obj[:freevars] = decode_pymarshal
                obj[:cellvars] = decode_pymarshal
                obj[:filename] = decode_pymarshal
                obj[:name] = decode_pymarshal
                obj[:firstlineno] = decode_long
                obj[:lnotab] = decode_pymarshal
                @all_code << obj
                obj
        when 'u' # unicode
                @encoded.read(decode_long)
        #when '?' # unknown TODO
        #when '<' # set TODO
        #when '>' # set (frozen) TODO
        else
                raise "unsupported python marshal #{c.inspect}"
        end
end
decode_word(edata=@encoded) click to toggle source
# File metasm/exe_format/pyc.rb, line 28
def decode_word(edata=@encoded) edata.decode_imm(:u32, @endianness) end
each_section() { |encoded, 0| ... } click to toggle source
# File metasm/exe_format/pyc.rb, line 150
def each_section
        yield @encoded, 0
end
get_default_entrypoints() click to toggle source
# File metasm/exe_format/pyc.rb, line 154
def get_default_entrypoints
        if @root.kind_of? Hash and @root[:type] == :code
                [@root[:fileoff]]
        else
                []
        end
end
sizeof_half() click to toggle source
# File metasm/exe_format/pyc.rb, line 30
def sizeof_half ; 2 ; end
sizeof_long() click to toggle source
# File metasm/exe_format/pyc.rb, line 32
def sizeof_long ; 4 ; end
sizeof_word() click to toggle source
# File metasm/exe_format/pyc.rb, line 31
def sizeof_word ; 4 ; end