void glk_make_sdl_window(void) { s=initsdl(w,h,&bpp,SDL_OPENGL); SDL_EnableUNICODE(1); SDL_InitSubSystem( SDL_INIT_TIMER); SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY/2, SDL_DEFAULT_REPEAT_INTERVAL/3); gle(); resetviewport(); resetmatrices(); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glClearColor( 0.0, 0.0, 0.0, 0.0 ); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); printf("LEMON\n"); }
//========================================================================= BOOL Mhook_Unhook(PVOID *ppHookedFunction) { ODPRINTF((L"mhooks: Mhook_Unhook: %p", *ppHookedFunction)); BOOL bRet = FALSE; EnterCritSec(); // get the trampoline structure that corresponds to our function MHOOKS_TRAMPOLINE* pTrampoline = TrampolineGet((PBYTE)*ppHookedFunction); if (pTrampoline) { // make sure nobody's executing code where we're about to overwrite a few bytes SuspendOtherThreads(pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode); ODPRINTF((L"mhooks: Mhook_Unhook: found struct at %p", pTrampoline)); // open ourselves so we can VirtualProtectEx HANDLE hProc = GetCurrentProcess(); DWORD dwOldProtectSystemFunction = 0; // make memory writable if (VirtualProtectEx(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode, PAGE_EXECUTE_READWRITE, &dwOldProtectSystemFunction)) { ODPRINTF((L"mhooks: Mhook_Unhook: readwrite set on system function")); PBYTE pbCode = (PBYTE)pTrampoline->pSystemFunction; for (DWORD i = 0; i<pTrampoline->cbOverwrittenCode; i++) { pbCode[i] = pTrampoline->codeUntouched[i]; } // flush instruction cache and make memory unwritable FlushInstructionCache(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode); VirtualProtectEx(hProc, pTrampoline->pSystemFunction, pTrampoline->cbOverwrittenCode, dwOldProtectSystemFunction, &dwOldProtectSystemFunction); // return the original function pointer *ppHookedFunction = pTrampoline->pSystemFunction; bRet = TRUE; ODPRINTF((L"mhooks: Mhook_Unhook: sysfunc: %p", *ppHookedFunction)); // free the trampoline while not really discarding it from memory TrampolineFree(pTrampoline, FALSE); ODPRINTF((L"mhooks: Mhook_Unhook: unhook successful")); } else { ODPRINTF((L"mhooks: Mhook_Unhook: failed VirtualProtectEx 1: %d", gle())); } // make the other guys runnable ResumeOtherThreads(); } LeaveCritSec(); return bRet; }
void draw (int picking) { if(picking==2)return; gle(); glPushAttrib(GL_ALL_ATTRIB_BITS); gle(); if(!picking) { CameraUpdate (); gle(); EntityUpdate (); gle(); WorldUpdate (); gle(); TextureUpdate (); gle(); VisibleUpdate (); gle(); CarUpdate (); } gle(); RenderResize(); gle(); RenderUpdate (picking); resetviewport(); gle(); glPopAttrib(); gle(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); }
//========================================================================= BOOL Mhook_SetHook(PVOID *ppSystemFunction, PVOID pHookFunction) { MHOOKS_TRAMPOLINE* pTrampoline = NULL; PVOID pSystemFunction = *ppSystemFunction; // ensure thread-safety EnterCritSec(); ODPRINTF((L"mhooks: Mhook_SetHook: Started on the job: %p / %p", pSystemFunction, pHookFunction)); // find the real functions (jump over jump tables, if any) pSystemFunction = SkipJumps((PBYTE)pSystemFunction); pHookFunction = SkipJumps((PBYTE)pHookFunction); ODPRINTF((L"mhooks: Mhook_SetHook: Started on the job: %p / %p", pSystemFunction, pHookFunction)); // figure out the length of the overwrite zone MHOOKS_PATCHDATA patchdata = {0}; DWORD dwInstructionLength = DisassembleAndSkip(pSystemFunction, MHOOK_JMPSIZE, &patchdata); if (dwInstructionLength >= MHOOK_JMPSIZE) { ODPRINTF((L"mhooks: Mhook_SetHook: disassembly signals %d bytes", dwInstructionLength)); // suspend every other thread in this process, and make sure their IP // is not in the code we're about to overwrite. SuspendOtherThreads((PBYTE)pSystemFunction, dwInstructionLength); // allocate a trampoline structure (TODO: it is pretty wasteful to get // VirtualAlloc to grab chunks of memory smaller than 100 bytes) pTrampoline = TrampolineAlloc((PBYTE)pSystemFunction, patchdata.nLimitUp, patchdata.nLimitDown); if (pTrampoline) { ODPRINTF((L"mhooks: Mhook_SetHook: allocated structure at %p", pTrampoline)); DWORD dwOldProtectSystemFunction = 0; DWORD dwOldProtectTrampolineFunction = 0; // set the system function to PAGE_EXECUTE_READWRITE if (VirtualProtect(pSystemFunction, dwInstructionLength, PAGE_EXECUTE_READWRITE, &dwOldProtectSystemFunction)) { ODPRINTF((L"mhooks: Mhook_SetHook: readwrite set on system function")); // mark our trampoline buffer to PAGE_EXECUTE_READWRITE if (VirtualProtect(pTrampoline, sizeof(MHOOKS_TRAMPOLINE), PAGE_EXECUTE_READWRITE, &dwOldProtectTrampolineFunction)) { ODPRINTF((L"mhooks: Mhook_SetHook: readwrite set on trampoline structure")); // create our trampoline function PBYTE pbCode = pTrampoline->codeTrampoline; // save original code.. for (DWORD i = 0; i<dwInstructionLength; i++) { pTrampoline->codeUntouched[i] = pbCode[i] = ((PBYTE)pSystemFunction)[i]; } pbCode += dwInstructionLength; // plus a jump to the continuation in the original location pbCode = EmitJump(pbCode, ((PBYTE)pSystemFunction) + dwInstructionLength); ODPRINTF((L"mhooks: Mhook_SetHook: updated the trampoline")); // fix up any IP-relative addressing in the code FixupIPRelativeAddressing(pTrampoline->codeTrampoline, (PBYTE)pSystemFunction, &patchdata); DWORD_PTR dwDistance = (PBYTE)pHookFunction < (PBYTE)pSystemFunction ? (PBYTE)pSystemFunction - (PBYTE)pHookFunction : (PBYTE)pHookFunction - (PBYTE)pSystemFunction; if (dwDistance > 0x7fff0000) { // create a stub that jumps to the replacement function. // we need this because jumping from the API to the hook directly // will be a long jump, which is 14 bytes on x64, and we want to // avoid that - the API may or may not have room for such stuff. // (remember, we only have 5 bytes guaranteed in the API.) // on the other hand we do have room, and the trampoline will always be // within +/- 2GB of the API, so we do the long jump in there. // the API will jump to the "reverse trampoline" which // will jump to the user's hook code. pbCode = pTrampoline->codeJumpToHookFunction; pbCode = EmitJump(pbCode, (PBYTE)pHookFunction); ODPRINTF((L"mhooks: Mhook_SetHook: created reverse trampoline")); FlushInstructionCache(GetCurrentProcess(), pTrampoline->codeJumpToHookFunction, pbCode - pTrampoline->codeJumpToHookFunction); // update the API itself pbCode = (PBYTE)pSystemFunction; pbCode = EmitJump(pbCode, pTrampoline->codeJumpToHookFunction); } else { // the jump will be at most 5 bytes so we can do it directly // update the API itself pbCode = (PBYTE)pSystemFunction; pbCode = EmitJump(pbCode, (PBYTE)pHookFunction); } // update data members pTrampoline->cbOverwrittenCode = dwInstructionLength; pTrampoline->pSystemFunction = (PBYTE)pSystemFunction; pTrampoline->pHookFunction = (PBYTE)pHookFunction; // flush instruction cache and restore original protection FlushInstructionCache(GetCurrentProcess(), pTrampoline->codeTrampoline, dwInstructionLength); VirtualProtect(pTrampoline, sizeof(MHOOKS_TRAMPOLINE), dwOldProtectTrampolineFunction, &dwOldProtectTrampolineFunction); } else { ODPRINTF((L"mhooks: Mhook_SetHook: failed VirtualProtect 2: %d", gle())); } // flush instruction cache and restore original protection FlushInstructionCache(GetCurrentProcess(), pSystemFunction, dwInstructionLength); VirtualProtect(pSystemFunction, dwInstructionLength, dwOldProtectSystemFunction, &dwOldProtectSystemFunction); } else { ODPRINTF((L"mhooks: Mhook_SetHook: failed VirtualProtect 1: %d", gle())); } if (pTrampoline->pSystemFunction) { // this is what the application will use as the entry point // to the "original" unhooked function. *ppSystemFunction = pTrampoline->codeTrampoline; ODPRINTF((L"mhooks: Mhook_SetHook: Hooked the function!")); } else { // if we failed discard the trampoline (forcing VirtualFree) TrampolineFree(pTrampoline, TRUE); pTrampoline = NULL; } } // resume everybody else ResumeOtherThreads(); } else { ODPRINTF((L"mhooks: disassembly signals %d bytes (unacceptable)", dwInstructionLength)); } LeaveCritSec(); return (pTrampoline != NULL); }
//========================================================================= // Internal function: // // Suspend all threads in this process while trying to make sure that their // instruction pointer is not in the given range. //========================================================================= static BOOL SuspendOtherThreads(PBYTE pbCode, DWORD cbBytes) { BOOL bRet = FALSE; // make sure we're the most important thread in the process INT nOriginalPriority = GetThreadPriority(GetCurrentThread()); SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); // get a view of the threads in the system HANDLE hSnap = fnCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, GetCurrentProcessId()); if (GOOD_HANDLE(hSnap)) { THREADENTRY32 te; te.dwSize = sizeof(te); // count threads in this process (except for ourselves) DWORD nThreadsInProcess = 0; if (fnThread32First(hSnap, &te)) { do { if (te.th32OwnerProcessID == GetCurrentProcessId()) { if (te.th32ThreadID != GetCurrentThreadId()) { nThreadsInProcess++; } } te.dwSize = sizeof(te); } while(fnThread32Next(hSnap, &te)); } ODPRINTF((L"mhooks: SuspendOtherThreads: counted %d other threads", nThreadsInProcess)); if (nThreadsInProcess) { // alloc buffer for the handles we really suspended g_hThreadHandles = (HANDLE*)malloc(nThreadsInProcess*sizeof(HANDLE)); if (g_hThreadHandles) { ZeroMemory(g_hThreadHandles, nThreadsInProcess*sizeof(HANDLE)); DWORD nCurrentThread = 0; BOOL bFailed = FALSE; te.dwSize = sizeof(te); // go through every thread if (fnThread32First(hSnap, &te)) { do { if (te.th32OwnerProcessID == GetCurrentProcessId()) { if (te.th32ThreadID != GetCurrentThreadId()) { // attempt to suspend it g_hThreadHandles[nCurrentThread] = SuspendOneThread(te.th32ThreadID, pbCode, cbBytes); if (GOOD_HANDLE(g_hThreadHandles[nCurrentThread])) { ODPRINTF((L"mhooks: SuspendOtherThreads: successfully suspended %d", te.th32ThreadID)); nCurrentThread++; } else { ODPRINTF((L"mhooks: SuspendOtherThreads: error while suspending thread %d: %d", te.th32ThreadID, gle())); // TODO: this might not be the wisest choice // but we can choose to ignore failures on // thread suspension. It's pretty unlikely that // we'll fail - and even if we do, the chances // of a thread's IP being in the wrong place // is pretty small. // bFailed = TRUE; } } } te.dwSize = sizeof(te); } while(fnThread32Next(hSnap, &te) && !bFailed); } g_nThreadHandles = nCurrentThread; bRet = !bFailed; } } CloseHandle(hSnap); //TODO: we might want to have another pass to make sure all threads // in the current process (including those that might have been // created since we took the original snapshot) have been // suspended. } else { ODPRINTF((L"mhooks: SuspendOtherThreads: can't CreateToolhelp32Snapshot: %d", gle())); } SetThreadPriority(GetCurrentThread(), nOriginalPriority); if (!bRet) { ODPRINTF((L"mhooks: SuspendOtherThreads: Had a problem (or not running multithreaded), resuming all threads.")); ResumeOtherThreads(); } return bRet; }