0×02 | API’s
0×03 | Inyectando con DLL
0×04 | Inyectando sin DLL
0×01 | Intro
Voy a explicar mas o menos como inyectar nuestro propio código en otro proceso. Primero inyectaremos una dll, después lo haremos a pelo.0×02 | API’s
Primero necesitamos conocer algunas APIs de windows:OpenProcess
HANDLE WINAPI OpenProcess(
__in DWORD dwDesiredAccess,
__in BOOL bInheritHandle,
__in DWORD dwProcessId
);
al proceso, o NULL en caso de error.
VirtualAllocEx:
LPVOID WINAPI VirtualAllocEx(
__in HANDLE hProcess,
__in_opt LPVOID lpAddress,
__in SIZE_T dwSize,
__in DWORD flAllocationType,
__in DWORD flProtect
);
Devuelve un puntero a esa memoriam o NULL en caso de error.
WriteProcessMemory:
BOOL WINAPI WriteProcessMemory(
__in HANDLE hProcess,
__in LPVOID lpBaseAddress,
__in LPCVOID lpBuffer,
__in SIZE_T nSize,
__out SIZE_T *lpNumberOfBytesWritten
);
CreateRemoteThread:
HANDLE WINAPI CreateRemoteThread(
__in HANDLE hProcess,
__in LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in SIZE_T dwStackSize,
__in LPTHREAD_START_ROUTINE lpStartAddress,
__in LPVOID lpParameter,
__in DWORD dwCreationFlags,
__out LPDWORD lpThreadId
);
También usaremos Tlhelp32.h para obtener el PID de un proceso sabiendo su nombre.
HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pInfo;
BOOL st=TRUE;
pInfo.dwSize=sizeof(PROCESSENTRY32);
Process32First(processList, &pInfo);
int myPid=0;
do
{
if(strcmp(pInfo.szExeFile, "test.exe")==0)
{
myPid=pInfo.th32ProcessID;
break;
}
Process32Next(lista, &pInfo);
}
while(st!=FALSE);
0×03 | Inyectando con DLL
Primero necesitamos una DLL que inyectar, la cual al ser programada por nosotros hará lo que queramos.#include
; #include
; BOOL APIENTRY DllMain (HINSTANCE hInst,
DWORD reason,
LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_ATTACH:
MessageBoxA(NULL, "Hi!", "Hey!", 0);
break;
}
return TRUE;
}
- Abrimos el proceso, reservamos memoria en él, y escribimos en esa memoria la ruta de la DLL.
- Obtener la dirección de LoadLibrary con GetProcAddress. LoadLibrary se encuentra en kernel32.dll, y su dirección es compartida, por lo que podemos cargarla desde el inyector y usarla desde el inyectado.
- Lanzar un hilo en el proceso abierto, dando como punto de entrada la dirección de LoadLibrary y como argumento la dirección del nombre de la DLL previamente escrito.
#include
; #include
; #include
; void error(char *err);
HANDLE myProc=NULL;
int main(int argc, char *argv[])
{
HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pInfo;
BOOL st=TRUE;
pInfo.dwSize=sizeof(PROCESSENTRY32);
Process32First(processList, &pInfo);
int myPid=0;
do
{
if(strcmp(pInfo.szExeFile, "test.exe")==0)
{
myPid=pInfo.th32ProcessID;
break;
}
Process32Next(processList, &pInfo);
}
while(st!=FALSE);
// Abrir el proceso
printf("[+] Opening process %i\n", myPid);
myProc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, myPid);
if(myProc==NULL) error("[-] Error abriendo proceso.\n");
else printf("[+] Proceso abierto.\n");
// Reservar memoria para el argumento (ruta de la DLL)
char thData[]="dll.dll";
LPVOID dirToArg=VirtualAllocEx(myProc, NULL, strlen(thData), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(dirToArg==NULL) error("[-] Error reservando memoria para argumento.\n");
else printf("[+] Memoria reservada para argumento (%i bytes).\n", strlen(thData));
// Escribir la ruta de la DLL en la memoria reservada
SIZE_T written=0;
if(WriteProcessMemory(myProc, dirToArg, (LPVOID)&thData, strlen(thData), &written)==0) error("[-] Error escribiendo memoria.\n");
else printf("[+] Memoria escrita (arg %i bytes).\n", written);
// Lanzar un hilo con LoadLibrary
HANDLE rThread=CreateRemoteThread(myProc, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(LoadLibrary("Kernel32.dll"), "LoadLibraryA"), dirToArg, 0, NULL);
if(rThread==NULL) error("[-] Error creando el hilo.\n");
else printf("[+] Hilo creado.\n");
CloseHandle(myProc);
}
void error(char *err)
{
if(myProc!=NULL) CloseHandle(myProc);
printf("%s", err);
exit(0);
}
0×04 | Inyectando sin DLL
Aquí la cosa se complica. Las diferencias entre un método y otro son:- Ahora no podemos utilizar cadenas de texto directamente como argumentos a funciones. Ya veremos por qué.
- No podemos llamar a ninguna función que no carguemos previamente con LoadLibrary + GetProcAddress. Esas dos están cargadas en todos los ejecutables de Windows desde kernel32, así que podemos usar un puntero a ellas.
- Tenemos que escribir todo el código de nuestras funciones en el espacio de memoria del proceso.
- Necesitaremos estructuras mas complejas como argumento de nuestros hilos remotos.
- Crear una estructura de datos con TODAS las cadenas de texto que vayamos a usar en el código inyectado, y con un puntero a LoadLibrary y GetProcAddress.
- Abrir el proceso.
- Reservar memoria para la estructura de datos. Escribirla.
- Reservar memoria para nuestro código. Escribirlo.
- Lanzar el hilo remoto, dando como punto de entrada el puntero a neustro código y como argumento el puntero a nuestra estructura de datos.
#include
#include
; #include
; void error(char *err);
static DWORD WINAPI myFunc(LPVOID data);
HANDLE myProc=NULL;
// Con esto cargaremos punteros a LoadLibrary y GetProcAddress en nuestra estrucura de datos
typedef int (WINAPI *datLoadLibrary)(LPCTSTR);
typedef int (WINAPI *datGetProcAddress)(HMODULE, LPCSTR);
int main(int argc, char *argv[])
{
if(argc<2) error("Uso: hook.exe PROCESO\n"); // Esta es nuestra estructura de argumentos
struct {
char lnUser32[50]; // ->; "User32.dll"
char fnMessageBoxA[50]; // -> "MessageBoxA"
datLoadLibrary apiLoadLibrary; // Puntero a LoadLibrary
datGetProcAddress apiGetProcAddress; // Puntero a GetProcAddress
char Msg[50]; // Texto que usaremos en MessageBoxA
} thData;
strcpy(thData.lnUser32, "User32.dll");
strcpy(thData.fnMessageBoxA, "MessageBoxA");
strcpy(thData.Msg, "Hola!");
thData.apiLoadLibrary=GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
thData.apiGetProcAddress=GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProcAddress");
int funcSize=600; // El tamaño de nuestra función. Podria calcularse de forma exacta, pero como ejemplo
// exagerado nos vale .
HANDLE processList=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pInfo;
BOOL st=TRUE;
pInfo.dwSize=sizeof(PROCESSENTRY32);
Process32First(processList, &pInfo);
int myPid=0;
do
{
if(strcmp(pInfo.szExeFile, argv[1])==0)
{
myPid=pInfo.th32ProcessID;
break;
}
Process32Next(processList, &pInfo);
}
while(st!=FALSE);
// Abrir proceso
printf("[+] Abriendo proceso %i\n", myPid);
myProc=OpenProcess(PROCESS_ALL_ACCESS, FALSE, myPid);
if(myProc==NULL) error("[-] Error abriendo proceso.\n");
else printf("[+] Proceso abierto.\n");
// Reservar memoria para argumentos
LPVOID dirToArg=VirtualAllocEx(myProc, NULL, sizeof(thData), MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(dirToArg==NULL) error("[-] Error reservando memoria para arg.\n");
else printf("[+] Memoria reservada para arg (%i bytes).\n", sizeof(thData));
// Escribir argumentos
SIZE_T written=0;
if(WriteProcessMemory(myProc, dirToArg, (LPVOID)&thData, sizeof(thData), &written)==0) error("[-] Error escribiendo la estructura de datos.\n");
else printf("[+] Memoria escrita (arg %i bytes).\n", written);
// Reservar memoria para la funcion
LPVOID dirToWrite=VirtualAllocEx(myProc, NULL, funcSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if(dirToWrite==NULL) error("[-] Error rreservando memoria para codigo.\n");
else printf("[+] Memoria reservada para codigo (%i bytes).\n", funcSize);
// Escribimos el codigo de nuestra funcion
if(WriteProcessMemory(myProc, dirToWrite, (LPVOID)myFunc, funcSize, &written) == 0) error("[-]Error escribiendo memoria.\n");
else printf("[+] Memoria escrita (codigo).\n");
// Lanzamos el hilo
HANDLE rThread=CreateRemoteThread(myProc, NULL, 0, (LPTHREAD_START_ROUTINE)dirToWrite, dirToArg, 0, NULL);
if(rThread==NULL) error("[-] Error lanzando hilo.\n");
else printf("[+] Hilo lanzado.\n");
CloseHandle(myProc);
return 0;
}
void error(char *err)
{
if(myProc!=NULL) CloseHandle(myProc);
printf("%s", err);
exit(0);
}
static DWORD WINAPI myFunc(LPVOID data)
{
// Cargamos nuestros datos en una estructura como la que hicimos
struct {
char lnUser32[50];
char fnMessageBoxA[50];
datLoadLibrary apiLoadLibrary;
datGetProcAddress apiGetProcAddress;
char MSG[50];
} *thData;
thData=data;
// Podemos conseguir cualquier API con estas dos, siempre que tengamos su nombre en la estructura
void *apiDir=(void *)thData->apiGetProcAddress((HANDLE)thData->apiLoadLibrary(thData->lnUser32), thData->fnMessageBoxA);
// Puntero a funcion similar a MessageBoxA
INT WINAPI (*myMessageBox)(HWND, LPCSTR, LPCSTR, UINT);
myMessageBox=apiDir;
myMessageBox(NULL, thData->MSG, thData->MSG, 0);
return;
}
AGRADECIMIENTOS TOTALES A:
http://blog.ka0labs.org
No hay comentarios:
Publicar un comentario