Open
Conversation
Replace -fno-asynchronous-unwind-tables with -fasynchronous-unwind-tables and add -mabi=ms to OPTIMIZATION_FLAGS.
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.
BOF Module Stomping — Execute BOF Sections from Legitimate DLL
.textMemoryOverview
Adds module stomping for BOF execution, allowing BOF sections to execute from within the
.textregion of a legitimate Windows DLL instead of anonymousVirtualAllocmemory.Two techniques are supported and selected at compile time via
BOF_STOMP_METHOD.Techniques
Technique 0 —
LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES)Loads the sacrificial DLL without resolving imports. Simple and reliable. However, the DLL is still subject to CFG and ETW callbacks, and a PEB loader entry is automatically created.
Technique 1 —
NtCreateSection+NtMapViewOfSectionMaps the DLL directly via NT APIs with:
LoadLibraryETW callbacksA synthetic
LDR_DATA_TABLE_ENTRYis manually inserted intoInLoadOrderModuleListandInMemoryOrderModuleListso stack walkers resolve the DLL name correctly.Key Properties
PAGE_EXECUTE_READ— no RWX at execution time.pdatahandlingRtlAddFunctionTabledynamic entries.textbytes saved and restored after each BOF executionCRITICAL_SECTIONguards the stomp region against concurrent BOF executionUI Changes
The BOF Module Stomping group in the agent config now exposes a Method combo box (
LoadLibraryEx/NtCreateSection + NtMapViewOfSection), disabled automatically when x86 arch is selected.Call Stack Comparison
Without BOF Stomping
Anonymous
0x7ff...address at frame 2 — immediately flagged by stack-based EDR heuristics.With BOF Stomping (Technique 1 —
NtCreateSection)Frame 2 resolves to
edgehtml.dll+0x1095— indistinguishable from a legitimate DLL-backed call stack.Compile Flags — Unwind Table Fix for Clean Sleep Stack
Change
Why
-fno-unwind-tables+-fno-asynchronous-unwind-tablesstrips.pdata/.xdatafrom the agent binary entirely. Without RUNTIME_FUNCTION entries, the x64 stack unwinder cannot walk past agent frames — frames that lack unwind metadata show up as raw0x25000000000,0xd14cdff920, etc., polluting the call stack with ~20 unresolvable pointers that are a trivial EDR signal.Switching to
-fasynchronous-unwind-tablesre-emits.pdataso the unwinder can correctly walk every agent frame.-mabi=msenforces the Microsoft x64 calling convention, required for correct unwind info when targeting Windows from a cross-compiler.Call Stack Comparison
Without fix — frames 10–31 are garbage addresses; unwinder falls off a cliff after
agent.x64.exe+0x1666b:With fix — clean 17-frame stack, all agent frames resolve, terminates properly at
kernel32!BaseThreadInitThunk→ntdll!RtlUserThreadStart: