pugi::xml_node CXmlFile::Load() { Close(); m_error.clear(); wxCHECK(!m_fileName.empty(), m_element); std::wstring redirectedName = GetRedirectedName(); GetXmlFile(redirectedName); if (!m_element) { wxString err = wxString::Format(_("The file '%s' could not be loaded."), m_fileName); if (m_error.empty()) { err += wxString(_T("\n")) + _("Make sure the file can be accessed and is a well-formed XML document."); } else { err += _T("\n") + m_error; } // Try the backup file GetXmlFile(redirectedName + _T("~")); if (!m_element) { // Loading backup failed. If both original and backup file are empty, create new file. if (fz::local_filesys::get_size(fz::to_native(redirectedName)) <= 0 && fz::local_filesys::get_size(fz::to_native(redirectedName + _T("~"))) <= 0) { m_error.clear(); CreateEmpty(); m_modificationTime = fz::local_filesys::get_modification_time(fz::to_native(redirectedName)); return m_element; } // File corrupt and no functional backup, give up. m_error = err; m_modificationTime.clear(); return m_element; } // Loading the backup file succeeded, restore file bool res; { wxLogNull null; res = wxCopyFile(redirectedName + _T("~"), redirectedName); } if (!res) { // Could not restore backup, give up. Close(); m_error = err.ToStdWstring(); m_error += _T("\n") + wxString::Format(_("The valid backup file %s could not be restored"), redirectedName + _T("~")).ToStdWstring(); m_modificationTime.clear(); return m_element; } // We no longer need the backup wxRemoveFile(redirectedName + _T("~")); m_error.clear(); } m_modificationTime = fz::local_filesys::get_modification_time(fz::to_native(redirectedName)); return m_element; }
bool CXmlFile::SaveXmlFile() { bool exists = false; bool isLink = false; int flags = 0; wxString redirectedName = GetRedirectedName(); if (CLocalFileSystem::GetFileInfo(redirectedName, isLink, 0, 0, &flags) == CLocalFileSystem::file) { #ifdef __WXMSW__ if (flags & FILE_ATTRIBUTE_HIDDEN) SetFileAttributes(redirectedName, flags & ~FILE_ATTRIBUTE_HIDDEN); #endif exists = true; bool res; { wxLogNull null; res = wxCopyFile(redirectedName, redirectedName + _T("~")); } if (!res) { m_error = _("Failed to create backup copy of xml file"); return false; } } bool success = false; { wxFFile f(redirectedName, _T("w")); success = f.IsOpened() && m_pDocument->SaveFile(f.fp()); } if (!success) { wxRemoveFile(redirectedName); if (exists) { wxLogNull null; wxRenameFile(redirectedName + _T("~"), redirectedName); } m_error = _("Failed to write xml file"); return false; } if (exists) wxRemoveFile(redirectedName + _T("~")); return true; }
bool CXmlFile::SaveXmlFile() { bool exists = false; bool isLink = false; int flags = 0; wxString redirectedName = GetRedirectedName(); if (fz::local_filesys::get_file_info(fz::to_native(redirectedName), isLink, 0, 0, &flags) == fz::local_filesys::file) { #ifdef __WXMSW__ if (flags & FILE_ATTRIBUTE_HIDDEN) SetFileAttributes(redirectedName.c_str(), flags & ~FILE_ATTRIBUTE_HIDDEN); #endif exists = true; bool res; { wxLogNull null; res = wxCopyFile(redirectedName, redirectedName + _T("~")); } if (!res) { m_error = _("Failed to create backup copy of xml file").ToStdWstring(); return false; } } bool success = m_document.save_file(static_cast<wchar_t const*>(redirectedName.c_str())); if (!success) { wxRemoveFile(redirectedName); if (exists) { wxLogNull null; wxRenameFile(redirectedName + _T("~"), redirectedName); } m_error = _("Failed to write xml file").ToStdWstring(); return false; } if (exists) wxRemoveFile(redirectedName + _T("~")); return true; }
HMODULE CustomLoadLibrary(const PWCHAR wszFullDllName, const PWCHAR wszBaseDllName, ULONG_PTR pDllBase) { // File handles HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE hMap = NULL; PCHAR pFile = NULL; // PE headers PIMAGE_DOS_HEADER pDosHeader; PIMAGE_NT_HEADERS pNtHeader; PIMAGE_SECTION_HEADER pSectionHeader; // Library PCHAR pLibraryAddr = NULL; DWORD dwIdx; // Relocation PIMAGE_DATA_DIRECTORY pDataDir; PIMAGE_BASE_RELOCATION pBaseReloc; ULONG_PTR pReloc; DWORD dwNumRelocs; ULONG_PTR pInitialImageBase; PIMAGE_RELOC pImageReloc; // Import PIMAGE_IMPORT_DESCRIPTOR pImportDesc; PCHAR szDllName; SIZE_T stDllName; PWSTR wszDllName = NULL; PWCHAR wsRedir = NULL; PWSTR wszRedirName = NULL; SIZE_T stRedirName; SIZE_T stSize; HMODULE hModule; PIMAGE_THUNK_DATA pThunkData; FARPROC* pIatEntry; // clr.dll hotpatches itself at runtime for performance reasons, so skip it if (wcscmp(L"clr.dll", wszBaseDllName) == 0) goto cleanup; dprintf("[REFRESH] Opening file: %S", wszFullDllName); // ---- // Step 1: Map the file into memory // ---- hFile = CreateFileW(wszFullDllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) goto cleanup; hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if (hMap == NULL) goto cleanup; pFile = (PCHAR)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); if (pFile == NULL) goto cleanup; // ---- // Step 2: Parse the file headers and load it into memory // ---- pDosHeader = (PIMAGE_DOS_HEADER)pFile; pNtHeader = (PIMAGE_NT_HEADERS)(pFile + pDosHeader->e_lfanew); // allocate memory to copy DLL into dprintf("[REFRESH] Allocating memory for library"); pLibraryAddr = (PCHAR)VirtualAlloc(NULL, pNtHeader->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); // copy header dprintf("[REFRESH] Copying PE header into memory"); memcpy(pLibraryAddr, pFile, pNtHeader->OptionalHeader.SizeOfHeaders); // copy sections dprintf("[REFRESH] Copying PE sections into memory"); pSectionHeader = (PIMAGE_SECTION_HEADER)(pFile + pDosHeader->e_lfanew + sizeof(IMAGE_NT_HEADERS)); for (dwIdx = 0; dwIdx < pNtHeader->FileHeader.NumberOfSections; dwIdx++) { memcpy(pLibraryAddr + pSectionHeader[dwIdx].VirtualAddress, pFile + pSectionHeader[dwIdx].PointerToRawData, pSectionHeader[dwIdx].SizeOfRawData); } // update our pointers to the loaded image pDosHeader = (PIMAGE_DOS_HEADER)pLibraryAddr; pNtHeader = (PIMAGE_NT_HEADERS)(pLibraryAddr + pDosHeader->e_lfanew); // ---- // Step 3: Calculate relocations // ---- dprintf("[REFRESH] Calculating file relocations"); pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; pInitialImageBase = pNtHeader->OptionalHeader.ImageBase; // set the ImageBase to the already loaded module's base pNtHeader->OptionalHeader.ImageBase = pDllBase; // check if their are any relocations present if (pDataDir->Size) { // calculate the address of the first IMAGE_BASE_RELOCATION entry pBaseReloc = (PIMAGE_BASE_RELOCATION)(pLibraryAddr + pDataDir->VirtualAddress); // iterate through each relocation entry while ((PCHAR)pBaseReloc < (pLibraryAddr + pDataDir->VirtualAddress + pDataDir->Size) && pBaseReloc->SizeOfBlock) { // the VA for this relocation block pReloc = (ULONG_PTR)(pLibraryAddr + pBaseReloc->VirtualAddress); // number of entries in this relocation block dwNumRelocs = (pBaseReloc->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC); // first entry in the current relocation block pImageReloc = (PIMAGE_RELOC)((PCHAR)pBaseReloc + sizeof(IMAGE_BASE_RELOCATION)); // iterate through each entry in the relocation block while (dwNumRelocs--) { // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. // we subtract the initial ImageBase and add in the original dll base if (pImageReloc->type == IMAGE_REL_BASED_DIR64) { *(ULONG_PTR *)(pReloc + pImageReloc->offset) -= pInitialImageBase; *(ULONG_PTR *)(pReloc + pImageReloc->offset) += pDllBase; } else if (pImageReloc->type == IMAGE_REL_BASED_HIGHLOW) { *(DWORD *)(pReloc + pImageReloc->offset) -= (DWORD)pInitialImageBase; *(DWORD *)(pReloc + pImageReloc->offset) += (DWORD)pDllBase; } else if (pImageReloc->type == IMAGE_REL_BASED_HIGH) { *(WORD *)(pReloc + pImageReloc->offset) -= HIWORD(pInitialImageBase); *(WORD *)(pReloc + pImageReloc->offset) += HIWORD(pDllBase); } else if (pImageReloc->type == IMAGE_REL_BASED_LOW) { *(WORD *)(pReloc + pImageReloc->offset) -= LOWORD(pInitialImageBase); *(WORD *)(pReloc + pImageReloc->offset) += LOWORD(pDllBase); } // get the next entry in the current relocation block pImageReloc = (PIMAGE_RELOC)((PCHAR)pImageReloc + sizeof(IMAGE_RELOC)); } // get the next entry in the relocation directory pBaseReloc = (PIMAGE_BASE_RELOCATION)((PCHAR)pBaseReloc + pBaseReloc->SizeOfBlock); } } // ---- // Step 4: Update import table // ---- dprintf("[REFRESH] Resolving Import Address Table (IAT) "); pDataDir = &pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]; if (pDataDir->Size) { pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)(pLibraryAddr + pDataDir->VirtualAddress); while (pImportDesc->Characteristics) { hModule = NULL; wszDllName = NULL; szDllName = (PCHAR)(pLibraryAddr + pImportDesc->Name); stDllName = strnlen(szDllName, MAX_PATH); wszDllName = (PWSTR)calloc(stDllName + 1, sizeof(WCHAR)); if (wszDllName == NULL) goto next_import; mbstowcs_s(&stSize, wszDllName, stDllName + 1, szDllName, stDllName); dprintf("[REFRESH] Loading library: %S", wszDllName); // If the DLL starts with api- or ext-, resolve the redirected name and load it if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0) { // wsRedir is not null terminated wsRedir = GetRedirectedName(wszBaseDllName, wszDllName, &stRedirName); if (wsRedir) { // Free the original wszDllName and allocate a new buffer for the redirected dll name free(wszDllName); wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR)); if (wszDllName == NULL) goto next_import; memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR)); dprintf("[REFRESH] Redirected library: %S", wszDllName); } } // Load the module hModule = CustomGetModuleHandleW(wszDllName); // Ignore libraries that fail to load if (hModule == NULL) goto next_import; if (pImportDesc->OriginalFirstThunk) pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->OriginalFirstThunk); else pThunkData = (PIMAGE_THUNK_DATA)(pLibraryAddr + pImportDesc->FirstThunk); pIatEntry = (FARPROC*)(pLibraryAddr + pImportDesc->FirstThunk); // loop through each thunk and resolve the import for(; DEREF(pThunkData); pThunkData++, pIatEntry++) { if (IMAGE_SNAP_BY_ORDINAL(pThunkData->u1.Ordinal)) *pIatEntry = CustomGetProcAddressEx(hModule, (PCHAR)IMAGE_ORDINAL(pThunkData->u1.Ordinal), wszDllName); else *pIatEntry = CustomGetProcAddressEx(hModule, ((PIMAGE_IMPORT_BY_NAME)(pLibraryAddr + DEREF(pThunkData)))->Name, wszDllName); } next_import: if (wszDllName != NULL) { free(wszDllName); wszDllName = NULL; } pImportDesc = (PIMAGE_IMPORT_DESCRIPTOR)((PCHAR)pImportDesc + sizeof(IMAGE_IMPORT_DESCRIPTOR)); } } cleanup: if (pFile != NULL) UnmapViewOfFile(pFile); if (hMap != NULL) CloseHandle(hMap); if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); return (HMODULE) pLibraryAddr; }
// This code is modified from Stephen Fewer's GetProcAddress implementation //===============================================================================================// // Copyright (c) 2013, Stephen Fewer of Harmony Security (www.harmonysecurity.com) // 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. // // * Neither the name of Harmony Security nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR // CONTRIBUTORS 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. //===============================================================================================// FARPROC WINAPI CustomGetProcAddressEx(HMODULE hModule, const PCHAR lpProcName, PWSTR wszOriginalModule) { UINT_PTR uiLibraryAddress = 0; UINT_PTR uiAddressArray = 0; UINT_PTR uiNameArray = 0; UINT_PTR uiNameOrdinals = 0; UINT_PTR uiFuncVA = 0; PCHAR cpExportedFunctionName; PCHAR szFwdDesc; PCHAR szRedirFunc; PWSTR wszDllName; SIZE_T stDllName; PWCHAR wsRedir; PWSTR wszRedirName = NULL; SIZE_T stRedirName; HMODULE hFwdModule; PIMAGE_NT_HEADERS pNtHeaders = NULL; PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; FARPROC fpResult = NULL; DWORD dwCounter; if (hModule == NULL) return NULL; // a module handle is really its base address uiLibraryAddress = (UINT_PTR)hModule; // get the VA of the modules NT Header pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; // get the VA of the export directory pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(uiLibraryAddress + pDataDirectory->VirtualAddress); // get the VA for the array of addresses uiAddressArray = (uiLibraryAddress + pExportDirectory->AddressOfFunctions); // get the VA for the array of name pointers uiNameArray = (uiLibraryAddress + pExportDirectory->AddressOfNames); // get the VA for the array of name ordinals uiNameOrdinals = (uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals); // test if we are importing by name or by ordinal... #pragma warning(suppress: 4311) if (((DWORD)lpProcName & 0xFFFF0000) == 0x00000000) { // import by ordinal... // use the import ordinal (- export ordinal base) as an index into the array of addresses #pragma warning(suppress: 4311) uiAddressArray += ((IMAGE_ORDINAL((DWORD)lpProcName) - pExportDirectory->Base) * sizeof(DWORD)); // resolve the address for this imported function fpResult = (FARPROC)(uiLibraryAddress + DEREF_32(uiAddressArray)); } else { // import by name... dwCounter = pExportDirectory->NumberOfNames; while (dwCounter--) { cpExportedFunctionName = (PCHAR)(uiLibraryAddress + DEREF_32(uiNameArray)); // test if we have a match... if (strcmp(cpExportedFunctionName, lpProcName) == 0) { // use the functions name ordinal as an index into the array of name pointers uiAddressArray += (DEREF_16(uiNameOrdinals) * sizeof(DWORD)); uiFuncVA = DEREF_32(uiAddressArray); // check for redirected exports if (pDataDirectory->VirtualAddress <= uiFuncVA && uiFuncVA < (pDataDirectory->VirtualAddress + pDataDirectory->Size)) { szFwdDesc = (PCHAR)(uiLibraryAddress + uiFuncVA); // Find the first character after "." szRedirFunc = strstr(szFwdDesc, ".") + 1; stDllName = (SIZE_T)(szRedirFunc - szFwdDesc); // Allocate enough space to append "dll" wszDllName = (PWSTR)calloc(stDllName + 3 + 1, sizeof(WCHAR)); if (wszDllName == NULL) break; mbstowcs_s(NULL, wszDllName, stDllName + 1, szFwdDesc, stDllName); memcpy(wszDllName + stDllName, L"dll", 3 * sizeof(WCHAR)); // check for a redirected module name if (_wcsnicmp(wszDllName, L"api-", 4) == 0 || _wcsnicmp(wszDllName, L"ext-", 4) == 0) { wsRedir = GetRedirectedName(wszOriginalModule, wszDllName, &stRedirName); if (wsRedir) { // Free the original buffer and allocate a new one for the redirected dll name free(wszDllName); wszDllName = (PWSTR)calloc(stRedirName + 1, sizeof(WCHAR)); if (wszDllName == NULL) break; memcpy(wszDllName, wsRedir, stRedirName * sizeof(WCHAR)); } } hFwdModule = GetModuleHandleW(wszDllName); fpResult = CustomGetProcAddressEx(hFwdModule, szRedirFunc, wszDllName); free(wszDllName); } else { // calculate the virtual address for the function fpResult = (FARPROC)(uiLibraryAddress + uiFuncVA); } // finish... break; } // get the next exported function name uiNameArray += sizeof(DWORD); // get the next exported function name ordinal uiNameOrdinals += sizeof(WORD); } } return fpResult; }