Parcheo de EAT y de IAT automático

Iniciado por 85, 2 Marzo 2013, 09:59 AM

0 Miembros y 1 Visitante están viendo este tema.

85

NIVEL: Beginner
TEST: win XP SP3

En este post a modo de tutorial se han utilizado dos rutinas, googleadas de las miles que hay, que hacen los parches respectivos (EAT e IAT), automáticamente,  encontrando la ubicación de la entrada correspondiente a una función, dentro de estas tablas. Para el ejemplo del parcheo de IAT se procede a usar la IAT local  del ejecutable, mientras que para el parcheo de EAT se hace en la EAT de la librería (DLL) kernel32.dll.

El objetivo de esta demostración es interceptar la función
GetProcAddress con ningún propósito más que demostrar como
se puede interceptar una función.

Se pueden valorar los casos que se pueden dar en los siguientes
dos ejemplos de programas:

En el primer programa contamos con un EXE el cual tiene dos opciones
que se le ofrecen al usuario:

1_ parchear la eat de kernel32.dll
2_ parchear la iat local


luego de elegir una de ambas opciones, se procede a cargar una DLL
en el proceso (ver el código de la DLL para ver que hace).

DEMO 1

EXE
Código (cpp) [Seleccionar]

//
// By 85
// PatchEAT, PatchIAT (Googleadas en 5 segundos XD)
// elhacker.net
// etalking.com.ar
// 2013
//

#include<windows.h>
#include<stdio.h>

//
FARPROC (WINAPI* pGetProcAddress) ( HMODULE hModule, LPCSTR lpProcName );

typedef FARPROC (WINAPI* GetProcAddress_t) ( HMODULE hModule, LPCSTR lpProcName );

//
FARPROC WINAPI newGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
FARPROC nResult;
nResult=pGetProcAddress(hModule, lpProcName);
if (HIWORD(lpProcName))
{
if (!lstrcmp(lpProcName, "GetProcAddress"))
{
return (FARPROC) &newGetProcAddress;
}
}
return nResult;
}

//
bool PatchEAT(HMODULE hTargetMod,CHAR* FuncName,VOID* newAdd,VOID** OrigAdd)
{

#define _sword sizeof(WORD) //AddressOfNameOrdinals
#define _sdword sizeof(DWORD)
   DWORD addEAT,beforeProtection;
   IMAGE_DOS_HEADER* dos_header=(IMAGE_DOS_HEADER*)hTargetMod;
   IMAGE_NT_HEADERS* nt_header=NULL;
   if(dos_header->e_magic!=IMAGE_DOS_SIGNATURE)
return false;

nt_header=((PIMAGE_NT_HEADERS)((DWORD)(dos_header)+(DWORD)(dos_header->e_lfanew)));
if(nt_header->Signature!=IMAGE_NT_SIGNATURE)
return false;

   addEAT=nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
   IMAGE_EXPORT_DIRECTORY* pEAT=(IMAGE_EXPORT_DIRECTORY*)((DWORD)addEAT+(DWORD)hTargetMod);
   for(DWORD i=0;i<pEAT->NumberOfFunctions;i++){
       DWORD* pName=(DWORD*)((DWORD)hTargetMod+((DWORD)pEAT->AddressOfNames+(_sdword*i)));
//printf("add nombre 0x%X\n",pName);
//system("pause");
       if(strcmp((char*)((DWORD)hTargetMod+*pName),FuncName) == 0){
           WORD* AddNamePtrs=(WORD*)((DWORD)hTargetMod+((DWORD)pEAT->AddressOfNameOrdinals+(i*_sword)));
           DWORD* AddFuncRVA=(DWORD*)((DWORD)hTargetMod+((DWORD)pEAT->AddressOfFunctions+(_sdword**AddNamePtrs)));
           

//if(!strcmp((char*)((DWORD)hTargetMod+*pName),"GetProcAddress")){
//printf("AddNamePtrs 0x%X\n",AddNamePtrs);
// printf("Add de la func rva 0x%X\n",AddFuncRVA);
// printf("Add func 0x%X\n",*AddFuncRVA+DWORD(hTargetMod));
// system("pause");
//}

if(!VirtualProtect(AddFuncRVA,_sdword,PAGE_READWRITE,&beforeProtection))
return false;

*OrigAdd=(void*)(*AddFuncRVA+DWORD(hTargetMod));
           *AddFuncRVA=(((DWORD)newAdd)-DWORD(hTargetMod));//copia el nuevo rva
           if(!VirtualProtect(AddFuncRVA,_sdword,beforeProtection,&beforeProtection))
return false;

break;
       }
   }
   return true;
}

