首页
社区
课程
招聘
[原创]伪造句柄方法结束进程
发表于: 2010-6-13 11:51 13107

[原创]伪造句柄方法结束进程

2010-6-13 11:51
13107

伪造句柄方法结束进程(无需驱动)

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

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


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 7
支持
分享
最新回复 (7)
雪    币: 251
活跃值: (31)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
主要代码, 没有整理...

BOOL        CHandleList::OnSupperKill()
{
        if(m_MenuOpItem.dwTypeTag != (DWORD &)"Proc")
                return FALSE;

        HANDLE                                hProc;
        STARTUPINFOA                si;
        PROCESS_INFORMATION pi;

        NNtKrn::EPROCESS_XP        *                pKrnProc;
        DWORD                                                dwKrnAddr;
        DWORD                                                dwSize;
        DWORD                                                dwWriteAddr;
        EPROCESS_XP_R3                                ShellProc;
        ETHREAD_XP_R3                                ShellThread;

        DWORD                                        dwAddr;
        DWORD                                        dwAddrDlt;

        EPROCESS_XP_R3                        DestProc;
        ETHREAD_XP_R3                        DestThread;

        NNtKrn::LIST_ENTRY                        ShellThreadList;
        NNtKrn::LIST_ENTRY                        DestThreadList;

        memset(&si, 0, sizeof(si));
        si.cb = sizeof(si);

        CreateProcessA(NULL, "Notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);

//        壳 数据
        dwKrnAddr = NNtKrn::GetHandleKrnObject(pi.hProcess);
        if(dwKrnAddr == 0)
                return FALSE;

        NLog::LogString("Shell dwKrnAddr: %08X", dwKrnAddr);

        ShellProc.dwObjAddr = dwKrnAddr;
        NNtKrn::ReadKrnObject(ShellProc);

        dwAddr = GetEThreadByThreadListHead(&ShellProc.Obj.ThreadListHead);
        ShellThread.dwObjAddr = dwAddr;
        NNtKrn::ReadKrnObject(ShellThread);

        if((DWORD)(__int64)ShellProc.Obj.UniqueProcessId != pi.dwProcessId)
                return FALSE;
        if((DWORD)(__int64)ShellThread.Obj.Cid.UniqueProcess != pi.dwProcessId)
                return FALSE;

//        目标 数据
        DestProc.dwObjAddr = (DWORD)(__int64)m_MenuOpItem.Base.Object;
        DestProc.Obj = m_MenuOpItem.KrnObj.EProcessXp;

        dwAddr = GetEThreadByThreadListHead(&DestProc.Obj.ThreadListHead);
        DestThread.dwObjAddr = dwAddr;
        NNtKrn::ReadKrnObject(DestThread);
        if((DWORD)(__int64)DestProc.Obj.UniqueProcessId != (DWORD)(__int64)DestThread.Obj.Cid.UniqueProcess)
                return FALSE;

        dwAddr  = NNtKrn::GetLastThreadAddr((DWORD)(__int64)m_MenuOpItem.Base.Object);
        if(dwAddr == 0)
                return FALSE;

        DestThread.dwObjAddr = dwAddr;
        NNtKrn::ReadKrnObject(DestThread);

        if((DWORD)(__int64)DestProc.Obj.UniqueProcessId != (DWORD)(__int64)DestThread.Obj.Cid.UniqueProcess)
                return FALSE;

        NNtKrn::ETHREAD_XP *                pKrnDestLastThread;
        NNtKrn::LIST_ENTRY *                pHead;
        LIST_ENTRY_R3                                OldList;
        LIST_ENTRY_R3                                MokeList;

        pKrnProc = (NNtKrn::EPROCESS_XP *)ShellProc.dwObjAddr;
        pHead = &pKrnProc->ThreadListHead;

        MokeList.Obj.Blink = pHead;
        MokeList.Obj.Flink = pHead;

        pKrnDestLastThread = (NNtKrn::ETHREAD_XP *)DestThread.dwObjAddr;
        MokeList.dwObjAddr = (DWORD)(__int64)&pKrnDestLastThread->ThreadListEntry;
        OldList.dwObjAddr = MokeList.dwObjAddr;
        NNtKrn::ReadKrnObject(OldList);
        NNtKrn::WriteKrnObject(MokeList);                //写入结束线程

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

//        伪造
        ShellThreadList = ShellProc.Obj.ThreadListHead;
        DestThreadList = DestProc.Obj.ThreadListHead;

        pKrnProc = (NNtKrn::EPROCESS_XP *)ShellProc.dwObjAddr;
        dwWriteAddr = (DWORD)(__int64)&pKrnProc->ThreadListHead;

        dwSize = sizeof(NNtKrn::LIST_ENTRY);
        Nntdll::WriteKernelMem(dwWriteAddr, dwSize, &DestThreadList);        //写入首线程
        TerminateProcess(pi.hProcess, 0);

        NNtKrn::WriteKrnObject(OldList);                        //恢复原来的列表

        Nntdll::WriteKernelMem(dwWriteAddr, dwSize, &ShellThreadList);        //恢复首线程
        TerminateProcess(pi.hProcess, 0);
        return TRUE;
}
2010-6-13 11:55
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
3
能直接读写R0内存的话,能搞的事情多了…何必如此
2010-6-13 15:59
0
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
你在R0搞,直接就能把进程搞挂。何必绕了一大圈?
2010-6-13 16:24
0
雪    币: 364
活跃值: (91)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
是不是伪造某个正常使用的进程 的句柄,然后非法的把这个目标进程杀掉???
2010-6-13 16:29
0
雪    币: 411
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
我觉得算是一种思路,应该说伪造线程链更准确。但这样不稳定吧,线程切换的时候会出问题的。
2010-6-13 16:54
0
雪    币: 522
活跃值: (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
吃力不讨好.
你这样 还不如直接转投apc.
2010-6-16 08:48
0
雪    币: 132
活跃值: (30)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
劫杀过路高手
2010-10-29 19:45
0
游客
登录 | 注册 方可回帖
返回
//