欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

伪造句柄方法结束进程

伪造句柄方法结束进程

伪造句柄方法结束进程(无需驱动)
2010-6-13
系统为WinXp
XP_5.1.2600.2180
EULAID: XPSP2_RM.0_PRO_RTL_CN

TerminateProcess函数分析:
TerminateProcess
NtTerminateProcess
PspTerminateThreadByPointer(ObReferenceObjectByHandle, PsGetNextProcessThread(loop))
->Self: PspExitThread
->Other: KeInsertQueueApc, KiInsertQueueApc 
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
                   IN NTSTATUS ExitStatus)
{
    NTSTATUS Status;
    PEPROCESS Process, CurrentProcess = PsGetCurrentProcess();
    PETHREAD Thread, CurrentThread = PsGetCurrentThread();
    BOOLEAN KillByHandle;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG,
            "ProcessHandle: %p ExitStatus: %p\n", ProcessHandle, ExitStatus);
    /* Were we passed a process handle? */
    if (ProcessHandle)
    {
        /* Yes we were, use it */
        KillByHandle = TRUE;
    }
    else
    {
        /* We weren't... we assume this is suicide */
        KillByHandle = FALSE;
        ProcessHandle = NtCurrentProcess();
    }
    /* Get the Process Object */
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                       PROCESS_TERMINATE,
                                       PsProcessType,
                                       KeGetPreviousMode(),
                                       (PVOID*)&Process,
                                       NULL);
    if (!NT_SUCCESS(Status)) return(Status);
    /* Check if this is a Critical Process, and Bugcheck */
    if (Process->BreakOnTermination)
    {
        /* Break to debugger */
        PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
                              Process,
                              Process->ImageFileName);
    }
    /* Lock the Process */
    if (!ExAcquireRundownProtection(&Process->RundownProtect))
    {
        /* Failed to lock, fal */
        ObDereferenceObject (Process);
        return STATUS_PROCESS_IS_TERMINATING;
    }
    /* Set the delete flag, unless the process is comitting suicide */
    if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT);
    /* Get the first thread */
    Status = STATUS_NOTHING_TO_TERMINATE;
    Thread = PsGetNextProcessThread(Process, NULL);
    if (Thread)
    {
        /* We know we have at least a thread */
        Status = STATUS_SUCCESS;
        /* Loop and kill the others */
        do
        {
            /* Ensure it's not ours*/
            if (Thread != CurrentThread)
            {
                /* Kill it */
                PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
            }
            /* Move to the next thread */
            Thread = PsGetNextProcessThread(Process, Thread);
        } while (Thread);
    }
    /* Unlock the process */
    ExReleaseRundownProtection(&Process->RundownProtect);
    /* Check if we are killing ourselves */
    if (Process == CurrentProcess)
    {
        /* Also make sure the caller gave us our handle */
        if (KillByHandle)
        {
            /* Dereference the project */
            ObDereferenceObject(Process);
            /* Terminate ourselves */
            PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
        }
    }
    else if (ExitStatus == DBG_TERMINATE_PROCESS)
    {
        /* Disable debugging on this process */
        DbgkClearProcessDebugObject(Process, NULL);
    }
    /* Check if there was nothing to terminate, or if we have a Debug Port */
    if ((Status == STATUS_NOTHING_TO_TERMINATE) ||
        ((Process->DebugPort) && (KillByHandle)))
    {
        /* Clear the handle table */
        ObClearProcessHandleTable(Process);
        /* Return status now */
        Status = STATUS_SUCCESS;
    }
    /* Decrease the reference count we added */
    ObDereferenceObject(Process);
    /* Return status */
    return Status;
}
/*  H:\ntoskrnl\ps\kill.c
 * See "Windows Internals" - Chapter 13, Page 49
 */
NTSTATUS
NTAPI
PspTerminateThreadByPointer(IN PETHREAD Thread,
                            IN NTSTATUS ExitStatus,
                            IN BOOLEAN bSelf)
{
    PKAPC Apc;
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Flags;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "Thread: %p ExitStatus: %p\n", Thread, ExitStatus);
    PSREFTRACE(Thread);
    /* Check if this is a Critical Thread, and Bugcheck */
    if (Thread->BreakOnTermination)
    {
        /* Break to debugger */
        PspCatchCriticalBreak("Terminating critical thread 0x%p (%s)\n",
                              Thread,
                              Thread->ThreadsProcess->ImageFileName);
    }
    /* Check if we are already inside the thread */
    if ((bSelf) || (PsGetCurrentThread() == Thread))
    {
        /* This should only happen at passive */
        ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
        /* Mark it as terminated */
        PspSetCrossThreadFlag(Thread, CT_TERMINATED_BIT);
        /* Directly terminate the thread */
        PspExitThread(ExitStatus);
    }
    /* This shouldn't be a system thread */
    if (Thread->SystemThread) return STATUS_ACCESS_DENIED;
    /* Allocate the APC */
    Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
    /* Set the Terminated Flag */
    Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT;
    /* Set it, and check if it was already set while we were running */
    if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) &
          CT_TERMINATED_BIT))
    {
        /* Initialize a Kernel Mode APC to Kill the Thread */
        KeInitializeApc(Apc,
                        &Thread->Tcb,
                        OriginalApcEnvironment,
                        PsExitSpecialApc,
                        PspExitApcRundown,
                        PspExitNormalApc,
                        KernelMode,
                        (PVOID)ExitStatus);
        /* Insert it into the APC Queue */
        if (!KeInsertQueueApc(Apc, Apc, NULL, 2))
        {
            /* The APC was already in the queue, fail */
            ExFreePool(Apc);
            Status = STATUS_UNSUCCESSFUL;
        }
        else
        {
            /* Forcefully resume the thread and return */
            KeForceResumeThread(&Thread->Tcb);
            return Status;
        }
    }
    /* We failed, free the APC */
    ExFreePool(Apc);
    /* Return Status */
    return Status;
}

