void GetCallbacks(OutputIterator callbacks) const { using OutputIteratorCategory = typename std::iterator_traits<OutputIterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::output_iterator_tag, OutputIteratorCategory>::value); auto const image_base = GetRuntimeBase(*process_, *pe_file_); auto callbacks_raw = reinterpret_cast<PIMAGE_TLS_CALLBACK*>( RvaToVa(*process_, *pe_file_, static_cast<DWORD>(GetAddressOfCallBacks() - image_base))); if (!callbacks_raw) { HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"TLS callbacks are invalid."}); } for (auto callback = Read<PIMAGE_TLS_CALLBACK>(*process_, callbacks_raw); callback; callback = Read<PIMAGE_TLS_CALLBACK>(*process_, ++callbacks_raw)) { auto const callback_offset = reinterpret_cast<ULONGLONG>(callback) - image_base; *callbacks = reinterpret_cast<PIMAGE_TLS_CALLBACK>( static_cast<ULONG_PTR>(callback_offset)); ++callbacks; } }
inline ModuleRegionInfo GetModuleInfo(Process const& process, std::wstring const& module) { ModuleRegionInfo mod_info; if (module.empty()) { mod_info.module = std::make_shared<Module>(process, nullptr); } else { mod_info.module = std::make_shared<Module>(process, module); } auto const base = reinterpret_cast<std::uint8_t*>(mod_info.module->GetHandle()); PeFile const pe_file{process, base, hadesmem::PeFileType::Image, 0}; DosHeader const dos_header{process, pe_file}; NtHeaders const nt_headers{process, pe_file}; SectionList const sections{process, pe_file}; for (auto const& s : sections) { bool const is_code_section = !!(s.GetCharacteristics() & IMAGE_SCN_CNT_CODE); bool const is_data_section = !!(s.GetCharacteristics() & IMAGE_SCN_CNT_INITIALIZED_DATA); if (!is_code_section && !is_data_section) { continue; } auto const section_beg = static_cast<std::uint8_t*>( RvaToVa(process, pe_file, s.GetVirtualAddress())); if (section_beg == nullptr) { HADESMEM_DETAIL_THROW_EXCEPTION( Error() << ErrorString("Could not get section base address.")); } DWORD const section_size = s.GetVirtualSize(); if (!section_size) { continue; } auto const section_end = section_beg + section_size; auto& regions = is_code_section ? mod_info.code_regions : mod_info.data_regions; regions.emplace_back(section_beg, section_end); } if (mod_info.code_regions.empty() && mod_info.data_regions.empty()) { HADESMEM_DETAIL_THROW_EXCEPTION( Error() << ErrorString("No valid sections to scan found.")); } return mod_info; }
void SetHint(WORD hint) { std::uint8_t* const name_import = static_cast<PBYTE>( RvaToVa(*process_, *pe_file_, static_cast<DWORD>(GetAddressOfData()))); return Write( *process_, name_import + offsetof(IMAGE_IMPORT_BY_NAME, Hint), hint); }
explicit RelocationBlockIterator(Process const& process, PeFile const& pe_file) { try { NtHeaders const nt_headers{process, pe_file}; DWORD const data_dir_va = nt_headers.GetDataDirectoryVirtualAddress(PeDataDir::BaseReloc); DWORD const size = nt_headers.GetDataDirectorySize(PeDataDir::BaseReloc); if (!data_dir_va || !size) { return; } auto base = static_cast<std::uint8_t*>(RvaToVa(process, pe_file, data_dir_va)); if (!base) { return; } // Cast to integer and back to avoid pointer overflow UB. auto const reloc_dir_end = reinterpret_cast<void const*>( reinterpret_cast<std::uintptr_t>(base) + size); auto const file_end = static_cast<std::uint8_t*>(pe_file.GetBase()) + pe_file.GetSize(); // Sample: virtrelocXP.exe if (pe_file.GetType() == PeFileType::Data && (reloc_dir_end < base || reloc_dir_end > file_end)) { return; } // TODO: Dump should warn for this. RelocationBlock const relocation_block{ process, pe_file, reinterpret_cast<IMAGE_BASE_RELOCATION*>(base), reloc_dir_end}; if (relocation_block.IsInvalid()) { return; } impl_ = std::make_shared<Impl>( process, pe_file, relocation_block, reloc_dir_end); } catch (std::exception const& /*e*/) { // Nothing to do here. } }
std::string GetName() const { auto const name_import = static_cast<std::uint8_t*>( RvaToVa(*process_, *pe_file_, static_cast<DWORD>(GetAddressOfData()))); if (!name_import) { HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"Invalid import name and hint."}); } return detail::CheckedReadString<char>( *process_, *pe_file_, name_import + offsetof(IMAGE_IMPORT_BY_NAME, Name)); }
explicit TlsDir(Process const& process, PeFile const& pe_file) : process_{&process}, pe_file_{&pe_file} { NtHeaders const nt_headers{process, pe_file}; DWORD const data_dir_va = nt_headers.GetDataDirectoryVirtualAddress(PeDataDir::TLS); // Windows will load images which don't specify a size for the // TLS directory. if (!data_dir_va) { HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"PE file has no TLS directory."}); } base_ = static_cast<std::uint8_t*>(RvaToVa(process, pe_file, data_dir_va)); if (!base_) { HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"TLS directory is invalid."}); } UpdateRead(); }
BOOL ImportEnumerate(HINSTANCE hInst) { PBYTE pbBase = (PBYTE)hInst; PIMAGE_NT_HEADERS pNtHeader; // Read & Write PIMAGE_SECTION_HEADER pSectionHeaders; DWORD nPeOffset; DWORD nSectionsOffset; ////////////////////////////////////////////////////// Process DOS Header. // PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pbBase; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { return FALSE; } nPeOffset = pDosHeader->e_lfanew; /////////////////////////////////////////////////////// Process PE Header. // pNtHeader = (PIMAGE_NT_HEADERS)RvaToVa(pbBase, nPeOffset); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { return FALSE; } if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) { return FALSE; } nSectionsOffset = nPeOffset + sizeof(pNtHeader->Signature) + sizeof(pNtHeader->FileHeader) + pNtHeader->FileHeader.SizeOfOptionalHeader; ///////////////////////////////////////////////// Process Section Headers. // pSectionHeaders = (PIMAGE_SECTION_HEADER)RvaToVa(pbBase, nSectionsOffset); //////////////////////////////////////////////////////// Get Import Table. // DWORD rvaImageDirectory = pNtHeader->OptionalHeader .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; PIMAGE_IMPORT_DESCRIPTOR iidp = (PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(pbBase, rvaImageDirectory); if (iidp == NULL) { return FALSE; } for (DWORD nFiles = 0; iidp[nFiles].Characteristics != 0; nFiles++) { // Count the files. } for (DWORD n = 0; n < nFiles; n++, iidp++) { DWORD rvaName = iidp->Name; PCHAR pszName = (PCHAR)RvaToVa(pbBase, rvaName); DWORD rvaThunk = (DWORD)iidp->OriginalFirstThunk; PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk); rvaThunk = (DWORD)iidp->FirstThunk; PIMAGE_THUNK_DATA pBoundThunk = (PIMAGE_THUNK_DATA)RvaToVa(pbBase, rvaThunk); Syelog(SYELOG_SEVERITY_INFORMATION, "%s [%08x %08x]\n", pszName, pThunk, pBoundThunk); DWORD nNames = 0; if (pThunk == NULL) { break; } for (; pThunk[nNames].u1.Ordinal; nNames++) { // Count the imports. } for (DWORD f = 0; f < nNames; f++) { DWORD nOrdinal = 0; PCHAR pszName = NULL; PDWORD pFunc = (PDWORD)pBoundThunk[f].u1.Function; DWORD rvaName = pThunk[f].u1.Ordinal; if (rvaName & IMAGE_ORDINAL_FLAG) { nOrdinal = IMAGE_ORDINAL(rvaName); } else { PIMAGE_IMPORT_BY_NAME pName = (PIMAGE_IMPORT_BY_NAME)RvaToVa(pbBase, rvaName); if (pName) { pszName = (PCHAR)pName->Name; } } Syelog(SYELOG_SEVERITY_INFORMATION, " %-32.32s %4d %08x\n", pszName, nOrdinal, pFunc); } } return TRUE; }