当前位置:首页 > 今天的世界杯

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

admin 2025-09-09 22:42:47 7849

一、背景

最近想写一个杀毒软件,可是别人在任务管理器里轻轻松松就把我的进程结束了,我希望把我的杀毒软件做成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

#include

#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

#include

#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

#include

#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

#include

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

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位系统没有测试过。