//
BOOL PatchIAT(HMODULE ModHandle, DWORD OriginalFunc, DWORD HookFunc, void **pOriginalFunc)
{
DWORD pe_offset,CurAddr,CurPointer,IATanfang,IATende,base;
BOOL Hooked=FALSE;
IMAGE_NT_HEADERS *pehdr;

if(!ModHandle || !OriginalFunc || !HookFunc)
return FALSE;

base=(DWORD)ModHandle;

memcpy(&pe_offset,(void *)(base+0x3C),sizeof(DWORD));
pehdr=(IMAGE_NT_HEADERS *)((DWORD)base + pe_offset);

IATanfang=(DWORD)base+pehdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress;
IATende=IATanfang+pehdr->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size;

CurAddr=IATanfang;

while(CurAddr<IATende)
{
memcpy(&CurPointer,(void *)CurAddr,sizeof(DWORD));

if(CurPointer==OriginalFunc)
{
if(pOriginalFunc)
*pOriginalFunc=(PVOID)CurPointer;
DWORD old_attributes,old_attributes2;
if(!VirtualProtect((void *)CurAddr,sizeof(DWORD), PAGE_EXECUTE_READWRITE, &old_attributes))
return FALSE;
memcpy((void *)CurAddr,&HookFunc,sizeof(DWORD));
if(!VirtualProtect((void *)CurAddr,sizeof(DWORD), old_attributes, &old_attributes2))
return FALSE;
Hooked=TRUE;
}

CurAddr+=sizeof(DWORD);
}
return Hooked;
}

//
int main(){

/*DWORD test0a = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD test0b = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
//printf("GPA original: 0x%X\n",pGetProcAddress);
printf("GPA hook: 0x%X\n",newGetProcAddress);
printf("GPA es ahora (k32): 0x%X\n",test0a);
printf("GPA es ahora (EXE): 0x%X\n",test0b);
system("pause");*/
////////////////////////////////

HINSTANCE lib;
int Res=0;
int hookmode=0;
while( hookmode<1||hookmode>3){

system("cls");
printf("Bienvenido!\n");
printf("Ingrese 1 para realizar un EAT HOOK\n");
printf("Ingrese 2 para realizar un IAT HOOK\n");
scanf("%d",&hookmode);
}

if(hookmode == 1) __asm jmp eathook;
else if(hookmode == 2) __asm jmp iathook;
else if(hookmode == 3) __asm jmp salida;

/////////////////////////////////////////////////
// EAT HOOK

eathook:
Res = PatchEAT(GetModuleHandle("kernel32.dll"),"GetProcAddress",
((VOID*)(&newGetProcAddress)),((VOID**)(&pGetProcAddress)));

if(!Res){

printf("No se ha modificado la EAT objetivo!\n");
ExitProcess(0);
}

// Test 1
DWORD test1a = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD test1b = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
printf("GPA original: 0x%X\n",pGetProcAddress);
printf("GPA hook: 0x%X\n",newGetProcAddress);
printf("GPA es ahora (k32): 0x%X\n",test1a);
printf("GPA es ahora (EXE): 0x%X\n",test1b);
system("pause");

lib = LoadLibrary("loaddll.dll");
FreeLibrary(lib);
return 0;
//

////////////////////////////////////////////////
// IAT HOOK

iathook:
Res = PatchIAT(GetModuleHandle(NULL),(DWORD)GetProcAddress,
(DWORD)newGetProcAddress,(void **)&pGetProcAddress);

if(!Res){

printf("No se ha modificado la IAT objetivo!\n");
ExitProcess(0);
}

// Test 2
DWORD test2a = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD test2b = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
printf("GPA original: 0x%X\n",pGetProcAddress);
printf("GPA hook: 0x%X\n",newGetProcAddress);
printf("GPA es ahora (k32): 0x%X\n",test2a);
printf("GPA es ahora (EXE): 0x%X\n",test2b);
system("pause");

lib = LoadLibrary("loaddll.dll");
FreeLibrary(lib);
return 0;
//

/////////////////////////////////////////////////
//
salida:
return 0;
}

