Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory exhaustion - likely due to incorrect section parsing #635

Open
mr-tz opened this issue Nov 8, 2023 · 6 comments
Open

Memory exhaustion - likely due to incorrect section parsing #635

mr-tz opened this issue Nov 8, 2023 · 6 comments

Comments

@mr-tz
Copy link
Contributor

mr-tz commented Nov 8, 2023

Analyzing malware sample (sha256: c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316) results in memory exhaustion.

vivbin.exe -vvvv -B c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316
2023-11-08 14:17:21,380:DEBUG:vivisect.parsers.pe: initial file baseva: 0x400000  size: 0xe064d3a2[pe.py:loadPeIntoWorkspace:91]
2023-11-08 14:17:21,391:INFO:vivisect.parsers.pe: loadPeIntoWorkspace:  loading 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316' (size: 0xe064d3a2) at 0x400000[pe.py:loadPeIntoWorkspace:93]
2023-11-08 14:17:21,418:INFO:vivisect.parsers.pe: PE loader: Arch: 'i386'       Format: pe      Platform: 'windows'     Filename: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'       BaseAddr: 0x400000[pe.py:loadP
eIntoWorkspace:118]
2023-11-08 14:17:21,418:INFO:vivisect.parsers.pe: PE Imagebase: 0x400000        entry: 0x40859e codebase: 0x1000        codesize: 0x8000[pe.py:loadPeIntoWorkspace:134]
2023-11-08 14:17:21,420:INFO:vivisect.parsers.pe: PE dllname: None      fvivname: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'       md5: '5afcd5cc66ab0ddf68b1368d356bcea3' sha256: 'C177E0A9E745A247A944F805189DA
F4C2F3F059340290C8C0EC0861BACAA8316'[pe.py:loadPeIntoWorkspace:150]
2023-11-08 14:18:22,404:ERROR:vivisect.base: Traceback (most recent call last):
  File "\vivisect\vivisect\base.py", line 636, in _fireEvent
    self.ehand[event](einfo)
  File "\vivisect\vivisect\base.py", line 424, in _handleADDMMAP
    self.blockmap.initMapLookup(va, blen)
  File "\vivisect\envi\pagelookup.py", line 53, in initMapLookup
    marray = [obj] * size
MemoryError

The issue seems to be that the section table (section headers) offset gets identified as 480 (0x1E0) instead of 488 (0x1E8) which then leads to parsing a section with VirtualSize 2019914798.

@atlas0fd00m
Copy link
Contributor

thanks @mr-tz . will look into it.

@atlas0fd00m
Copy link
Contributor

confirmed:

$ vivbin -vvvvvvvvvv -B c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316 
2023-11-09 14:14:47,837:DEBUG:vivisect.parsers.pe: initial file baseva: 0x400000  size: 0xe064d3a2[pe.py:loadPeIntoWorkspace:91]
2023-11-09 14:14:47,838:INFO:vivisect.parsers.pe: loadPeIntoWorkspace:  loading 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316' (size: 0xe064d3a2) at 0x400000[pe.py:loadPeIntoWorkspace:93]
2023-11-09 14:14:47,861:INFO:vivisect.parsers.pe: PE loader: Arch: 'i386'       Format: pe      Platform: 'windows'     Filename: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'    BaseAddr: 0x400000[pe.py:loadPeIntoWorkspace:118]
2023-11-09 14:14:47,861:INFO:vivisect.parsers.pe: PE Imagebase: 0x400000        entry: 0x40859e codebase: 0x1000        codesize: 0x8000[pe.py:loadPeIntoWorkspace:134]
2023-11-09 14:14:47,864:INFO:vivisect.parsers.pe: PE dllname: None      fvivname: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'    md5: '5afcd5cc66ab0ddf68b1368d356bcea3' sha256: 'C177E0A9E745A247A944F805189DAF4C2F3F059340290C8C0EC0861BACAA8316'[pe.py:loadPeIntoWorkspace:150]
2023-11-09 14:14:47,864:DEBUG:vivisect.base: Adding Memory Map: 0x400000(0x1000 big) name: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'  (align: None)[base.py:_handleADDMMAP:421]
getting struct 'pe.IMAGE_DOS_HEADER':  IMAGE_DOS_HEADER
getting struct 'pe.IMAGE_FILE_HEADER':  IMAGE_FILE_HEADER
getting struct 'pe.IMAGE_OPTIONAL_HEADER':  IMAGE_OPTIONAL_HEADER
getting struct 'pe.IMAGE_SECTION_HEADER':  IMAGE_SECTION_HEADER
2023-11-09 14:14:49,627:DEBUG:vivisect.base: Adding Memory Map: 0x400074(0x7865742e big) name: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'  (align: 4096)[base.py:_handleADDMMAP:421]
getting struct 'pe.IMAGE_SECTION_HEADER':  IMAGE_SECTION_HEADER
2023-11-09 14:15:01,050:DEBUG:vivisect.base: Adding Memory Map: 0x7f406174(0x6164722e big) name: 'c177e0a9e745a247a944f805189daf4c2f3f059340290c8c0ec0861bacaa8316'  (align: 4096)[base.py:_handleADDMMAP:421]
Killed

still uncertain why it's loading that map. will have to schedule some time to investigate. any input/context you may be able to add about this bin would be awesome. otherwise, we'll have to look through the PE parser and look for ways it differs from the PE Loader. if there's simply logic as to why this is misreading or why this map wouldn't normally be loaded into RAM on a target, that would speed resolution ;)
(yes, i'm asking if you've done part of my job for me already ;)

thx either way!

@atlas0fd00m
Copy link
Contributor

sorry, you already did give great context.
anything else is welcome, but i don't want to forget to appreciate this:

The issue seems to be that the section table (section headers) offset gets identified as 480 (0x1E0) instead of 488 (0x1E8) which then leads to parsing a section with VirtualSize 2019914798.

@atlas0fd00m
Copy link
Contributor

the reason i ask for anything else is because malware tends to exploit how an OS works in undocumented ways to make our jobs harder. obviously you know that already :)
so it could be us parsing the size wrong, or missing some other oddity that would use intentionally corrupted headers in a way that works on real hardware but breaks tools like ours.

@mr-tz
Copy link
Contributor Author

mr-tz commented Nov 10, 2023

PE.PE.parseSections() calculates the offset to the start of the section headers.

In my limited testing and per my understanding [1] this should suffice to get the offset:
off = self.IMAGE_DOS_HEADER.e_lfanew + len(self.IMAGE_NT_HEADERS)

For the sample above that's 488 (0x1E8).

The issue here seems to be that the used calculation then subtracts the length of the DataDirectory before adding the NumberOfRvaAndSizes * sizeof(IMAGE_DATA_DIRECTORY).

Here:
len(self.IMAGE_NT_HEADERS.OptionalHeader.DataDirectory) is 128

and

self.IMAGE_NT_HEADERS.OptionalHeader.NumberOfRvaAndSizes * len(vstruct.getStructure("pe.IMAGE_DATA_DIRECTORY")) is 120 (where the last 8 bytes [Reserved, must be zero] are missing?)

Obviously, this is a core parsing part and worked well so far. So more testing and reading is necessary. I wanted to provide what I had so far though.

[1] The PE file header consists of a Microsoft MS-DOS stub, the PE signature, the COFF file header, and an optional header. A COFF object file header consists of a COFF file header and an optional header. In both cases, the file headers are followed immediately by section headers. - via https://learn.microsoft.com/en-us/windows/win32/debug/pe-format

@atlas0fd00m
Copy link
Contributor

thank you, @mr-tz ! that's truly very helpful analysis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants