C++ Inline hook实现进程防终止(不用写驱动)

一、背景

最近想写一个杀毒软件,可是别人在任务管理器里轻轻松松就把我的进程结束了,我希望把我的杀毒软件做成360那样,一旦结束就提示“拒绝访问”,而且不管你用任务管理器,还是taskkill,进程都无法结束。

于是,我在网上搜集了大量的资料,很多资料都说要写驱动,可我是一名小白,根本不会写驱动,正准备去学的时候,突然发现写驱动需要数字签名,还要花250美金,也就是1750人民币左右!我可不想花这么多钱。

我一开始误以为写驱动是为了在Ring0运行,从而让进程杀不掉,但是杀毒软件这个进程其实还是在Ring3运行的,所以不是通过提高权限来防止别人终止程序的。后来听说驱动是通过注册回调来实现的,而注册回调实际上和HOOK差不多。我学过Inline hook,于是想用Inline hook实现进程防终止。不过,Inline hook需要DLL注入,也就是说,只有注入DLL的进程才会被HOOK。网上大部分人都是把DLL写好之后,注入任务管理器,可是我用taskkill依然可以结束进程。也就是说,我必须想出一个方法,这个方法能HOOK所有程序,或者说把DLL注入所有程序。经过一番苦思冥想,我终于想出了解决办法。

二、思路

关于Inline hook,网上有很多博客,这里就不说了。我要HOOK住OpenProcess,当检测到要Open的进程是受保护的进程时,就返回拒绝访问。

我现在要解决的问题是,如何将DLL注入所有程序。

注意,这里的“注入所有程序”指的是:不管你怎么运行新进程,这个进程都会被注入我们的DLL,而不是将DLL注入所有现有的系统进程。比如说,你想打开任务管理器结束进程,而任务管理器一打开就要被注入DLL,导致你无法注入。

我想了两个思路,但是只有一个成功,不过我还是都分享出来吧。

思路一

既然要注入所有进程,一个很自然的想法是:写一个死循环,不停地枚举系统中所有进程,对于每一个进程,枚举它加载的DLL,如果没有我们的DLL,就立刻往里面注入DLL。这样,你打开任务管理器的时候,因为没有我们的DLL,所以会立刻被注入DLL。

事实也是如此。用任务管理器无法结束进程。但是用taskkill可以结束。

为什么呢?

原来,这个方法有一个缺陷:那些已经注入DLL的进程,在枚举的时候会不停地枚举,导致做了很多无用功。而且,像taskkill这样的进程,一启动就会立刻调用OpenProcess,如果枚举的时候刚好错过了taskkill这个进程,还没有再次枚举到的时候,taskkill已经调用了OpenProcess,结果是:出现了漏网之鱼!

于是,我只好乖乖地使用第二种方法。

思路二

思路一失败了。我突然想到了一种方法可以解决思路一的缺陷(做了很多无用功):那些“老进程”(系统中正在运行的进程)第一次循环时就会被注入DLL,然后需要注入DLL的,只是那些“新进程”(刚启动,没有注入DLL的进程)。而第一种方法为了捕获到“新进程”,会反反复复地枚举“老进程”,做了很多无用功,耗费了宝贵的时间。

那么,一个新的思路就出现了:只要检测到新进程启动,就注入DLL。这样,就不用枚举老进程了。

问题来了:怎么检测新进程启动?难道要修改操作系统的代码吗???

其实不用。搜集了一些资料以后,我发现:大部分用户进程是通过explorer.exe调用CreateProcessW产生的。那么,我们只需要再HOOK住CreateProcessW就可以了。

因此,我写了两个DLL(其实写一个也行)。一个负责HOOK OpenProcess。另一个负责HOOK CreateProcessW,一旦调用CreateProcessW创建子进程,就立刻往新的进程里注入这两个DLL。为什么要同时注入两个呢?因为这样操作之后,子进程的CreateProcessW也会被HOOK,这样子进程的子进程也会被注入DLL,以此类推,所有explorer.exe的子进程都会被注入DLL。

最后,将两个DLL同时注入explorer.exe即可。

三、代码实现

部分代码参考:[Win32] API Hook(1)在32位系统上的实现

HOOK OpenProcess DLL: 

代码中的notepad.exe要换成自己要保护的进程。

(processapi.h是我自己写的头文件,待会会展示)

#include <stdio.h>
#include <windows.h>
#include "processapi.h"
 
unsigned char code[5];
unsigned char oldcode[5];
FARPROC addr;
 

HANDLE WINAPI MyOpenProcess(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId){
	HANDLE handle;
	char exe[256];
	GetExeName(dwProcessId,exe);
	if (stricmp(exe,"notepad.exe") == 0){
		SetLastError(5);
		return NULL;
	}
 
	DWORD old;
	if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
		WriteProcessMemory(GetCurrentProcess(), (void*)addr, oldcode, 5, NULL);
		VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
	}
	handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
	if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
		WriteProcessMemory(GetCurrentProcess(), (void*)addr, code, 5, NULL);
		VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
	}
 
	return handle;
}
 
BOOL WINAPI DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		addr = 0;
		HMODULE hdll; hdll = LoadLibrary(TEXT("Kernel32.dll"));
		addr = GetProcAddress(hdll, "OpenProcess");
		if (addr){
			code[0] = 0xe9;
			DWORD a = (DWORD)MyOpenProcess - (DWORD)addr - 5;
			RtlMoveMemory(code + 1, &a, 4);
 
			DWORD old;
			if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
				RtlMoveMemory(oldcode, (void*)addr, 5);
				WriteProcessMemory(GetCurrentProcess(), (void*)addr, code, 5, NULL);
				VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
			}
		}
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

