背景
所谓的进程伪装,指的修改任意一个指定进程的信息,是它的信息在系统中的显示是另一个进程的信息,这样看来,指定的进程就像是被伪装的进程一样,因为进程信息相同,但实际上,它还是原来的进程,做着原来的进程操作。
实现原理
具体实现原理如下:
(1)首先通过OpenProcess函数获取指定PID进程的句柄
(2)然后,通过GetProcAddress获取位于ntdll.dll动态链接库中的NtQueryInformationProcess这个未导出的API
该函数返回一个NTSTATUS状态码
(3)然后,使用 NtQueryInformationProcess 函数获取指定进程的进程基本信息 PROCESS_BASIC_INFORMATION,并从中获取指定进程的进程环境块 PEB
获取环境块PEB需要用到ReadProcessMemory函数,因为我们是要去其他进程空间找相关数据
(4)最后,我们开始对指定进程 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;
}
测试代码
int _tmain(int argc, _TCHAR* argv[])
{if (FALSE == DisguiseProcess(4368, L"C:\\Windows\\explorer.exe", L"explorer.exe")){printf("Dsisguise Process Error.\n");}printf("Dsisguise Process OK.\n");system("pause");return 0;
}