//


DLL
Código (cpp) [Seleccionar]


//
// By 85
// PatchEAT, PatchIAT (googleadas en 5 segundos XD)
// elhacker.net
// etalking.com.ar
// 2013
//

#include<windows.h>
#include<stdio.h>

//////////////////////////

BOOL APIENTRY DllMain(
HANDLE hModule, // Handle to DLL module
DWORD ul_reason_for_call,
LPVOID lpReserved ) // Reserved
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
// A process is loading the DLL.

{

DWORD res1 = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD res2 = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
printf("GPA desde la dll mod=k32 0x%X\n", res1);
printf("GPA desde la dll mod=EXE 0x%X\n", res2);
system("pause");
}


break;
case DLL_THREAD_ATTACH:
// A process is creating a new thread.
break;
case DLL_THREAD_DETACH:
// A thread exits normally.
break;
case DLL_PROCESS_DETACH:
// A process unloads the DLL.
break;
}
return TRUE;
}

////////////////


En el segundo programa, contamos con un EXE el cual es un programa
simple. Sólo carga una DLL (Ver código de la DLL).

El código de la DLL se trata de realizar una de dos opciones.

1_ parchear la EAT kernel32.dll
2_ parchear la IAT del ejecutable

En realidad, se propone sólamente modificar la IAT del ejecutable,
el código del otro parche está deshabilitado.

En realidad el segundo programa no tiene mucho sentido tal cual está
expuesto, pero cobra sentido si nosotros quisiéramos aplicar este
método para algo relacionado al hacking.

Si queremos cambiar algo dentro de un proceso (por ejemplo un juego),
entonces una posible idea sería cargar una DLL en dicho proceso y
realizar un parche a la IAT del EXE. Siempre que sepamos que el EXE
hace uso de GetProcAddress para resolver alguna dirección interesante
para nosotros XD.

Un escenario en el cual se puede encontrar utilidad para esto pueder
ser, por ejemplo un programa (EXE) que utilice GetProcAddress para
resolver la dirección de ciertas funciones en una DLL que está cargada
en el proceso.

Al estár interceptada GetProcAddress, nosotros podemos arreglar que
retorne las direcciones de nuestros hooks en lugar de las direcciones
originales.

DEMO 2

EXE
Código (cpp) [Seleccionar]


//
// By 85
// elhacker.net
// etalking.com.ar
// 2013
//

#include<windows.h>
#include<stdio.h>

//
int main(){


HINSTANCE lib = LoadLibrary("loaddll2.dll");
FreeLibrary(lib);

printf("GPA original desde el EXE: 0x%X\n", GetProcAddress);
system("pause");
return 0;
}

//



DLL
Código (cpp) [Seleccionar]


//
// By 85
// PatchEAT, PatchIAT (googleadas en 5 segundos XD)
// elhacker.net
// etalking.com.ar
// 2013
//

#include<windows.h>
#include<stdio.h>

/////////////////////

FARPROC (WINAPI* pGetProcAddress) ( HMODULE hModule, LPCSTR lpProcName );

typedef FARPROC (WINAPI* GetProcAddress_t) ( HMODULE hModule, LPCSTR lpProcName );