伪造句柄结束进程, 创建一个进程句柄, 修改EPROCESS_XP 的 ThreadListHead 指向目标的进程的线程, 然后 调用TerminateProcess
CreateProcessA
pKrnProc = (NNtKrn::EPROCESS_XP *)ShellProc.dwObjAddr;
dwWriteAddr = (DWORD)(__int64)&pKrnProc->ThreadListHead;
dwSize = sizeof(NNtKrn::LIST_ENTRY);
Nntdll::WriteKernelMem(dwWriteAddr, dwSize, &DestThreadList);  //写入首线程
结果: 篮屏
分析:
经WinDbg调试发现死循环 循环代码
    Thread = PsGetNextProcessThread(Process, NULL);
    if (Thread)
    {
        /* We know we have at least a thread */
        Status = STATUS_SUCCESS;
        /* Loop and kill the others */
        do
        {
            /* Ensure it's not ours*/
            if (Thread != CurrentThread)
            {
                /* Kill it */
                PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
            }
            /* Move to the next thread */
            Thread = PsGetNextProcessThread(Process, Thread);
        } while (Thread);
    }
->PsGetNextProcessThread
   if (Thread)
    {
        /* Start where we left off */
        Entry = Thread->ThreadListEntry.Flink;
    }
    else
    {
        /* Start at the beginning */
        Entry = Process->ThreadListHead.Flink;
    }
    /* Set the list head and start looping */
    ListHead = &Process->ThreadListHead;
    while (ListHead != Entry)
    {
        /* Get the Thread */
        FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
        /* Safe reference the thread */
        if (ObReferenceObjectSafe(FoundThread)) break;
        /* Nothing found, keep looping */
        FoundThread = NULL;
        Entry = Entry->Flink;
    }
原因:
线程链没有闭合, 导致循环 PspTerminateThreadByPointer -> KeInsertQueueApc
KeInsertQueueApc 过多导致资源不够, 出现访问异常
结论: 
修改EPROCESS_XP 的方法会导致死循环

再次尝试: 修改线程链
NNtKrn::GetLastThreadAddr
MokeList.dwObjAddr = (DWORD)(__int64)&pKrnDestLastThread->ThreadListEntry;
NNtKrn::WriteKrnObject(MokeList);    //写入结束线程
结果: 进程CPU 50% 然后无法响应
分析: 
WinDbg 调试发现 线程 PspExitThread 循环没退出所以(CPU 50%, 无法响应)
  CurrentProcess = Thread->ThreadsProcess;       (ShellProc)
  ...
    FirstEntry = &CurrentProcess->ThreadListHead;  
    CurrentEntry = FirstEntry->Flink;
        while (FirstEntry != CurrentEntry)
        {
            /* Get the thread on the list */
            OtherThread = CONTAINING_RECORD(CurrentEntry,
                                            ETHREAD,
                                            ThreadListEntry);
            /* Check if it's a thread that's still alive */
            if ((OtherThread != Thread) &&
                !(KeReadStateThread(&OtherThread->Tcb)) &&
                (ObReferenceObjectSafe(OtherThread)))
            {
                /* It's a live thread and we referenced it, unlock process */
                ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
                KeLeaveCriticalRegion();
                /* Wait on the thread */
                KeWaitForSingleObject(OtherThread,
                                      Executive,
                                      KernelMode,
                                      FALSE,
                                      NULL);
                /* Check if we had a previous thread to dereference */
                if (PreviousThread) ObDereferenceObject(PreviousThread);
                /* Remember the thread and re-lock the process */
                PreviousThread = OtherThread;
                KeEnterCriticalRegion();
                ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
            }
            /* Go to the next thread */
            CurrentEntry = CurrentEntry->Flink;
        }
原因跟前面一样, 因为线程没有闭合, 导致死循环

尝试修改线程的Proc指针
dwAddr = (DWORD)(__int64)&pKrnDestLastThread->pThreadsProcess;
Nntdll::WriteKernelMem(dwAddr, sizeof(NNtKrn::EPROCESS_XP *), &ShellProc.dwObjAddr);  //修改线程的Proc指针

结果:篮屏, 
分析: PspExitThread
PAGE:805D18D6                 mov     eax, [esi+KTHREAD_XP.ApcState.Process]
PAGE:805D18D9                 cmp     edi, eax
PAGE:805D18DB                 jz      short loc_805D18EF
判定 当前进程不正常, 导致异常(KTHREAD_XP.ApcState.Process), 修改线程的Proc指针还有其他问题, 换个方法

回到前面的方法(CPU 50%, 无法响应)
在TerminateProcess 之后再恢复目标线程的链
结果: OK

想过修改句柄表, 这样更简单, 不过句柄表结构有点复杂

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功