FunctionPass::FunctionPass(duint VirtualStart, duint VirtualEnd, BBlockArray & MainBlocks) : AnalysisPass(VirtualStart, VirtualEnd, MainBlocks) { // Zero values m_FunctionInfo = nullptr; m_FunctionInfoSize = 0; // This will only be valid if the address range is within a loaded module m_ModuleStart = ModBaseFromAddr(VirtualStart); if(m_ModuleStart != 0) { char modulePath[MAX_PATH]; memset(modulePath, 0, sizeof(modulePath)); ModPathFromAddr(m_ModuleStart, modulePath, ARRAYSIZE(modulePath)); HANDLE fileHandle; DWORD fileSize; HANDLE fileMapHandle; ULONG_PTR fileMapVa; if(StaticFileLoadW( StringUtils::Utf8ToUtf16(modulePath).c_str(), UE_ACCESS_READ, false, &fileHandle, &fileSize, &fileMapHandle, &fileMapVa)) { // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); m_FunctionInfoSize = (ULONG)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); // Unload the file StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); // Get a copy of the function table if(virtualOffset) { // Read the table into a buffer m_FunctionInfo = BridgeAlloc(m_FunctionInfoSize); if(m_FunctionInfo) MemRead(virtualOffset + m_ModuleStart, m_FunctionInfo, m_FunctionInfoSize); } } } }
ControlFlowAnalysis::ControlFlowAnalysis(uint base, uint size, bool exceptionDirectory) : Analysis(base, size) { _functionInfoData = nullptr; #ifdef _WIN64 // This will only be valid if the address range is within a loaded module _moduleBase = ModBaseFromAddr(base); if(exceptionDirectory && _moduleBase != 0) { char modulePath[MAX_PATH]; memset(modulePath, 0, sizeof(modulePath)); ModPathFromAddr(_moduleBase, modulePath, ARRAYSIZE(modulePath)); HANDLE fileHandle; DWORD fileSize; HANDLE fileMapHandle; ULONG_PTR fileMapVa; if(StaticFileLoadW( StringUtils::Utf8ToUtf16(modulePath).c_str(), UE_ACCESS_READ, false, &fileHandle, &fileSize, &fileMapHandle, &fileMapVa)) { // Find a pointer to IMAGE_DIRECTORY_ENTRY_EXCEPTION for later use ULONG_PTR virtualOffset = GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALOFFSET); _functionInfoSize = (uint)GetPE32DataFromMappedFile(fileMapVa, IMAGE_DIRECTORY_ENTRY_EXCEPTION, UE_SECTIONVIRTUALSIZE); // Unload the file StaticFileUnloadW(nullptr, false, fileHandle, fileSize, fileMapHandle, fileMapVa); // Get a copy of the function table if(virtualOffset) { // Read the table into a buffer _functionInfoData = emalloc(_functionInfoSize); if(_functionInfoData) MemRead(virtualOffset + _moduleBase, _functionInfoData, _functionInfoSize); } } } #endif //_WIN64 }
int PatchFile(const PATCHINFO* List, int Count, const char* FileName, char* Error) { // // This function returns an int based on the number // of patches applied. -1 indicates a failure. // if(Count <= 0) { // Notify the user of the error if(Error) strcpy_s(Error, MAX_ERROR_SIZE, "No patches to apply"); return -1; } // Get a copy of the first module name in the array char moduleName[MAX_MODULE_SIZE]; strcpy_s(moduleName, List[0].mod); // Check if all patches are in the same module for(int i = 0; i < Count; i++) { if(_stricmp(List[i].mod, moduleName)) { if(Error) sprintf_s(Error, MAX_ERROR_SIZE, "Not all patches are in module %s", moduleName); return -1; } } // See if the module was loaded duint moduleBase = ModBaseFromName(moduleName); if(!moduleBase) { if(Error) sprintf_s(Error, MAX_ERROR_SIZE, "Failed to get base of module %s", moduleName); return -1; } // Get the unicode version of the module's path wchar_t originalName[MAX_PATH]; if(!GetModuleFileNameExW(fdProcessInfo->hProcess, (HMODULE)moduleBase, originalName, ARRAYSIZE(originalName))) { if(Error) sprintf_s(Error, MAX_ERROR_SIZE, "Failed to get module path of module %s", moduleName); return -1; } // Create a temporary backup file if(!CopyFileW(originalName, StringUtils::Utf8ToUtf16(FileName).c_str(), false)) { if(Error) strcpy_s(Error, MAX_ERROR_SIZE, "Failed to make a copy of the original file (patch target is in use?)"); return -1; } HANDLE fileHandle; DWORD loadedSize; HANDLE fileMap; ULONG_PTR fileMapVa; if(!StaticFileLoadW(StringUtils::Utf8ToUtf16(FileName).c_str(), UE_ACCESS_ALL, false, &fileHandle, &loadedSize, &fileMap, &fileMapVa)) { strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileLoad failed"); return -1; } // Begin iterating all patches, applying them to a file int patchCount = 0; for(int i = 0; i < Count; i++) { // Convert the virtual address to an offset within disk file data unsigned char* ptr = (unsigned char*)ConvertVAtoFileOffsetEx(fileMapVa, loadedSize, moduleBase, List[i].addr, false, true); // Skip patches that do not have a raw address if(!ptr) continue; *ptr = List[i].newbyte; patchCount++; } // Unload the file from memory and commit changes to disk if(!StaticFileUnloadW(StringUtils::Utf8ToUtf16(FileName).c_str(), true, fileHandle, loadedSize, fileMap, fileMapVa)) { if(Error) strcpy_s(Error, MAX_ERROR_SIZE, "StaticFileUnload failed"); return -1; } // Zero the error message and return count if(Error) memset(Error, 0, MAX_ERROR_SIZE * sizeof(char)); return patchCount; }
bool ModLoad(uint Base, uint Size, const char* FullPath) { // // Handle a new module being loaded // // TODO: Do loaded modules always require a path? if(!Base || !Size || !FullPath) return false; MODINFO info; // Copy the module path in the struct strcpy_s(info.path, FullPath); // Break the module path into a directory and file name char dir[MAX_PATH] = ""; char file[MAX_MODULE_SIZE] = ""; strcpy_s(dir, FullPath); _strlwr(dir); char* fileStart = strrchr(dir, '\\'); if(fileStart) { strcpy_s(file, fileStart + 1); *fileStart = '\0'; } //calculate module hash from full file name info.hash = ModHashFromName(file); // Copy the extension into the module struct { char* extensionPos = strrchr(file, '.'); if(extensionPos) { strcpy_s(info.extension, extensionPos); extensionPos[0] = '\0'; } } // Copy the name to the module struct strcpy_s(info.name, file); // Module base address/size info.base = Base; info.size = Size; // Process module sections info.sections.clear(); WString wszFullPath = StringUtils::Utf8ToUtf16(FullPath); if(StaticFileLoadW(wszFullPath.c_str(), UE_ACCESS_READ, false, &info.Handle, &info.FileMapSize, &info.MapHandle, &info.FileMapVA)) { // Get the entry point info.entry = GetPE32DataFromMappedFile(info.FileMapVA, 0, UE_OEP) + info.base; // Enumerate all PE sections int sectionCount = (int)GetPE32DataFromMappedFile(info.FileMapVA, 0, UE_SECTIONNUMBER); for(int i = 0; i < sectionCount; i++) { MODSECTIONINFO curSection; curSection.addr = GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONVIRTUALOFFSET) + info.base; curSection.size = GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONVIRTUALSIZE); const char* sectionName = (const char*)GetPE32DataFromMappedFile(info.FileMapVA, i, UE_SECTIONNAME); // Escape section name when needed strcpy_s(curSection.name, StringUtils::Escape(sectionName).c_str()); // Add entry to the vector info.sections.push_back(curSection); } } // Add module to list EXCLUSIVE_ACQUIRE(LockModules); modinfo.insert(std::make_pair(Range(Base, Base + Size - 1), info)); EXCLUSIVE_RELEASE(); SymUpdateModuleList(); return true; }