mirror of
https://github.com/jdu2600/Get-InjectedThreadEx
synced 2026-06-08 14:59:49 +00:00
114 lines
5.0 KiB
C++
114 lines
5.0 KiB
C++
#include "Get-InjectedThreadEx.h"
|
|
|
|
BOOL IsExecutable(const MEMORY_BASIC_INFORMATION& mbi) {
|
|
constexpr auto PAGE_EXECUTE_ANY = PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
|
return MEM_COMMIT == mbi.State && 0 != (mbi.Protect & PAGE_EXECUTE_ANY);
|
|
}
|
|
|
|
BOOL ReadProcessMemorySafely(HANDLE hProcess, PVOID address, std::string& buffer, const MEMORY_BASIC_INFORMATION& mbi) {
|
|
if (MEM_COMMIT != mbi.State || 0 != (mbi.Protect & PAGE_GUARD))
|
|
return FALSE;
|
|
// TODO(jdu) NEXT handle reads split over multiple regions
|
|
return ReadProcessMemory(hProcess, address, buffer.data(), buffer.size(), NULL);
|
|
}
|
|
|
|
BOOL ReadProcessMemorySafely(HANDLE hProcess, PVOID address, std::string& buffer) {
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
if(!VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)))
|
|
return FALSE;
|
|
return ReadProcessMemorySafely(hProcess, address, buffer, mbi);
|
|
}
|
|
|
|
BOOL ReadProcessMemorySafely(HANDLE hProcess, PVOID address, PDWORD64 buffer) {
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
if (!VirtualQueryEx(hProcess, address, &mbi, sizeof(mbi)))
|
|
return FALSE;
|
|
auto b = MEM_COMMIT != mbi.State;
|
|
auto b2 = 0 != (mbi.Protect & PAGE_GUARD);
|
|
auto b3 = (MEM_COMMIT != mbi.State || 0 != (mbi.Protect & PAGE_GUARD));
|
|
if (MEM_COMMIT != mbi.State || 0 != (mbi.Protect & PAGE_GUARD))
|
|
return FALSE;
|
|
return ReadProcessMemory(hProcess, address, buffer, sizeof(DWORD64), NULL);
|
|
}
|
|
|
|
BOOL GetMappedFileNameAsDosPath(HANDLE hProcess, PVOID address, std::wstring& buffer) {
|
|
|
|
// Cache #1 - the mapping of shared image allocations to DOS paths
|
|
const auto bIsSharedDll = InSystemImageRange(address);
|
|
const auto allocationBase = (ULONG_PTR)address & ~0xFFFFull;
|
|
static std::unordered_map<ULONG_PTR, std::wstring> s_DosPathCache;
|
|
if (bIsSharedDll) {
|
|
const auto it = s_DosPathCache.find(allocationBase);
|
|
if (it != s_DosPathCache.end()) {
|
|
buffer = it->second;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Cache #2 - the mapping from Device prefixes to Dos prefixes
|
|
static std::unordered_map<std::wstring, std::wstring> s_Device2DosPrefixMap;
|
|
if (s_Device2DosPrefixMap.empty()) {
|
|
wchar_t drive[3] = L"A:";
|
|
for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
|
|
std::wstring deviceName;
|
|
deviceName.resize(MAX_PATH);
|
|
if (!QueryDosDeviceW(drive, deviceName.data(), (DWORD)deviceName.size())) {
|
|
const auto dwError = GetLastError();
|
|
if (ERROR_FILE_NOT_FOUND != dwError)
|
|
LogError("QueryDosDeviceW(%S) failed with %d\n", drive, dwError);
|
|
continue;
|
|
}
|
|
deviceName.resize(wcslen(deviceName.c_str()));
|
|
s_Device2DosPrefixMap.insert(std::make_pair(deviceName, std::wstring(drive)));
|
|
}
|
|
}
|
|
|
|
buffer.clear();
|
|
buffer.resize(MAX_PATH);
|
|
|
|
// Note - K32GetMappedFileName returns the device path such as \Device\Harddisk0\Windows\System32\ntdll.dll
|
|
auto nBytesReturned = K32GetMappedFileNameW(hProcess, address, buffer.data(), (DWORD)buffer.size());
|
|
if (MAX_PATH == nBytesReturned) {
|
|
buffer.resize(MAX_LONG_PATH);
|
|
nBytesReturned = K32GetMappedFileNameW(hProcess, address, buffer.data(), (DWORD)buffer.size());
|
|
if (MAX_LONG_PATH == nBytesReturned)
|
|
LogError("K32GetMappedFileNameW(%p) exceeded maximum long path - %S\n", address, buffer.substr(0, MAX_PATH).c_str());
|
|
}
|
|
|
|
if (0 == nBytesReturned)
|
|
return FALSE;
|
|
|
|
// We have a device path - now convert it to a DOS path
|
|
constexpr auto DEVICE_PREFIX = L"\\Device\\";
|
|
if (buffer.length() < sizeof(DEVICE_PREFIX) || 0 != _wcsnicmp(buffer.c_str(), DEVICE_PREFIX, sizeof(DEVICE_PREFIX))) {
|
|
LogError("K32GetMappedFileNameW(%p) did not return device path - %S\n", address, buffer.substr(0, MAX_PATH).c_str());
|
|
return TRUE; // best effort - return what we have
|
|
}
|
|
|
|
// Loopkup DOS prefix of "\device\<name>" component in our cached mapping
|
|
const auto pos = buffer.find(L'\\', std::char_traits<WCHAR>::length(DEVICE_PREFIX));
|
|
const auto devicePrefixLength = (std::wstring::npos == pos) ? buffer.length() : pos;
|
|
const auto device2DosPrefixMapping = s_Device2DosPrefixMap.find(buffer.substr(0, devicePrefixLength));
|
|
if (s_Device2DosPrefixMap.end() == device2DosPrefixMapping) {
|
|
LogError("Could not resolve device prefix to DOS drive letter - %S\n", buffer.substr(0, MAX_PATH).c_str());
|
|
return TRUE; // best effort - return what we have
|
|
}
|
|
|
|
buffer = device2DosPrefixMapping->second + buffer.substr(devicePrefixLength);
|
|
buffer.resize(wcslen(buffer.c_str()));
|
|
|
|
// Update our path cache
|
|
if (nBytesReturned && bIsSharedDll)
|
|
s_DosPathCache.insert(std::make_pair(allocationBase, buffer));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
std::string ToHex(std::string bytes) {
|
|
std::stringstream hexBytes;
|
|
hexBytes << std::hex << std::setfill('0');
|
|
for (size_t i = 0; i < bytes.length(); i++) {
|
|
hexBytes << std::setw(2) << (DWORD)(BYTE)bytes[i];
|
|
}
|
|
return hexBytes.str();
|
|
} |