线程

 Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

线程

1. _ETHREAD中重要的数据结构

2. 进程与线程的位置关系

3. ETHREAD+0x218 StartAddress

4. 几个重要的知识点

 

 

1. _ETHREAD中重要的数据结构

  +0x000 Header 可等待对象

  +0x018 InitialStack / +0x01c StackLimit / +0x028 KernelStack 线程切换相关

  +0x020 TEB 在三环描述了该线程相关信息(fs:[0]在三环指向TEB)

  +0x02c DebugActive 如果为-1,则不能使用调试寄存器 Dr0~Dr7

  +0x034 ApcState / +0x0e8 ApcQueueLock / +0x138 ApcStatePointer / +0x14c SavedApcState Apc相关

  +0x02d State 线程状态:就绪、运行还是等待

  + 0x06c BasePriority 当前线程优先级

  +0x070 WaitBlock 等待哪个对象

  +0x0e0 ServiceTable 系统服务表机制

  +0x134 TrapFrame 进零环时保存的环境

  +0x140 PreviousMode  某些内核函数会判断程序是0环调用的还是3环调用的

  +0x1b0 ThreadListEntry 双向链表,一个进程的所有线程,都挂在这样一个链表中(图解)。

  +0x1ec Cid 当前线程和进程的编号

  +0x220 ThreadProcess 当前线程所属的进程

  +0x22c ThreadListEntry 双向链表,一个进程的所有线程,都挂在这样一个链表中(图解)。

 

2. 进程与线程的位置关系

  

 

3. ETHREAD+0x218 StartAddress

  其表示线程开始的位置,我们可以遍历其全部线程的起始地址,然后检测其属于哪个模块。

  如果该线程起始地址不匹配所有模块,则该线程可能是被注入出来的,这个你应该明确。

  反制措施:线程的伪装-将线程起始地址写到一个模块地址,该地址jmp回原线程继续执行线程代码。

 

4. 几个重要的知识点:

  1)遍历线程

    遍历线程的思路非常简单,从进程KThread+0x50开始一直遍历,注意其对应的偏移量即可。

// 遍历线程Id
NTSTATUS TraverseThreadId(HANDLE pId) {

    PEPROCESS pEprocess;
    
    if (!NT_SUCCESS(PsLookupProcessByProcessId(pId,&pEprocess))) {
        return STATUS_UNSUCCESSFUL;
    }

    PULONG pPrcoessListEntry = (PULONG)((PUCHAR)pEprocess + 0x50); // 获取进程链表
    PULONG pThreadListEntry = (PULONG)*pPrcoessListEntry; // 获取对应线程
    while (pPrcoessListEntry != pThreadListEntry) {
        DbgPrint("该线程ID:%d  \r\n", *MACRO_GetThreadIdThreadListHead(pThreadListEntry));
        pThreadListEntry = *pThreadListEntry;
    }
    

    return STATUS_SUCCESS;
}

 

  2)进程断链

    使用之前的断链方式即可,注意其双向链表,一般情况下要两条线都断,这是必须要明确的。

 

posted @ 2020-04-17 15:52  OneTrainee  阅读(281)  评论(0编辑  收藏  举报