El gancho en línea de C++ implementa la prevención de terminación del proceso (no es necesario escribir un controlador)

1. Antecedentes

Hace poco quise escribir un software antivirus, pero alguien terminó fácilmente mi proceso en el administrador de tareas. Espero que mi software antivirus sea como 360. Una vez que finalice, aparecerá el mensaje "Acceso denegado" y pase lo que pase. utilizas Ni el Administrador de tareas ni el taskkill pueden finalizar el proceso.

Entonces, recopilé mucha información en Internet, y mucha información decía que necesito escribir un controlador, pero soy un novato y no puedo escribir un controlador en absoluto. Cuando estaba a punto de aprender, De repente descubrí que escribir un controlador requiere una firma digital, que cuesta 250 dólares estadounidenses, ¡lo que equivale a unos 1.750 RMB! No quiero gastar tanto dinero.

Al principio, pensé erróneamente que el propósito de escribir el controlador era ejecutarlo en Ring0 para que el proceso no pudiera finalizarse, sin embargo, el proceso del software antivirus todavía se ejecuta en Ring3, por lo que no es necesario aumentar los permisos. para evitar que otros finalicen el programa. Más tarde escuché que el controlador se implementa registrando devoluciones de llamada, y las devoluciones de llamada registradas son en realidad similares a los HOOK. Aprendí el gancho en línea, por lo que quiero usarlo para evitar la terminación del proceso. Sin embargo, el gancho en línea requiere la inyección de DLL, es decir, solo el proceso en el que se inyecta la DLL será HOOK. La mayoría de las personas en Internet escriben la DLL y luego la inyectan en el administrador de tareas, pero aún puedo finalizar el proceso usando taskkill. En otras palabras, tengo que encontrar un método que pueda conectar todos los programas o inyectar DLL en todos los programas. Después de pensarlo mucho, finalmente se me ocurrió una solución.

2.Ideas

Con respecto a los ganchos en línea, hay muchos blogs en Internet, por lo que no los analizaré aquí. Quiero ENGANCHAR OpenProcess, y cuando se detecta que el proceso a abrir es un proceso protegido, se deniega el acceso.

El problema que quiero resolver ahora es cómo inyectar DLL en todos los programas.

Tenga en cuenta que "inyectar todos los programas" aquí significa: no importa cómo ejecute el nuevo proceso, este proceso se inyectará en nuestra DLL, en lugar de inyectar la DLL en todos los procesos existentes del sistema. Por ejemplo, si desea abrir el administrador de tareas para finalizar el proceso, la DLL se inyectará tan pronto como se abra el administrador de tareas, por lo que no podrá inyectarla.

Pensé en dos ideas, pero solo una tuvo éxito, pero las compartiré ambas.

Idea 1

Dado que todos los procesos necesitan ser inyectados, una idea natural es escribir un bucle infinito y enumerar continuamente todos los procesos en el sistema. Para cada proceso, enumere las DLL que carga. Si no existe nuestra DLL, insértela inmediatamente. Inyecte la DLL . De esta manera, cuando abra el administrador de tareas, debido a que no existe nuestra DLL, la DLL se inyectará inmediatamente.

Esto también es cierto. El proceso no se puede finalizar usando el Administrador de tareas. Pero se puede acabar con taskkill.

¿por qué?

Resulta que este método tiene un defecto: los procesos que han inyectado archivos DLL continuarán enumerando durante la enumeración, lo que resultará en una gran cantidad de trabajo inútil. Además, un proceso como taskkill llamará a OpenProcess tan pronto como se inicie. Si el proceso de taskkill se pierde durante la enumeración, taskkill ya ha llamado a OpenProcess antes de volver a enumerarlo. El resultado es: hay una fuga. ¡pez!

Entonces, tuve que usar el segundo método obedientemente.

idea 2

La idea fracasó. De repente pensé en una forma de resolver el defecto de la idea 1 (mucho trabajo inútil): esos "procesos antiguos" (procesos que se ejecutan en el sistema) se inyectarán en la DLL cuando realicen el ciclo por primera vez, y luego Es necesario inyectar DLL, solo aquellos "nuevos procesos" (procesos que acaban de iniciarse, sin DLL inyectada). Para capturar el "nuevo proceso", el primer método enumerará repetidamente el "proceso antiguo", lo que generará una gran cantidad de trabajo inútil y consumirá un tiempo valioso.

Entonces, aparece una nueva idea: siempre que detecte que se inicia un nuevo proceso, inyectar la DLL. De esta forma, no es necesario enumerar procesos antiguos.

Aquí surge la pregunta: ¿Cómo detectar el inicio de un nuevo proceso? ¿Necesitamos modificar el código del sistema operativo? ? ?

No precisamente. Después de recopilar cierta información, descubrí que la mayoría de los procesos de usuario se generan llamando a CreateProcessW a través de explorer.exe. Luego, sólo nos falta enganchar CreateProcessW nuevamente.

Por lo tanto, escribí dos archivos DLL (en realidad, podría escribir solo uno). Uno es responsable de HOOK OpenProcess. El otro es responsable de HOOK CreateProcessW. Una vez que se llama a CreateProcessW para crear un proceso secundario, inmediatamente inyectará estas dos DLL en el nuevo proceso. ¿Por qué inyectar dos al mismo tiempo? Debido a que después de esta operación, el CreateProcessW del proceso secundario también se ENGANCHARÁ, por lo que los procesos secundarios del proceso secundario también se inyectarán en la DLL y, por analogía, todos los procesos secundarios de explorer.exe se inyectarán en la DLL. .

Finalmente, inyecte las dos DLL en explorer.exe al mismo tiempo.

3. Implementación del código

Referencia de código parcial: [Win32] Implementación de API Hook (1) en sistemas de 32 bits

GANCHO DLL de proceso abierto: 

Notepad.exe en el código debe ser reemplazado por el proceso que desea proteger.

(processapi.h es un archivo de encabezado escrito por mí, que se mostrará más adelante)

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

GANCHO CreateProcess DLL:

K:\\tools\\Process Termination Prevention\\OpenProcess\\DLL.dll en el código debe reemplazarse con la ruta de la DLL de HOOK OpenProcess y K:\\tools\\Process Termination Prevention\\CreateProcess\\DLL .dll debe reemplazarse con la ruta a la DLL de HOOK CreateProcess.

(injectdll.h también es un archivo de encabezado escrito por mí)

#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: (Este código es responsable de inyectar la DLL en 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;
}

procesopi.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

inyectardll.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

4. Precauciones

Este método tuvo éxito en Win7 de 32 bits, pero no se ha probado en sistemas de 64 bits.

Supongo que te gusta

Origin blog.csdn.net/nnKevi/article/details/125428867
Recomendado
Clasificación