/* Copyright (c) 2007, Peter "Corsix" Cawley * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY PETER CAWLEY ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL PETER CAWLEY BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // These functions are my babies for rewriting processor opcodes on the fly. // They allow us to inject our own code into other people's code. Yes, I am // evil. The Microsoft detours library (http://research.microsoft.com/sn/detours/) // is a cleaner way of doing many of these things, but is much more easily // detectable and is only free for non-commercial apps. #include "AsmRewrites.h" #include namespace AssemblerUtil { void WriteJump(unsigned char *pWriteLocation, DWORD pJumpLocation) { *pWriteLocation = 0xE9; // JMP // Jump value is relative to the value of EIP after the jump command // has been read: *((LPDWORD)( pWriteLocation + 1 ) ) = pJumpLocation - ( ((DWORD)pWriteLocation) + 5 ); } void WriteCall(unsigned char *pWriteLocation, DWORD pJumpLocation) { *pWriteLocation = 0xE8; // CALL // Jump value is relative to the value of EIP after the call command // has been read: *((LPDWORD)( pWriteLocation + 1 ) ) = pJumpLocation - ( ((DWORD)pWriteLocation) + 5 ); } // Jump, Call, (replaced code), Jump // returns the trampoline unsigned char* WriteJCJ(unsigned char *pInterceptLocation, DWORD iOpcodeLength, DWORD pCallTarget, const char *sAsmCode, unsigned long iAsmLen) { unsigned char *pTrampoline = new unsigned char[10 + iOpcodeLength + iAsmLen]; DWORD dwDummy; VirtualProtect((LPVOID)pTrampoline, 10 + iOpcodeLength + iAsmLen, PAGE_EXECUTE_READWRITE, &dwDummy); memcpy((void*)pTrampoline, (const void*)sAsmCode, iAsmLen); WriteCall(pTrampoline + iAsmLen, pCallTarget); memcpy((void*)(pTrampoline + 5 + iAsmLen), (void*)pInterceptLocation, iOpcodeLength); WriteJump(pTrampoline + 5 + iOpcodeLength + iAsmLen, (DWORD)(pInterceptLocation + iOpcodeLength)); VirtualProtect((LPVOID)pInterceptLocation, iOpcodeLength, PAGE_EXECUTE_READWRITE, &dwDummy); WriteJump(pInterceptLocation, (DWORD)pTrampoline); VirtualProtect((LPVOID)pInterceptLocation, iOpcodeLength, dwDummy, &dwDummy); for(DWORD i = 5; i < iOpcodeLength; ++i) pInterceptLocation[i] = 0x90; // NOP return pTrampoline; } // Jump, Call, (replaced code), Jump // returns the trampoline unsigned char* WriteJCJOverCall(unsigned char *pInterceptLocation, DWORD pCallTarget, const char *sAsmCode, unsigned long iAsmLen) { unsigned char *pTrampoline = new unsigned char[15 + iAsmLen]; memcpy((void*)pTrampoline, (const void*)sAsmCode, iAsmLen); WriteCall(pTrampoline + iAsmLen, pCallTarget); DWORD pOrigTarget = ((DWORD)pInterceptLocation) + 5 + *(LPDWORD)(pInterceptLocation + 1); WriteCall(pTrampoline + 5 + iAsmLen, pOrigTarget); WriteJump(pTrampoline + 10 + iAsmLen, (DWORD)(pInterceptLocation + 5)); DWORD dwDummy; VirtualProtect((LPVOID)pInterceptLocation, 5, PAGE_EXECUTE_READWRITE, &dwDummy); WriteJump(pInterceptLocation, (DWORD)pTrampoline); return pTrampoline; } unsigned char* WritePreCall(unsigned char *pInterceptLocation, const char *sAsmCode, unsigned long iAsmLen) { unsigned char *pTrampoline = new unsigned char[10 + iAsmLen]; memcpy((void*)pTrampoline, (const void*)sAsmCode, iAsmLen); DWORD pCallTarget = ((DWORD)pInterceptLocation) + 5 + *(LPDWORD)(pInterceptLocation + 1); WriteCall(pTrampoline + iAsmLen, pCallTarget); WriteJump(pTrampoline + iAsmLen + 5, (DWORD)(pInterceptLocation + 5) ); DWORD dwDummy; VirtualProtect((LPVOID)pInterceptLocation, 5, PAGE_EXECUTE_READWRITE, &dwDummy); WriteJump(pInterceptLocation, (DWORD)pTrampoline); return pTrampoline; } // This function is messy. I really need a better way to search through memory for // a string. Standard functions cannot be used the memory has to be made readable // or skipped if it is unreadable. DWORD ScanForString(const char* sString, SIZE_T iCheckSize, DWORD dwBase) { char *sRequiredDllIdent = new char[iCheckSize + 1]; SIZE_T iBytesRead; DWORD dwOldProtect; DWORD dwN = dwBase; while(1) { do { ++dwN; } while((VirtualProtect((LPVOID)(dwN), iCheckSize, PAGE_READWRITE, &dwOldProtect) == FALSE) && dwN < 0xffffffff); if(memcmp((void*)dwN, sString, iCheckSize) == 0) { return dwN; } } return 0; } // This is used for debugging ^_^ void DumpMem(unsigned char* pOffset, unsigned long iL) { fprintf(stderr, "Memory @ %X: ", (int)pOffset); while(iL) { fprintf(stderr, "%c%c ", "0123456789ABCDEF"[(*pOffset) >> 4], "0123456789ABCDEF"[(*pOffset) & 0xF]); --iL; ++pOffset; } fprintf(stderr, "\n"); fflush(stderr); } }