fix the inline hook scan bug

This commit is contained in:
BeneficialCode
2026-05-09 21:56:28 +08:00
parent c2c2c9c6e0
commit 51a57fb6ef
9 changed files with 316 additions and 364 deletions
+73 -80
View File
@@ -45,9 +45,10 @@ PEParser::PEParser(const wchar_t* path, bool isScylla) :_path(path) {
}
}
PEParser::PEParser(void* base) {
PEParser::PEParser(void* base, SIZE_T mappedSize) {
_address = reinterpret_cast<PUCHAR>(base);
_moduleBase = (DWORD_PTR)base;
_fileSize.QuadPart = static_cast<LONGLONG>(mappedSize);
_isFileMap = false;
CheckValidity();
if (IsValid()) {
@@ -56,13 +57,13 @@ PEParser::PEParser(void* base) {
}
void PEParser::GetSectionHeaders() {
ReleaseSectionData();
_PESections.clear();
int count = GetSectionCount();
_PESections.reserve(count);
PEFileSection peFileSection;
for (WORD i = 0; i < count; i++) {
PEFileSection peFileSection;
memcpy_s(&peFileSection._sectionHeader, sizeof(IMAGE_SECTION_HEADER), &_sections[i], sizeof(IMAGE_SECTION_HEADER));
_PESections.push_back(peFileSection);
}
@@ -73,10 +74,13 @@ HANDLE PEParser::GetFileHandle() {
}
PEParser::~PEParser() {
ReleaseSectionData();
if (_resModule)
::FreeLibrary(_resModule);
if (_hMemMap) {
::UnmapViewOfFile(_address);
if (_address) {
::UnmapViewOfFile(_address);
}
::CloseHandle(_hMemMap);
}
if (_hFile != INVALID_HANDLE_VALUE)
@@ -440,6 +444,15 @@ void PEParser::CheckValidity() {
_valid = true;
}
void PEParser::ReleaseSectionData() {
for (auto& section : _PESections) {
delete[] section._pData;
section._pData = nullptr;
section._dataSize = 0;
section._normalSize = 0;
}
}
unsigned PEParser::RvaToFileOffset(unsigned rva) const {
for (int i = 0; i < GetSectionCount(); ++i) {
if (rva >= _PESections[i]._sectionHeader.VirtualAddress && rva <
@@ -886,12 +899,20 @@ bool PEParser::DumpProcess(DWORD_PTR modBase, DWORD_PTR entryPoint, const WCHAR*
}
void PEParser::GetPESections() {
DWORD_PTR offset = 0;
const int count = GetSectionCount();
if (count <= 0) {
return;
}
int count = GetSectionCount();
_PESections.reserve(count);
if (static_cast<int>(_PESections.size()) != count) {
GetSectionHeaders();
}
else {
ReleaseSectionData();
}
for (WORD i = 0; i < count; i++) {
DWORD_PTR offset = 0;
if (_isFileMap) {
_PESections[i]._normalSize = _sections[i].SizeOfRawData;
_PESections[i]._dataSize = _sections[i].SizeOfRawData;
@@ -919,63 +940,28 @@ DWORD PEParser::IsMemoryNotNull(BYTE* pData, int dataSize) {
}
void PEParser::GetPESectionData(DWORD_PTR offset, PEFileSection& peFileSection) {
const DWORD maxReadSize = 100;
DWORD currentReadSize;
DWORD valuesFound = 0;
DWORD readSize = 0;
DWORD_PTR currentOffset = 0;
BYTE data[maxReadSize] = { 0 };
peFileSection._dataSize = 0;
peFileSection._pData = nullptr;
readSize = peFileSection._normalSize;
const DWORD readSize = peFileSection._normalSize;
if (!readSize || !offset) {
// section without data is valid
return;
}
if (readSize <= maxReadSize) {
peFileSection._dataSize = readSize;
peFileSection._normalSize = readSize;
peFileSection._pData = new BYTE[peFileSection._dataSize];
memcpy(peFileSection._pData, _address + offset, peFileSection._dataSize);
const BYTE* sectionData = _address + offset;
DWORD lastNonZero = readSize;
while (lastNonZero > 0 && sectionData[lastNonZero - 1] == 0) {
--lastNonZero;
}
if (!lastNonZero) {
return;
}
currentReadSize = readSize % maxReadSize;
if (!currentReadSize) {
currentReadSize = maxReadSize;
}
currentOffset = offset + readSize - currentReadSize;
while (currentOffset >= offset) {
ZeroMemory(data, currentReadSize);
memcpy(data, _address + currentOffset, currentReadSize);
valuesFound = IsMemoryNotNull(data, currentReadSize);
if (valuesFound) {
// found some real code
currentOffset += valuesFound;
if (offset < currentOffset) {
// real size
peFileSection._dataSize = (DWORD)(currentOffset - offset);
peFileSection._dataSize += sizeof(DWORD);
if (peFileSection._normalSize < peFileSection._dataSize) {
peFileSection._dataSize = peFileSection._normalSize;
}
}
break;
}
currentReadSize = maxReadSize;
currentOffset -= currentReadSize;
}
if (peFileSection._dataSize) {
peFileSection._pData = new BYTE[peFileSection._dataSize];
memcpy(peFileSection._pData, _address + offset, peFileSection._dataSize);
peFileSection._dataSize = (std::min)(readSize, lastNonZero + static_cast<DWORD>(sizeof(DWORD)));
peFileSection._pData = new BYTE[peFileSection._dataSize];
if (peFileSection._pData) {
memcpy(peFileSection._pData, sectionData, peFileSection._dataSize);
}
}
@@ -1011,16 +997,20 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
bool ret = true;
DWORD fileOffset = 0, writeSize = 0;
HANDLE outputFile = INVALID_HANDLE_VALUE;
const WORD sectionCount = static_cast<WORD>(GetSectionCount());
do
{
ret = OpenWriteFileHandle(pNewFile);
if (!ret)
outputFile = pNewFile ? ::CreateFile(pNewFile, GENERIC_WRITE, FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0) : _hFile;
ret = outputFile != INVALID_HANDLE_VALUE;
if (!ret) {
break;
}
writeSize = sizeof(IMAGE_DOS_HEADER);
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, GetBaseAddress())) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, GetBaseAddress())) {
ret = false;
break;
}
@@ -1035,7 +1025,7 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
BYTE* pDosStub = GetDosStub();
if (pDosStub) {
writeSize = dosStubSize;
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, pDosStub)) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, pDosStub)) {
ret = false;
break;
}
@@ -1045,14 +1035,14 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
if (!IsPe64()) {
writeSize = sizeof(IMAGE_NT_HEADERS32);
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, &_ntHeader32Copy)) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, &_ntHeader32Copy)) {
ret = false;
break;
}
}
else {
writeSize = sizeof(IMAGE_NT_HEADERS64);
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, &_ntHeader64Copy)) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, &_ntHeader64Copy)) {
ret = false;
break;
}
@@ -1063,8 +1053,8 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
writeSize = sizeof(IMAGE_SECTION_HEADER);
for (WORD i = 0; i < GetSectionCount(); i++) {
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, &_PESections[i]._sectionHeader)) {
for (WORD i = 0; i < sectionCount; i++) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, &_PESections[i]._sectionHeader)) {
ret = false;
break;
}
@@ -1072,7 +1062,7 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
}
for (WORD i = 0; i < GetSectionCount(); i++) {
for (WORD i = 0; i < sectionCount; i++) {
if (!_PESections[i]._sectionHeader.PointerToRawData)
continue;
@@ -1080,7 +1070,7 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
// padding
writeSize = _PESections[i]._sectionHeader.PointerToRawData - fileOffset;
if (!WriteZeroMemoryToFile(_hFile, fileOffset, writeSize)) {
if (!WriteZeroMemoryToFile(outputFile, fileOffset, writeSize)) {
ret = false;
break;
}
@@ -1090,7 +1080,7 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
writeSize = _PESections[i]._dataSize;
if (writeSize) {
if (!WriteMemoryToFile(_hFile, _PESections[i]._sectionHeader.PointerToRawData,
if (!WriteMemoryToFile(outputFile, _PESections[i]._sectionHeader.PointerToRawData,
writeSize, _PESections[i]._pData)) {
ret = false;
break;
@@ -1100,7 +1090,7 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
if (_PESections[i]._dataSize < _PESections[i]._sectionHeader.SizeOfRawData) {
// padding
writeSize = _PESections[i]._sectionHeader.SizeOfRawData - _PESections[i]._dataSize;
if (!WriteZeroMemoryToFile(_hFile, fileOffset, writeSize)) {
if (!WriteZeroMemoryToFile(outputFile, fileOffset, writeSize)) {
ret = false;
break;
}
@@ -1112,13 +1102,13 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
DWORD overlayOffset = GetSectionHeaderBasedFileSize();
LARGE_INTEGER fileSize = GetFileSize();
if (fileSize.QuadPart > 0) {
DWORD overlaySize = fileSize.QuadPart - overlayOffset;
if (_isFileMap && fileSize.QuadPart > overlayOffset) {
DWORD overlaySize = static_cast<DWORD>(fileSize.QuadPart - overlayOffset);
if (overlaySize) {
writeSize = overlaySize;
BYTE* pOverlayData = GetFileAddress(overlayOffset);
if (!WriteMemoryToFile(_hFile, fileOffset, writeSize, pOverlayData)) {
if (!WriteMemoryToFile(outputFile, fileOffset, writeSize, pOverlayData)) {
ret = false;
break;
}
@@ -1126,26 +1116,29 @@ bool PEParser::SavePEFileToDisk(const WCHAR* pNewFile) {
}
}
SetEndOfFile(_hFile);
SetEndOfFile(outputFile);
} while (false);
if (_hFile != INVALID_HANDLE_VALUE) {
CloseHandle(_hFile);
_hFile = INVALID_HANDLE_VALUE;
if (outputFile != INVALID_HANDLE_VALUE && outputFile != _hFile) {
CloseHandle(outputFile);
}
return ret;
}
bool PEParser::WriteZeroMemoryToFile(HANDLE hFile, DWORD fileOffset, DWORD size) {
bool ret = false;
PVOID pZeroMemory = calloc(size, 1);
constexpr DWORD kZeroChunkSize = 64 * 1024;
BYTE zeroBuffer[kZeroChunkSize] = {};
if (pZeroMemory) {
ret = WriteMemoryToFile(hFile, fileOffset, size, pZeroMemory);
free(pZeroMemory);
while (size) {
const DWORD chunkSize = (std::min)(size, kZeroChunkSize);
if (!WriteMemoryToFile(hFile, fileOffset, chunkSize, zeroBuffer)) {
return false;
}
fileOffset += chunkSize;
size -= chunkSize;
}
return ret;
}
return true;
}
+3 -2
View File
@@ -168,7 +168,7 @@ class PEParser {
public:
explicit PEParser(const wchar_t* path,bool isScylla = false);
~PEParser();
PEParser(void* base);
PEParser(void* base, SIZE_T mappedSize = 0);
bool IsValid() const;
bool IsPe64() const;
@@ -278,6 +278,7 @@ protected:
private:
bool IsObjectPe64() const;
void CheckValidity();
void ReleaseSectionData();
//CString GetResourceName(void* data) const;
@@ -304,4 +305,4 @@ private:
bool _valid = false;
bool _importLib = false, _objectFile = false;
bool _isFileMap = true;
};
};
+13 -4
View File
@@ -64,15 +64,21 @@ ImagehlpSymbol::~ImagehlpSymbol() {
SymbolHandler::SymbolHandler(HANDLE hProcess, PCSTR searchPath,DWORD symOptions){
m_hProcess = hProcess;
if (m_hProcess != INVALID_HANDLE_VALUE && m_hProcess != ::GetCurrentProcess()) {
::SymSetOptions(symOptions);
_initialized = ::SymInitialize(m_hProcess, searchPath, TRUE);
}
}
SymbolHandler::~SymbolHandler() {
if (_initialized)
::SymCleanup(m_hProcess);
if (m_hProcess != ::GetCurrentProcess())
::CloseHandle(m_hProcess);
}
ULONG64 SymbolHandler::LoadSymbolsForModule(PCSTR imageName, PCSTR moduleName, DWORD64 baseAddress,DWORD dllSize) {
_address = SymLoadModuleEx(m_hProcess, nullptr, imageName, nullptr, baseAddress, dllSize, nullptr, 0);
_address = SymLoadModuleEx(m_hProcess, nullptr, imageName, moduleName, baseAddress, dllSize, nullptr, 0);
return _address;
}
@@ -219,10 +225,13 @@ BOOL SymbolHandler::Callback(ULONG code, ULONG64 data) {
}
std::unique_ptr<SymbolHandler> SymbolHandler::CreateForProcess(DWORD pid, PCSTR searchPath) {
auto hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
auto hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE, FALSE, pid);
if (!hProcess)
return nullptr;
return std::make_unique<SymbolHandler>(hProcess, searchPath);
auto handler = std::make_unique<SymbolHandler>(hProcess, searchPath);
if (!handler->_initialized)
return nullptr;
return handler;
}
ULONG SymbolHandler::GetStructSize(std::string name) {
@@ -292,4 +301,4 @@ DWORD SymbolHandler::GetBitFieldPos(std::string name, std::string fieldName) {
free(childrenParams);
return pos;
}
}
+2 -1
View File
@@ -213,5 +213,6 @@ private:
HANDLE m_hProcess{ INVALID_HANDLE_VALUE };
DWORD64 _address{ 0 };
bool _initialized{ false };
static inline bool _first = false;
};
};
+127 -130
View File
@@ -3,6 +3,31 @@
#include <PEParser.h>
#include "Helpers.h"
namespace {
DWORD_PTR GetPageSizeCached() {
static DWORD_PTR s_pageSize = [] {
SYSTEM_INFO si = {};
::GetSystemInfo(&si);
return static_cast<DWORD_PTR>(si.dwPageSize);
}();
return s_pageSize;
}
DWORD_PTR GetPageBaseCached(DWORD_PTR address) {
const auto pageSize = GetPageSizeCached();
return address & ~(pageSize - 1);
}
ImportModuleThunk* FindModuleThunkByRva(std::map<DWORD_PTR, ImportModuleThunk>& moduleMap, DWORD_PTR rva) {
auto it = moduleMap.upper_bound(rva);
if (it == moduleMap.begin()) {
return nullptr;
}
--it;
return &it->second;
}
}
void ApiReader::ReadApisFromModuleList() {
for (unsigned int i = 0; i < _moduleList.size(); i++) {
SetModulePriority(&_moduleList[i]);
@@ -319,34 +344,7 @@ bool ApiReader::AddFunctionToModuleList(ApiInfo* pApiFound, DWORD_PTR va, DWORD_
WORD ordinal, bool valid, bool suspect)
{
ImportThunk thunk;
ImportModuleThunk* pModuleThunk = nullptr;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iter;
if (_moduleThunkMap->size() > 1) {
iter = _moduleThunkMap->begin();
while (iter != _moduleThunkMap->end()) {
if (rva >= iter->second.m_FirstThunk) {
iter++;
if (iter == _moduleThunkMap->end()) {
iter--;
pModuleThunk = &iter->second;
break;
}
else if (rva < iter->second.m_FirstThunk) {
iter--;
pModuleThunk = &iter->second;
break;
}
}
else {
break;
}
}
}
else {
iter = _moduleThunkMap->begin();
pModuleThunk = &iter->second;
}
ImportModuleThunk* pModuleThunk = FindModuleThunkByRva(*_moduleThunkMap, rva);
if (!pModuleThunk) {
return false;
@@ -370,41 +368,37 @@ bool ApiReader::AddFunctionToModuleList(ApiInfo* pApiFound, DWORD_PTR va, DWORD_
bool ApiReader::AddNotFoundApiToModuleList(DWORD_PTR iat, DWORD_PTR apiAddress)
{
ImportThunk thunk;
ImportModuleThunk* pModuleThunk = nullptr;
std::map<DWORD_PTR, ImportModuleThunk>::iterator iter;
DWORD_PTR rva = iat - _targetImageBase;
ImportModuleThunk* pModuleThunk = nullptr;
auto next = _moduleThunkMap->upper_bound(rva);
if (_moduleThunkMap->size() > 0) {
iter = _moduleThunkMap->begin();
while (iter != _moduleThunkMap->end()) {
if (rva >= iter->second.m_FirstThunk) {
iter++;
if (iter == _moduleThunkMap->end()) {
iter--;
if (iter->second.m_ModuleName[0] == L'?') {
pModuleThunk = &iter->second;
}
else {
AddUnknownModuleToModuleList(rva);
pModuleThunk = &(_moduleThunkMap->find(rva)->second);
}
break;
}
else if (rva < iter->second.m_FirstThunk) {
iter--;
pModuleThunk = &iter->second;
break;
}
}
else {
break;
}
}
}
else {
if (next == _moduleThunkMap->begin()) {
AddUnknownModuleToModuleList(rva);
pModuleThunk = &(_moduleThunkMap->find(rva)->second);
}
else {
auto prev = next;
--prev;
if (next == _moduleThunkMap->end()) {
if (prev->second.m_ModuleName[0] == L'?') {
pModuleThunk = &prev->second;
}
else {
AddUnknownModuleToModuleList(rva);
pModuleThunk = &(_moduleThunkMap->find(rva)->second);
}
}
else {
pModuleThunk = &prev->second;
}
}
if (!pModuleThunk) {
if (_moduleThunkMap->empty()) {
AddUnknownModuleToModuleList(rva);
pModuleThunk = &(_moduleThunkMap->find(rva)->second);
}
}
if (!pModuleThunk) {
return false;
@@ -627,12 +621,10 @@ ApiInfo* ApiReader::GetApiByVirtualAddress(DWORD_PTR virtualAddress, bool* pIsSu
void ApiReader::ReadAndParseIAT(DWORD_PTR iat, DWORD size, std::map<DWORD_PTR, ImportModuleThunk>& moduleListNew)
{
_moduleThunkMap = &moduleListNew;
BYTE* pIAT = new BYTE[size];
if (ReadMemoryFromProcess(iat, size, pIAT)) {
ParseIAT(iat, pIAT, size);
std::unique_ptr<BYTE[]> pIAT(new BYTE[size]);
if (ReadMemoryFromProcess(iat, size, pIAT.get())) {
ParseIAT(iat, pIAT.get(), size);
}
delete[] pIAT;
}
void ApiReader::AddFoundApiToModuleList(DWORD_PTR iat, ApiInfo* pApiFound, bool isNewModule, bool isSuspect)
@@ -675,76 +667,81 @@ bool ApiReader::IsInvalidMemoryForIAT(DWORD_PTR address)
}
void ApiReader::ParseIAT(DWORD_PTR iat, BYTE* pIAT, SIZE_T size) {
ApiInfo* pApiFound = nullptr;
ModuleInfo* pModule = nullptr;
bool isSuspect = false;
int countApiFound = 0, countApiNotFound = 0;
DWORD_PTR* p64 = (DWORD_PTR*)pIAT;
DWORD* p32 = reinterpret_cast<DWORD*>(pIAT);
SIZE_T iatSize = 0;
DWORD pointerSize = 0;
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
if (isWow64) {
pointerSize = 4;
iatSize = size / pointerSize;
for (SIZE_T i = 0; i < iatSize; i++) {
if (!IsInvalidMemoryForIAT(p32[i])) {
if (p32[i] > _minApiAddress && p32[i] < _maxApiAddress) {
pApiFound = GetApiByVirtualAddress(p32[i], &isSuspect);
if (pApiFound != nullptr) {
countApiFound++;
if (pModule != pApiFound->pModule) {
pModule = pApiFound->pModule;
AddFoundApiToModuleList(iat + (DWORD_PTR)&p32[i] - (DWORD_PTR)pIAT, pApiFound, true, isSuspect);
}
else {
AddFoundApiToModuleList(iat + (DWORD_PTR)&p32[i] - (DWORD_PTR)pIAT, pApiFound, false, isSuspect);
}
}
else {
countApiNotFound++;
AddNotFoundApiToModuleList(iat + (DWORD_PTR)&p32[i] - (DWORD_PTR)pIAT, p32[i]);
}
}
else {
countApiNotFound++;
AddNotFoundApiToModuleList(iat + (DWORD_PTR)&p32[i] - (DWORD_PTR)pIAT, p32[i]);
}
}
}
}
else {
pointerSize = 8;
iatSize = size / pointerSize;
for (SIZE_T i = 0; i < iatSize; i++) {
if (!IsInvalidMemoryForIAT(p64[i])) {
if (p64[i] > _minApiAddress && p64[i] < _maxApiAddress) {
pApiFound = GetApiByVirtualAddress(p64[i], &isSuspect);
if (pApiFound != nullptr) {
countApiFound++;
if (pModule != pApiFound->pModule) {
pModule = pApiFound->pModule;
AddFoundApiToModuleList(iat + (DWORD_PTR)&p64[i] - (DWORD_PTR)pIAT, pApiFound, true, isSuspect);
}
else {
AddFoundApiToModuleList(iat + (DWORD_PTR)&p64[i] - (DWORD_PTR)pIAT, pApiFound, false, isSuspect);
}
}
else {
countApiNotFound++;
AddNotFoundApiToModuleList(iat + (DWORD_PTR)&p64[i] - (DWORD_PTR)pIAT, p64[i]);
}
}
else {
countApiNotFound++;
AddNotFoundApiToModuleList(iat + (DWORD_PTR)&p64[i] - (DWORD_PTR)pIAT, p64[i]);
}
}
}
}
const DWORD pointerSize = isWow64 ? sizeof(DWORD) : sizeof(DWORD_PTR);
const SIZE_T iatSize = size / pointerSize;
std::unordered_map<DWORD_PTR, bool> pageValidityCache;
pageValidityCache.reserve(iatSize);
struct ApiLookupResult {
ApiInfo* api{ nullptr };
bool suspect{ false };
};
std::unordered_map<DWORD_PTR, ApiLookupResult> apiLookupCache;
apiLookupCache.reserve(iatSize);
auto isInvalidAddress = [&](DWORD_PTR address) {
if (address == 0 || address == static_cast<DWORD_PTR>(-1)) {
return true;
}
const DWORD_PTR pageBase = GetPageBaseCached(address);
auto cacheIt = pageValidityCache.find(pageBase);
if (cacheIt != pageValidityCache.end()) {
return cacheIt->second;
}
MEMORY_BASIC_INFORMATION mbi = {};
if (!::VirtualQueryEx(_hProcess, reinterpret_cast<LPVOID>(address), &mbi, sizeof(mbi))) {
pageValidityCache.emplace(pageBase, false);
return false;
}
const bool invalid = !(mbi.State == MEM_COMMIT && IsPageAccessable(mbi.Protect));
const DWORD_PTR regionStart = reinterpret_cast<DWORD_PTR>(mbi.BaseAddress);
const DWORD_PTR regionEnd = regionStart + mbi.RegionSize;
const DWORD_PTR pageSize = GetPageSizeCached();
for (DWORD_PTR current = regionStart; current < regionEnd; current += pageSize) {
pageValidityCache.emplace(current, invalid);
}
return invalid;
};
auto getApiInfo = [&](DWORD_PTR apiAddress, bool& isSuspect) -> ApiInfo* {
auto [it, inserted] = apiLookupCache.emplace(apiAddress, ApiLookupResult{});
if (inserted) {
it->second.api = GetApiByVirtualAddress(apiAddress, &it->second.suspect);
}
isSuspect = it->second.suspect;
return it->second.api;
};
for (SIZE_T i = 0; i < iatSize; i++) {
const DWORD_PTR thunkAddress = iat + i * pointerSize;
const DWORD_PTR apiAddress = isWow64
? static_cast<DWORD_PTR>(reinterpret_cast<DWORD*>(pIAT)[i])
: reinterpret_cast<DWORD_PTR*>(pIAT)[i];
if (isInvalidAddress(apiAddress)) {
continue;
}
bool isSuspect = false;
ApiInfo* pApiFound = nullptr;
if (apiAddress > _minApiAddress && apiAddress < _maxApiAddress) {
pApiFound = getApiInfo(apiAddress, isSuspect);
}
if (pApiFound != nullptr) {
const bool isNewModule = pModule != pApiFound->pModule;
pModule = pApiFound->pModule;
AddFoundApiToModuleList(thunkAddress, pApiFound, isNewModule, isSuspect);
}
else {
AddNotFoundApiToModuleList(thunkAddress, apiAddress);
}
}
}
void ApiReader::AddApi(const char* pName, WORD hint, WORD ordinal,
@@ -866,4 +863,4 @@ void ApiReader::AddUnknownModuleToModuleList(DWORD_PTR firstThunk) {
wcscpy_s(thunk.m_ModuleName, L"?");
_moduleThunkMap->insert(std::pair<DWORD_PTR, ImportModuleThunk>(firstThunk, thunk));
}
}
+23 -48
View File
@@ -1,6 +1,14 @@
#include "stdafx.h"
#include "IATSearcher.h"
namespace {
DWORD GetTargetPointerSize(HANDLE hProcess) {
BOOL isWow64 = FALSE;
::IsWow64Process(hProcess, &isWow64);
return isWow64 ? sizeof(DWORD) : sizeof(DWORD_PTR);
}
}
bool IATSearcher::SearchImportAddressTableInProcess(DWORD_PTR startAddress, DWORD_PTR* pIAT, DWORD* pSize, bool advance) {
DWORD_PTR addressInIAT = 0;
*pIAT = 0;
@@ -24,6 +32,7 @@ bool IATSearcher::FindIATAdvanced(DWORD_PTR startAddress, DWORD_PTR* pIAT, DWORD
std::unique_ptr<BYTE[]> buffer;
DWORD_PTR baseAddress;
SIZE_T memorySize;
const DWORD pointerSize = GetTargetPointerSize(_hProcess);
FindExecutableMemoryPagesByStartAddress(startAddress, &baseAddress, &memorySize);
@@ -67,16 +76,6 @@ bool IATSearcher::FindIATAdvanced(DWORD_PTR startAddress, DWORD_PTR* pIAT, DWORD
*pIAT = start;
iter = iatPointers.end();
DWORD_PTR end = *(--iter);
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
DWORD pointerSize = 0;
if (isWow64) {
pointerSize = 4;
}
else {
pointerSize = 8;
}
*pSize = (DWORD)(end - start + pointerSize);
if (*pSize > (2000000 * pointerSize)) {
@@ -141,6 +140,8 @@ DWORD_PTR IATSearcher::FindNextFunctionAddress() {
}
DWORD_PTR IATSearcher::FindIATPointer() {
const bool is32BitTarget = GetTargetPointerSize(_hProcess) == sizeof(DWORD);
for (unsigned int i = 0; i < _instCount; i++) {
if (_insts[i].flags == FLAG_NOT_DECODABLE) {
continue;
@@ -149,9 +150,7 @@ DWORD_PTR IATSearcher::FindIATPointer() {
if (META_GET_FC(_insts[i].meta) == FC_CALL
|| META_GET_FC(_insts[i].meta) == FC_UNC_BRANCH) {
if (_insts[i].size >= 5) {
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
if (isWow64) {
if (is32BitTarget) {
if (_insts[i].ops[0].type == O_DISP) {
// jmp dword ptr || call dword ptr
return _insts[i].disp;
@@ -172,15 +171,7 @@ DWORD_PTR IATSearcher::FindIATPointer() {
bool IATSearcher::IsIATPointerValid(DWORD_PTR iatPointer, bool checkRedirects) {
DWORD_PTR apiAddress = 0;
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
DWORD pointerSize = 0;
if (isWow64) {
pointerSize = 4;
}
else {
pointerSize = 8;
}
const DWORD pointerSize = GetTargetPointerSize(_hProcess);
if (!ReadMemoryFromProcess(iatPointer, pointerSize, &apiAddress)) {
return false;
}
@@ -212,23 +203,11 @@ bool IATSearcher::FindIATStartAndSize(DWORD_PTR address, DWORD_PTR* pIAT, DWORD*
if (!baseAddress)
return false;
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
DWORD pointerSize = 0;
if (isWow64) {
pointerSize = 4;
}
else {
pointerSize = 8;
}
size_t size = baseSize * pointerSize * 3;
buffer = std::make_unique<BYTE[]>(size);
buffer = std::make_unique<BYTE[]>(baseSize);
if (!buffer)
return false;
ZeroMemory(buffer.get(), size);
if (!ReadMemoryFromProcess(baseAddress, baseSize, buffer.get())) {
return false;
}
@@ -240,10 +219,7 @@ bool IATSearcher::FindIATStartAndSize(DWORD_PTR address, DWORD_PTR* pIAT, DWORD*
}
DWORD_PTR IATSearcher::FindIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR startAddress, BYTE* pData) {
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
DWORD pointerSize = 0;
if (isWow64) {
if (GetTargetPointerSize(_hProcess) == sizeof(DWORD)) {
DWORD* p32 = nullptr;
p32 = (DWORD*)((startAddress - baseAddress) + (DWORD_PTR)pData);
@@ -298,13 +274,12 @@ DWORD_PTR IATSearcher::FindIATStartAddress(DWORD_PTR baseAddress, DWORD_PTR star
DWORD IATSearcher::FindIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE* pData, DWORD dataSize) {
PBYTE* pIATAddress = nullptr;
pIATAddress = (PBYTE*)((iatAddress - baseAddress) + (DWORD_PTR)pData);
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
DWORD* p32 = (DWORD*)pIATAddress;
DWORD_PTR* p64 = (DWORD_PTR*)pIATAddress;
const BYTE* end = pData + dataSize;
if (isWow64) {
while ((DWORD_PTR)p32 < ((DWORD_PTR)pData + dataSize - 1)) {
if (GetTargetPointerSize(_hProcess) == sizeof(DWORD)) {
while (reinterpret_cast<const BYTE*>(p32 + 2) < end) {
if (IsInvalidMemoryForIAT(*p32)) {
if (IsInvalidMemoryForIAT(*(p32 + 1))) {
DWORD_PTR apiAddress = *(p32 + 2);
@@ -317,7 +292,7 @@ DWORD IATSearcher::FindIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE
}
}
else {
while ((DWORD_PTR)p64 < ((DWORD_PTR)pData + dataSize - 1)) {
while (reinterpret_cast<const BYTE*>(p64 + 2) < end) {
if (IsInvalidMemoryForIAT(*p64)) {
if (IsInvalidMemoryForIAT(*(p64 + 1))) {
DWORD_PTR apiAddress = *(p64 + 2);
@@ -334,14 +309,14 @@ DWORD IATSearcher::FindIATSize(DWORD_PTR baseAddress, DWORD_PTR iatAddress, BYTE
}
void IATSearcher::FindIATPointers(std::set<DWORD_PTR>& iatPointers) {
const bool is32BitTarget = GetTargetPointerSize(_hProcess) == sizeof(DWORD);
for (unsigned int i = 0; i < _instCount; i++) {
if (_insts[i].flags != FLAG_NOT_DECODABLE) {
uint16_t fc = META_GET_FC(_insts[i].meta);
if (fc == FC_CALL || fc == FC_UNC_BRANCH) {
if (_insts[i].size >= 5) {
BOOL isWow64 = FALSE;
::IsWow64Process(_hProcess, &isWow64);
if (isWow64) {
if (is32BitTarget) {
if (_insts[i].ops[0].type == O_DISP) {
iatPointers.insert((DWORD_PTR)_insts[i].disp);
}
@@ -521,4 +496,4 @@ void IATSearcher::GetMemoryBaseAndSizeForIAT(DWORD_PTR address, DWORD_PTR* pBase
}
}
}
}
}
+34 -59
View File
@@ -3,6 +3,17 @@
#include "ImportsHandling.h"
#include "Architecture.h"
namespace {
ImportModuleThunk* FindModuleThunkByRva(std::map<DWORD_PTR, ImportModuleThunk>& moduleMap, DWORD_PTR rva) {
auto it = moduleMap.upper_bound(rva);
if (it == moduleMap.begin()) {
return nullptr;
}
--it;
return &it->second;
}
}
void ImportsHandling::SetItemData(CTreeItem item, const TreeItemData* pData)
{
ItemDataMap[item] = *pData;
@@ -147,41 +158,27 @@ bool ImportsHandling::AddNotFoundApiToModuleList(const ImportThunk* pApiNotFound
ImportModuleThunk* pModule = nullptr;
DWORD_PTR rva = pApiNotFound->m_RVA;
if (m_ModuleMapNew.size() > 0) {
auto it_module = m_ModuleMapNew.begin();
while (it_module != m_ModuleMapNew.end()) {
if (rva >= it_module->second.m_FirstThunk) {
it_module++;
if (it_module == m_ModuleMapNew.end()) {
it_module--;
//new unknown module
if (it_module->second.m_ModuleName[0] == L'?')
{
pModule = &(it_module->second);
}
else
{
AddUnknownModuleToModuleList(pApiNotFound->m_RVA);
pModule = &(m_ModuleMapNew.find(rva)->second);
}
break;
}
else if (rva < it_module->second.m_FirstThunk) {
it_module--;
pModule = &(it_module->second);
break;
}
}
else {
break;
}
}
}
else {
auto next = m_ModuleMapNew.upper_bound(rva);
if (next == m_ModuleMapNew.begin()) {
AddUnknownModuleToModuleList(pApiNotFound->m_RVA);
pModule = &(m_ModuleMapNew.find(rva)->second);
}
else {
auto prev = next;
--prev;
if (next == m_ModuleMapNew.end()) {
if (prev->second.m_ModuleName[0] == L'?') {
pModule = &(prev->second);
}
else {
AddUnknownModuleToModuleList(pApiNotFound->m_RVA);
pModule = &(m_ModuleMapNew.find(rva)->second);
}
}
else {
pModule = &(prev->second);
}
}
if (!pModule) {
return false;
@@ -207,33 +204,8 @@ bool ImportsHandling::AddNotFoundApiToModuleList(const ImportThunk* pApiNotFound
bool ImportsHandling::AddFunctionToModuleList(const ImportThunk* pApiFound)
{
ImportThunk import;
ImportModuleThunk* pModule = nullptr;
DWORD_PTR rva = pApiFound->m_RVA;
auto it_module = m_ModuleMapNew.begin();
if (m_ModuleMapNew.size() > 1) {
while (it_module != m_ModuleMapNew.end()) {
if (rva >= it_module->second.m_FirstThunk) {
it_module++;
if (it_module == m_ModuleMapNew.end()) {
it_module--;
pModule = &(it_module->second);
break;
}
else if (rva < it_module->second.m_FirstThunk) {
it_module--;
pModule = &(it_module->second);
break;
}
}
else {
break;
}
}
}
else {
it_module = m_ModuleMapNew.begin();
pModule = &(it_module->second);
}
ImportModuleThunk* pModule = FindModuleThunkByRva(m_ModuleMapNew, rva);
if (!pModule) {
return false;
@@ -334,6 +306,7 @@ void ImportsHandling::DisplayAllImports()
std::map<DWORD_PTR, ImportModuleThunk>::iterator it_module;
std::map<DWORD_PTR, ImportThunk>::iterator it_import;
TreeImports.SetRedraw(FALSE);
TreeImports.DeleteAllItems();
ItemDataMap.clear();
TreeImports.SetImageList(TreeIcons);
@@ -357,6 +330,8 @@ void ImportsHandling::DisplayAllImports()
it_module++;
}
TreeImports.SetRedraw(TRUE);
TreeImports.Invalidate();
UpdateCounts();
}
@@ -570,7 +545,7 @@ void ImportsHandling::ScanAndFixModuleList()
it_module++;
}
m_ModuleMap = m_ModuleMapNew;
m_ModuleMap.swap(m_ModuleMapNew);
m_ModuleMapNew.clear();
}
+19 -3
View File
@@ -748,6 +748,7 @@ void CProcessInlineHookTable::Refresh() {
m_Items = GetItems();
m_ModuleTracker.EnumModules();
m_Modules = m_ModuleTracker.GetModules();
std::unordered_map<ULONG_PTR, bool> moduleArchCache;
m_Sys64Modules.clear();
m_Table.data.n = 0;
@@ -784,9 +785,24 @@ void CProcessInlineHookTable::Refresh() {
if (m != nullptr) {
moduleSize = m->ModuleSize;
moduleBase = (ULONG_PTR)m->Base;
std::wstring path = m->Path;
PEParser parser(path.c_str());
isX64Module = parser.IsPe64();
auto it = moduleArchCache.find(moduleBase);
if (it != moduleArchCache.end()) {
isX64Module = it->second;
}
else {
const SIZE_T headerSize = std::min<SIZE_T>(moduleSize, 0x4000);
if (headerSize != 0) {
std::vector<BYTE> moduleHeader(headerSize);
SIZE_T bytesRead = 0;
if (::ReadProcessMemory(m_hProcess, m->Base, moduleHeader.data(), headerSize, &bytesRead) && bytesRead == headerSize) {
PEParser parser(moduleHeader.data(), headerSize);
if (parser.IsValid()) {
isX64Module = parser.IsPe64();
}
}
}
moduleArchCache.emplace(moduleBase, isX64Module);
}
//uint32_t image_size = parser.GetImageSize();
//local_image_base = ::VirtualAlloc(nullptr, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+22 -37
View File
@@ -9,6 +9,7 @@
#include "PickDLLDlg.h"
#include "TreeImportExport.h"
#include <Helpers.h>
#include <memory>
CScyllaDlg::CScyllaDlg(const WinSys::ProcessManager& pm, ProcessInfoEx& px)
@@ -207,7 +208,7 @@ void CScyllaDlg::IATAutoSearchActionHandler() {
SetDialogIATAddressAndSize(addressIAT, sizeIAT);
}
else if (addressIAT == 0 && addressIATAdv != 0) {
SetDialogIATAddressAndSize(addressIATAdv, sizeIAT);
SetDialogIATAddressAndSize(addressIATAdv, sizeIATAdv);
}
else if (addressIAT != 0 && addressIATAdv != 0) {
if (addressIAT != addressIATAdv || sizeIAT != sizeIATAdv) {
@@ -284,51 +285,49 @@ void CScyllaDlg::OnDump(UINT uNotifyCode, int nID, CWindow wndCtl) {
void CScyllaDlg::DumpHandler() {
WCHAR filePath[MAX_PATH] = { 0 };
WCHAR defaultFileName[MAX_PATH] = { 0 };
const WCHAR* pFileFilter;
const WCHAR* pDefExtension;
const bool isModuleDump = ProcessAccessHelper::_pSelectedModule != nullptr;
const WCHAR* pFileFilter = isModuleDump ? s_FilterDll : s_FilterExe;
const WCHAR* pDefExtension = isModuleDump ? L"dll" : L"exe";
DWORD_PTR modBase = 0;
SIZE_T modSize = 0;
DWORD_PTR entryPoint = 0;
WCHAR fileName[MAX_PATH] = { 0 };
if (ProcessAccessHelper::_pSelectedModule) {
pFileFilter = s_FilterDll;
pDefExtension = L"dll";
}
else {
pFileFilter = s_FilterExe;
pDefExtension = L"exe";
}
GetCurrentModulePath(_text, _countof(_text));
GetCurrentDefaultDumpFilename(defaultFileName, _countof(defaultFileName));
if (ShowFileDialog(filePath, true, defaultFileName, pFileFilter, pDefExtension, _text)) {
entryPoint = _oepAddress.GetValue();
if (ProcessAccessHelper::_pSelectedModule) {
if (isModuleDump) {
modBase = ProcessAccessHelper::_pSelectedModule->_modBaseAddr;
wcscpy_s(fileName, ProcessAccessHelper::_pSelectedModule->_fullPath);
modSize = ProcessAccessHelper::_pSelectedModule->_modBaseSize;
}
else {
modBase = ProcessAccessHelper::_targetImageBase;
wcscpy_s(fileName, m_px.GetExecutablePath().c_str());
modSize = ProcessAccessHelper::_targetSizeOfImage;
}
void* pImageBase = new BYTE[modSize];
if (!modBase || !modSize) {
MessageBox(L"Invalid module range.", L"Failure", MB_ICONERROR);
return;
}
ProcessAccessHelper::ReadMemoryFromProcess(modBase, modSize, pImageBase);
auto imageBuffer = std::make_unique<BYTE[]>(modSize);
if (!ProcessAccessHelper::ReadMemoryFromProcess(modBase, modSize, imageBuffer.get()) &&
!ProcessAccessHelper::ReadMemoryPartlyFromProcess(modBase, modSize, imageBuffer.get())) {
MessageBox(L"Cannot read image from process memory.", L"Failure", MB_ICONERROR);
return;
}
PEParser parser(pImageBase);
PEParser parser(imageBuffer.get(), modSize);
if (parser.IsValid()) {
bool success = parser.DumpProcess(modBase, entryPoint, filePath);
if (!success) {
MessageBox(L"Cannot dump image.", L"Failure", MB_ICONERROR);
}
}
delete[] pImageBase;
else {
MessageBox(L"Invalid PE image in process memory.", L"Failure", MB_ICONERROR);
}
}
}
@@ -422,18 +421,7 @@ void CScyllaDlg::FixDumpHandler() {
WCHAR newFilePath[MAX_PATH] = { 0 };
WCHAR selectedFilePath[MAX_PATH] = { 0 };
const WCHAR* pFileFilter = nullptr;
DWORD_PTR modBase = 0;
DWORD_PTR entryPoint = _oepAddress.GetValue();
if (ProcessAccessHelper::_pSelectedModule) {
modBase = ProcessAccessHelper::_pSelectedModule->_modBaseAddr;
pFileFilter = s_FilterDll;
}
else {
modBase = ProcessAccessHelper::_targetImageBase;
pFileFilter = s_FilterExe;
}
const WCHAR* pFileFilter = ProcessAccessHelper::_pSelectedModule ? s_FilterDll : s_FilterExe;
GetCurrentModulePath(_text, _countof(_text));
if (ShowFileDialog(selectedFilePath, false, nullptr, pFileFilter, nullptr, _text)) {
@@ -464,13 +452,10 @@ void CScyllaDlg::OnPERebuild(UINT uNotifyCode, int nID, CWindow wndCtl) {
}
void CScyllaDlg::PERebuildHandler() {
DWORD newSize = 0;
WCHAR selectedFilePath[MAX_PATH] = { 0 };
GetCurrentModulePath(_text, _countof(_text));
if (ShowFileDialog(selectedFilePath, false, nullptr, s_FilterExeDll, nullptr, _text)) {
DWORD fileSize = ProcessAccessHelper::GetFileSize(selectedFilePath);
PEParser parser(selectedFilePath, true);
if (!parser.IsValid()) {
@@ -738,7 +723,7 @@ void CScyllaDlg::LoadTreeHandler() {
}
else {
swprintf_s(_text, L"Are you sure? Replace the OEP, IAT, and IAT size with %p %p %x",
swprintf_s(_text, L"Are you sure? Replace the OEP, IAT, and IAT size with " PRINTF_DWORD_PTR_FULL L" " PRINTF_DWORD_PTR_FULL L" %x",
oep, iat, iatSize);
int result = MessageBox(_text, L"Confirmation", MB_YESNO | MB_ICONQUESTION);