我已经制作了大约两个星期的内核级DLL注入(inject)器。我克服了很多错误,并从中汲取了很多教训,但我仍坚持最后一期。当我将UserMode APC插入目标进程时,正常例程可以正常执行,并且正常运行,但只有以下一行异常(exception):调用LdrLoadDll
例程将DLL加载到目标进程中。当访问冲突异常调用LdrLoadDll
时,目标进程崩溃。
这是插入APC的代码:
PTITANIUM_INJECTION_INFO InjectionInfo = FindInjectionInfo(ProcessId);
wchar_t DllPathBuffer[] = L"C:\\Users\\alber\\Desktop\\TestDLL.dll";
RtlInitUnicodeString(&InjectionInfo->DllPath, DllPathBuffer);
DbgPrint("\nTarget DLL Path: %wZ\n", InjectionInfo->DllPath);
DbgPrint("LdrLoadDllRoutine is at 0x%p\n", InjectionInfo->LdrLoadDllRoutine);
PEPROCESS pProcess;
PsLookupProcessByProcessId(ProcessId, &pProcess);
PETHREAD AvailableThread = FindAvailableThread(ProcessId);
if (!AvailableThread)
{
DbgPrint("Failed to find available thread in target process\n\n");
return;
}
KeAttachProcess(pProcess);
DbgPrint("Attached to Process\n\n");
PVOID DllPathBufferAddress = NULL;
SIZE_T DllPathBufferAddressSize = 4096;
NTSTATUS status0 = ZwAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&DllPathBufferAddress, 0, &DllPathBufferAddressSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(status0))
{
DbgPrint("[-] Failed to allocate memory for dll path buffer, error code: 0x%X [-]\n", status0);
KeDetachProcess();
DbgPrint("Detached from process\n\n");
return;
}
DbgPrint("Allocated 4096 bytes for DLL Path Buffer\n");
wcscpy(DllPathBufferAddress, LocalDllPathBuffer);
DbgPrint("Local DLL Path Buffer copied into usermode space: %ws\n", DllPathBufferAddress);
PVOID ContextAddress = NULL;
SIZE_T ContextAllocationSize = 4096;
NTSTATUS status = ZwAllocateVirtualMemory(NtCurrentProcess(), &ContextAddress, 0, &ContextAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(status))
{
DbgPrint("[-] Failed to allocate memory for apc context, error code: 0x%X [-]\n", status);
KeDetachProcess();
DbgPrint("Detached from process\n\n");
return;
}
DbgPrint("APC Context allocated in the target process at 0x%p\n", ContextAddress);
memcpy(ContextAddress, InjectionInfo, sizeof(TITANIUM_INJECTION_INFO));
DbgPrint("Context copied into the target process\n");
PVOID NormalRoutineAddress = NULL;
SIZE_T NormalRoutineAllocationSize = (SIZE_T)((ULONG_PTR)NRStubFn - (ULONG_PTR)InjectorAPCNormalRoutine);
DbgPrint("Normal Routine function size: %i bytes\n", NormalRoutineAllocationSize);
status = ZwAllocateVirtualMemory(NtCurrentProcess(), &NormalRoutineAddress, 0, &NormalRoutineAllocationSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!NT_SUCCESS(status))
{
DbgPrint("[-] Failed to allocate memory for apc normal routine [-]\n");
KeDetachProcess();
DbgPrint("Detached from process\n\n");
return;
}
DbgPrint("APC Normal Routine allocated in the target process at 0x%p\n", NormalRoutineAddress);
memcpy(NormalRoutineAddress, InjectorAPCNormalRoutine, NormalRoutineAllocationSize);
DbgPrint("Normal Routine copied into the target process\n");
PKAPC apc = (PKAPC)ExAllocatePool(NonPagedPool, sizeof(KAPC));
if (!apc)
{
DbgPrint("Error: Unable to allocate the APC object.");
KeDetachProcess();
DbgPrint("Detached from process\n");
return;
}
KeInitializeApc(apc, AvailableThread, OriginalApcEnvironment, KernelApc, NULL, (PKNORMAL_ROUTINE)NormalRoutineAddress, UserMode, ContextAddress);
DbgPrint("APC initialized\n");
KeInsertQueueApc(apc, NULL, NULL, IO_NO_INCREMENT);
DbgPrint("APC inserted into the queue\n");
/*LARGE_INTEGER delay;
delay.QuadPart = -200 * 10000;
for (int i = 1; i <= 20; i++)
{
DbgPrint("[***] InjectedInfo->Inject Real Value: %i [***]\n", ((PTITANIUM_INJECTION_INFO)ContextAddress)->Injected);
if (!((PTITANIUM_INJECTION_INFO)ContextAddress)->Injected)
{
KeDelayExecutionThread(KernelMode, FALSE, &delay);
DbgPrint("[*] InjectedInfo->Inject: FALSE | Retrying: %i [*]\n", i);
}
else
{
DbgPrint("[!] InjectedInfo->Inject: TRUE | DllBase: 0x%p [!]\n", ((PTITANIUM_INJECTION_INFO)ContextAddress)->DllBase);
break;
}
}*/
KeDetachProcess();
DbgPrint("Detached from process\n");
DbgPrint("\n");
这是我的常规例程:VOID InjectorAPCNormalRoutine(PVOID Context, PVOID SysArg1, PVOID SysArg2)
{
PTITANIUM_INJECTION_INFO InjectionInfo = (PTITANIUM_INJECTION_INFO)Context;
InjectionInfo->LdrLoadDllRoutine(NULL, 0, &InjectionInfo->DllPath, &InjectionInfo->DllBase);
InjectionInfo->Injected = TRUE;
}
我尝试从一个单独的用户模式项目中手动调用LdrLoadDll,它运行良好。我还验证了两种情况下LdrLoadDll
例程地址是否相同。我真的不知道该怎么做,并相信我已经浏览了所有我能想到的Google搜索。
这是一些调试和反汇编的图像,以防可能有用:
最佳答案
我设法自己找到了解决问题的办法。显然我的代码没有错,但是编译器正在生成一条错误的指令。在我的第一个截屏call
指令上方的屏幕截图中,有一个mov
指令,它将正确的LdrLoadDll
函数地址移入rax寄存器,但是下一条指令调用了一些奇怪的地址,而不是rax寄存器中的正确地址。
我通过创建一个单独的.asm文件并编写自己的汇编程序来解决我的问题。如果有人感兴趣,这是汇编代码:
NormalRoutineNativeAssembly proc
mov qword ptr [rsp+18h], r8
mov qword ptr [rsp+10h], rdx
sub rsp, 48h
mov rax, qword ptr [rsp+50h]
mov qword ptr [rsp+30h], rax
mov rax, qword ptr [rsp+30h]
add rax, 30h
mov rcx, qword ptr [rsp+30h]
add rcx, 20h
mov rdx, qword ptr [rsp+30h]
mov rdx, qword ptr [rdx+18h]
mov qword ptr [rsp+38h], rdx
mov r9, rax
mov r8, rcx
xor edx, edx
xor ecx, ecx
mov rax, qword ptr [rsp+38h]
call rax
mov rax, qword ptr [rsp+30h]
mov byte ptr [rax+38h], 1
add rsp, 48h
ret
NormalRoutineNativeAssembly endp
感谢所有帮助我尝试找到此问题的解决方案的人。关于c - 从APC调用LdrLoadDll会导致访问冲突,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62520765/