// dllmain.cpp : DLL アプリケーションのエントリ ポイントを定義します。 #include "stdafx.h" //#define USE_LOG //#define USE_LOG_MORE BOOL APIENTRY DllMain(HMODULE, DWORD, LPVOID); void DllInit(); void DllExit(); void $_StreamReaderThread(); void ProxOpenFile(); HANDLE WINAPI CreateFile_Hook(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); HANDLE (WINAPI *CreateFile_Real)(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE); #define patch(a, v, s) _patch((void*)(a), (void*)(v), (s)) void _patch(void*, void*, int); #define nop(a, s) _nop((void*)(a), (s)) void _nop(void*, int); bool check(void*, unsigned char, const char*, bool); bool _check(void*, unsigned char); typedef struct _VirtualIMG { int iType; char cIMGPath[MAX_PATH]; char cDirPath[MAX_PATH]; HANDLE hIMGFile; HANDLE hNewFile; int iIMGFile; char* cIMGFile; } VirtualIMG; int iIMGCount; VirtualIMG* pVirtualIMG; int iAttachCount; char cSelfPath[MAX_PATH]; #ifdef USE_LOG FILE* pLogFile; #endif char* cOriginalFile; int loop_i; char cReplaceFile[MAX_PATH]; const char* cVImgExt = ".vimg"; unsigned long dwEDI; unsigned long dwRealOpenFile; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: if (iAttachCount++ == 0) DllInit(); break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: if (--iAttachCount == 0) DllExit(); break; } return TRUE; } void DllInit() { #ifdef USE_LOG fopen_s(&pLogFile, "vimg.log", "w"); #endif { GetModuleFileName(NULL, cSelfPath, MAX_PATH); if (strrchr(cSelfPath, '\\')) *(char*)(strrchr(cSelfPath, '\\') + 1) = '\0'; char cFilePath[MAX_PATH]; strcpy_s(cFilePath, MAX_PATH, cSelfPath); strcat_s(cFilePath, MAX_PATH, "virtualimg.dat"); FILE* pFile; if (fopen_s(&pFile, cFilePath, "r")) { MessageBox(0, "Failed to open virtualimg.dat.", "Virtual IMG", MB_OK | MB_ICONERROR); ExitProcess(0); } char cType[16]; int iType; char cIMGPath[MAX_PATH]; char cDirPath[MAX_PATH]; while (fscanf_s(pFile, "%s\t%s\t%s", cType, 16, cIMGPath, MAX_PATH, cDirPath, MAX_PATH) == 3) { iType = 0; if (!_stricmp(cType, "MARGE")) iType = 1; if (!_stricmp(cType, "CREATE")) iType = 2; if (!_stricmp(cType, "APPEND")) iType = 3; if (!_stricmp(cType, "IGNORE")) continue; pVirtualIMG = (VirtualIMG*)realloc(pVirtualIMG, sizeof(VirtualIMG) * (iIMGCount + 1)); pVirtualIMG[iIMGCount].iType = iType; strcpy_s(pVirtualIMG[iIMGCount].cIMGPath, MAX_PATH, cIMGPath); strcpy_s(pVirtualIMG[iIMGCount].cDirPath, MAX_PATH, cDirPath); pVirtualIMG[iIMGCount].hIMGFile = 0; pVirtualIMG[iIMGCount].hNewFile = 0; pVirtualIMG[iIMGCount].iIMGFile = 0; pVirtualIMG[iIMGCount].cIMGFile = NULL; if (!pVirtualIMG[iIMGCount].iType) continue; strcpy_s(cIMGPath, MAX_PATH, cSelfPath); strcat_s(cIMGPath, MAX_PATH, pVirtualIMG[iIMGCount].cIMGPath); strcpy_s(cFilePath, MAX_PATH, cIMGPath); strcat_s(cFilePath, MAX_PATH, ".vimg"); pVirtualIMG[iIMGCount].hIMGFile = CreateFile(cIMGPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL); HANDLE hNewIMG; HANDLE hFind; WIN32_FIND_DATA ffd; unsigned long dwCurrentFile = 0x00800000; unsigned long dwVersion; unsigned long dwFileNum; unsigned long dwBuffer[8]; unsigned long dwSize; unsigned long dwIMGFile; hNewIMG = CreateFile(cFilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL); ReadFile(pVirtualIMG[iIMGCount].hIMGFile, &dwVersion, 0x4, &dwSize, NULL); WriteFile(hNewIMG, &dwVersion, 0x4, &dwSize, NULL); dwFileNum = 0; WriteFile(hNewIMG, &dwFileNum, 0x4, &dwSize, NULL); strcpy_s(cDirPath, MAX_PATH, cSelfPath); strcat_s(cDirPath, MAX_PATH, pVirtualIMG[iIMGCount].cDirPath); strcat_s(cDirPath, MAX_PATH, "*"); pVirtualIMG[iIMGCount].iIMGFile = 0; hFind = FindFirstFile(cDirPath, &ffd); while (true) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (!FindNextFile(hFind, &ffd)) break; continue; } dwBuffer[0] = dwCurrentFile; dwBuffer[1] = (ffd.nFileSizeLow >> 11 | ffd.nFileSizeHigh << 21) + 1; ZeroMemory(&dwBuffer[2], 0x18); strcpy_s((char*)&dwBuffer[2], 0x18, strrchr(ffd.cFileName, '\\') ? strrchr(ffd.cFileName, '\\') + 1 : ffd.cFileName); WriteFile(hNewIMG, dwBuffer, 0x20, &dwSize, NULL); pVirtualIMG[iIMGCount].cIMGFile =(char*)realloc(pVirtualIMG[iIMGCount].cIMGFile, MAX_PATH * (pVirtualIMG[iIMGCount].iIMGFile + 1)); strcpy_s(&pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * pVirtualIMG[iIMGCount].iIMGFile], MAX_PATH, cSelfPath); strcat_s(&pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * pVirtualIMG[iIMGCount].iIMGFile], MAX_PATH, pVirtualIMG[iIMGCount].cDirPath); strcat_s(&pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * pVirtualIMG[iIMGCount].iIMGFile], MAX_PATH, ffd.cFileName); pVirtualIMG[iIMGCount].iIMGFile++; dwFileNum++; dwCurrentFile++; if (!FindNextFile(hFind, &ffd)) break; } FindClose(hFind); switch (pVirtualIMG[iIMGCount].iType) { case 1: { ReadFile(pVirtualIMG[iIMGCount].hIMGFile, &dwIMGFile, 0x4, &dwSize, NULL); for (unsigned long i = 0; i < dwIMGFile; i++) { ReadFile(pVirtualIMG[iIMGCount].hIMGFile, dwBuffer, 0x20, &dwSize, NULL); for (int j = 0; j < pVirtualIMG[iIMGCount].iIMGFile; j++) if (!_stricmp((const char*)&dwBuffer[2], (strrchr(&pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * j], '\\')) ? strrchr(&pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * j], '\\') + 1 : &pVirtualIMG[iIMGCount].cIMGFile[MAX_PATH * j])) { dwBuffer[1] = 0; break; } if (!dwBuffer[1]) continue; WriteFile(hNewIMG, dwBuffer, 0x20, &dwSize, NULL); dwFileNum++; } break; } case 2: { break; } case 3: { ReadFile(pVirtualIMG[iIMGCount].hIMGFile, &dwIMGFile, 0x4, &dwSize, NULL); for (unsigned long i = 0; i < dwIMGFile; i++) { ReadFile(pVirtualIMG[iIMGCount].hIMGFile, dwBuffer, 0x20, &dwSize, NULL); WriteFile(hNewIMG, dwBuffer, 0x20, &dwSize, NULL); dwFileNum++; } break; } } CloseHandle(pVirtualIMG[iIMGCount].hIMGFile); pVirtualIMG[iIMGCount].hIMGFile = CreateFile(cIMGPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_RANDOM_ACCESS, NULL); SetFilePointer(hNewIMG, 0x4, NULL, FILE_BEGIN); WriteFile(hNewIMG, &dwFileNum, 0x4, &dwSize, NULL); CloseHandle(hNewIMG); iIMGCount++; } } unsigned char cJump = 0xE9; unsigned long pFunc; if (check((void*)0x4069B4, 0x68, "StreamReader - CreateThread", false)) { pFunc = (unsigned long)&$_StreamReaderThread; patch(0x4069B5, &pFunc, 4); } if (check((void*)0x1564AE2, 0x68, "FileManager - OpenFile", false)) { dwRealOpenFile = *(unsigned long*)0x538901 + 0x538905; patch(0x538900, &cJump, 1); pFunc = (unsigned long)&ProxOpenFile - 0x538905; patch(0x538901, &pFunc, 4); } { DWORD dwBase; DWORD dwIdataSize; PIMAGE_IMPORT_DESCRIPTOR pImgDesc; char* lpModule; PIMAGE_IMPORT_BY_NAME pImportName; dwBase = (DWORD)GetModuleHandle(NULL); pImgDesc = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData((HMODULE)dwBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &dwIdataSize); while(pImgDesc->Name) { lpModule = (char*)(dwBase+pImgDesc->Name); if (!_stricmp(lpModule, "KERNEL32.dll")) break; pImgDesc++; } if (pImgDesc->Name) { PIMAGE_THUNK_DATA pIAT, pINT; pIAT = (PIMAGE_THUNK_DATA)(dwBase + pImgDesc->FirstThunk); pINT = (PIMAGE_THUNK_DATA)(dwBase + pImgDesc->OriginalFirstThunk); while(pIAT->u1.Function) { if (IMAGE_SNAP_BY_ORDINAL(pINT->u1.Ordinal)) continue; pImportName = (PIMAGE_IMPORT_BY_NAME)(dwBase + (DWORD)pINT->u1.AddressOfData); if (!_stricmp((const char*)pImportName->Name, "CreateFileA")) { CreateFile_Real = *(HANDLE (WINAPI **)(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE))pIAT; pFunc = (unsigned long)&CreateFile_Hook; patch(pIAT, &pFunc, 4); } pIAT++; pINT++; } } } return; } void DllExit() { for (int i = 0; i < iIMGCount; i++) { if (!pVirtualIMG[iIMGCount].iType) continue; CloseHandle(pVirtualIMG[i].hIMGFile); free(pVirtualIMG[i].cIMGFile); char cFilePath[MAX_PATH]; strcpy_s(cFilePath, MAX_PATH, cSelfPath); strcat_s(cFilePath, MAX_PATH, pVirtualIMG[i].cIMGPath); strcat_s(cFilePath, MAX_PATH, ".vimg"); DeleteFile(cFilePath); } free(pVirtualIMG); #ifdef USE_LOG fclose(pLogFile); #endif return; } typedef struct _StreamRW { DWORD dwFilePos; DWORD dwFileSize; LPVOID pBuffer; BYTE bUnknown; BYTE bSemaphoreFlag; WORD wUseFlag; DWORD dwReadRequest; HANDLE hSemaphore; HANDLE hFile; OVERLAPPED olStruct; } StreamRW; DWORD* dwFileFlag = (DWORD*)0x8E3FE0; DWORD* dwUnk8E3FE4 = (DWORD*)0x8E3FE4; DWORD* dwEnableOverlap = (DWORD*)0x8E3FE8; DWORD** pStreamIndex = (DWORD**)0x8E3FEC; LONG* dwReqStream = (LONG*)0x8E3FF0; LONG* dwCurStream = (LONG*)0x8E3FF4; DWORD* dwMaxRW = (DWORD*)0x8E3FF8; StreamRW** pStreamRW = (StreamRW**)0x8E3FFC; DWORD* dwStreamThreadID = (DWORD*)0x8E4000; HANDLE* hStreamSemaphore = (HANDLE*)0x8E4004; HANDLE* hStreamThreadHandle = (HANDLE*)0x8E4008; HANDLE* hStreamFile = (HANDLE*)0x8E4010; CHAR* cStreamFilePath = (CHAR*)0x8E4098; DWORD* dwMaxSteam = (DWORD*)0x8E4090; HANDLE* hCurStreamFile = (HANDLE*)0x8E4898; LPVOID** ppBuffer = (LPVOID**)0x8E4CAC; void $_StreamReaderThread() { LONG _StreamIndex; DWORD _ReadSize; HANDLE _DummyHandle; DWORD _DummyPos; while (true) { WaitForSingleObject(*hStreamSemaphore, INFINITE); _StreamIndex = (*dwReqStream == *dwCurStream) ? -1 : (*pStreamIndex)[*dwReqStream]; (*pStreamRW)[_StreamIndex].wUseFlag = 1; if (!(*pStreamRW)[_StreamIndex].dwReadRequest) { _DummyPos = 0; for (int i = 0; i < iIMGCount; i++) if (pVirtualIMG[i].hNewFile == (*pStreamRW)[_StreamIndex].hFile) if ((*pStreamRW)[_StreamIndex].dwFilePos & 0x800000) { #ifdef USE_LOG fputs("[Read Dummy]\t", pLogFile); fputs(&pVirtualIMG[i].cIMGFile[MAX_PATH * ((*pStreamRW)[_StreamIndex].dwFilePos & 0x7FFFFF)], pLogFile); #endif _DummyHandle = (*pStreamRW)[_StreamIndex].hFile; (*pStreamRW)[_StreamIndex].hFile = CreateFile(&pVirtualIMG[i].cIMGFile[MAX_PATH * ((*pStreamRW)[_StreamIndex].dwFilePos & 0x7FFFFF)], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, ((*dwEnableOverlap) ? FILE_FLAG_OVERLAPPED : 0) | FILE_FLAG_RANDOM_ACCESS, NULL); _DummyPos = (*pStreamRW)[_StreamIndex].dwFilePos; (*pStreamRW)[_StreamIndex].dwFilePos = 0; ZeroMemory((*pStreamRW)[_StreamIndex].pBuffer, (*pStreamRW)[_StreamIndex].dwFileSize << 11); break; } else { #ifdef USE_LOG #ifdef USE_LOG_MORE fputs("[Read Dummy]\t", pLogFile); fputs(cSelfPath, pLogFile); fputs(pVirtualIMG[i].cIMGPath, pLogFile); #endif #endif _DummyHandle = (*pStreamRW)[_StreamIndex].hFile; (*pStreamRW)[_StreamIndex].hFile = pVirtualIMG[i].hIMGFile; _DummyPos = (*pStreamRW)[_StreamIndex].dwFilePos; break; } if (*dwEnableOverlap) { (*pStreamRW)[_StreamIndex].olStruct.Offset = (*pStreamRW)[_StreamIndex].dwFilePos << 11; (*pStreamRW)[_StreamIndex].olStruct.OffsetHigh = (*pStreamRW)[_StreamIndex].dwFilePos >> 21; if (ReadFile((*pStreamRW)[_StreamIndex].hFile, (*pStreamRW)[_StreamIndex].pBuffer, min((*pStreamRW)[_StreamIndex].dwFileSize << 11, GetFileSize((*pStreamRW)[_StreamIndex].hFile, NULL)), 0, &(*pStreamRW)[_StreamIndex].olStruct) == TRUE) (*pStreamRW)[_StreamIndex].dwReadRequest = 0; else { switch (GetLastError()) { case ERROR_IO_PENDING: { if (GetOverlappedResult((*pStreamRW)[_StreamIndex].hFile, &(*pStreamRW)[_StreamIndex].olStruct, &_ReadSize, TRUE)) (*pStreamRW)[_StreamIndex].dwReadRequest = 0; else (*pStreamRW)[_StreamIndex].dwReadRequest = 0xFE; break; } case ERROR_NOACCESS: { #ifdef USE_LOG char buf[256]; sprintf_s(buf, 256, "[ERROR]\t%d\t0x%08X%08X-0x%08X", GetLastError(), (*pStreamRW)[_StreamIndex].olStruct.OffsetHigh, (*pStreamRW)[_StreamIndex].olStruct.Offset, (*pStreamRW)[_StreamIndex].dwFileSize << 11); fputs(buf, pLogFile); fputs("\n", pLogFile); #endif if (MessageBox(0, "An ERROR_NOACCESS error has occured.\nAn .img file might have broken the limit.\nPlease press [Enter] to kill this process.", "GTA San Andreas", MB_OKCANCEL) == IDOK) { DllExit(); ExitProcess(0); } (*pStreamRW)[_StreamIndex].dwReadRequest = 0xFE; break; } default: { #ifdef USE_LOG char buf[256]; sprintf_s(buf, 256, "[ERROR]\t%d\t0x%08X%08X-0x%08X", GetLastError(), (*pStreamRW)[_StreamIndex].olStruct.OffsetHigh, (*pStreamRW)[_StreamIndex].olStruct.Offset, (*pStreamRW)[_StreamIndex].dwFileSize << 11); fputs(buf, pLogFile); fputs("\n", pLogFile); #endif (*pStreamRW)[_StreamIndex].dwReadRequest = 0xFE; break; } } } } else { _ReadSize = (*pStreamRW)[_StreamIndex].dwFilePos >> 21; SetFilePointer((*pStreamRW)[_StreamIndex].hFile, (*pStreamRW)[_StreamIndex].dwFilePos << 11, (PLONG)&_ReadSize, FILE_BEGIN); (*pStreamRW)[_StreamIndex].dwReadRequest = (ReadFile((*pStreamRW)[_StreamIndex].hFile, (*pStreamRW)[_StreamIndex].pBuffer, min((*pStreamRW)[_StreamIndex].dwFileSize << 11, GetFileSize((*pStreamRW)[_StreamIndex].hFile, NULL)), 0, NULL)) ? 0 : 0xFE; } if (_DummyPos) if (_DummyPos & 0x800000) { #ifdef USE_LOG fputs(((*pStreamRW)[_StreamIndex].dwReadRequest) ? "\tFailed\n" : "\tSuccessed\n", pLogFile); #endif CloseHandle((*pStreamRW)[_StreamIndex].hFile); (*pStreamRW)[_StreamIndex].hFile = _DummyHandle; (*pStreamRW)[_StreamIndex].dwFilePos = _DummyPos; } else { #ifdef USE_LOG #ifdef USE_LOG_MORE fputs(((*pStreamRW)[_StreamIndex].dwReadRequest) ? "\tFailed\n" : "\tSuccessed\n", pLogFile); #endif #endif (*pStreamRW)[_StreamIndex].hFile = _DummyHandle; (*pStreamRW)[_StreamIndex].dwFilePos = _DummyPos; } } if (*dwReqStream != *dwCurStream) *dwReqStream = (*dwReqStream + 1) % *dwMaxRW; (*pStreamRW)[_StreamIndex].dwFileSize = 0; if ((*pStreamRW)[_StreamIndex].bSemaphoreFlag) ReleaseSemaphore((*pStreamRW)[_StreamIndex].hSemaphore, 1, NULL); (*pStreamRW)[_StreamIndex].wUseFlag = 0; } } #ifdef USE_LOG const char* cPrefixI = "[Ignore]\t"; const char* cPrefix = "[Use Dummy]\t"; const char* cTab = "\t"; const char* cReturn = "\n"; #endif void __declspec(naked) ProxOpenFile() { __asm { mov dwEDI, edi; mov edi, dwRealOpenFile; push edi; push eax; push esi; mov edi, [esp+0x10]; mov esi, iIMGCount; test esi, esi; jz IMG_EXIT; IMG_LOOP: dec esi; mov eax, esi; imul eax, eax, 0x021C; add eax, 0x0004; add eax, pVirtualIMG; push eax; push edi; call _stricmp; add esp, 0x08; test eax, eax; jz IMG_BREAK; cmp eax, 0x20; je IMG_BREAK; test esi, esi; jnz IMG_LOOP; IMG_EXIT: #ifdef USE_LOG #ifdef USE_LOG_MORE push pLogFile; push cPrefixI; call fputs; add esp, 0x08; push pLogFile; push edi; call fputs; add esp, 0x08; push pLogFile; push cReturn; call fputs; add esp, 0x08; #endif #endif pop esi; pop eax; pop edi; push edi; mov edi, dwEDI; ret; IMG_BREAK: mov eax, esi; imul eax, eax, 0x021C; add eax, pVirtualIMG; add eax, 0x0004; push eax; push MAX_PATH; mov eax, OFFSET cReplaceFile; push eax; call strcpy_s; add esp, 0x0C; mov eax, cVImgExt; push eax; push MAX_PATH; mov eax, OFFSET cReplaceFile; push eax; call strcat_s; add esp, 0x0C; #ifdef USE_LOG push pLogFile; push cPrefix; call fputs; add esp, 0x08; push pLogFile; push edi; call fputs; add esp, 0x08; push pLogFile; push cTab; call fputs; add esp, 0x08; push pLogFile; push OFFSET cReplaceFile; call fputs; add esp, 0x08; push pLogFile; push cReturn; call fputs; add esp, 0x08; #endif pop esi; pop eax; mov edi, OFFSET cReplaceFile; mov [esp+0x08], edi; mov edi, dwEDI; ret; }; } HANDLE WINAPI CreateFile_Hook(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { for (int i = 0; i < iIMGCount; i++) { if (!pVirtualIMG[i].iType) continue; if (_stricmp(lpFileName, pVirtualIMG[i].cIMGPath) == '\0' || _stricmp(lpFileName, pVirtualIMG[i].cIMGPath) == ' ') { char cReplaceFile[MAX_PATH]; HANDLE hFile; strcpy_s(cReplaceFile, MAX_PATH, pVirtualIMG[i].cIMGPath); strcat_s(cReplaceFile, MAX_PATH, ".vimg"); #ifdef USE_LOG fputs("[Use Dummy]\t", pLogFile); fputs(lpFileName, pLogFile); fputs("\t", pLogFile); fputs(cReplaceFile, pLogFile); fputs("\n", pLogFile); #endif hFile = (*CreateFile_Real)(cReplaceFile, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); if (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED) pVirtualIMG[i].hNewFile = hFile; return hFile; } } #ifdef USE_LOG #ifdef USE_LOG_MORE fputs("[Ignore]\t", pLogFile); fputs(lpFileName, pLogFile); fputs("\n", pLogFile); #endif #endif return (*CreateFile_Real)(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } void _patch(void* pAddress, void* pData, int iSize) { unsigned long dwProtect[2]; VirtualProtect(pAddress, iSize, PAGE_EXECUTE_READWRITE, &dwProtect[0]); memcpy(pAddress, pData, iSize); VirtualProtect(pAddress, iSize, dwProtect[0], &dwProtect[1]); } void _nop(void* pAddress, int iSize) { unsigned long dwProtect[2]; VirtualProtect(pAddress, iSize, PAGE_EXECUTE_READWRITE, &dwProtect[0]); memset(pAddress, 0x90, iSize); VirtualProtect(pAddress, iSize, dwProtect[0], &dwProtect[1]); } bool check(void* pAddress, unsigned char cByte, const char* sExp, bool bContinue) { if (_check(pAddress, cByte)) return true; if (bContinue) return false; char buf[1024]; sprintf_s(buf, 1024, "An unknown code found at 0x%08X (%s).\nDo you want to continue without this Function?", pAddress, sExp); if (MessageBox(0, buf, "Virtual IMG", MB_YESNO | MB_ICONERROR | MB_DEFBUTTON2) == IDNO) ExitProcess(0); return false; } bool _check(void* pAddress, unsigned char cByte) { unsigned long dwProtect[2]; unsigned char cValue = cByte; VirtualProtect(pAddress, 1, PAGE_EXECUTE_READ, &dwProtect[0]); memcpy(&cValue, pAddress, 1); VirtualProtect(pAddress, 1, dwProtect[0], &dwProtect[1]); return (cValue == cByte); }