win0上的win0 APC DLL注入崩溃目标进程

时间:2012-11-18 12:46:03

标签: crash driver apc dll-injection

我正在尝试实现ring0 dll注入器驱动程序并通过APC注入实现。代码在win XP上完美运行。在win7上,它不断崩溃目标进程。

这是代码:

NTSTATUS InjectDll( IN ULONG ulProcessId, HANDLE hEvent, IN TCHAR * pszDllPath )
{
    NTSTATUS            ntStatus;
    HANDLE              hProcess = NULL;
    OBJECT_ATTRIBUTES   ObjectAttributes;
    CLIENT_ID           ClientId;
    PKEVENT             pevtWait;
    PKPROCESS           pPcb = NULL;
    PVOID               pArg = NULL;
    ULONG               ulSize = 0;
    KAPC_STATE          ApcState;
    PKAPC               pApc;
    PVOID               pTcb;
    PVOID               pfnLoadLibrary;
    KPROCESSOR_MODE     PreviousMode = ExGetPreviousMode();
    LARGE_INTEGER       nTimeout;

    nTimeout.QuadPart = (LONGLONG) -300000000;

    do
    {
        InitializeObjectAttributes( 
            &ObjectAttributes,
            NULL,
            0,
            NULL,
            NULL)

        ClientId.UniqueProcess = (HANDLE)ulProcessId;
        ClientId.UniqueThread = 0;

        ntStatus = ZwOpenProcess(
            &hProcess,
            PROCESS_ALL_ACCESS,
            &ObjectAttributes,
            &ClientId
        );
        if ( NT_ERROR(ntStatus) )
        {
            DbgPrint("Open process %d failed - error 0x%X\r\n", ulProcessId, ntStatus);
            break;
        }

        ulSize = MAX_FILENAME_LEN * sizeof(WCHAR);
        ntStatus = ZwAllocateVirtualMemory(
            hProcess,
            &pArg,
            0,
            &ulSize,
            MEM_RESERVE|MEM_COMMIT,
            PAGE_READWRITE);
        if ( NT_ERROR(ntStatus) )
        {
            DbgPrint("ZwAllocateVirtualMemory failed - error 0x%X\r\n", ntStatus);
            // thus, make it leak in target process space!
            break;
        }

        ntStatus = ObReferenceObjectByHandle( 
            hProcess,
            PROCESS_ALL_ACCESS,
            0,//should be PsProcessType,
            PreviousMode,
            (PVOID*)&pPcb,
            NULL);
        if ( NT_ERROR(ntStatus) )
        {
            DbgPrint("ObReferenceObjectByHandle 0x%X failed - error 0x%X\r\n", hProcess, ntStatus);
            break;
        }

        //enter target process space
        KeStackAttachProcess(pPcb,&ApcState);

        pfnLoadLibrary = GetLoadLibraryAddress(pPcb);
        if (!pfnLoadLibrary)
        {
            DbgPrint("Failed to get address of LoadLibrary\r\n");
            // leave target process space
            KeUnstackDetachProcess(&ApcState);
            break;
        }
        else
        {
            DbgPrint("Get address of LoadLibrary : 0x%X\r\n", pfnLoadLibrary);
        }

        RtlCopyMemory( pArg, pszDllPath, MAX_FILENAME_LEN * sizeof(TCHAR));

        // leave target process space
        KeUnstackDetachProcess(&ApcState);

        // get target thread
        pTcb = GetThreadByProcess(pPcb);
        if (!pTcb)
        {
            DbgPrint("Get thread failed!\r\n");
            ntStatus = STATUS_UNSUCCESSFUL;
            break;
        }

        // start inject
        pApc = (PKAPC)ExAllocatePoolWithTag(NonPagedPool,sizeof(KAPC),POOL_TAG);
        if (!pApc)
        {
            DbgPrint("Failed to allocate memory for the APC structure\r\n");
            ntStatus = STATUS_INSUFFICIENT_RESOURCES;
            break;
        }

        KeInitializeApc(
            pApc,
            (PETHREAD)pTcb,
            OriginalApcEnvironment,
            &ApcKernelRoutine,
            NULL,
            (PKNORMAL_ROUTINE)pfnLoadLibrary,
            UserMode,
            pArg);


        if (!KeInsertQueueApc(pApc,NULL,NULL,0))
        {
            DbgPrint("Failed to insert APC\r\n");
            ntStatus = STATUS_UNSUCCESSFUL;
            ExFreePool(pApc);
            break;
        }

    } while (0);


    if ( pPcb )
    {
        ObDereferenceObject(pPcb);
    }

    if ( hProcess)
    {
        ZwClose(hProcess);
    }

    DbgPrint("InjectDll end - status = 0x%X\r\n", ntStatus);
    return ntStatus;
}

