Closed michaelweiser closed 3 years ago
I have had the same issue running capemon_32 bit on WINWORD 32bit , though on 64bit it runs fine
Sorry for taking a long time to respond. Results of tests with Office are that both 32bit and 64bit Winword and Excel also crash with PEB hiding active on my Windows 10 test system. With PEB hiding disabled they get further but still don't fully work. E.g. 64-bit Winword runs into #12. 32-bit Winword seems to crash early on which I haven't dug into yet.
Another tidbit: cmd
's message Not enough memory resources are available to process this command.
is a ubiquitous catch-all for all kinds of unexpected situations and totally misleading most of the time. With PEB hiding disabled I dug into another instance of this message appearing which eventually turned out to be related to the fact that my cmd
is elevated (i.e. implicitly "Run as Administrator" because UAC is fully disabled) and is therefore not allowed to query the current console title using GetConsoleTitleW
to prepend Administrator:
to it before displaying a prompt. Only after I went all the way down into remote Windows kernel debugging of the related syscall did I notice that this message also appears without capemon being present at all, so is a "normal" Windows bug or rather "works as designed".
Firstly Michael a thank you for investing so much time and effort into diagnosing these Win10 issues. I haven't had time to look into this yet but today merged a PR (https://github.com/kevoreilly/capemon/commit/7697da441eec778f196dcbc29f22d93f68f82cc5) which addresses an issue parsing InLoadOrderModuleList (https://github.com/kevoreilly/capemon/issues/13) within hide_module_from_peb(). So I would ask you to try these fixes to see if this might by some stroke of luck boil down to the same issue.
I was hoping the same when I saw #13 and tried and just retried it now after being merged. Unfortunately, it does not seem to have any direct positive impact on our problem here. I still need to comment out the memset(mod, 0, ...)
in hide_module_from_peb()
in order for my test case not to run into the access violation leading to that infamous resource message from cmd.exe
. This is likely because with regards to the address pointed to by mod
and the size of the structure, nothing has changed with the modifications of #13.
In desperation I just tried clearing each structure member individually and struck gold: I can clear every member but BaseAddress
without problems. But as soon as I touch BaseAddress
, the problem returns. So with the following change, I can more selectively avoid the issue:
@@ -811,7 +811,20 @@ void hide_module_from_peb(HMODULE module_handle)
// like InLoadOrderModuleList etc
CUT_LIST(mod->HashTableEntry);
- memset(mod, 0, sizeof(LDR_DATA_TABLE_ENTRY));
+ //memset(mod, 0, sizeof(LDR_DATA_TABLE_ENTRY));
+ memset(&mod->InLoadOrderModuleList, 0, sizeof(mod->InLoadOrderModuleList));
+ memset(&mod->InMemoryOrderModuleList, 0, sizeof(mod->InMemoryOrderModuleList));
+ memset(&mod->InInitializationOrderModuleList, 0, sizeof(mod->InMemoryOrderModuleList));
+ //mod->BaseAddress = 0;
+ mod->EntryPoint = 0;
+ mod->SizeOfImage = 0;
+ memset(&mod->FullDllName, 0, sizeof(mod->FullDllName));
+ memset(&mod->BaseDllName, 0, sizeof(mod->BaseDllName));
+ mod->Flags = 0;
+ mod->LoadCount = 0;
+ mod->TlsIndex = 0;
+ memset(&mod->HashTableEntry, 0, sizeof(mod->HashTableEntry));
+ mod->TimeDateStamp = 0;
break;
}
}
This would support my initial guess that someone else is still referencing that structure and is using BaseAddress
in particular. I think it's not a stretch to point fingers at LdrResolveDelayLoadedAPI
. Now we'd need to figure out, where that reference lives and how to clear it as well.
The original code ref for this technique has commented out the memset and marked it optional: http://www.openrce.org/blog/view/844/How_to_hide_dll. Also removing the entry from the linked list is sufficient to achieve the function's goal, so the memset is technically superfluous. You must be right that something is still referencing this entry, but if removing the memset solves the issue and still means the module is removed from the peb's linked list, that's good enough for me. I'll push the fix soon.
This is now pushed so hopefully that's the end of this issue - thanks as ever for the all the effort and feedback!
We're trying to use CAPEv2 to analyse malware on Windows 10. After we had various types of analyses fail with changing errors on Windows 10 but succeeding on Windows 7, we dug into a simple test case to try and determine the root cause. We used a simple
downloadExe.bat
which initially employedpowershell.exe
but eventually only consisted of anecho hi
.By itself it (obviously) runs fine. When run under observation by
capemon.dll
it reliably ends in a state where a console window is open and shows error message:but no
hi
. This is when started from CAPE via its web frontend in a freshly resumed Windows 10 VM as well as when run from a debug setup with a manually set up analyzer,analysis.conf
and various debug and devel tools at hand (particularly Visual Studio Community 2019 and x96dbg). We focused on only the 32-bitcmd.exe
andcapemon.dll
for now.Digging into this further we determined that this message is a misleading catch-all follow-up error and that the actual cause is a memory access violation exception in
cmd.exe
. Digging into this showedLdrResolveDelayLoadedAPI
returning a Null Pointer for theShellExecuteExW
function which is indeed delay-loaded incmd.exe
. We were not able to determine a cause for this or reproduce it in simpler hand-written test cases involving a small C program using a delay-loadedShellExecuteExW
to run e.g.nodepad.exe
.By pure coincidence when doing a debug build we then found that disabling the call to
hide_module_from_peb()
incapemon.c
makes our test case run successfully. https://github.com/kevoreilly/capemon/blob/de2c595dffcaf69ebdbfcfcd7fcd42476b8f42e6/capemon.c#L584Further tests revealed that clearing the
LDR_MODULE
element usingmemset()
after removing it from the various linked lists seems to cause the fallout we're seeing. https://github.com/kevoreilly/capemon/blob/5f9e800e33bbf78dd816fd107de2ac01be9cd264/misc.c#L799 Disabling it makes our small test-case run through or at least further (see below).Considering the observed behaviour, it would make sense for
LdrResolveDelayLoadedAPI
to become confused if module bookkeeping became corrupted ever so slightly by thememset()
. It seems unlikely though, that the structure became smaller with Windows 10. Rather I'd speculate there to be more references on it which then point to zeroed memory, perhaps as part of an explicit hardening measure.What do you make of this? Are you aware of any security measure introduced with Windows 10 that would prevent modification of the PEB and could be disabled?
What might point to a security measure is a peculiar behaviour of Visual Studio we've observed: While Visual Studio is running (even just the startup project/solution selection screen), there seems to be some kind of DLL hosting and/or debugging aid provided by it which tolerates the
memset()
incapemon.dll
and obscures the problem. While it runs, successive analysis runs not only succeed but also seem to share the same, seemingly preloadedcapemon.dll
even if it's been replaced on disk in the meantime. As soon as Visual Studio is closed, the error behaviour returns. We've not been able to determine what functionality we're dealing with there and any pointer would be welcome.Also: Disabling the
memset()
doesn't solve all our problems. Analyses still fail, but increasingly randomly so. What's particularly confounding is that memory access violation exceptions seem to be silently ignored with release as well as debug builds ofcapemon.dll
which greatly hinders debugging. In the case ofcmd.exe
they lead to above error message (Not enough resources...
) but do not terminate the process so we can not get an automatic post-mortem debugger attach e.g. from WinDbg. The same seems to be the case on Windows 7. We've looked but not been able to find a Windows configuration setting for this. Is there any intentional compiler/linker setting or code causing this behaviour we could disable to trigger faulting on all access errors (not explicitly handled) so we can find more of these problems quicker?