d0c-s4vage / pfp

pfp - Python Format Parser - a python-based 010 Editor template interpreter
MIT License
196 stars 37 forks source link

Support for DEX template? #14

Open Disane opened 9 years ago

Disane commented 9 years ago

Hi,

I've noticed that when trying to use the DEX template, PFP yields a no attribute error on an 'Array'. I used the following template: http://www.sweetscape.com/010editor/templates/files/DEXTemplate.bt

Is there a possibility for you to add DEX binary template support to PFP?

In [2]: dom = pfp.parse(data_file='/mnt/hgfs//classes.dex', template_file='/mnt/hgfs//DEXTemplate.bt')--------------------------------------------------------------------------- PfpError Traceback (most recent call last)

in () ----> 1 dom = pfp.parse(data_file='/mnt/hgfs//classes.dex', template_file='/mnt/hgfs//DEXTemplate.bt') /usr/local/lib/python2.7/dist-packages/pfp/**init**.pyc in parse(data, template, data_file, template_file, interp, debug, predefines, int3, cpp_path, cpp_args, keep_successful) 62 data = BitwrappedStream(data) 63 ---> 64 dom = interp.parse(data, template, predefines=predefines, orig_filename=orig_filename, keep_successful=keep_successful) 65 66 # close the data stream if a data_file was specified /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in parse(self, stream, template, predefines, orig_filename, keep_successful) 668 self._dlog("parsed template into ast") 669 --> 670 res = self._run(keep_successful) 671 return res 672 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _run(self, keep_successfull) 872 errors.PfpError, 873 errors.PfpError(exc_obj.__class__.**name** + ": " + exc_obj.args[0] + more_info if len(exc_obj.args) > 0 else more_info), --> 874 traceback 875 ) 876 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _run(self, keep_successfull) 851 # it is important to pass the stream in as the stream 852 # may change (e.g. compressed data) --> 853 res = self._handle_node(self._ast, None, None, self._stream) 854 except errors.InterpReturn as e: 855 # TODO handle exit/return codes (e.g. return -1) /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_file_ast(self, node, scope, ctxt, stream) 967 968 for child in node.children(): --> 969 self._handle_node(child, scope, ctxt, stream) 970 971 ctxt._pfp__process_fields_metadata() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_decl(self, node, scope, ctxt, stream) 1152 1153 field_res._pfp__interp = self -> 1154 field._pfp__init(stream) 1155 added_child = True 1156 else: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _pfp__init(self, stream) 48 ) 49 param_list = params.instantiate(scope, struct_args, self._pfp__interp) ---> 50 super(self.__class__, self)._pfp__init(stream) 51 52 new_class = type(struct_cls.__name__ + "_", (struct_cls,), { /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _pfp__init(self, stream) 78 decls, 79 ctxt=self, ---> 80 stream=stream 81 ) 82 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_struct_decls(self, node, scope, ctxt, stream) 1429 for decl in node.decls: 1430 # new context! (struct) -> 1431 self._handle_node(decl, scope, ctxt, stream) 1432 1433 ctxt._pfp__process_fields_metadata() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_decl(self, node, scope, ctxt, stream) 1155 added_child = True 1156 else: -> 1157 field = field(stream, metadata_processor=metadata_processor) 1158 1159 if not added_child: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in **init**(self, stream, metadata_processor) 102 width = fields.PYVAL(item_count) 103 def **init**(self, stream=None, metadata_processor=None): --> 104 fields.Array.**init**(self, self.width, self.field_cls, stream, metadata_processor=metadata_processor) 105 new_class = type("Array_{}_{}".format(item_cls.__name__, width), (fields.Array,), { 106 "**init**" : **init**, /usr/local/lib/python2.7/dist-packages/pfp/fields.pyc in **init**(self, width, field_cls, stream, metadata_processor) 1408 1409 if stream is not None: -> 1410 self._pfp__parse(stream, save_offset=True) 1411 else: 1412 if width is not None: /usr/local/lib/python2.7/dist-packages/pfp/fields.pyc in _pfp__parse(self, stream, save_offset) 1523 self.items = [] 1524 for x in six.moves.range(PYVAL(self.width)): -> 1525 field = self.field_cls(stream) 1526 field._pfp__name = "{}[{}]".format( 1527 self._pfp__name, /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in **init**(self, stream, metadata_processor, do_init) 72 73 if do_init: ---> 74 self._pfp__init(stream) 75 76 def _pfp__init(self, stream): /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _pfp__init(self, stream) 78 decls, 79 ctxt=self, ---> 80 stream=stream 81 ) 82 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_struct_decls(self, node, scope, ctxt, stream) 1429 for decl in node.decls: 1430 # new context! (struct) -> 1431 self._handle_node(decl, scope, ctxt, stream) 1432 1433 ctxt._pfp__process_fields_metadata() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_decl(self, node, scope, ctxt, stream) 1152 1153 field_res._pfp__interp = self -> 1154 field._pfp__init(stream) 1155 added_child = True 1156 else: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _pfp__init(self, stream) 78 decls, 79 ctxt=self, ---> 80 stream=stream 81 ) 82 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_struct_decls(self, node, scope, ctxt, stream) 1429 for decl in node.decls: 1430 # new context! (struct) -> 1431 self._handle_node(decl, scope, ctxt, stream) 1432 1433 ctxt._pfp__process_fields_metadata() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_decl(self, node, scope, ctxt, stream) 1152 1153 field_res._pfp__interp = self -> 1154 field._pfp__init(stream) 1155 added_child = True 1156 else: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _pfp__init(self, stream) 78 decls, 79 ctxt=self, ---> 80 stream=stream 81 ) 82 /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_struct_decls(self, node, scope, ctxt, stream) 1429 for decl in node.decls: 1430 # new context! (struct) -> 1431 self._handle_node(decl, scope, ctxt, stream) 1432 1433 ctxt._pfp__process_fields_metadata() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_if(self, node, scope, ctxt, stream) 2034 if cond: 2035 # there should always be an iftrue -> 2036 return self._handle_node(node.iftrue, scope, ctxt, stream) 2037 else: 2038 if node.iffalse is not None: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_compound(self, node, scope, ctxt, stream) 1917 try: 1918 for child in node.children(): -> 1919 self._handle_node(child, scope, ctxt, stream) 1920 1921 # in case a return occurs, be sure to pop the scope /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_if(self, node, scope, ctxt, stream) 2031 """ 2032 self._dlog("handling if") -> 2033 cond = self._handle_node(node.cond, scope, ctxt, stream) 2034 if cond: 2035 # there should always be an iftrue /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_node(self, node, scope, ctxt, stream) 944 raise errors.UnsupportedASTNode(node.coord, node.__class__.**name**) 945 --> 946 res = self._node_switch[node.**class**](node, scope, ctxt, stream) 947 948 self._log.dec() /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in _handle_binary_op(self, node, scope, ctxt, stream) 1592 raise errors.UnsupportedBinaryOperator(node.coord, node.op) 1593 -> 1594 res = switch[node.op](left_val, right_val) 1595 1596 if type(res) is bool: /usr/local/lib/python2.7/dist-packages/pfp/interp.pyc in (x, y) 1574 "&": lambda x,y: x&y, 1575 "%": lambda x,y: x%y, -> 1576 ">": lambda x,y: x>y, 1577 "<": lambda x,y: x 506 return self._pfp__value > val 507 508 def __ge__(self, other): PfpError: AttributeError: 'Array' object has no attribute '_pfp__value' Exception at /mnt/hgfs//DEXTemplate.bt:87
d0c-s4vage commented 9 years ago

The DEX template is actually the one I am currently working through - it brings up a lot of interesting behaviors in 010 editor that I hadn't initially thought of (#17, #13, #8 (not so much an error, but I had to implement #3 to get it to work), and a few more).

Could you provide the dex file you're parsing? I'm assuming you're just using the standard DEXTemplate.bt from 010's template archive?

Disane commented 9 years ago

Hi, The classes.dex was recovered from a malware sample that encrypted it and embedded it in its assets. It's a chinese AD library if I understood it correctly:

http://www.filedropper.com/classes

MD5: 9d8f9f88e08c790dc949b85416d9794a

Yes, I'm using the standard DEXTemplate.bt found here: http://www.sweetscape.com/010editor/templates/

d0c-s4vage commented 9 years ago

I've opened #18 to address the issue

strazzere commented 9 years ago

I'd suggest using the more up to date DEXTemplate.bt from my repository. 010Editor staff doesn't seem to like updating things on their web site and also does not want to do links to repos. This one will be the most up to date and contain bug fixes;

https://github.com/strazzere/010Editor-stuff/blob/master/Templates/DEXTemplate.bt

d0c-s4vage commented 9 years ago

Thanks! I'm still going to work on getting the 010 editor DEXTemplate.bt to work; it has a lot of interesting cases that I need to work through with pfp.

d0c-s4vage commented 4 years ago

With the latest version of pfp:

python -m pfp -t DEX.bt ~/Downloads/classes.dex
Traceback (most recent call last):
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 996, in _run
    res = self._handle_node(self._ast, None, None, self._stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1148, in _handle_file_ast
    self._handle_node(child, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1370, in _handle_decl
    field._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 57, in _pfp__init
    super(self.__class__, self)._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1374, in _handle_decl
    stream, metadata_processor=metadata_processor
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 196, in __init__
    metadata_processor=metadata_processor,
  File "/home/james/__ws__/dev/pfp/pfp/fields.py", line 1974, in __init__
    self._pfp__parse(stream, save_offset=True)
  File "/home/james/__ws__/dev/pfp/pfp/fields.py", line 2113, in _pfp__parse
    field = self.field_cls(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 147, in __init__
    self._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2317, in _handle_if
    return self._handle_node(node.iftrue, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2186, in _handle_compound
    self._handle_node(child, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1370, in _handle_decl
    field._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2317, in _handle_if
    return self._handle_node(node.iftrue, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2186, in _handle_compound
    self._handle_node(child, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1370, in _handle_decl
    field._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 57, in _pfp__init
    super(self.__class__, self)._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2343, in _handle_for
    self._handle_node(node.stmt, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2186, in _handle_compound
    self._handle_node(child, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1370, in _handle_decl
    field._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 57, in _pfp__init
    super(self.__class__, self)._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1370, in _handle_decl
    field._pfp__init(stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 150, in _pfp__init
    self._pfp__interp._handle_node(decls, ctxt=self, stream=stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1667, in _handle_struct_decls
    self._handle_node(decl, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2317, in _handle_if
    return self._handle_node(node.iftrue, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2186, in _handle_compound
    self._handle_node(child, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 2314, in _handle_if
    cond = self._handle_node(node.cond, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1105, in _handle_node
    res = self._node_switch[node.__class__](node, scope, ctxt, stream)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1839, in _handle_binary_op
    res = switch[node.op](left_val, right_val)
  File "/home/james/__ws__/dev/pfp/pfp/interp.py", line 1821, in <lambda>
    ">": lambda x, y: x > y,
  File "/home/james/__ws__/dev/pfp/pfp/fields.py", line 610, in __gt__
    return self._pfp__value > val
AttributeError: 'Array' object has no attribute '_pfp__value'

Using the DEX template from 010 and the classes.dex from google/enjarify