Fix shellcode emulation: use memory-mapped image for decoy PEs#284
Draft
williballenthin wants to merge 4 commits intomasterfrom
Draft
Fix shellcode emulation: use memory-mapped image for decoy PEs#284williballenthin wants to merge 4 commits intomasterfrom
williballenthin wants to merge 4 commits intomasterfrom
Conversation
Co-authored-by: Moritz <mr-tz@users.noreply.github.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
05b1a1e to
c5c7ea4
Compare
The ApiModuleLoader was writing raw PE file bytes into emulated memory, but PE sections have different file offsets vs virtual addresses. Shellcode that walks the PEB InInitializationOrderModuleList to find kernel32 and then parses its export directory would read garbage because the .edata section data was at its file offset rather than its virtual address. Use pefile's get_memory_mapped_image() so sections are placed at their correct virtual addresses, matching how Windows loads DLLs. Also fixes Process.ldr_entries being a shared class-level mutable default instead of a per-instance list, and corrects the test config module order to list ntdll before kernel32 (matching the default config). Closes #45
c5c7ea4 to
1e486dc
Compare
williballenthin
commented
Mar 10, 2026
|
|
||
| jit = JitPeFile(self._arch, base=self._base) | ||
| img_data = jit.get_decoy_pe_image(self._name, all_exports) | ||
| jit.get_decoy_pe_image(self._name, all_exports) |
Collaborator
Author
There was a problem hiding this comment.
now this doesn't return anything that we use? that seems like the API is designed wrong, then.
Collaborator
Author
There was a problem hiding this comment.
are we using it for a side effect (in which case the name shouldn't be get_*)? or is this now dead code?
williballenthin
commented
Mar 10, 2026
Collaborator
Author
There was a problem hiding this comment.
remove this file, too contrived.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ApiModuleLoaderwrote raw PE file bytes into emulated memory, but PE sections have different file offsets vs virtual addresses. Shellcode walking the PEBInInitializationOrderModuleListto find kernel32 and parse its export directory would read garbage data because.edatawas at its file offset rather than its virtual address.pefile.get_memory_mapped_image()so sections are placed at their correct virtual addresses, matching how Windows actually loads DLLs.Process.ldr_entrieswas a shared class-level mutable list (classic Python gotcha) instead of per-instance, causing cross-test contamination. Moved to__init__.test.jsonnow lists ntdll before kernel32, matching the default config order.Test plan
test_peb_shellcode.pywith two tests:WinExecfrom kernel32 viaInInitializationOrderModuleList_ordered_peb_modules())Closes #45
🤖 Generated with Claude Code