injectIll由DeviceIoControl服务程序调用。

    DRIVER_DISPATCH InjectorDeviceControl;
NTSTATUS NTAPI InjectorDeviceControl( 
    IN PDEVICE_OBJECT pDeviceObject, 
    PIRP pIrp)
{
    PIO_STACK_LOCATION pStack;
    PINJECT_DLL_PARAM pParam;
    NTSTATUS ntStatus;

    DbgPrint("call InjectorDeviceControl...\r\n");

    /* Get the stack location and parameters */
    pStack = IoGetCurrentIrpStackLocation(pIrp);
    pParam = (PINJECT_DLL_PARAM)pIrp->AssociatedIrp.SystemBuffer;


    if (pStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_INJECTDLL)
    {
        /* Unsupported command */
        ntStatus = STATUS_NOT_IMPLEMENTED;
    }
    else
    {
        /* Validate the input buffer length */
        if (pStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(INJECT_DLL_PARAM))
        {
            /* Invalid buffer */
            ntStatus = STATUS_INVALID_PARAMETER;
        }
        else
        {
            /* Inject dll */
            ntStatus = InjectDll(pParam->ulProcessId, pParam->hEvent, pParam->DllName);
        }
    }

    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
    return ntStatus;
} 

这是目标进程的崩溃堆栈跟踪。

FAULTING_IP: 
ntdll!RtlActivateActivationContextUnsafeFast+9c
7770f59a 8933            mov     dword ptr [ebx],esi

EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 7770f59a (ntdll!RtlActivateActivationContextUnsafeFast+0x0000009c)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 00000000
Attempt to write to address 00000000

DEFAULT_BUCKET_ID:  NULL_POINTER_WRITE

PROCESS_NAME:  QQProtect.exe

ERROR_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - 0x%08lx

EXCEPTION_PARAMETER1:  00000001

EXCEPTION_PARAMETER2:  00000000

WRITE_ADDRESS:  00000000 

FOLLOWUP_IP: 
ntdll!RtlActivateActivationContextUnsafeFast+9c
7770f59a 8933            mov     dword ptr [ebx],esi

NTGLOBALFLAG:  0

FAULTING_THREAD:  00000300

PRIMARY_PROBLEM_CLASS:  NULL_POINTER_WRITE

BUGCHECK_STR:  APPLICATION_FAULT_NULL_POINTER_WRITE

LAST_CONTROL_TRANSFER:  from 77740baa to 7770f59a

