功能技术-进程遍历

本文最后更新于:2022-01-12 晚上

进程遍历

进程遍历就是遍历当前计算机上所有的进程信息,对于恶意代码来说,可以通过遍历获取进程的信息,可以通过这些信息来判断是否存在指定的进程,比如调试器、杀毒软件。遍历进程的方法有很多,最常用的就是通过进程快照来实现。

函数介绍

CreateToolhelp32Snapshot

获取指定进程的快照,以及这些进程使用的堆、模块和线程。

1
2
3
4
HANDLE CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);

参数

dwFlags:指定快照中包含的系统内容,这个参数能够使用下列数值中的一个或者多个。

含义
THE32CS_INHERIT 声明快照句柄是可继承的
THE32CS_SNAPALL 在快照中包含系统中所有的进程和线程
THE32CS_SNAPHEAPLIST 在快照中包含在the32ProcessID中指定进程的所有堆
THE32CS_SNAPMODULE 在快照中包含在the32ProcessID中指定进程的所有模块
THE32CS_SNAPPROCESS 在快照中包含系统中所有的进程
THE32CS_SNAPTHREAD 在快照中包含系统中所有的线程

th32ProcessID:指定将要快照的进程ID。如果该参数为0,则表示快照当前进程。该参数只有在设置了THE32CS_SNAPHEAPLIST或者THE32CS_SNAPMODULE后才有效,其他情况下应该忽略此参数,快照所有的进程。

返回值

若调用成功,则返回快照的句柄;若调用失败,则返回INVALID_HANDLE_VALUE。

Process32First

检索系统快照中遇到的第一个进程信息

1
2
3
4
BOOL Process32First(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);

参数

hSnapshot:从上次调用CreateToolhelp32Snapshot函数返回的快照句柄。

lppe:指向PROCESSENTRY32结构的指针 。它包含进程信息,例如可执行文件的名称、进程标识符和父进程的进程标识符。

返回值

TRUE标识进程列表的第一个条目已经复制到缓冲区,FALSE表示失败。

Process32Next

检索有关记录在系统快照中的下一个进程信息。

1
2
3
4
BOOL Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);

参数

hSnapshot:处理从先前调用CreateToolhelp32Snapshot函数返回的快照句柄

lppe:指向PROCESSENTRY32结构的指针。

返回值

如果进程列表的下一个条目已经复制到缓冲区,则返回TRUE;否则返回FALSE。如果不存在任何进程或者快照不包含进程信息,则GetLastError会显示ERROR_NO_MORE_FILES。

实现原理

调用CreateToolhelp32Snapshot可以获取当前的进程快照,如果成功便会得到一个进程信息列表,并且返回这个列表的起始索引。然后调用Process32First获取第一个进程信息,进程的信息都保存在PROCESSENTRY32结构体的缓冲区中。若要获取下一个进程信息,就可以调用Process32Next,循环即可获取所有的进程信息。直到Process32Next函数返回值是FALSE,且GetLastError错误代码为ERROR_NO_MORE_FILES,这就表示遍历已经结束了。

编写代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>
int main()
{
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(PROCESSENTRY32);
//进程快照
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hProcessSnap == INVALID_HANDLE_VALUE)
{
return -1;
}
//获取第一个进程信息
BOOL flag = Process32First(hProcessSnap, &pe);
while (flag)
{
printf("[PID:%d]\t", pe.th32ProcessID);
printf("[%s]\n", pe.szExeFile);
//获取下一个进程信息
flag = Process32Next(hProcessSnap, &pe);
}
CloseHandle(hProcessSnap);
system("pause");
return 0;
}

测试

运行查看效果,可以看到可以打印出当前的所有进程信息

反调试功能测试

可以通过遍历所有进程来查找是否存在一个调试器,只需要比较一下进程名即可

1
2
3
4
5
if (!lstrcmp(pe.szExeFile, "吾爱破解[LCG].exe"))
{
MessageBoxA(NULL, "发现调试器", "!!!", NULL);
break;
}

打开OD,可以看到就会弹窗提示存在调试器。

参考

《Windows黑客编程技术详解》