我已经制作了大约两个星期的内核级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搜索。
这是一些调试和反汇编的图像,以防可能有用:
c - 从APC调用LdrLoadDll会导致访问冲突-LMLPHP
c - 从APC调用LdrLoadDll会导致访问冲突-LMLPHP

最佳答案

我设法自己找到了解决问题的办法。显然我的代码没有错,但是编译器正在生成一条错误的指令。在我的第一个截屏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/

10-13 05:55