Issues when injecting DLL from PsSetLoadImageNotifyRoutineEx callback
pussinboots1992 opened this issue · 0 comments
Hi @DarthTon ,
I am trying use the BBInjectDll() function from a callback function registered using PsSetLoadImageNotifyRoutineEx .
I want to inject automatically into certain processes very early on in the process creation process. Here is my callback function, I have some boilerplate code in this example to restrict the injection to "notepad.exe" processes (to avoid crashing the system). (I know that I should manage the DLL architecture in the code, but in my case I am testing with the x86 version of notepad and a x86 DLL):
void ModuleLoadRoutineEx(PUNICODE_STRING FullImageName, HANDLE ProcessId, PIMAGE_INFO ImageInfo)
{
NTSTATUS status;
INJECT_DLL pData;
if (FullImageName != NULL)
{
const wchar_t* path = L"C:\\MyDLL.dll";
WCHAR kernel32Mask[] = L"*\\KERNEL32.DLL";
UNICODE_STRING kernel32us;
RtlInitUnicodeString(&kernel32us, kernel32Mask);
if (FsRtlIsNameInExpression(&kernel32us, FullImageName, TRUE, NULL))
{
if (ProcessId == notepad_pid)
{
pData.pid = ProcessId;
wcscpy_s(pData.FullDllPath,512, path);
pData.type = IT_Thread;
pData.initRVA = 0;
pData.unlink = FALSE;
pData.erasePE = FALSE;
pData.wait = FALSE;
KdPrint(("[Info] notepad.exe is loading Kernel32.dll"));
//DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "[Info] Module is being loaded\n [Info] Module name: %wZ\n", FullImageName);
status = BBInjectDll(&pData);
KdPrint(("Ran BBInjectDLL..."));
notepad_pid = NULL;
}
}
}
}
It seems to fail in the BBExecuteInNewThread call, the only message I get in the debugger is Module base = 0. Aborting. If I set the pData.wait to TRUE, the process appears to hang for 60 seconds :
if (pData->type == IT_Thread)
{
status = BBExecuteInNewThread(pUserBuf, NULL, THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER, pData->wait, &threadStatus);
// Injection failed
if (!NT_SUCCESS(threadStatus))
{
status = threadStatus;
DPRINT("BlackBone: %s: User thread failed with status - 0x%X\n", __FUNCTION__, status);
}
// Call Init routine
else
{
if (pUserBuf->module != 0 && pData->initRVA != 0)
{
RtlCopyMemory(pUserBuf->buffer, pData->initArg, sizeof(pUserBuf->buffer));
BBExecuteInNewThread(
(PUCHAR)pUserBuf->module + pData->initRVA,
pUserBuf->buffer,
THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER,
TRUE,
&threadStatus
);
}
else if (pUserBuf->module == 0)
DPRINT("BlackBone: %s: Module base = 0. Aborting\n", __FUNCTION__);
}
}
I can see errors in the Windows Event Log (the fault offset corresponds to the pUserBuf which contains the shellcode which calls the LdrLoadDll). The code is the x86 shellcode because the notepad process is an x86 process, the C:\MyDLL.dll file is also an x86 DLL:
Faulting application name: notepad.exe, version: 10.0.18362.1316, time stamp: 0xa3e22dbb
Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000
Exception code: 0xc0000005
Fault offset: 0x00250000
Faulting process ID: 0x16c4
Faulting application start time: 0x01d70c286653ce1e
Faulting application path: C:\Windows\SysWOW64\notepad.exe
Faulting module path: unknown
Report ID: 61a40e4e-cf78-423e-9645-f250f53e8e0a
Faulting package full name:
Faulting package-relative application ID:
Can someone point me to an example which uses the Blackbone library to perform DLL injections from a module load callback routine ?
I suppose that the 60 second hang is related to the timeout of the call to ZwWaitForSingleObject inside the BBExecuteInNewThread. I wonder if the fact that my driver calls the LdrLoadDll (which obviously needs to go through the callback routine too since it will load a DLL) function inside a user-mode application and waits for completion from within a PsSetLoadImageNotifyRoutineEx callback routine isn't the underlying issue which leads to a deadlock which is freed by the timeout once reached...
This article explains what I mean by this...
That being said, I also get the errors if I set the pData.wait to FALSE...And I once again get the Module base = 0. Aborting message printing to the debugger.
Thanks