Habíamos visto en otros tutoriales como se hace, y que se trata de una técnica intrusiva porque requiere parchear la memoria (código) del proceso víctima.
http://foro.elhacker.net/programacion_cc/detours-t168884.0.html
No tiene nada que ver con otros tutoriales que muestran como se modifican los valores de algunos punteros que corresponden a datos en el proceso.
Ej: http://foro.elhacker.net/programacion_cc/codigo_fuente_cheat_cs_16-t387341.0.html
Dejo el código funcional y el proyecto para descargar como siempre, dejo unas imágenes..
En este caso para diferenciarnos de otros tutoriales, explico la forma en que se puede cargar esta DLL en el proceso "hl.exe" que corresponde al juego Counter-Strike.
Se trata de ir a la carpeta del juego, y buscar una DLL de las que sabemos que no son necesarias en el juego pero de todas formas son cargadas al proceso.
Hay otras DLLs que son cargadas y algunas de sus funciones o todas, son utilizadas en el proceso, por lo que no se puede quitarlas, sino más bien hacer un 'wrapper' de ellas. Pero no quitarlas.
Vamos a ver una DLL que si la podemos quitar que se llama "DemoPlayer.dll". Vamos a quitarla y poner nuestra DLL con el WH en su lugar. Obviamente la tenemos que renombrar a "demoplayer.DLL" si es que no tiene ese nombre toda via.
Al final quiero decir que los sistemas de seguridad suelen escanear en la memoria, por ejemplo los primeros 5 bytes de algunas funciones para determinar si tienen 'detours'.
Pero a veces hacen otras comprobaciones como CRC32 de toda una función, o quien sabe que otras comprobaciones.. el tema es que este es un método intrusivo.
Código
// // Modifications: By 85 // Credits: gamedeception (detour function), SharkBoy999 base // elhacker.net // etalking.com.ar // david_bs@live.com // 2013 // /////////////////////////////////////////////////////////////////////////////////////// #pragma comment(lib,"OpenGL32.lib") #include <windows.h> #include <gl/gl.h> #include <tlhelp32.h> #include<stdio.h> /////////////////////////////////////////////////////////////////////////////////////// #define wallhack_key GetAsyncKeyState(VK_NUMPAD1) &1 #define lambert_key GetAsyncKeyState(VK_NUMPAD2) &1 #define nosmoke_key GetAsyncKeyState(VK_NUMPAD3) &1 #define noflash_key GetAsyncKeyState(VK_NUMPAD4) &1 bool wallhack = true; bool lambert = true; bool nosmoke = true; bool noflash = true; bool bDrawingSmoke = false; bool bDrawingFlash = false; /////////////////////////////////////////////////////////////////////////////////////// typedef FARPROC (APIENTRY* GetProcAddress_t)(HMODULE, LPCSTR); typedef void (APIENTRY* glBegin_t)(GLenum mode); typedef void (APIENTRY* glViewport_t)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRY* glVertex3fv_t)(const GLfloat* v); typedef void (APIENTRY* glVertex2f_t)(GLfloat,GLfloat); /////////////////////////////////////////////////////////////////////////////////////// GetProcAddress_t pGetProcAddress = 0; glBegin_t pglBegin; glViewport_t pglViewport; glVertex3fv_t pglVertex3fv; glVertex2f_t pglVertex2f; /////////////////////////////////////////////////////////////////////////////////////// void toggle(bool var) { var = !var; } /////////////////////////////////////////////////////////////////////////////////////// void* Detour1(BYTE* src, const BYTE* dst, const int len) { BYTE* jmp = (BYTE*)malloc(len+5); DWORD dwback; while(!VirtualProtect(src, len, PAGE_READWRITE, &dwback)); memcpy(jmp, src, len);jmp+=len; jmp[0] = 0xE9; *(DWORD*)(jmp+1)=(DWORD)(src+len-jmp)-5; src[0] = 0xE9; *(DWORD*)(src+1)=(DWORD)(dst-src)-5; while(!VirtualProtect(src, len, dwback, &dwback)); return (jmp-len); } /////////////////////////////////////////////////////////////////////////////////////// FARPROC APIENTRY new_GetProcAddress(HMODULE hModule, LPCSTR lpProcName) { //FARPROC fpResult = (*pGetProcAddress)(hModule, lpProcName); FARPROC fpResult = pGetProcAddress(hModule, lpProcName); if(HIWORD(lpProcName)) { if(!lstrcmp(lpProcName,"GetProcAddress")) return((FARPROC)&new_GetProcAddress); } return fpResult; } /////////////////////////////////////////////////////////////////////////////////////// void APIENTRY new_glBegin(GLenum mode) { if(wallhack) { if(mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_FAN) glDepthRange( 0, 0.5 ); else glDepthRange( 0.5, 1 ); } if(lambert) { if(mode == GL_TRIANGLE_STRIP || mode == GL_TRIANGLE_FAN) glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL); } if(nosmoke) { if(mode==GL_QUADS) { GLfloat curcol[4]; glGetFloatv(GL_CURRENT_COLOR, curcol); if(mode==GL_QUADS && (curcol[0]==curcol[1]) && (curcol[0]==curcol[2]) && (curcol[0]!=0.0) && (curcol[0]!=1.0)) { bDrawingSmoke = true; } else bDrawingSmoke = false; } } if(noflash) { GLfloat color[4]; glGetFloatv(GL_CURRENT_COLOR, color); if(mode == GL_QUADS && (color[0]==1 && color[1]==1 && color[2]==1) ) { bDrawingFlash = true; } else bDrawingFlash = false; } pglBegin(mode); } /////////////////////////////////////////////////////////////////////////////////////// void APIENTRY new_glViewport(GLint x, GLint y, GLsizei w, GLsizei h) { if(wallhack_key) toggle(wallhack); if(lambert_key) toggle(lambert); if(nosmoke_key) toggle(nosmoke); if(noflash_key) toggle(noflash); pglViewport(x,y,w,h); } /////////////////////////////////////////////////////////////////////////////////////// void APIENTRY new_glVertex3fv(const GLfloat* v) { if(bDrawingSmoke) return; pglVertex3fv(v); } /////////////////////////////////////////////////////////////////////////////////////// void APIENTRY new_glVertex2f(GLfloat x,GLfloat y) { /* if (bDrawingFlash) { GLfloat color[4]; glGetFloatv(GL_CURRENT_COLOR, color); //color[0]=0, color[1]=0, color[2]=0; glDisable(GL_TEXTURE_2D); glColor4f(color[0], color[1], color[2], 0.01f); }*/ pglVertex2f(x,y); } /////////////////////////////////////////////////////////////////////////////////////// void Hook(void) { pglBegin = (glBegin_t) Detour1((LPBYTE)glBegin, (LPBYTE)new_glBegin, 6); pglViewport = (glViewport_t) Detour1((LPBYTE)glViewport, (LPBYTE)new_glViewport, 7); pglVertex3fv = (glVertex3fv_t) Detour1((LPBYTE)glVertex3fv, (LPBYTE)new_glVertex3fv, 6); pglVertex2f = (glVertex2f_t) Detour1((LPBYTE)glVertex2f, (LPBYTE)new_glVertex2f, 6); } /////////////////////////////////////////////////////////////////////////////////////// bool APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { if(dwReason == DLL_PROCESS_ATTACH) { // No es necesario este Detour para la demostración.. pGetProcAddress = (GetProcAddress_t)Detour1((LPBYTE)GetProcAddress, (LPBYTE)new_GetProcAddress, 5); if(GetModuleHandle("Opengl32.dll")) Hook(); } else if(dwReason == DLL_PROCESS_DETACH) { // Restaurar bytes en GPA // (no hace falta suspender el mismo hilo! no sirve para nada XD) // Salida con retardo. // Permite que se ejecuten los últimos llamados a GPA // (Y no hace falta restaurar los bytes parcheados XD) ExitProcess(100); } return (true); } ///////////////////////////////////////////////////////////////////////////////////////
otra cosa que quiero agregar, es que el 'hook' a GetProcAddress no es necesario, pero está hecho y sirve para demostrar algo importante.
cuando salimos del juego, osea del proceso, antes se descargan las DLLs entre otras cosas, pero cuando se descarga nuestra DLL la memoria del proceso continua parcheada (los hooks que instalamos), y las referencias a los hooks son inválidas ya que la DLL se ha descargado.
Esto no importa para Opengl32 porque nadie va a utilizar Opengl32 al salir, pero con GetProcAddress si pasa esto. Por eso se debería considerar restaurar los bytes parcheados en GetProcAddress, o más fácil es hacer que la DLL se descargue cuando ya no sea necesaria (cuando no se haga más referencia a los hooks). Con un ExitProcess(100) queda resuelto, en realidad no investigué acerca de este tema, sólo traté de arreglarlo de alguna forma. Pero es un detalle a considerar.
PROYECTO
http://www.mediafire.com/?qfb65fsfgaf5doa