STACK_TEXT:  
021df8a0 77740baa 75655a2c 00000000 02790000 ntdll!RtlActivateActivationContextUnsafeFast+0x9c
021df91c 77740461 002b5cd0 021dfab8 756559bc ntdll!LdrpProcessStaticImports+0x1b8
021dfa8c 7774232c 021dfaec 021dfab8 00000000 ntdll!LdrpLoadDll+0x314
021dfac0 759088ee 0026f074 021dfb00 021dfaec ntdll!LdrLoadDll+0x92
021dfaf8 75dc3c12 00000000 00000000 00000001 KERNELBASE!LoadLibraryExW+0x15a
021dfb0c 77726f7d 02790000 00000000 00000000 kernel32!LoadLibraryW+0x11
021dff88 75dc3c45 00000000 021dffd4 777437f5 ntdll!KiUserApcDispatcher+0x25
021dff94 777437f5 00295fe8 75655ce4 00000000 kernel32!BaseThreadInitThunk+0xe
021dffd4 777437c8 7770fd0f 00295fe8 00000000 ntdll!__RtlUserThreadStart+0x70
021dffec 00000000 7770fd0f 00295fe8 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  ~1s; .ecxr ; kb

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  ntdll!RtlActivateActivationContextUnsafeFast+9c

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: ntdll

IMAGE_NAME:  ntdll.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  4ce7b96e

FAILURE_BUCKET_ID:  NULL_POINTER_WRITE_c0000005_ntdll.dll!RtlActivateActivationContextUnsafeFast

BUCKET_ID:  APPLICATION_FAULT_NULL_POINTER_WRITE_ntdll!RtlActivateActivationContextUnsafeFast+9c

WATSON_STAGEONE_URL:  http://watson.microsoft.com/StageOne/QQProtect_exe/3_0_1_3629/50a06369/ntdll_dll/6_1_7601_17514/4ce7b96e/c0000005/0002f59a.htm?Retriage=1

Followup: MachineOwner

任何想法?

2 个答案:

答案 0 :(得分:0)

我正在研究dll-injetion的一些apc,并遇到了同样的问题。
在进行了反向强化后,我发现了为什么会发生这种情况。

这是由于当前线程的TEB没有ActivationContextStackPointer成员引起的:

ntdll!_TEB
   +0x000 NtTib            : _NT_TIB 
   +0x01c EnvironmentPointer : (null) 
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : (null) 
   +0x02c ThreadLocalStoragePointer : (null) 
   +0x030 ProcessEnvironmentBlock : 0x7ffd8000 _PEB
   +0x034 LastErrorValue   : 0
   +0x038 CountOfOwnedCriticalSections : 0
   +0x03c CsrClientThread  : (null) 
   +0x040 Win32ThreadInfo  : (null) 
   +0x044 User32Reserved   : [26] 0
   +0x0ac UserReserved     : [5] 0
   +0x0c0 WOW32Reserved    : (null) 
   +0x0c4 CurrentLocale    : 0x804
   +0x0c8 FpSoftwareStatusRegister : 0
   +0x0cc SystemReserved1  : [54] (null) 
   +0x1a4 ExceptionCode    : 0n0
   +0x1a8 ActivationContextStackPointer : (null) <---it's null

RtlActivateActivationContextUnsafeFast函数尝试在ActivationContext列表中插入一个节点,但是ActivationContextStackPointernull,因此引发了ACCESS_VIOLATION

    mov     dword ptr [ebx],esi  //ebx = teb->ActivationContextStackPointer  which is 000000000  esi = node

ActivationContextDLL的清单有关。

您可以在Microsoft help中获得有关此信息的更多信息。

在加载清单文件的dll时,将调用RtlActivateActivationContextUnsafeFast

在这种情况下,我通过禁用dll清单文件的生成来解决了这个问题:

  

链接器->(/MANIFEST:NO

或者您可以通过使目标线程调用ActivationContextStack函数来尝试强制系统为目标线程分配ActivateActCtx(我不确定是否可能吗?)。 / p>

希望这对您有所帮助。

答案 1 :(得分:0)

我偶然发现了一个相同的问题,在Windows 10上崩溃略有不同(无效的地址访问,但没有NULL指针取消引用)。我不喜欢王云路的解决方案,因为我希望能够加载任何DLL。对我有用的是直接调用NtQueueApcThread而不是使用QueueUserAPC。在这种情况下,RtlDispatchAPC被绕过,激活函数不会被调用。

参考:
https://repnz.github.io/posts/apc/user-apc/#queueuserapc-kernelbase-dll-layer