Description
A number of users of Dr. Memory have complained about startup failures on Windows Enterprise. Since Dr. Memory prints a list of libraries it sees in its launcher that are not on an (old-ish) known library list as possible interoperability causes (since security software often fails to work well with low-level tools like ours), Dr. Memory was printing out that "bcrypt.dll" might be the culprit and so many users put that in the issue titles or used that to refer to the problem.
E.g.: https://groups.google.com/g/drmemory-users/c/9wM120ukp6c
I managed to reproduce this and the external symptoms are like this:
---------------------------
DynamoRIO Notice: C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2407.9.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe(4584)
---------------------------
Application C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2407.9.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe (4584). Out of memory. Program aborted. Source I, type 0x0000000000000001, code 0x00000000c000001c.
---------------------------
OK
---------------------------
Debug build hits this assert on failing to allocate:
SYSLOG_ERROR: Application C:\Program Files\WindowsApps\Microsoft.WindowsNotepad_11.2407.9.0_x64__8wekyb3d8bbwe\Notepad\Notepad.exe (10560). Internal Error: DynamoRIO debug check failure: D:\a\drmemory\drmemory\dynamorio\core\win32\os.c:4982 false
The failure code is usually this one:
#define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS)0xC000001CL)
Though I have seen it vary: I've seen 0x80000002, 0xc0000005, and others.
This seems to be the same as DynamoRIO/drmemory#2447.
On looking deeper we see:
- This is not from DEP: DEP is opt-in on this machine; plus a standalone test app successfully allocates +rwx memory
- This is not some security policy disallowing raw syscalls: a standalone test app can call NtAllocateVirtualMemory in assembly
The problem is that DR gets the wrong system call number for NtAllocateVirtualMemory:
syscalls_init: enum=15 name=NtAllocateVirtualMemory wrapper=0x00007ffdcfd10420 hook=0 #=0x8eb4a
bytes @:
4c 8b d1 e9 4a eb 08 00 f6 04 25 08 03 fe 7f 01 75 03 0f 05 c3 cd 2e c3 0f 1f 84 00 00 00
The number should be 0x18:
00000001800A0420: 4C 8B D1 mov r10,rcx
00000001800A0423: B8 18 00 00 00 mov eax,18h
00000001800A0428: F6 04 25 08 03 FE test byte ptr [000000007FFE0308h],1
7F 01
00000001800A0430: 75 03 jne 00000001800A0435
00000001800A0432: 0F 05 syscall
00000001800A0434: C3 ret
00000001800A0435: CD 2E int 2Eh
00000001800A0437: C3 ret
00000001800A0438: 0F 1F 84 00 00 00 nop dword ptr [rax+rax+0000000000000000h]
00 00
There's a hook in there clobbering the number:
(gdb) x/30i 0x04311420
0x4311420: mov %rcx,%r10
0x4311423: jmpq 0x439ff72
0x4311428: testb $0x1,0x7ffe0308
0x4311430: jne 0x4311435
0x4311432: syscall
0x4311434: retq
0x4311435: int $0x2e
0x4311437: retq
0x4311438: nopl 0x0(%rax,%rax,1)
DR tries to detect a hook during number acquisition but it only looks at the entry pc: so this deeper hook is not caught there.
I don't have a debugger in my test machine: but I do see that DrMemory complains about c:\windows\system32\umppc18613.dll
in addition to bcrypt.dll. And umppc18613.dll
is CrowdStrike Falcon Sensor Support Module
which is almost certainly the culprit doing this hooking.
Action items:
- Address regression making popup messages silent by default: one reason external users had so much trouble figuring this out; things just failed silently ==> filed as Package builds disable Windows notifications due to regression from Dec 2022 #7025 and now fixed
- Add bcrypt.dll to the known list: done in i#2498 bcrypt init: Add bcrypt.dll to allowlist drmemory#2516
- Figure out how to handle Windows syscall numbers going forward
For that last one this comment in the code lists the options:
/* XXX i#2713: With the frequent major win10 updates, adding new tables here is
* getting tedious and taking up space. Should we stop adding the win10 updates here
* and give up on our table of numbers, relying on reading the wrappers (i#1598
* changed DR to work purely on wrapper-obtained numbers)? We'd lose robustness vs
* hooks, and clients like Dr. Memory who have to distinguish win10 versions would
* have to do their own versioning. I guess we could still have
* DR_WINDOWS_VERSION_xx and not have corresponding tables here. Or we could go the
* planned Dr. Memory route (DrMi#1848) and store these numbers in a separate file
* that is updated via a separate standalone utility run once by the user.
*/
SYS_CONST int windows_10_1803_x64_syscalls[TRAMPOLINE_MAX] = {
If we had detected the hook, we would have fallen back to the windows_10_1803_x64_syscalls
numbers: which do have NtAllocateVirtualMemory correct but may have others wrong.
Trying to make the options more concise here for the numbers:
- Just add deep hook detection of invalid number detection (tough on wow64 w/ prefixes) and hope our old hardcoded numbers work
- The prior item, plus add the most recent number snapshot
- Adopt Dr. Memory's separate file and utility approach