首页
社区
课程
招聘
[讨论]滴水线上班系列调用PspTerminateProcess习题
发表于: 2025-6-5 11:59 243

[讨论]滴水线上班系列调用PspTerminateProcess习题

2025-6-5 11:59
243

滴水线上班驱动03的课后作业,感觉挺有意思的,就尝试做了一下。这个习题是要求使用特征码查找PspTerminateProcess函数,然后调用此函数来结束进程。

主要难点在于特征码的寻找以及PspTerminateProcess参数的确定。

PspTerminateProcess参数的确定

我使用的是系统64位的win10。由于事先我不知道PspTerminateProcess的参数有哪些,因此结合windbg的符号和ida对ntoskrnl.exe进行了分析。首先使用kd调试,在NtTerminateProcess下断(这个函数调用了PspTerminateProcess),然后随便结束一个进程。

然后运行到call指令处,发现PspTerminateProcess接收4个参数,后两个参数推测为状态码,前两个参数看起来像是内核对象。

于是使用!object命令查看,

kd> !object ffffd70c0c920340
Object: ffffd70c0c920340  Type: (ffffd70c07abdd20) Process
    ObjectHeader: ffffd70c0c920310 (new version)
    HandleCount: 11  PointerCount: 327001
kd> !object ffffd70c0bcaa080
Object: ffffd70c0bcaa080  Type: (ffffd70c07abd380) Thread
    ObjectHeader: ffffd70c0bcaa050 (new version)
    HandleCount: 2  PointerCount: 65538

并使用dt _eprocess和dt _ethread进一步分析,发现这两个参数分别是要结束进程的eprocess结构和属于调用NtTerminateProcess的进程的某个线程的ethread结构,从而确定了调用的参数。

特征码

对于特征码,我使用了两个自定义的结构来表示

typedef struct PATTERN {
    PVOID pBuffer;
    int len;
}PATTERN;

typedef struct SIGNATURE {
    int sigLen;
    PATTERN pattern[15];
    int offset[14];
} SIGNATURE;

并且定义了一套函数来查找特征码

SIGNATURE initSignature(PATTERN* p, int *offset, int sigLen) {
    if (sigLen > 15)
        return (SIGNATURE) {.sigLen=0};
    SIGNATURE sigRet = { .sigLen = sigLen };
    for (int i = 0; i < sigLen; i++) {
        if (p[i].pBuffer == NULL || p[i].len < 0) { // 不允许出现指向NULL的buffer或者长度小于0
            sigRet.sigLen = 0;
            return sigRet;
        }
        sigRet.pattern[i] = p[i];
        if (i < sigLen - 1)
            sigRet.offset[i] = offset[i];
    }
    return sigRet;
}

BOOLEAN myMemcmp(PVOID buf1, PVOID buf2, size_t maxCmpLen) {
    for (size_t i = 0; i < maxCmpLen; i++)
        if (((char*)buf1)[i] != ((char*)buf2)[i])
            return FALSE;
    return TRUE;
}

PVOID findProcBySignature(PVOID startAddress, int maxSearchLen, SIGNATURE s) {
    if (maxSearchLen <= 0)
        return NULL;
    PVOID ret = NULL;
    for (int curSearchInd = 0; curSearchInd < maxSearchLen; curSearchInd++) {
        int patternSearchInd = curSearchInd;
        for (int i = 0; i < s.sigLen && patternSearchInd < maxSearchLen; i++) {
            // 与特征码不匹配的情况:如果当前的pattern长度已经超过了最大长度(也就是特征码本身比搜索长度还长,这种情况认为不匹配),或者pattern[i]
            // 与内存对比不匹配,或者pattern[i].pBuffer为NULL
            if (patternSearchInd + s.pattern[i].len > maxSearchLen || s.pattern[i].pBuffer == NULL || 
                !myMemcmp(s.pattern[i].pBuffer, (char*)startAddress + patternSearchInd, s.pattern[i].len))
                break;
            // 更新curSearchInd
            if (i != s.sigLen - 1)
                patternSearchInd += s.pattern[i].len + s.offset[i];
            else // 如果能走到i == s.sigLen-1且memcmp通过,则说明特征码查找成功
                ret = (char*)startAddress + curSearchInd;
        }
        if (ret != NULL)
            break;
    }
    if (ret != NULL)
        DbgPrint("Found process at %p\n", ret);
    return ret;
}

然后我使用ida查看了PspTerminateProcess函数的代码,并确定了其特征码,编写了寻找PspTerminateProcess的函数

PVOID findPspTerminateProcessBySignature(void) {
    char patterns[] = { 
        0x48, 0x89, 0x5c, 0x24, 0x08, // 15
        0x48, 0x83, 0xec, 0x20, 0x41, // 11
        0x0f, 0x0d, 0x89, 0x64, 0x04, // 55
        0xe8, 0xfb, 0xf2, 0xc4, 0xff, // 5
        0xe8, 0x1d, 0xf2, 0xc4, 0xff, // 28
        0xe8, 0x40, 0xef, 0xb6, 0xff};
    int offset[] = { 15, 11, 55, 5, 28 };
    PATTERN p[6];
    for (int i = 0; i < 6; i++) {
        p[i].len = 5;
        p[i].pBuffer = patterns+i*5;
    }
    SIGNATURE s = initSignature(p, offset, 6);
    PVOID ntBase = FindNt();
    return findProcBySignature((CHAR*)ntBase, 0xffffff, s);
}

找到特征码之后,根据函数参数,编写了一个调用PspTerminateProcess的函数

VOID terminateProcessBypass(ULONG64 pid) {
    EPROC* currentProcess = PsGetCurrentProcess();
    EPROC* nextProcess = (EPROC*)((CHAR*)(currentProcess->ActiveProcessLinks.Flink)-0x448);
    PVOID currentThread = (PETHREAD)((CHAR*)(currentProcess->ThreadListHead.Flink) - 0x4e8);
    VOID (*pspTerminateProc)(PEPROCESS, PETHREAD, int, int) = findPspTerminateProcessBySignature();

    while (nextProcess->UniqueProcessId != pid && nextProcess != currentProcess && nextProcess != NULL) {
        DbgPrint("current processId - %lld\n", nextProcess->UniqueProcessId);
        nextProcess = (EPROC*)((CHAR*)(nextProcess->ActiveProcessLinks.Flink)-0x448);
    }
    
    if (nextProcess == currentProcess || nextProcess == NULL) {
        DbgPrint("Pid not found\n");
        return;
    }
    pspTerminateProc(nextProcess, currentThread, 0, 0);
}

完整的驱动代码见附件main.c


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2025-6-5 13:46 被nstlgst134编辑 ,原因: 排版问题
上传的附件:
收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 23
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
这个课程可以分享下吗
5天前
0
游客
登录 | 注册 方可回帖
返回