首页
社区
课程
招聘
[原创] Windows线程恢复流程逆向分析
发表于: 2023-5-9 16:29 18125

[原创] Windows线程恢复流程逆向分析

2023-5-9 16:29
18125

这线程恢复真的是比线程挂起麻烦的多,挂起线程插个apc就结了,线程恢复这块流程和分支非常多,wrk在这块的源码也不全,本次分析的流程和分支仅按照下方测试代码进行,不考虑其它情况;调试的操作系统是WindowsXP,单核

以下操作流程用伪代码表示(非IDA)(if均成立)

如分析有错,欢迎指出

VOID WINAPI testThreadA() {
    while (TRUE) {
        Sleep(1000);
        printf("AAA\n");
    }
}
HANDLE threadA = -1;
int main()
{
    threadA = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)testThreadA, 0, 0, 0);
    SuspendThread(threadA);
    __asm {
        int 3;
    }
    ResumeThread(threadA);
    system("pause");
    return 0;
}
VOID WINAPI testThreadA() {
    while (TRUE) {
        Sleep(1000);
        printf("AAA\n");
    }
}
HANDLE threadA = -1;
int main()
{
    threadA = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)testThreadA, 0, 0, 0);
    SuspendThread(threadA);
    __asm {
        int 3;
    }
    ResumeThread(threadA);
    system("pause");
    return 0;
}
ResumeThread(ThreadHandle);
    //
NtResumeThread(ThreadHandle);
    //
PsResumeThread(Thread);
    //
KeResumeThread(Thread);
    //
KiWaitTest(Thread->SuspendSemaphore,increment(0));
    //
KiUnwaitThread(increment(0),OUT &waitListEntry);
    //
KiUnlinkThread(Thread,increment(0));//断链WaitBlockList
    //
KiReadyThread(); //挂入调度链表
ResumeThread(ThreadHandle);
    //
NtResumeThread(ThreadHandle);
    //
PsResumeThread(Thread);
    //
KeResumeThread(Thread);
    //
KiWaitTest(Thread->SuspendSemaphore,increment(0));
    //
KiUnwaitThread(increment(0),OUT &waitListEntry);
    //
KiUnlinkThread(Thread,increment(0));//断链WaitBlockList
    //
KiReadyThread(); //挂入调度链表
KiWaitTest  -> KiUnwaitThread -> KiUnlinkThread
            -> KiReadyThread
KiWaitTest  -> KiUnwaitThread -> KiUnlinkThread
            -> KiReadyThread
