danielplohmann / apiscout

This project aims at simplifying Windows API import recovery on arbitrary memory dumps
BSD 2-Clause "Simplified" License
241 stars 41 forks source link

Lief error reading file in Python 3.10 #38

Closed malware-kitten closed 1 year ago

malware-kitten commented 1 year ago

The file I used is a copy of plugx from Malpedia, but the error should reproduce regardless.

When using ApiScout on 3.8 this all works as expected

Python 3.8.10 (default, Nov 14 2022, 12:59:47) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from apiscout.ApiScout import ApiScout
>>> buf = open('malpedia/win.plugx/vt-2021-08-03-MustangPanda/9c89776d100ecb57dc84742b433c7d7d0eca291f523cc662c94e2582c1a476f4_unpacked', 'rb').read()
>>> scout = ApiScout()
>>> scout.setBaseAddress(0)
>>> scout_ev = scout.evaluateImportTable(buf, is_unmapped=True)
 is not an ELF
>>> scout.getWinApi1024Vectors(scout_ev).get('import_table', {}).get('vector', None)
'A109EA5wA3QA4EA5BAQA5CA4IQA7SAExoAgQXpD}-MpYyl?'

However when using 3.10:

Python 3.10.9 (main, Dec 08 2022, 14:49:06) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from apiscout.ApiScout import ApiScout
>>> buf = open('malpedia/win.plugx/vt-2021-08-03-MustangPanda/9c89776d100ecb57dc84742b433c7d7d0eca291f523cc662c94e2582c1a476f4_unpacked', 'rb').read()
>>> scout = ApiScout()
>>> scout.setBaseAddress(0)
>>> scout_ev = scout.evaluateImportTable(buf, is_unmapped=True)
.....snipped.....
                                                                                                                                                               ????? ?$?(?,?0?4?8?<?@?D?H?L?P?\?`?d?h?l?p?t?x?|?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�h00                                                                                                                                                                                                                                                                                                                040D0T0d0t0�0�0�0�0�0�0H2P2T2X2\2`2d2h2l2p2t2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2�2'
Unknown format
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.10/site-packages/apiscout-2.0.0-py3.10.egg/apiscout/ApiScout.py", line 194, in evaluateImportTable
    bitness = 32 if lief_binary.header.machine == lief.PE.MACHINE_TYPES.I386 else 64
AttributeError: 'NoneType' object has no attribute 'header'

It looks like the actual error is just above the line mentioned in the error.

lief_binary = lief.parse(bytearray(binary))

When not explicitly casting it to a bytearray the file will parse.

Working example (under 3.10)

Python 3.10.9 (main, Dec 08 2022, 14:49:06) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import lief
>>> from apiscout.ApiScout import ApiScout
>>> scout = ApiScout()
>>> scout.setBaseAddress(0)
>>> buf = open('malpedia/win.plugx/vt-2021-08-03-MustangPanda/9c89776d100ecb57dc84742b433c7d7d0eca291f523cc662c94e2582c1a476f4_unpacked', 'rb').read()
>>> lief_binary = lief.parse(buf)
>>> results = {"import_table": []}
>>> bitness = 32 if lief_binary.header.machine == lief.PE.MACHINE_TYPES.I386 else 64
>>> for imported_library in lief_binary.imports:
...     for func in imported_library.entries:
...         if func.name:
...             results["import_table"].append((func.iat_address + 0, 0xFFFFFFFF, imported_library.name.lower() + "_0x0", func.name, bitness, True, 1, set()))
... 
>>> scout.getWinApi1024Vectors(results).get('import_table', {}).get('vector', None)
'A109EA5wA3QA4EA5BAQA5CA4IQA7SAExoAgQXpD}-MpYyl?'
danielplohmann commented 1 year ago

Happy new year to you! Thanks for highlighting this issue! I haven't upgraded to Python3.10 yet, so that went unnoticed. ;) It's fixed in apiscout-2.0.1 which I just pushed here and to PyPI!