背景

所谓的进程伪装,指的修改任意一个指定进程的信息,是它的信息在系统中的显示是另一个进程的信息,这样看来,指定的进程就像是被伪装的进程一样,因为进程信息相同,但实际上,它还是原来的进程,做着原来的进程操作。

实现原理

具体实现原理如下:

(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;
}

 

 

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