//
FARPROC WINAPI newGetProcAddress(HMODULE hModule, LPCSTR lpProcName)
{
FARPROC nResult;
// nResult=pGetProcAddress(hModule, lpProcName);
nResult=GetProcAddress(hModule, lpProcName);
if (HIWORD(lpProcName))
{
if (!lstrcmp(lpProcName, "GetProcAddress"))
{
return (FARPROC) &newGetProcAddress;
}
}
return nResult;
}

//
bool PatchEAT(HMODULE hTargetMod,CHAR* FuncName,VOID* newAdd,VOID** OrigAdd)
{
       // misma que el anterior programa
...
}

//
BOOL PatchIAT(HMODULE ModHandle, DWORD OriginalFunc, DWORD HookFunc, void **pOriginalFunc)
{
// misma que el anterior programa
...
}

//
//////////////////////////

BOOL APIENTRY DllMain(
HANDLE hModule, // Handle to DLL module
DWORD ul_reason_for_call,
LPVOID lpReserved ) // Reserved
{
switch ( ul_reason_for_call )
{
case DLL_PROCESS_ATTACH:
// A process is loading the DLL.

{
int Res=0;
//

//////////////////////////
// EAT HOOK

/* Res = PatchEAT(GetModuleHandle("kernel32.dll"),"GetProcAddress",
((VOID*)(&newGetProcAddress)),((VOID**)(&pGetProcAddress)));

if(!Res){

printf("No se ha modificado la EAT objetivo!\n");
ExitProcess(0);
}

// Test 1
DWORD test1a = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD test1b = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
//DWORD test1b = (DWORD)GetProcAddress(GetModuleHandle("loaddll2.dll"),"GetProcAddress");//NO
printf("DLL: GPA original: 0x%X\n",pGetProcAddress);
printf("DLL: GPA original: 0x%X\n",GetProcAddress);
printf("DLL: GPA hook: 0x%X\n",newGetProcAddress);
printf("DLL: GPA es ahora (k32): 0x%X\n",test1a);
printf("DLL: GPA es ahora (EXE): 0x%X\n",test1b);
system("pause");*/

/////////////////////////
// IAT HOOK


Res = PatchIAT(GetModuleHandle(NULL),(DWORD)GetProcAddress,
(DWORD)newGetProcAddress,(void **)&pGetProcAddress);

if(!Res){

printf("No se ha modificado la IAT objetivo!\n");
ExitProcess(0);
}

// Test 2
DWORD test2a = (DWORD)GetProcAddress(GetModuleHandle("kernel32.dll"),"GetProcAddress");
DWORD test2b = (DWORD)GetProcAddress(GetModuleHandle(NULL),"GetProcAddress");
//DWORD test2b = (DWORD)GetProcAddress(GetModuleHandle("loaddll2.dll"),"GetProcAddress");//NO
printf("DLL: GPA original: 0x%X\n",pGetProcAddress);
printf("DLL: GPA original: 0x%X\n",GetProcAddress);
printf("DLL: GPA hook: 0x%X\n",newGetProcAddress);
printf("DLL: GPA es ahora (k32): 0x%X\n",test2a);
printf("DLL: GPA es ahora (EXE): 0x%X\n",test2b);
system("pause");

}


break;
case DLL_THREAD_ATTACH:
// A process is creating a new thread.
break;
case DLL_THREAD_DETACH:
// A thread exits normally.
break;
case DLL_PROCESS_DETACH:
// A process unloads the DLL.
break;
}
return TRUE;
}

////////////////


Dejo ambos proyectos en MSVC++ 6.0
http://www.mediafire.com/?ha8768ul77a300z
http://www.mediafire.com/?cdeog97h39c770i

Más información
http://msdn.microsoft.com/en-us/magazine/cc301805.aspx
http://www.reverse-engineering.info/SystemHooking/export.htm
http://www.masmforum.com/board/index.php?PHPSESSID=8d46cd4ecb1688be429ab49694ec53e6&topic=4286.0


hasta luego
Me cerraron el Windows Live Spaces, entonces me creé un WordPress XD
http://etkboyscout.wordpress.com/