Introdución
El método CreateRemoteThread
El método SetWindowsHookEx
El método "code cave"
Apéndice A - métodos para obtener el process ID
Apéndice B - métodos para obtener el thread ID
Apéndice C - ejemplo completo con CreateRemoteThread
Apéndice D - ejemplo comleto con SetWindowsHookEx
Apéndice E - ejemplo completo de "code cave"
la inyección dll es de gran uso para muchas cosas (game hacking, hooking de funciones, parcheamiento de code, crear keygens, desempackar, etc).
estos son los métodos más comunes y cada uno tiene su pro y su contra..
bla bla bla..
este post mismo, junto con estos:
https://foro.elhacker.net/index.php/topic,177895.0.html
https://foro.elhacker.net/index.php/topic,172561.0.html
más otros post similares, pueden ayudarte a construir tu loader para un hack.
método CreateRemoteThread
la función provista por la api de windows, CreateRemoteThread() nos permite empezar un hilo en otro proceso. pero para leer esto es necesario saber lo básico de como usar hilos y usar funciones como CreateThread().
para usarla hay que estar en un sistema basado en NT. con lo cual hay que hacer un check de esto mismo.
bool IsWindowsNT()
{
// checkea la versión de windows
DWORD version = GetVersion();
// parse return
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
return (version < 0x80000000);
}
la definición de la MSDN para CreateRemoteThread() es esta:
HANDLE CreateRemoteThread( HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags,
LPDWORD lpThreadId );
es escencialmente CreateThread, con un argumento hProcess, cosa que nosotros podamos decirle en cual proceso para crear un nuevo hilo.
ahora, normalmente nosotros queremos empezar el hilo ejecutándose sobre alguna función interna de el proceso con el que estamos interactuando.
sin embargo, para inyectar una dll, tenemos que hacer algo un poco diferente.
BOOL InjectDLL(DWORD ProcessID)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!ProcessID)
return false;
Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);
if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, DLL_NAME,strlen(DLL_NAME), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
este código, llama a CreateRemoteThread() con un lpStartAddress de LoadLibrary(). entonces empieza un nuevo hilo es el proceso remoto y ejecuta la función LoadLibrary().
por suerte, esta función toma sólo un argumento, el nombre de la dll que carga.
podemos pasar este en el espacio de argumentos de CreateRemoteThread().
sin embargo, hay un pequeño dilema, desde que este hilo no va a estar ejecutándose en nuestro espacio de direcciones, este no va a ser capáz de referirse a cadenas (como el nombre de la dll que está en nuestro espacio de direcciones).
entonces, antes de llamar a CreateRemoteThread(), tenemos que allocar espacio en otro proceso usando VirtualAllocEx(), y escribir nuestra string (cadena) ahí.
finalmente pasamos el puntero a la cadena dentro del proceso remoto en el espacio simple de argumentos de CreateRemoteThread(), y listo..
nuestra dll es cargada y corre perfecto en el proceso remoto.
este es un programa loader genérico que se usa cuando necesitás cargar una dll.
El método SetWindowsHookEx
este método es un poco más intrusivo que el primero, y crea más de una conmoción en el proceso inyectado, lo cual normalmente nosotros no deseamos. sin embargo, este es un poco más fácil de usar que el primero, y tiene sus propias ventajas.
(como ser capás de inyectarse dentro de cada proceso en el sistema, de un tiro).
el método SetWindowsHookEx está designado para permitirte "HOOKEAR" mensajes de ventanas para un hilo dado. esto requiere que vos inyectés una dll en el espacio de direcciones de ese proceso, entonces SetWindowsHookEx() maneja todo por nosotros. la dll debe tener una función para el HOOK que SetWindowsHookEx ha creado, de otra forma la dll va a crashear.
Citar
HHOOK SetWindowsHookEx(
int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
int idHook,
HOOKPROC lpfn,
HINSTANCE hMod,
DWORD dwThreadId
);
idHook es sólo eso, el ID del mensaje que nosotros queremos HOOKEAR. hay varios de ellos (se puede conseguir una lista completa). sin embargo nosotros vamos a querer usar uno que es tan intrusivo como sea posible, y tiene la probabilidad de causar alarmas en los antivirus (SetWindowsHookEx es la clave de todos los keyloggers en ring3). el mensaje WH_CBT parece bastante inofensivo:
WH_CBT
Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information,
see the CBTProc hook procedure.
--MSDN
entonces, necesitaremos crear un proceso hook CBT en nuestra dll, entonces cuando el HOOK es llamado, nosotros podemos manejarlo propiamente.
Citar
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(0, nCode, wParam, lParam);
};
{
return CallNextHookEx(0, nCode, wParam, lParam);
};
todo lo que estamos haciendo es llamar al próximo hook en la cadena de hooks que existe para este mensaje. volviendo ala función SetWindowsHookEx(), el siguiente parámetro que vemos es lpfn. lpfn es exactamente como suena "long pointer to funcion". ese es un puntero a nuestra función de proceso hook CBT. entonces, para obtenerlo, vamos a tener o que hardcodear la dirección o cargar la dll primero nosotros mismos. hardcodear cualquier cosa es mala idea, entonces cargaremos la dll usando LoadLibrary(), y usar GetProcAddress() para obtener la dirección de nuestra función.
Citar
HMODULE hDll;
unsigned long cbtProcAddr;
hDll = LoadLibrary("injected.dll");
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
unsigned long cbtProcAddr;
hDll = LoadLibrary("injected.dll");
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
ahora encbtProcAddr tenemos la dirección de nuestra función. parámetro 3, de SetWindowsHookEx() es el handle de nuestra dll, ya lo hemos obtenido en este proceso de obtener la dirección de CBTProc (hDll es el handle de nuestra dll, retornado por LoadLibrary).
queda sólo un parámetro en la función SetWindowsHookEx(), el parámetro dwThread. si quieres inyectar tu dll en cada proceso en el sistema (usado para hookeo de funciones globales, keyloggers, troyanos, rootkits, etc) puedes simplemente especificar 0 para este parámetro. si quieres apuntar a un proceso específico, vas a necesitar obtener el ID de uno de esos hilos. hay muchas formas de ponerlo todo junto en una pequeña función.
Citar
BOOL InjectDll(char *dllName)
{
HMODULE hDll;
unsigned long cbtProcAddr;
hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromWindow("targetApp"));
return TRUE;
}
{
HMODULE hDll;
unsigned long cbtProcAddr;
hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromWindow("targetApp"));
return TRUE;
}
El método "CODE CAVE"
aclaraciones:
stub = porción, trozo
en lugar de explotar una función API de windows para forzar el proceso para cargar nuestra dll, esta ves vamos a allocar un pequeño trozo de memoria dentro de la aplicación objetivo, e inyectar una pequeña porción que cargue nuestra dll. la ventaja es que esto funcionará en cualquier versión de windows, y esto es también el menos detectable de cualquier método mencionado. nuestra porción queda así:
Citar
__declspec(naked) loadDll(void)
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF
// Save the flags and registers
pushfd
pushad
// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF
// Call LoadLibrary with the string parameter
call eax
// Restore the registers and flags
popad
popfd
// Return control to the hijacked thread
ret
}
}
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF
// Save the flags and registers
pushfd
pushad
// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF
// Call LoadLibrary with the string parameter
call eax
// Restore the registers and flags
popad
popfd
// Return control to the hijacked thread
ret
}
}
0xDEADBEEF está sólo ahí para marcar direcciones que nosotros no podemos saber antes de usar, y tener que parchear durante runtime. ok, entonces vamos a hacer una lista de las cosas que necesitamos para hacer andar esto:
_ allocar espacio para la porción.
_ allocar espacio para el nombre de la dll.
_ suspender el hilo principal de nuestro objetivo.
_ obtener la dirección de la siguiente instrucción para ser ejecutada
(necesitado para el siguiente paso).
_ parchear la propia dirección para retornar en la porción.
_ parchear la dirección de el nombre de la dll.
_ parchear la dirección de LoadLibrary.
_ setear la dirección de la siguiente instrucción para ser ejecutada en el hilo
objetivo, hacia la dirección de el comienzo de nuestra porción.
_ resumir el hilo objetivo.
para allocar espacio dentro del objetivo, usaremos VirtualAllocEx(). necesitaremos abrir un handle para el proceso con el privilegio VM_OPERATION especificado, para poder hacer esto. para nuestra cadena del nombre de la dll, necesitaremos sólo leer y escribir privilegios.
para la porción sin embargo, necesitaremos privilegios para leer, escribir y ejecutar. luego escribiremos en nuestra cadena dllname, para poder referenciar esto desde la porción una ves que está insertada.
Citar
void *dllString, *stub;
unsigned long wowID;
HANDLE hProcess
//See Appendix A for
//this function
wowID = GetTargetProcessIdFromProcname(PROC_NAME);
hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);
dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);
unsigned long wowID;
HANDLE hProcess
//See Appendix A for
//this function
wowID = GetTargetProcessIdFromProcname(PROC_NAME);
hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);
dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);
para continuar con nuestras siguientes acciones, necesitaremos un handle para uno de nuestros hilos objetivo. podemos usar las funciones del APËNDICE B. para obtener el ID de uno de esos hilos, y luego usar la api OpenThread() para obtener el handle. necesitaremos se capaces de obtener y setear contexto, y también suspender y resumir el hilo.
Citar
unsigned long threadID;
HANDLE hThread;
threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
HANDLE hThread;
threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
ahora necesitamos pausar el hilo para poder obtener el "contexto". el contexto de un hilo es el estado correspondiente de todos sus registros, también de otra información periférica. sin embargo, estamos más relacionados con el registro EIP, el cual apunta a la siguiente instrucción para ser ejecutada. entonces, si nosotros no queremos suspender el hilo antes de recuperar su información del contexto, éste va a continuar ejecutándose y por el tiempo obtendremos la información, ésta será inválida. una ves que hemos pausado el hilo, recuperaremos su información de contexto usando la función GetThreadContext() . vamos a tener un valor de la siguiente instrucción correspondiente para ser ejecutada, luego de eso sabremos adonde nuestra porción debería retornar. luego no importa sobre parchear la porción para tener todos los punteros propios, y forzar el hilo para ejecutarlo:
Citar
SuspendThread(hThread);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
//Set the EIP of the context to the address of our stub
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
//Right now loadDll is code, which isn't writable. We need
//to change that.
VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
//Patch the first push instruction
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
//Patch the 2nd push instruction
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
//Patch the mov eax, 0xDEADBEEF to mov eax, LoadLibrary
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);
WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL); //Write the stub into the target
//Set the new context of the target's thread
SetThreadContext(hThread, &ctx);
//Let the target thread continue execution, starting at our stub
ResumeThread(hThread);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
//Set the EIP of the context to the address of our stub
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
//Right now loadDll is code, which isn't writable. We need
//to change that.
VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
//Patch the first push instruction
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
//Patch the 2nd push instruction
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
//Patch the mov eax, 0xDEADBEEF to mov eax, LoadLibrary
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);
WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL); //Write the stub into the target
//Set the new context of the target's thread
SetThreadContext(hThread, &ctx);
//Let the target thread continue execution, starting at our stub
ResumeThread(hThread);
todo lo que queda ahora es limpiar la evidencia. antes de eso, deberíamos pausar el inyector por un momento, para asegurarnos que el objetivo tiene tiempo de ejecutar nuestra porción. usaremos Sleep() para pausar por 8 segundos antes de desmapear la memoria que hemos allocado y sacar el inyector.
Citar
Sleep(8000);
VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);
VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);
este método debería funcionar para cualquier versión de windows, y debería ser lo menos probable de provocar alarmas en los AV o causar malfuncionamiento.
si entiendes e implementas esto apropiadamente, este es entonces el mejor método de los 3.
Apéndice A - métodos para obtener el PID (process ID)
si el proceso que tienes de objetivo tiene una ventana, puedes usar la función FindWindow, en conjunto con GetWindowThreadProcessId.
Código:
unsigned long GetTargetProcessIdFromWindow(char *className, char *windowName)
{
unsigned long procID;
HWND targetWnd;
targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &procId);
return procID;
}
{
unsigned long procID;
HWND targetWnd;
targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &procId);
return procID;
}
si sólo sabes el nombre de el archivo ejecutable o si este no tiene una ventana.
Código:
unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
return pe.th32ProcessID;
}
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
return pe.th32ProcessID;
}
Apéndice B - Metodos de obtener el TID (thread ID)
Si el proceso que tienes de objetivo tiene una ventana, puedes usar la función FindWindow en conjunto con GetWindowThreadProcessId y la api toolhelp como se ve continuación:
Código:
unsigned long GetTargetThreadIdFromWindow(char *className, char *windowName)
{
HWND targetWnd;
HANDLE hProcess
unsigned long processId, pTID, threadID;
targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &processId);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, processID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
{
HWND targetWnd;
HANDLE hProcess
unsigned long processId, pTID, threadID;
targetWnd = FindWindow(className, windowName);
GetWindowThreadProcessId(targetWnd, &processId);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, processID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
Si tu sólo sabes el nombre de el ejecutable de tu objetivo, entonces puedes usar este code para localizarlo:
Código:
unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
Apéndice C - ejemplo completo con CreateRemoteThread
Código:
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#define PROCESS_NAME "target.exe"
#define DLL_NAME "injected.dll"
//I could just use PROCESS_ALL_ACCESS but it's always best to use the absolute bare minimum of priveleges, so that your code works in as
//many circumstances as possible.
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL WriteProcessBYTES(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize);
BOOL LoadDll(char *procName, char *dllName);
BOOL InjectDLL(DWORD ProcessID, char *dllName);
unsigned long GetTargetProcessIdFromProcname(char *procName);
bool IsWindowsNT()
{
// check current version of Windows
DWORD version = GetVersion();
// parse return
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
return (version < 0x80000000);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
if(IsWindowsNT())
LoadDll(PROCESS_NAME, DLL_NAME);
else
MessageBox(0, "Your system does not support this method", "Error!", 0);
return 0;
}
BOOL LoadDll(char *procName, char *dllName)
{
DWORD ProcID = 0;
ProcID = GetProcID(procName);
if(!(InjectDLL(ProcID, dllName)))
MessageBox(NULL, "Process located, but injection failed", "Loader", NULL);
return true;
}
BOOL InjectDLL(DWORD ProcessID, char *dllName)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!ProcessID)
return false;
Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);
if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
return pe.th32ProcessID;
}
#include <stdio.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#define PROCESS_NAME "target.exe"
#define DLL_NAME "injected.dll"
//I could just use PROCESS_ALL_ACCESS but it's always best to use the absolute bare minimum of priveleges, so that your code works in as
//many circumstances as possible.
#define CREATE_THREAD_ACCESS (PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ)
BOOL WriteProcessBYTES(HANDLE hProcess,LPVOID lpBaseAddress,LPCVOID lpBuffer,SIZE_T nSize);
BOOL LoadDll(char *procName, char *dllName);
BOOL InjectDLL(DWORD ProcessID, char *dllName);
unsigned long GetTargetProcessIdFromProcname(char *procName);
bool IsWindowsNT()
{
// check current version of Windows
DWORD version = GetVersion();
// parse return
DWORD majorVersion = (DWORD)(LOBYTE(LOWORD(version)));
DWORD minorVersion = (DWORD)(HIBYTE(LOWORD(version)));
return (version < 0x80000000);
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
if(IsWindowsNT())
LoadDll(PROCESS_NAME, DLL_NAME);
else
MessageBox(0, "Your system does not support this method", "Error!", 0);
return 0;
}
BOOL LoadDll(char *procName, char *dllName)
{
DWORD ProcID = 0;
ProcID = GetProcID(procName);
if(!(InjectDLL(ProcID, dllName)))
MessageBox(NULL, "Process located, but injection failed", "Loader", NULL);
return true;
}
BOOL InjectDLL(DWORD ProcessID, char *dllName)
{
HANDLE Proc;
char buf[50]={0};
LPVOID RemoteString, LoadLibAddy;
if(!ProcessID)
return false;
Proc = OpenProcess(CREATE_THREAD_ACCESS, FALSE, ProcessID);
if(!Proc)
{
sprintf(buf, "OpenProcess() failed: %d", GetLastError());
MessageBox(NULL, buf, "Loader", NULL);
return false;
}
LoadLibAddy = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
RemoteString = (LPVOID)VirtualAllocEx(Proc, NULL, strlen(DLL_NAME), MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Proc, (LPVOID)RemoteString, dllName, strlen(dllName), NULL);
CreateRemoteThread(Proc, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibAddy, (LPVOID)RemoteString, NULL, NULL);
CloseHandle(Proc);
return true;
}
unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
return pe.th32ProcessID;
}
Apéndice D - ejemplo completo con SetWindowsHookEx
Código:
#include <windows.h>
#include <tlhelp32.h>
#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"
void LoadDll(char *procName, char *dllName);
unsigned long GetTargetThreadIdFromProcname(char *procName);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
LoadDll(PROC_NAME, DLL_NAME);
return 0;
}
void LoadDll(char *procName, char *dllName)
{
HMODULE hDll;
unsigned long cbtProcAddr;
hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromProcName(procName));
return TRUE;
}
unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
#include <tlhelp32.h>
#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"
void LoadDll(char *procName, char *dllName);
unsigned long GetTargetThreadIdFromProcname(char *procName);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
LoadDll(PROC_NAME, DLL_NAME);
return 0;
}
void LoadDll(char *procName, char *dllName)
{
HMODULE hDll;
unsigned long cbtProcAddr;
hDll = LoadLibrary(dllName);
cbtProcAddr = GetProcAddress(hDll, "CBTProc");
SetWindowsHookEx(WH_CBT, cbtProcAddr, hDll, GetTargetThreadIdFromProcName(procName));
return TRUE;
}
unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
Apéndice E - ejemplo completo de "CODE CAVE"
Código:
#include <windows.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"
unsigned long GetTargetProcessIdFromProcname(char *procName);
unsigned long GetTargetThreadIdFromProcname(char *procName);
__declspec(naked) loadDll(void)
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF
// Save the flags and registers
pushfd
pushad
// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF
// Call LoadLibrary with the string parameter
call eax
// Restore the registers and flags
popad
popfd
// Return control to the hijacked thread
ret
}
}
__declspec(naked) loadDll_end(void)
{
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
void *dllString;
void *stub;
unsigned long wowID, threadID, stubLen, oldIP, oldprot, loadLibAddy;
HANDLE hProcess, hThread;
CONTEXT ctx;
stubLen = (unsigned long)loadDll_end - (unsigned long)loadDll;
loadLibAddy = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
wowID = GetTargetProcessIdFromProcname(PROC_NAME);
hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);
dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);
threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
SuspendThread(hThread);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);
WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL);
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
Sleep(8000);
VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);
return 0;
}
unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
return pe.th32ProcessID;
}
unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
#include <tlhelp32.h>
#include <shlwapi.h>
#define PROC_NAME "target.exe"
#define DLL_NAME "injected.dll"
unsigned long GetTargetProcessIdFromProcname(char *procName);
unsigned long GetTargetThreadIdFromProcname(char *procName);
__declspec(naked) loadDll(void)
{
_asm{
// Placeholder for the return address
push 0xDEADBEEF
// Save the flags and registers
pushfd
pushad
// Placeholder for the string address and LoadLibrary
push 0xDEADBEEF
mov eax, 0xDEADBEEF
// Call LoadLibrary with the string parameter
call eax
// Restore the registers and flags
popad
popfd
// Return control to the hijacked thread
ret
}
}
__declspec(naked) loadDll_end(void)
{
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
void *dllString;
void *stub;
unsigned long wowID, threadID, stubLen, oldIP, oldprot, loadLibAddy;
HANDLE hProcess, hThread;
CONTEXT ctx;
stubLen = (unsigned long)loadDll_end - (unsigned long)loadDll;
loadLibAddy = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
wowID = GetTargetProcessIdFromProcname(PROC_NAME);
hProcess = OpenProcess((PROCESS_VM_WRITE | PROCESS_VM_OPERATION), false, wowID);
dllString = VirtualAllocEx(hProcess, NULL, (strlen(DLL_NAME) + 1), MEM_COMMIT, PAGE_READWRITE);
stub = VirtualAllocEx(hProcess, NULL, stubLen, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(hProcess, dllString, DLL_NAME, strlen(DLL_NAME), NULL);
threadID = GetTargetThreadIdFromProcname(PROC_NAME);
hThread = OpenThread((THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME), false, threadID);
SuspendThread(hThread);
ctx.ContextFlags = CONTEXT_CONTROL;
GetThreadContext(hThread, &ctx);
oldIP = ctx.Eip;
ctx.Eip = (DWORD)stub;
ctx.ContextFlags = CONTEXT_CONTROL;
VirtualProtect(loadDll, stubLen, PAGE_EXECUTE_READWRITE, &oldprot);
memcpy((void *)((unsigned long)loadDll + 1), &oldIP, 4);
memcpy((void *)((unsigned long)loadDll + 8), &dllString, 4);
memcpy((void *)((unsigned long)loadDll + 13), &loadLibAddy, 4);
WriteProcessMemory(hProcess, stub, loadDll, stubLen, NULL);
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
Sleep(8000);
VirtualFreeEx(hProcess, dllString, strlen(DLL_NAME), MEM_DECOMMIT);
VirtualFreeEx(hProcess, stub, stubLen, MEM_DECOMMIT);
CloseHandle(hProcess);
CloseHandle(hThread);
return 0;
}
unsigned long GetTargetProcessIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot;
BOOL retval, ProcFound = false;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
return pe.th32ProcessID;
}
unsigned long GetTargetThreadIdFromProcname(char *procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapshot, hProcess;
BOOL retval, ProcFound = false;
unsigned long pTID, threadID;
thSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if(thSnapshot == INVALID_HANDLE_VALUE)
{
MessageBox(NULL, "Error: unable to create toolhelp snapshot", "Loader", NULL);
return false;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapshot, &pe);
while(retval)
{
if(StrStrI(pe.szExeFile, procName) )
{
ProcFound = true;
break;
}
retval = Process32Next(thSnapshot,&pe);
pe.dwSize = sizeof(PROCESSENTRY32);
}
CloseHandle(thSnapshot);
_asm {
mov eax, fs:[0x18]
add eax, 36
mov [pTID], eax
}
hProcess = OpenProcess(PROCESS_VM_READ, false, pe.th32ProcessID);
ReadProcessMemory(hProcess, (const void *)pTID, &threadID, 4, NULL);
CloseHandle(hProcess);
return threadID;
}
-- una vez más van a disculpar la traducción hehe pero cualquiera está invitado a mejorarla
--









Autor



En línea





