/* (C) 2003 XDA Developers itsme@xs4all.nl * * $Header$ */ // // web: http://www.xs4all.nl/~itsme/projects/xda/rilhook.html // // this program inserts a small code hook into the code of the RIL_Iocontrol // function of rilgsm.dll. // // it tries to implement our own rilgsm device driver extension. // to be able to execute AT%UREG without the need for a wmodem compatible rom // // it only works with the rilgsm.dll of 2002-12-27 16:25, 208466 bytes // with md5sum of 393dc76613321fecaf0f1f40ad73b336 // that can be found in most radio updates // // we need a rilgsm located in RAM to be able to patch the code. // // uninstalling has not been tested yet. // #include #include "debug.h" #include "ril.h" #define peek(a) (*(DWORD*)(a)) // just directly writing to our own process memory does not seem to work // #define poke(a,w) peek(a)= (w) // probably code is execute+read only. void poke(BYTE *a, DWORD w) { DWORD n; WriteProcessMemory(GetCurrentProcess(), (void*)a, &w, sizeof(w), &n); } // this is the prototype of the result parser that is passed with the SendCommand // function. typedef HRESULT (*PFN_ParseResult)(char *response, BYTE **ppData, DWORD *pDatalen); // actually I am guessing what it does, just noticed that all ioctl handler call // this function. typedef HRIL (*PFN_LockRil)(HRIL hRil); PFN_LockRil LockRil; // this function is called to send an at command to the gsm. // I do not know the function of parameters 2 and 5. // parameter 3 seems to be related to the cmd id returned by the ioctl. typedef HRESULT (*PFN_SendCommand)(HRIL hRil, char *cmd, DWORD r2, DWORD dwCmdId, PFN_ParseResult parser, DWORD arg5, DWORD *pdwResult); PFN_SendCommand SendCommand; // hook is not really a function, it is jumped to by the installed hook extern "C" void hook(); // our own handler // the last parameter is 'volatile' because it is actually a local var from // the caller, and not enough room for a real parameter. // and it happens to be the exact right variable. extern "C" bool Handle_My_RILIoctl(HRIL hRil, BYTE *input, DWORD dwInSize, BYTE *output, DWORD dwMaxOutSize, volatile DWORD dwOutSize); // these are referenced from the hookcode. extern "C" DWORD ioctl_exit; extern "C" DWORD ioctl_invalid; extern "C" DWORD ioctl_03000900; extern "C" DWORD ioctl_constant; // declare them here. DWORD ioctl_exit; DWORD ioctl_invalid; DWORD ioctl_03000900; DWORD ioctl_constant; // when loaded in IDA, rilgsm.dll is at 10001000 // when checked with loadlibrary, it is at 00931000 // 10021da4 MOV R3, #0x03000000 // 10021da8 ORR R3, R3, #0x0900 // 10021dac CMP R7, R3 // 10021db0 BNE loc_10021fC8 <<<< address is ioctl_invalid // 10021db4 <<<< ioctl_03000900 // // ADDR are offsets relative to the RIL_IOControl function // because the address where the dll ends up seems to vary. // // where the patch is made #define ADDR0 0x00950210 #define ADDR1 0x00951da4-ADDR0 #define ORIG1 0xe3a03403 #define ADDR2 0x00951da8-ADDR0 #define ORIG2 0xe3833c09 #define ADDR3 0x00951dac-ADDR0 #define ORIG3 0xe1570003 // pointers back into the original function #define ADDR_IOCTLEXIT 0x00951fc8-ADDR0 #define ADDR_IOCTLINVALID 0x00951fc8-ADDR0 #define ADDR_IOCTL03000900 0x00951db4-ADDR0 // utility functions #define ADDR_LOCKRIL 0x009520c8-ADDR0 #define ADDR_SENDCOMMAND 0x00936be4-ADDR0 /* * --- for 3.17.03 rilgsm.dll * ( which is unfortunately in rom, so we cannot patch it ) * #define ADDR0 0xcb03f8 * #define ADDR1 0xcb1fc4-ADDR0 * #define ORIG1 0xe3a03403 * #define ADDR2 0xcb1fc8-ADDR0 * #define ORIG2 0xe3833c09 * #define ADDR3 0xcb1fcc-ADDR0 * #define ORIG3 0xe1560003 * // pointers back into the original function * #define ADDR_IOCTLEXIT 0xcb21d4-ADDR0 * #define ADDR_IOCTLINVALID 0xcb21d4-ADDR0 * #define ADDR_IOCTL03000900 0xcb1fd4-ADDR0 * * // utility functions * #define ADDR_LOCKRIL 0xcb22d4-ADDR0 * #define ADDR_SENDCOMMAND 0xc96c14-ADDR0 */ HMODULE g_hMod=0; BYTE* g_pRILIoctl=0; int g_InstallCount=0; //--------- remove/install the hook. void RemoveHook() { if (--g_InstallCount>0) return; poke(g_pRILIoctl+ADDR1, ORIG1); poke(g_pRILIoctl+ADDR2, ORIG2); poke(g_pRILIoctl+ADDR3, ORIG3); FreeLibrary(g_hMod); debug("Hook removed %d\n", g_InstallCount); } bool InstallHook() { if (g_InstallCount++) return true; g_hMod= LoadLibrary(L"rilgsm.dll"); g_pRILIoctl= (BYTE*)GetProcAddress(g_hMod, L"RIL_IOControl"); debug("RIL_IOControl=%08lx\n", g_pRILIoctl); if (!(peek(g_pRILIoctl+ADDR1)==ORIG1 && peek(g_pRILIoctl+ADDR2)==ORIG2 && peek(g_pRILIoctl+ADDR3)==ORIG3)) { debug("no valid rilgsm signature found: %08lx %08lx %08lx\n", peek(g_pRILIoctl+ADDR1), peek(g_pRILIoctl+ADDR2), peek(g_pRILIoctl+ADDR3)); return false; } debug("valid rilgsm signature found at %08lx\n", g_pRILIoctl+ADDR1); // these are functions our handler will use LockRil= (PFN_LockRil)(g_pRILIoctl+ADDR_LOCKRIL); SendCommand= (PFN_SendCommand)(g_pRILIoctl+ADDR_SENDCOMMAND); // these are pointers back into the original code ioctl_exit= (DWORD)g_pRILIoctl+ADDR_IOCTLEXIT; ioctl_invalid= (DWORD)g_pRILIoctl+ADDR_IOCTLINVALID; ioctl_03000900= (DWORD)g_pRILIoctl+ADDR_IOCTL03000900; // our ioctl constant ioctl_constant= 0x03000800; debug("writing to memory %08lx\n", g_pRILIoctl+ADDR1); // set the actual hook poke(g_pRILIoctl+ADDR1, 0xe59f3000); // ldr r3, [pc] poke(g_pRILIoctl+ADDR2, 0xe1a0f003); // mov pc, r3 poke(g_pRILIoctl+ADDR3, (DWORD)hook); debug("done: %08lx:%08lx %08lx %08lx\n", g_pRILIoctl+ADDR1, peek(g_pRILIoctl+ADDR1), peek(g_pRILIoctl+ADDR2), peek(g_pRILIoctl+ADDR3)); debug("Hook installed %d\n", g_InstallCount); return true; } // this function should allocate memory, return it in ppData, // and return with '0'. // // somehow the result does not yet get passed back to ril.dll // HRESULT ParseResult(char *response, BYTE **ppData, DWORD *pDatalen) { debug("response=%08lx ppdata=%08lx plen=%08lx\n", response, ppData, pDatalen); if (!IsBadReadPtr(response, 1)) debug("response= %s\n", response); if (!IsBadReadPtr(ppData, sizeof(BYTE*))) debug("*ppdata= %08lx\n", *ppData); if (!IsBadReadPtr(pDatalen, sizeof(DWORD))) debug("*plen= %08lx\n", *pDatalen); *pDatalen= (strlen(response)|3) + 1; *ppData= (BYTE*)LocalAlloc(LMEM_MOVEABLE, *pDatalen); strcpy((char*)*ppData, response); //debug("stack: %hs\n", hexdump((BYTE*)(&pDatalen-4), 16, 4)); return 0; } // this is our ioctl handler, it is called from the rilhook.S file // // the dwOutSize parameter is actually a local variable of the // calling function. bool Handle_My_RILIoctl(HRIL hRil, BYTE *input, DWORD dwInSize, BYTE *output, DWORD dwMaxOutSize, volatile DWORD dwOutSize) { DWORD *p= (DWORD*)input; char cmd[80]; sprintf(cmd, "AT%%UREG?%08lx,%02x\r", p[0], p[4]); DWORD result; HRESULT hr= SendCommand(hRil, cmd, 0, 0x5d, ParseResult, 0, &result); debug("Handle_My_RILIoctl(%08lx): hr=%08lx res=%08lx\n", hRil, hr, result); *(DWORD*)output= result; dwOutSize= 4; return true; } BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { DebugSetLogfile("extendril.log"); debug("hook dllmain(%08lx, %08ld, %08lx)\n", hModule, ul_reason_for_call, lpReserved); switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: return InstallHook(); break; case DLL_PROCESS_DETACH: RemoveHook(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return TRUE; }