背景
所谓的进程伪装,指的修改任意一个指定进程的信息,是它的信息在系统中的显示是另一个进程的信息,这样看来,指定的进程就像是被伪装的进程一样,因为进程信息相同,但实际上,它还是原来的进程,做着原来的进程操作。
函数介绍
NtQueryInformationProcess
NTSTATUS WINAPI NtQueryInformationProcess(
_In_ HANDLE ProcessHandle, // 要获取信息的进程的句柄。
_In_ PROCESSINFOCLASS ProcessInformationClass, // 要获取的进程信息的类型
_Out_ PVOID ProcessInformation, // 指向由调用应用程序提供的缓冲区的指针
_In_ ULONG ProcessInformationLength, // 指向的缓冲区的大小
_Out_opt_ PULONG ReturnLength // 返回所请求信息的大小
);
实现原理
进程伪装的原理不是很复杂,就是修改指定进程的进程环境块 PEB 中的进程路径以及命令行信息,即可达到进程伪装的效果。
具体实现原理分析如下:
- 首先,我们根据进程的 PID 号打开指定进程,并获取进程的句柄。
- 然后,我们要从 ntdll.dll 中获取 NtQueryInformationProcess 函数的导出地址,因为 NtQueryInformationProcess 函数没有关联导入库,所以只能动态获取,这个函数是这个程序功能实现的关键步骤。
- 接着,使用 NtQueryInformationProcess 函数获取指定进程的进程基本信息 PROCESS_BASIC_INFORMATION,并从中获取指定进程的进程环境块 PEB。
- 然后,我们就可以根据进程环境块中的 ProcessParameters,获取指定进程的 RTL_USER_PROCESS_PARAMETERS 信息,因为PEB的路径信息、命令行信息存储在这个结构体中。
- 最后,我们开始对指定进程 PEB 中路径信息、命令行信息进行更改,实现进程伪装
编码实现
// 修改指定进程的进程环境块PEB中的路径和命令行信息, 实现进程伪装
BOOL DisguiseProcess(DWORD dwProcessId, wchar_t *lpwszPath, wchar_t *lpwszCmd)
{
// 打开进程获取句柄
HANDLE hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
ShowError("OpenProcess");
return FALSE;
}
typedef_NtQueryInformationProcess NtQueryInformationProcess = NULL;
PROCESS_BASIC_INFORMATION pbi = { 0 };
PEB peb = { 0 };
RTL_USER_PROCESS_PARAMETERS Param = { 0 };
USHORT usCmdLen = 0;
USHORT usPathLen = 0;
// 需要通过 LoadLibrary、GetProcessAddress 从 ntdll.dll 中获取地址
NtQueryInformationProcess = (typedef_NtQueryInformationProcess)::GetProcAddress(
::LoadLibrary("ntdll.dll"), "NtQueryInformationProcess");
if (NULL == NtQueryInformationProcess)
{
ShowError("GetProcAddress");
return FALSE;
}
// 获取指定进程的基本信息
NTSTATUS status = NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi, sizeof(pbi), NULL);
if (!NT_SUCCESS(status))
{
ShowError("NtQueryInformationProcess");
return FALSE;
}
/*
注意在读写其他进程的时候,注意要使用ReadProcessMemory/WriteProcessMemory进行操作,
每个指针指向的内容都需要获取,因为指针只能指向本进程的地址空间,必须要读取到本进程空间。
要不然一直提示位置访问错误!
*/
// 获取指定进程进本信息结构中的PebBaseAddress
::ReadProcessMemory(hProcess, pbi.PebBaseAddress, &peb, sizeof(peb), NULL);
// 获取指定进程环境块结构中的ProcessParameters, 注意指针指向的是指定进程空间中
::ReadProcessMemory(hProcess, peb.ProcessParameters, &Param, sizeof(Param), NULL);
// 修改指定进程环境块PEB中命令行信息, 注意指针指向的是指定进程空间中
usCmdLen = 2 + 2 * ::wcslen(lpwszCmd);
::WriteProcessMemory(hProcess, Param.CommandLine.Buffer, lpwszCmd, usCmdLen, NULL);
::WriteProcessMemory(hProcess, &Param.CommandLine.Length, &usCmdLen, sizeof(usCmdLen), NULL);
// 修改指定进程环境块PEB中路径信息, 注意指针指向的是指定进程空间中
usPathLen = 2 + 2 * ::wcslen(lpwszPath);
::WriteProcessMemory(hProcess, Param.ImagePathName.Buffer, lpwszPath, usPathLen, NULL);
::WriteProcessMemory(hProcess, &Param.ImagePathName.Length, &usPathLen, sizeof(usPathLen), NULL);
return TRUE;
}
程序测试
我们运行一个测试程序 Demon Memory.exe,先使用 Process Explorer 查看它的进程信息:
现在,我们运行我们的进程伪装程序,修改上述的测试程序 Demon Memory.exe 进程的PEB进程环境块信息,实现进程伪装。程序执行提示成功,我们再运行 Process Explorer 程序查看进程信息,发现测试程序 Demon Memory.exe 进程信息成功伪装了 explorer.exe 资源管理器进程。