int __stdcall KeResumeThread(_ETHREAD *Thread)
{
  char SuspendCount = Thread->Tcb.SuspendCount;
  if ( SuspendCount )//如果没调用过SuspendThread()挂起线程,该值为0
  {
    char newSuspendCount = SuspendCount - 1;
    Thread->Tcb.SuspendCount = newSuspendCount;
    if ( !newSuspendCount && !Thread->Tcb.FreezeCount )
    {
      ++Thread->Tcb.SuspendSemaphore.Header.SignalState;
      KiWaitTest(&Thread->Tcb.SuspendSemaphore, 0);
    }
  }
  KiUnlockDispatcherDatabase(KeRaiseIrqlToDpcLevel());
  return;
}
int __stdcall KeResumeThread(_ETHREAD *Thread)
{
  char SuspendCount = Thread->Tcb.SuspendCount;
  if ( SuspendCount )//如果没调用过SuspendThread()挂起线程,该值为0
  {
    char newSuspendCount = SuspendCount - 1;
    Thread->Tcb.SuspendCount = newSuspendCount;
    if ( !newSuspendCount && !Thread->Tcb.FreezeCount )
    {
      ++Thread->Tcb.SuspendSemaphore.Header.SignalState;
      KiWaitTest(&Thread->Tcb.SuspendSemaphore, 0);
    }
  }
  KiUnlockDispatcherDatabase(KeRaiseIrqlToDpcLevel());
  return;
}
__fastcall KiWaitTest(_KEVENT *Event, _KTHREAD *Increment)
{
    LIST_ENTRY waitListEntry;
    waitListEntry.Blink = &waitListEntry;
    waitListEntry.Flink = &waitListEntry;
 
    PLIST_ENTRY ListHead = &Event->Header.WaitListHead;
    PKWAIT_BLOCK = WaitEntry = Event->Header.WaitListHead.Flink;
    if(Event->Header.SignalState > 0){
        if ( WaitEntry != ListHead ){
            PKTHREAD Thread = WaitEntry->Thread;
            if(WaitEntry->WaitType == WaitAny){
                USHORT waitStatus = WaitEntry->WaitKey;
                UCHAR Type = Event->Header.Type;
            }
            //获得一个需要挂入调度链表的就绪线程链表
            KiUnwaitThread(Thread, waitStatus, increment, &waitListEntry);
            WaitEntry = ListHead->Flink;
            while(IsListEmpty(&waitListEntry)){
                PVOID nextThread = waitListEntry.Flink;
                WaitEntry = &waitListEntry;
                waitListEntry.Flink = waitListEntry.Flink->Flink;
                waitListEntry.Flink->Blink = &waitListEntry;
                KiReadyThread((KTHREAD *)(nextThread - 96));
            }
        }
    }
}
__fastcall KiWaitTest(_KEVENT *Event, _KTHREAD *Increment)
{
    LIST_ENTRY waitListEntry;
    waitListEntry.Blink = &waitListEntry;
    waitListEntry.Flink = &waitListEntry;
 
    PLIST_ENTRY ListHead = &Event->Header.WaitListHead;
    PKWAIT_BLOCK = WaitEntry = Event->Header.WaitListHead.Flink;
    if(Event->Header.SignalState > 0){
        if ( WaitEntry != ListHead ){
            PKTHREAD Thread = WaitEntry->Thread;
            if(WaitEntry->WaitType == WaitAny){
                USHORT waitStatus = WaitEntry->WaitKey;
                UCHAR Type = Event->Header.Type;
            }
            //获得一个需要挂入调度链表的就绪线程链表
            KiUnwaitThread(Thread, waitStatus, increment, &waitListEntry);
            WaitEntry = ListHead->Flink;
            while(IsListEmpty(&waitListEntry)){
                PVOID nextThread = waitListEntry.Flink;
                WaitEntry = &waitListEntry;
                waitListEntry.Flink = waitListEntry.Flink->Flink;
                waitListEntry.Flink->Blink = &waitListEntry;
                KiReadyThread((KTHREAD *)(nextThread - 96));
            }
        }
    }
}
KiUnwaitThread(_KTHREAD *thread, LONG_PTR WaitStatus, int Increment, OUT _LIST_ENTRY *WaitListEntry){
    //将线程的等待块摘除
    KiUnlinkThread(thread, WaitStatus);
    CHAR Priority = thread->Priority;
    KPROCESS Process = thread->ApcState.Process;
    if ( Priority >= 16 ){
        if(WaitListEntry != NULL){
            PLIST_ENTRY prev = WaitListEntry->Blink;
            PLIST_ENTRY waitList = &thread->WaitListEntry;
            thread->WaitListEntry.Flink = WaitListEntry;
            thread->WaitListEntry.Blink = Blink;
            prev->Flink = &thread->WaitListEntry;
            WaitListEntry->Blink = &thread->WaitListEntry;
            return;
        }
    }
}
KiUnwaitThread(_KTHREAD *thread, LONG_PTR WaitStatus, int Increment, OUT _LIST_ENTRY *WaitListEntry){
    //将线程的等待块摘除
    KiUnlinkThread(thread, WaitStatus);
    CHAR Priority = thread->Priority;
    KPROCESS Process = thread->ApcState.Process;
    if ( Priority >= 16 ){
        if(WaitListEntry != NULL){
            PLIST_ENTRY prev = WaitListEntry->Blink;
            PLIST_ENTRY waitList = &thread->WaitListEntry;
            thread->WaitListEntry.Flink = WaitListEntry;
            thread->WaitListEntry.Blink = Blink;
            prev->Flink = &thread->WaitListEntry;
            WaitListEntry->Blink = &thread->WaitListEntry;
            return;
        }
    }
}
BOOL __fastcall KiUnlinkThread(_KTHREAD *Thread, LONG_PTR WaitStatus){
    Thread->WaitStatus |= WaitStatus;
    WaitBlockList = Thread->WaitBlockList;
    do{//将Thread从等待链中断链
        PLIST_ENTRY Flink = WaitBlockList->WaitListEntry.Flink;
        PLIST_ENTRY Blink = WaitBlockList->WaitListEntry.Blink;
        Blink->Flink = WaitBlockList->WaitListEntry.Flink;
        Flink->Blink = Blink;
        WaitBlockList = WaitBlockList->NextWaitBlock;
    }while ( WaitBlockList != Thread->WaitBlockList );
    return;
}
BOOL __fastcall KiUnlinkThread(_KTHREAD *Thread, LONG_PTR WaitStatus){
    Thread->WaitStatus |= WaitStatus;
    WaitBlockList = Thread->WaitBlockList;
    do{//将Thread从等待链中断链
        PLIST_ENTRY Flink = WaitBlockList->WaitListEntry.Flink;
        PLIST_ENTRY Blink = WaitBlockList->WaitListEntry.Blink;
        Blink->Flink = WaitBlockList->WaitListEntry.Flink;
        Flink->Blink = Blink;
        WaitBlockList = WaitBlockList->NextWaitBlock;
    }while ( WaitBlockList != Thread->WaitBlockList );
    return;
}
KiReadyThread(_KTHREAD *Thread){
//设置字段属性
    Thread->State = Standby;
    Thread->WaitTime = KeTickCount
    Thread->NextProcessor = Thread->IdleProcessor
    Thread->State = Ready;
 
//将线程挂入调度链表
    Thread->WaitListEntry.Flink = KiDispatcherReadyListHead
    Thread->WaitListEntry.Blink = KiDispatcherReadyListHead.Blink
    KiDispatcherReadyListHead.Blink.Flink = Thread->WaitListEntry
    KiDispatcherReadyListHead.Blink = Thread->WaitListEntry
    KiReadySummary |= 1 << Thread->priority;
}
KiReadyThread(_KTHREAD *Thread){
//设置字段属性
    Thread->State = Standby;
    Thread->WaitTime = KeTickCount

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 9
支持
分享
最新回复 (10)
雪    币: 6
活跃值: (3290)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
很好,有x64的就更好了-_-
2023-5-9 16:38
0
雪    币: 1878
活跃值: (3287)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
3
咖啡_741298 很好,有x64的就更好了-_-
x32还没学完
2023-5-9 16:49
1
雪    币: 4711
活跃值: (4219)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
调度链表最后是怎么取出线程来执行的呢?
2023-5-9 17:53
0
雪    币: 1878
活跃值: (3287)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
5
木志本柯 调度链表最后是怎么取出线程来执行的呢?
在这里只是将它挂到表里,进入就绪状态,取是在KiFindReadyThread()里处理的,等系统切换
2023-5-9 18:16
0
雪    币: 1878
活跃值: (3287)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
6
还有一个抢占的情况,优先级大于原定的下一个线程的话,会把下一个线程挤下去,在系统调用KiSwapThread()的时候就不走KiFindReadyThread()去调度链表找了,直接找KPRCB->NextThread
2023-5-9 18:18
1
雪    币: 1878
活跃值: (3287)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
7
木志本柯 调度链表最后是怎么取出线程来执行的呢?
抢占的分支你可以看一下KiFindReadyThread()的汇编,nt!KiReadyThread+0x2d1处,我刚刚重新看了一下,比较的是 准备就绪的线程ReadyThread,也就是ResumeThread传入的线程,它的优先级和当前CPU正在运行的线程,KPRCB->CurrentThread的优先级作比较
 if(ReadyThread->Priority > CurrentThread->Priority){
    CurrentThread->Preempted = 1;
    kprcb->NextThread = ReadyThread;
    return;(进入这个分支后面就不挂调度链表了)
}
2023-5-9 18:29
1
雪    币: 8188
活跃值: (2842)
能力值: ( LV9,RANK:180 )
在线值:
发帖
回帖
粉丝
8
2003泄露后,wrk没什么意义了
2023-5-10 10:03
0
雪    币: 203
活跃值: (1094)
能力值: ( LV9,RANK:195 )
在线值:
发帖
回帖
粉丝
9
加油,来个win10、win11的
2023-5-10 16:08
0
雪    币: 3736
活跃值: (3867)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
感谢分享!
2023-5-10 17:01
0
雪    币: 1878
活跃值: (3287)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
11
我重新翻阅了WindowsXP的源码,关于KiUnwaitThread函数的补充定义如下:
KiUnwaitThread (
    IN PRKTHREAD Thread,
    IN LONG_PTR WaitStatus,
    IN KPRIORITY Increment,
    IN PLIST_ENTRY ThreadList OPTIONAL
    )
最后一个参数是一个线程链表指针,如果传入了该值,则会根据传入线程的等待链填充该链表,如果没有,会直接拿着传入线程调用KiReadyThread(thread);
2023-5-12 11:26
1
游客
登录 | 注册 方可回帖
返回
//