HOOK CreateProcess DLL:

代码中的K:\\tools\\进程防终止\\OpenProcess\\DLL.dll需要换成HOOK OpenProcess的DLL的路径,K:\\tools\\进程防终止\\CreateProcess\\DLL.dll需要换成HOOK CreateProcess的DLL的路径。

(injectdll.h也是我写的头文件)

#include <stdio.h>
#include <windows.h>
#include "injectdll.h"
 
unsigned char code[5];
unsigned char oldcode[5];
FARPROC addr;
 

WINBOOL WINAPI MyCP(LPCWSTR p1, LPWSTR p2, LPSECURITY_ATTRIBUTES p3, 
LPSECURITY_ATTRIBUTES p4, WINBOOL p5, DWORD p6, LPVOID p7, 
LPCWSTR p8, LPSTARTUPINFOW p9, LPPROCESS_INFORMATION p10){
	
	BOOL ret;
	
	DWORD old;
	if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
		WriteProcessMemory(GetCurrentProcess(), (void*)addr, oldcode, 5, NULL);
		VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
	}
	
	//MessageBox(NULL,"CreateProcessW被HOOK了!","HaHaHa",MB_SYSTEMMODAL);
	ret = CreateProcessW(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10);
	InjectDLL(p10 -> dwProcessId,"K:\\tools\\进程防终止\\OpenProcess\\DLL.dll");
	InjectDLL(p10 -> dwProcessId,"K:\\tools\\进程防终止\\CreateProcess\\DLL.dll");
	
	if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
		WriteProcessMemory(GetCurrentProcess(), (void*)addr, code, 5, NULL);
		VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
	}
 
	return ret;
}
 
BOOL WINAPI DllMain(HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		addr = 0;
		HMODULE hdll; hdll = LoadLibrary(TEXT("Kernel32.dll"));
		addr = GetProcAddress(hdll, "CreateProcessW");
		if (addr){
			code[0] = 0xe9;
			DWORD a = (DWORD)MyCP - (DWORD)addr - 5;
			RtlMoveMemory(code + 1, &a, 4);
 
			DWORD old;
			if (VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, PAGE_EXECUTE_READWRITE, &old)){
				RtlMoveMemory(oldcode, (void*)addr, 5);
				WriteProcessMemory(GetCurrentProcess(), (void*)addr, code, 5, NULL);
				VirtualProtectEx(GetCurrentProcess(), (void*)addr, 5, old, &old);
			}
		}
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}

main.cpp:(这段代码负责将DLL注入explorer.exe)

#include <windows.h>
#include <stdio.h>
#include "processapi.h"
#include "injectdll.h"
int main(){
	EnablePrivilege(SE_DEBUG_NAME,TRUE);
	InjectDLL(GetPID("explorer.exe"),"K:\\tools\\进程防终止\\CreateProcess\\DLL.dll");
	return 0;
}

processapi.h:

#ifndef _PROCESS_API_5216_
#define _PROCESS_API_5216_ 

#include <windows.h>
#include <tlhelp32.h>

BOOL EnablePrivilege(LPCSTR Name,BOOL fEnable)
{
      //Enabling the debug privilege allows the application to see
      //information about service application
     BOOL fOk = FALSE;     //Assume function fails
     HANDLE hToken;
     //Try to open this process's acess token
     if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
    {
         //Attempt to modify the "Debug" privilege
         TOKEN_PRIVILEGES tp;
         tp.PrivilegeCount = 1;
         LookupPrivilegeValue(NULL, Name, &tp.Privileges[0].Luid);
         tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;
        AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL);
        fOk  = (GetLastError() == 0);
        CloseHandle(hToken);
   }
   return fOk;
}

int GetPID(const char *szExeName){
	HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
	PROCESSENTRY32 pe = {sizeof(pe)};
	Process32First(hSnap,&pe);
	do{
		if (stricmp(pe.szExeFile,szExeName) == 0)return pe.th32ProcessID;
	}while (Process32Next(hSnap,&pe));
	return 1;
}

BOOL GetExeName(int pid,char *szExeName){
	HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
	PROCESSENTRY32 pe = {sizeof(pe)};
	Process32First(hSnap,&pe);
	do{
		if (pid == pe.th32ProcessID){
			strcpy(szExeName,pe.szExeFile);
			return TRUE;
		}
	}while (Process32Next(hSnap,&pe));
	return FALSE;
}

#endif

injectdll.h:

#ifndef _INJECT_DLL_5216_
#define _INJECT_DLL_5216_

#include <windows.h>

int InjectDLL(int pid,const char dllName[]){
	HANDLE ProcessHandle;
	LPVOID remotebuffer;
	BOOL write;
	
	ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
	if (ProcessHandle == NULL)return 1;
	
	int len = strlen(dllName);
	remotebuffer = VirtualAllocEx(ProcessHandle,NULL,len,MEM_COMMIT,PAGE_READWRITE);
	write = WriteProcessMemory(ProcessHandle,remotebuffer,(LPVOID)dllName,len,NULL);
	if (write == 0)return 2;
	PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
	HANDLE hThread = CreateRemoteThread(ProcessHandle, NULL, 0, threatStartRoutineAddress, remotebuffer, 0, NULL);
	if (hThread == 0)return 3;
	
	CloseHandle(ProcessHandle);
	CloseHandle(hThread);
	return 0;
}
#endif

四、注意事项

这种方法在32位Win7成功了,但是64位系统没有测试过。

猜你喜欢

转载自blog.csdn.net/nnKevi/article/details/125428867