mirror of https://github.com/x64dbg/TitanEngine
964 lines
26 KiB
C++
964 lines
26 KiB
C++
#include "stdafx.h"
|
|
#include "ProcessAccessHelp.h"
|
|
#include "DeviceNameResolver.h"
|
|
#include <Psapi.h>
|
|
#include "PeParser.h"
|
|
#include "NativeWinApi.h"
|
|
|
|
HANDLE ProcessAccessHelp::hProcess = 0;
|
|
|
|
ModuleInfo* ProcessAccessHelp::selectedModule;
|
|
DWORD_PTR ProcessAccessHelp::targetImageBase = 0;
|
|
DWORD_PTR ProcessAccessHelp::targetSizeOfImage = 0;
|
|
DWORD_PTR ProcessAccessHelp::maxValidAddress = 0;
|
|
|
|
std::vector<ModuleInfo> ProcessAccessHelp::moduleList; //target process module list
|
|
std::vector<ModuleInfo> ProcessAccessHelp::ownModuleList; //own module list
|
|
|
|
_DInst ProcessAccessHelp::decomposerResult[MAX_INSTRUCTIONS];
|
|
unsigned int ProcessAccessHelp::decomposerInstructionsCount = 0;
|
|
_CodeInfo ProcessAccessHelp::decomposerCi = {0};
|
|
|
|
_DecodedInst ProcessAccessHelp::decodedInstructions[MAX_INSTRUCTIONS];
|
|
unsigned int ProcessAccessHelp::decodedInstructionsCount = 0;
|
|
|
|
BYTE ProcessAccessHelp::fileHeaderFromDisk[PE_HEADER_BYTES_COUNT];
|
|
|
|
//#define DEBUG_COMMENTS
|
|
|
|
bool ProcessAccessHelp::openProcessHandle(DWORD dwPID)
|
|
{
|
|
if(dwPID > 0)
|
|
{
|
|
if(hProcess)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"openProcessHandle :: There is already a process handle, HANDLE %X", hProcess);
|
|
#endif
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
//hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE, 0, dwPID);
|
|
//if (!NT_SUCCESS(NativeWinApi::NtOpenProcess(&hProcess,PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE,&ObjectAttributes, &cid)))
|
|
|
|
hProcess = NativeOpenProcess(PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_SUSPEND_RESUME | PROCESS_TERMINATE, dwPID);
|
|
|
|
if(hProcess)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"openProcessHandle :: Failed to open handle, PID %X", dwPID);
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"openProcessHandle :: Wrong PID, PID %X", dwPID);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
HANDLE ProcessAccessHelp::NativeOpenProcess(DWORD dwDesiredAccess, DWORD dwProcessId)
|
|
{
|
|
HANDLE hProcess = 0;
|
|
CLIENT_ID cid = {0};
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS ntStatus = 0;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, 0, 0, 0, 0);
|
|
cid.UniqueProcess = (HANDLE)(DWORD_PTR)dwProcessId;
|
|
|
|
ntStatus = NativeWinApi::NtOpenProcess(&hProcess, dwDesiredAccess, &ObjectAttributes, &cid);
|
|
|
|
if(NT_SUCCESS(ntStatus))
|
|
{
|
|
return hProcess;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"NativeOpenProcess :: Failed to open handle, PID %X Error 0x%X", dwProcessId, NativeWinApi::RtlNtStatusToDosError(ntStatus));
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void ProcessAccessHelp::closeProcessHandle()
|
|
{
|
|
if(hProcess)
|
|
{
|
|
CloseHandle(hProcess);
|
|
hProcess = 0;
|
|
}
|
|
|
|
moduleList.clear();
|
|
targetImageBase = 0;
|
|
selectedModule = 0;
|
|
}
|
|
|
|
bool ProcessAccessHelp::readMemoryPartlyFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
|
|
{
|
|
DWORD_PTR addressPart = 0;
|
|
DWORD_PTR readBytes = 0;
|
|
DWORD_PTR bytesToRead = 0;
|
|
MEMORY_BASIC_INFORMATION memBasic = {0};
|
|
bool returnValue = false;
|
|
|
|
if(!hProcess)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: hProcess == NULL");
|
|
#endif
|
|
return returnValue;
|
|
}
|
|
|
|
if(!readMemoryFromProcess(address, size, dataBuffer))
|
|
{
|
|
addressPart = address;
|
|
|
|
do
|
|
{
|
|
if(!VirtualQueryEx(ProcessAccessHelp::hProcess, (LPCVOID)addressPart, &memBasic, sizeof(memBasic)))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryPartlyFromProcess :: Error VirtualQueryEx %X %X err: %u", addressPart, size, GetLastError());
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
bytesToRead = memBasic.RegionSize;
|
|
|
|
if((readBytes + bytesToRead) > size)
|
|
{
|
|
bytesToRead = size - readBytes;
|
|
}
|
|
|
|
if(memBasic.State == MEM_COMMIT)
|
|
{
|
|
if(!readMemoryFromProcess(addressPart, bytesToRead, (LPVOID)((DWORD_PTR)dataBuffer + readBytes)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory((LPVOID)((DWORD_PTR)dataBuffer + readBytes), bytesToRead);
|
|
}
|
|
|
|
|
|
readBytes += bytesToRead;
|
|
|
|
addressPart += memBasic.RegionSize;
|
|
|
|
}
|
|
while(readBytes < size);
|
|
|
|
if(readBytes == size)
|
|
{
|
|
returnValue = true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
returnValue = true;
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
bool ProcessAccessHelp::writeMemoryToProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
|
|
{
|
|
SIZE_T lpNumberOfBytesWritten = 0;
|
|
if(!hProcess)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
|
|
return (WriteProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesWritten) != FALSE);
|
|
}
|
|
|
|
bool ProcessAccessHelp::readMemoryFromProcess(DWORD_PTR address, SIZE_T size, LPVOID dataBuffer)
|
|
{
|
|
SIZE_T lpNumberOfBytesRead = 0;
|
|
DWORD dwProtect = 0;
|
|
bool returnValue = false;
|
|
|
|
if(!hProcess)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: hProcess == NULL");
|
|
#endif
|
|
return returnValue;
|
|
}
|
|
|
|
if(!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
|
|
#endif
|
|
if(!VirtualProtectEx(hProcess, (LPVOID)address, size, PAGE_READWRITE, &dwProtect))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: Error VirtualProtectEx %X %X err: %u", address, size, GetLastError());
|
|
#endif
|
|
returnValue = false;
|
|
}
|
|
else
|
|
{
|
|
if(!ReadProcessMemory(hProcess, (LPVOID)address, dataBuffer, size, &lpNumberOfBytesRead))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory %X %X err: %u", address, size, GetLastError());
|
|
#endif
|
|
returnValue = false;
|
|
}
|
|
else
|
|
{
|
|
returnValue = true;
|
|
}
|
|
VirtualProtectEx(hProcess, (LPVOID)address, size, dwProtect, &dwProtect);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
returnValue = true;
|
|
}
|
|
|
|
if(returnValue)
|
|
{
|
|
if(size != lpNumberOfBytesRead)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromProcess :: Error ReadProcessMemory read %d bytes requested %d bytes", lpNumberOfBytesRead, size);
|
|
#endif
|
|
returnValue = false;
|
|
}
|
|
else
|
|
{
|
|
returnValue = true;
|
|
}
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
bool ProcessAccessHelp::decomposeMemory(BYTE* dataBuffer, SIZE_T bufferSize, DWORD_PTR startAddress)
|
|
{
|
|
|
|
ZeroMemory(&decomposerCi, sizeof(_CodeInfo));
|
|
decomposerCi.code = dataBuffer;
|
|
decomposerCi.codeLen = (int)bufferSize;
|
|
decomposerCi.dt = dt;
|
|
decomposerCi.codeOffset = startAddress;
|
|
|
|
decomposerInstructionsCount = 0;
|
|
|
|
if(distorm_decompose(&decomposerCi, decomposerResult, sizeof(decomposerResult) / sizeof(decomposerResult[0]), &decomposerInstructionsCount) == DECRES_INPUTERR)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"decomposeMemory :: distorm_decompose == DECRES_INPUTERR");
|
|
#endif
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::disassembleMemory(BYTE* dataBuffer, SIZE_T bufferSize, DWORD_PTR startOffset)
|
|
{
|
|
// Holds the result of the decoding.
|
|
_DecodeResult res;
|
|
|
|
// next is used for instruction's offset synchronization.
|
|
// decodedInstructionsCount holds the count of filled instructions' array by the decoder.
|
|
|
|
decodedInstructionsCount = 0;
|
|
|
|
_OffsetType offset = startOffset;
|
|
|
|
res = distorm_decode(offset, dataBuffer, (int)bufferSize, dt, decodedInstructions, MAX_INSTRUCTIONS, &decodedInstructionsCount);
|
|
|
|
/* for (unsigned int i = 0; i < decodedInstructionsCount; i++) {
|
|
#ifdef SUPPORT_64BIT_OFFSET
|
|
printf("%0*I64x (%02d) %-24s %s%s%s\n", dt != Decode64Bits ? 8 : 16, decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
|
|
#else
|
|
printf("%08x (%02d) %-24s %s%s%s\n", decodedInstructions[i].offset, decodedInstructions[i].size, (char*)decodedInstructions[i].instructionHex.p, (char*)decodedInstructions[i].mnemonic.p, decodedInstructions[i].operands.length != 0 ? " " : "", (char*)decodedInstructions[i].operands.p);
|
|
#endif
|
|
|
|
}*/
|
|
|
|
if(res == DECRES_INPUTERR)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"disassembleMemory :: res == DECRES_INPUTERR");
|
|
#endif
|
|
return false;
|
|
}
|
|
else if(res == DECRES_SUCCESS)
|
|
{
|
|
//printf("disassembleMemory :: res == DECRES_SUCCESS\n");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"disassembleMemory :: res == %d", res);
|
|
#endif
|
|
return true; //not all instructions fit in buffer
|
|
}
|
|
}
|
|
|
|
DWORD_PTR ProcessAccessHelp::findPattern(DWORD_PTR startOffset, DWORD size, BYTE* pattern, const char* mask)
|
|
{
|
|
DWORD pos = 0;
|
|
size_t searchLen = strlen(mask) - 1;
|
|
|
|
for(DWORD_PTR retAddress = startOffset; retAddress < startOffset + size; retAddress++)
|
|
{
|
|
if(*(BYTE*)retAddress == pattern[pos] || mask[pos] == '?')
|
|
{
|
|
if(mask[pos + 1] == 0x00)
|
|
{
|
|
return (retAddress - searchLen);
|
|
}
|
|
pos++;
|
|
}
|
|
else
|
|
{
|
|
pos = 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool ProcessAccessHelp::readHeaderFromCurrentFile(const WCHAR* filePath)
|
|
{
|
|
return readHeaderFromFile(fileHeaderFromDisk, sizeof(fileHeaderFromDisk), filePath);
|
|
}
|
|
|
|
LONGLONG ProcessAccessHelp::getFileSize(const WCHAR* filePath)
|
|
{
|
|
LONGLONG fileSize = 0;
|
|
|
|
HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
fileSize = getFileSize(hFile);
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
return fileSize;
|
|
}
|
|
|
|
LONGLONG ProcessAccessHelp::getFileSize(HANDLE hFile)
|
|
{
|
|
LARGE_INTEGER lpFileSize = {0};
|
|
|
|
if((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
|
|
{
|
|
if(!GetFileSizeEx(hFile, &lpFileSize))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize :: GetFileSizeEx failed %u", GetLastError());
|
|
#endif
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return lpFileSize.QuadPart;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"ProcessAccessHelp::getFileSize hFile invalid");
|
|
#endif
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool ProcessAccessHelp::readMemoryFromFile(HANDLE hFile, LONG offset, DWORD size, LPVOID dataBuffer)
|
|
{
|
|
DWORD lpNumberOfBytesRead = 0;
|
|
DWORD retValue = 0;
|
|
DWORD dwError = 0;
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
|
|
dwError = GetLastError();
|
|
|
|
if((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromFile :: SetFilePointer failed error %u", dwError);
|
|
#endif
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(ReadFile(hFile, dataBuffer, size, &lpNumberOfBytesRead, 0))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromFile :: ReadFile failed - size %d - error %u", size, GetLastError());
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readMemoryFromFile :: hFile invalid");
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::writeMemoryToNewFile(const WCHAR* file, DWORD size, LPCVOID dataBuffer)
|
|
{
|
|
HANDLE hFile = CreateFileW(file, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
|
|
|
if(hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
bool resultValue = writeMemoryToFile(hFile, 0, size, dataBuffer);
|
|
CloseHandle(hFile);
|
|
return resultValue;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::writeMemoryToFile(HANDLE hFile, LONG offset, DWORD size, LPCVOID dataBuffer)
|
|
{
|
|
DWORD lpNumberOfBytesWritten = 0;
|
|
DWORD retValue = 0;
|
|
DWORD dwError = 0;
|
|
|
|
if((hFile != INVALID_HANDLE_VALUE) && dataBuffer)
|
|
{
|
|
retValue = SetFilePointer(hFile, offset, NULL, FILE_BEGIN);
|
|
dwError = GetLastError();
|
|
|
|
if((retValue == INVALID_SET_FILE_POINTER) && (dwError != NO_ERROR))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"writeMemoryToFile :: SetFilePointer failed error %u", dwError);
|
|
#endif
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"writeMemoryToFile :: WriteFile failed - size %d - error %u", size, GetLastError());
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"writeMemoryToFile :: hFile invalid");
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::writeMemoryToFileEnd(HANDLE hFile, DWORD size, LPCVOID dataBuffer)
|
|
{
|
|
DWORD lpNumberOfBytesWritten = 0;
|
|
DWORD retValue = 0;
|
|
|
|
if((hFile != INVALID_HANDLE_VALUE) && (hFile != 0))
|
|
{
|
|
SetFilePointer(hFile, 0, 0, FILE_END);
|
|
|
|
if(WriteFile(hFile, dataBuffer, size, &lpNumberOfBytesWritten, 0))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"writeMemoryToFileEnd :: WriteFile failed - size %d - error %u", size, GetLastError());
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"writeMemoryToFileEnd :: hFile invalid");
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::readHeaderFromFile(BYTE* buffer, DWORD bufferSize, const WCHAR* filePath)
|
|
{
|
|
DWORD lpNumberOfBytesRead = 0;
|
|
LONGLONG fileSize = 0;
|
|
DWORD dwSize = 0;
|
|
bool returnValue = 0;
|
|
|
|
HANDLE hFile = CreateFileW(filePath, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"readHeaderFromFile :: INVALID_HANDLE_VALUE %u", GetLastError());
|
|
#endif
|
|
returnValue = false;
|
|
}
|
|
else
|
|
{
|
|
fileSize = getFileSize(hFile);
|
|
|
|
if(fileSize > 0)
|
|
{
|
|
if(fileSize > bufferSize)
|
|
{
|
|
dwSize = bufferSize;
|
|
}
|
|
else
|
|
{
|
|
dwSize = (DWORD)(fileSize - 1);
|
|
}
|
|
|
|
returnValue = readMemoryFromFile(hFile, 0, dwSize, buffer);
|
|
}
|
|
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
LPVOID ProcessAccessHelp::createFileMappingViewRead(const WCHAR* filePath)
|
|
{
|
|
return createFileMappingView(filePath, GENERIC_READ, PAGE_READONLY | SEC_IMAGE, FILE_MAP_READ);
|
|
}
|
|
|
|
LPVOID ProcessAccessHelp::createFileMappingViewFull(const WCHAR* filePath)
|
|
{
|
|
return createFileMappingView(filePath, GENERIC_ALL, PAGE_EXECUTE_READWRITE, FILE_MAP_ALL_ACCESS);
|
|
}
|
|
|
|
LPVOID ProcessAccessHelp::createFileMappingView(const WCHAR* filePath, DWORD accessFile, DWORD flProtect, DWORD accessMap)
|
|
{
|
|
HANDLE hFile = CreateFileW(filePath, accessFile, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
|
|
|
if(hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"createFileMappingView :: INVALID_HANDLE_VALUE %u", GetLastError());
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
HANDLE hMappedFile = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL);
|
|
CloseHandle(hFile);
|
|
|
|
if(hMappedFile == NULL)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"createFileMappingView :: hMappedFile == NULL");
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
if(GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"createFileMappingView :: GetLastError() == ERROR_ALREADY_EXISTS");
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
LPVOID addrMappedDll = MapViewOfFile(hMappedFile, accessMap, 0, 0, 0);
|
|
|
|
if(addrMappedDll == NULL)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"createFileMappingView :: addrMappedDll == NULL");
|
|
#endif
|
|
CloseHandle(hMappedFile);
|
|
return NULL;
|
|
}
|
|
|
|
CloseHandle(hMappedFile);
|
|
|
|
return addrMappedDll;
|
|
}
|
|
|
|
DWORD ProcessAccessHelp::getProcessByName(const WCHAR* processName)
|
|
{
|
|
DWORD dwPID = 0;
|
|
HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
PROCESSENTRY32W pe32;
|
|
pe32.dwSize = sizeof(PROCESSENTRY32W);
|
|
|
|
if(!Process32FirstW(hProcessSnap, &pe32))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"getProcessByName :: Error getting first Process");
|
|
#endif
|
|
CloseHandle(hProcessSnap);
|
|
return 0;
|
|
}
|
|
|
|
do
|
|
{
|
|
if(!_wcsicmp(pe32.szExeFile, processName))
|
|
{
|
|
dwPID = pe32.th32ProcessID;
|
|
break;
|
|
}
|
|
}
|
|
while(Process32NextW(hProcessSnap, &pe32));
|
|
|
|
CloseHandle(hProcessSnap);
|
|
|
|
return dwPID;
|
|
}
|
|
|
|
bool ProcessAccessHelp::getProcessModules(HANDLE hProcess, std::vector<ModuleInfo> & moduleList)
|
|
{
|
|
ModuleInfo module;
|
|
WCHAR filename[MAX_PATH * 2] = {0};
|
|
DWORD cbNeeded = 0;
|
|
bool retVal = false;
|
|
DeviceNameResolver deviceNameResolver;
|
|
|
|
moduleList.reserve(20);
|
|
|
|
EnumProcessModules(hProcess, 0, 0, &cbNeeded);
|
|
|
|
HMODULE* hMods = (HMODULE*)malloc(cbNeeded * sizeof(HMODULE));
|
|
|
|
if(hMods)
|
|
{
|
|
if(EnumProcessModules(hProcess, hMods, cbNeeded, &cbNeeded))
|
|
{
|
|
for(unsigned int i = 1; i < (cbNeeded / sizeof(HMODULE)); i++) //skip first module!
|
|
{
|
|
module.modBaseAddr = (DWORD_PTR)hMods[i];
|
|
module.modBaseSize = (DWORD)getSizeOfImageProcess(hProcess, module.modBaseAddr);
|
|
module.isAlreadyParsed = false;
|
|
module.parsing = false;
|
|
|
|
filename[0] = 0;
|
|
module.fullPath[0] = 0;
|
|
|
|
if(GetMappedFileNameW(hProcess, (LPVOID)module.modBaseAddr, filename, _countof(filename)) > 0)
|
|
{
|
|
if(!deviceNameResolver.resolveDeviceLongNameToShort(filename, module.fullPath))
|
|
{
|
|
if(!GetModuleFileNameExW(hProcess, (HMODULE)module.modBaseAddr, module.fullPath, _countof(module.fullPath)))
|
|
{
|
|
wcscpy_s(module.fullPath, filename);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetModuleFileNameExW(hProcess, (HMODULE)module.modBaseAddr, module.fullPath, _countof(module.fullPath));
|
|
}
|
|
|
|
moduleList.push_back(module);
|
|
}
|
|
|
|
retVal = true;
|
|
}
|
|
|
|
free(hMods);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
bool ProcessAccessHelp::getMemoryRegionFromAddress(DWORD_PTR address, DWORD_PTR* memoryRegionBase, SIZE_T* memoryRegionSize)
|
|
{
|
|
MEMORY_BASIC_INFORMATION memBasic;
|
|
|
|
if(VirtualQueryEx(hProcess, (LPCVOID)address, &memBasic, sizeof(MEMORY_BASIC_INFORMATION)) != sizeof(MEMORY_BASIC_INFORMATION))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"getMemoryRegionFromAddress :: VirtualQueryEx error %u", GetLastError());
|
|
#endif
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
*memoryRegionBase = (DWORD_PTR)memBasic.BaseAddress;
|
|
*memoryRegionSize = memBasic.RegionSize;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::getSizeOfImageCurrentProcess()
|
|
{
|
|
DWORD_PTR newSizeOfImage = getSizeOfImageProcess(ProcessAccessHelp::hProcess, ProcessAccessHelp::targetImageBase);
|
|
|
|
if(newSizeOfImage != 0)
|
|
{
|
|
ProcessAccessHelp::targetSizeOfImage = newSizeOfImage;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SIZE_T ProcessAccessHelp::getSizeOfImageProcess(HANDLE processHandle, DWORD_PTR moduleBase)
|
|
{
|
|
SIZE_T sizeOfImage = 0, sizeOfImageNative = 0;
|
|
MEMORY_BASIC_INFORMATION lpBuffer = {0};
|
|
|
|
sizeOfImageNative = getSizeOfImageProcessNative(processHandle, moduleBase);
|
|
|
|
if(sizeOfImageNative)
|
|
{
|
|
return sizeOfImageNative;
|
|
}
|
|
|
|
WCHAR filenameOriginal[MAX_PATH * 2] = {0};
|
|
WCHAR filenameTest[MAX_PATH * 2] = {0};
|
|
|
|
GetMappedFileNameW(processHandle, (LPVOID)moduleBase, filenameOriginal, _countof(filenameOriginal));
|
|
|
|
do
|
|
{
|
|
moduleBase = (DWORD_PTR)((SIZE_T)moduleBase + lpBuffer.RegionSize);
|
|
sizeOfImage += lpBuffer.RegionSize;
|
|
|
|
|
|
if(!VirtualQueryEx(processHandle, (LPCVOID)moduleBase, &lpBuffer, sizeof(MEMORY_BASIC_INFORMATION)))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"getSizeOfImageProcess :: VirtualQuery failed %X", GetLastError());
|
|
#endif
|
|
lpBuffer.Type = 0;
|
|
sizeOfImage = 0;
|
|
}
|
|
|
|
GetMappedFileNameW(processHandle, (LPVOID)moduleBase, filenameTest, _countof(filenameTest));
|
|
|
|
if(_wcsicmp(filenameOriginal, filenameTest) != 0)//problem: 2 modules without free space
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
while(lpBuffer.Type == MEM_IMAGE);
|
|
|
|
|
|
//if (sizeOfImage != sizeOfImageNative)
|
|
//{
|
|
// WCHAR temp[1000] = {0};
|
|
// wsprintfW(temp, L"0x%X sizeofimage\n0x%X sizeOfImageNative", sizeOfImage, sizeOfImageNative);
|
|
// MessageBoxW(0, temp, L"Test", 0);
|
|
//}
|
|
|
|
return sizeOfImage;
|
|
}
|
|
|
|
DWORD ProcessAccessHelp::getEntryPointFromFile(const WCHAR* filePath)
|
|
{
|
|
PeParser peFile(filePath, false);
|
|
|
|
return peFile.getEntryPoint();
|
|
}
|
|
|
|
bool ProcessAccessHelp::createBackupFile(const WCHAR* filePath)
|
|
{
|
|
size_t fileNameLength = wcslen(filePath) + 5; //.bak + null
|
|
BOOL retValue = 0;
|
|
|
|
WCHAR* backupFile = new WCHAR[fileNameLength];
|
|
|
|
wcscpy_s(backupFile, fileNameLength, filePath);
|
|
wcscat_s(backupFile, fileNameLength, L".bak");
|
|
retValue = CopyFileW(filePath, backupFile, FALSE);
|
|
|
|
if(!retValue)
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"createBackupFile :: CopyFile failed with error 0x%X", GetLastError());
|
|
#endif
|
|
}
|
|
|
|
delete [] backupFile;
|
|
|
|
return retValue != 0;
|
|
}
|
|
|
|
DWORD ProcessAccessHelp::getModuleHandlesFromProcess(const HANDLE hProcess, HMODULE** hMods)
|
|
{
|
|
DWORD count = 30;
|
|
DWORD cbNeeded = 0;
|
|
bool notEnough = true;
|
|
|
|
*hMods = new HMODULE[count];
|
|
|
|
do
|
|
{
|
|
if(!EnumProcessModules(hProcess, *hMods, count * sizeof(HMODULE), &cbNeeded))
|
|
{
|
|
#ifdef DEBUG_COMMENTS
|
|
Scylla::debugLog.log(L"getModuleHandlesFromProcess :: EnumProcessModules failed count %d", count);
|
|
#endif
|
|
delete [] *hMods;
|
|
return 0;
|
|
}
|
|
|
|
if((count * sizeof(HMODULE)) < cbNeeded)
|
|
{
|
|
delete [] *hMods;
|
|
count = cbNeeded / sizeof(HMODULE);
|
|
*hMods = new HMODULE[count];
|
|
}
|
|
else
|
|
{
|
|
notEnough = false;
|
|
}
|
|
}
|
|
while(notEnough);
|
|
|
|
return cbNeeded / sizeof(HMODULE);
|
|
}
|
|
|
|
void ProcessAccessHelp::setCurrentProcessAsTarget()
|
|
{
|
|
ProcessAccessHelp::hProcess = GetCurrentProcess();
|
|
}
|
|
|
|
bool ProcessAccessHelp::suspendProcess()
|
|
{
|
|
if(NativeWinApi::NtSuspendProcess)
|
|
{
|
|
if(NT_SUCCESS(NativeWinApi::NtSuspendProcess(ProcessAccessHelp::hProcess)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ProcessAccessHelp::resumeProcess()
|
|
{
|
|
if(NativeWinApi::NtResumeProcess)
|
|
{
|
|
if(NT_SUCCESS(NativeWinApi::NtResumeProcess(ProcessAccessHelp::hProcess)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ProcessAccessHelp::terminateProcess()
|
|
{
|
|
if(NativeWinApi::NtTerminateProcess)
|
|
{
|
|
if(NT_SUCCESS(NativeWinApi::NtTerminateProcess(ProcessAccessHelp::hProcess, 0)))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ProcessAccessHelp::isPageAccessable(DWORD Protect)
|
|
{
|
|
if(Protect & PAGE_NOCACHE) Protect ^= PAGE_NOCACHE;
|
|
if(Protect & PAGE_GUARD) Protect ^= PAGE_GUARD;
|
|
if(Protect & PAGE_WRITECOMBINE) Protect ^= PAGE_WRITECOMBINE;
|
|
|
|
if(Protect != PAGE_NOACCESS)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ProcessAccessHelp::isPageExecutable(DWORD Protect)
|
|
{
|
|
if(Protect & PAGE_NOCACHE) Protect ^= PAGE_NOCACHE;
|
|
if(Protect & PAGE_GUARD) Protect ^= PAGE_GUARD;
|
|
if(Protect & PAGE_WRITECOMBINE) Protect ^= PAGE_WRITECOMBINE;
|
|
|
|
switch(Protect)
|
|
{
|
|
case PAGE_EXECUTE:
|
|
{
|
|
return true;
|
|
}
|
|
case PAGE_EXECUTE_READ:
|
|
{
|
|
return true;
|
|
}
|
|
case PAGE_EXECUTE_READWRITE:
|
|
{
|
|
return true;
|
|
}
|
|
case PAGE_EXECUTE_WRITECOPY:
|
|
{
|
|
return true;
|
|
}
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
SIZE_T ProcessAccessHelp::getSizeOfImageProcessNative(HANDLE processHandle, DWORD_PTR moduleBase)
|
|
{
|
|
MEMORY_REGION_INFORMATION memRegion = {0};
|
|
SIZE_T retLen = 0;
|
|
if(NativeWinApi::NtQueryVirtualMemory(processHandle, (PVOID)moduleBase, MemoryRegionInformation, &memRegion, sizeof(MEMORY_REGION_INFORMATION), &retLen) == STATUS_SUCCESS)
|
|
{
|
|
return memRegion.RegionSize;
|
|
}
|
|
|
|
return 0;
|
|
}
|