From b0b4f5ded39f8aef0ea290a98d048305d8a2f346 Mon Sep 17 00:00:00 2001 From: mrexodia Date: Tue, 23 May 2017 23:02:04 +0200 Subject: [PATCH] initial GleeBug implementation ready --- GleeBug/GleeBug.cpp | 41 ---- GleeBug/GleeBug.h | 5 - GleeBug/GleeBug.vcxproj | 1 - GleeBug/GleeBug.vcxproj.filters | 3 - TitanEngineEmulator/Emulator.h | 187 +++++++++++++----- TitanEngineEmulator/FileMap.h | 57 ++++++ TitanEngineEmulator/TitanEngineEmulator.cpp | 10 - .../TitanEngineEmulator.vcxproj | 1 + .../TitanEngineEmulator.vcxproj.filters | 3 + 9 files changed, 200 insertions(+), 108 deletions(-) delete mode 100644 GleeBug/GleeBug.cpp create mode 100644 TitanEngineEmulator/FileMap.h diff --git a/GleeBug/GleeBug.cpp b/GleeBug/GleeBug.cpp deleted file mode 100644 index e80795f..0000000 --- a/GleeBug/GleeBug.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "GleeBug.h" - -namespace GleeBug -{ - //Conversion functions taken from: http://www.nubaria.com/en/blog/?p=289 - std::string Utf16ToUtf8(const std::wstring & wstr) - { - std::string convertedString; - auto requiredSize = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, nullptr, 0, nullptr, nullptr); - if(requiredSize > 0) - { - std::vector buffer(requiredSize); - WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, &buffer[0], requiredSize, nullptr, nullptr); - convertedString.assign(buffer.begin(), buffer.end() - 1); - } - return convertedString; - } - - std::string Utf16ToUtf8(const wchar_t* wstr) - { - return Utf16ToUtf8(wstr ? std::wstring(wstr) : std::wstring()); - } - - std::wstring Utf8ToUtf16(const std::string & str) - { - std::wstring convertedString; - int requiredSize = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, nullptr, 0); - if(requiredSize > 0) - { - std::vector buffer(requiredSize); - MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &buffer[0], requiredSize); - convertedString.assign(buffer.begin(), buffer.end() - 1); - } - return convertedString; - } - - std::wstring Utf8ToUtf16(const char* str) - { - return Utf8ToUtf16(str ? std::string(str) : std::string()); - } -}; \ No newline at end of file diff --git a/GleeBug/GleeBug.h b/GleeBug/GleeBug.h index 253af83..b4ed193 100644 --- a/GleeBug/GleeBug.h +++ b/GleeBug/GleeBug.h @@ -70,11 +70,6 @@ namespace GleeBug return a.second < b.first; } }; - - std::string Utf16ToUtf8(const std::wstring & wstr); - std::string Utf16ToUtf8(const wchar_t* wstr); - std::wstring Utf8ToUtf16(const std::string & str); - std::wstring Utf8ToUtf16(const char* str); } #endif //GLEEBUG_H \ No newline at end of file diff --git a/GleeBug/GleeBug.vcxproj b/GleeBug/GleeBug.vcxproj index 1c2cd55..4c08e2a 100644 --- a/GleeBug/GleeBug.vcxproj +++ b/GleeBug/GleeBug.vcxproj @@ -167,7 +167,6 @@ - diff --git a/GleeBug/GleeBug.vcxproj.filters b/GleeBug/GleeBug.vcxproj.filters index d4c8fd8..f7ffc42 100644 --- a/GleeBug/GleeBug.vcxproj.filters +++ b/GleeBug/GleeBug.vcxproj.filters @@ -83,9 +83,6 @@ Source Files - - Source Files - Source Files\Zydis diff --git a/TitanEngineEmulator/Emulator.h b/TitanEngineEmulator/Emulator.h index b06fca8..5af3f3b 100644 --- a/TitanEngineEmulator/Emulator.h +++ b/TitanEngineEmulator/Emulator.h @@ -1,6 +1,9 @@ #include +#include +#include #include "TitanEngine.h" #include "ntdll.h" +#include "FileMap.h" using namespace GleeBug; @@ -54,7 +57,7 @@ public: } //Memory - bool MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) const + bool MemoryReadSafe(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead) { auto process = processFromHandle(hProcess); if (!process) @@ -72,6 +75,7 @@ public: bool Fill(LPVOID MemoryStart, DWORD MemorySize, PBYTE FillByte) { + //TODO: this is fucking inefficient if (!mProcess) return false; for (DWORD i = 0; i < MemorySize; i++) @@ -177,25 +181,30 @@ public: return PebAddress; } - void* GetTEBLocation(HANDLE hThread) + static bool getThreadInfo(HANDLE hThread, THREAD_BASIC_INFORMATION & tbi) { ULONG RequiredLen = 0; - void* TebAddress = 0; THREAD_BASIC_INFORMATION myThreadBasicInformation[5] = { 0 }; - if(NtQueryInformationThread(hThread, ThreadBasicInformation, myThreadBasicInformation, sizeof(THREAD_BASIC_INFORMATION), &RequiredLen) == 0) { - TebAddress = (void*)myThreadBasicInformation->TebBaseAddress; + tbi = myThreadBasicInformation[0]; + return true; } else { if(NtQueryInformationThread(hThread, ThreadBasicInformation, myThreadBasicInformation, RequiredLen, &RequiredLen) == 0) { - TebAddress = (void*)myThreadBasicInformation->TebBaseAddress; + tbi = myThreadBasicInformation[0]; + return true; } } + return false; + } - return TebAddress; + void* GetTEBLocation(HANDLE hThread) + { + THREAD_BASIC_INFORMATION tbi; + return getThreadInfo(hThread, tbi) ? tbi.TebBaseAddress : nullptr; } bool HideDebugger(HANDLE hProcess, DWORD PatchAPILevel) @@ -232,11 +241,13 @@ public: } //Registers - ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister) const + ULONG_PTR GetContextDataEx(HANDLE hActiveThread, DWORD IndexOfRegister) { - auto thread = threadFromHandle(hActiveThread); - if (!thread) + if(!hActiveThread) return 0; + auto thread = threadFromHandle(hActiveThread); + if(!thread) + __debugbreak(); //return 0; if(mIsRunning) thread->RegReadContext(); return thread->registers.Get(registerFromDword(IndexOfRegister)); @@ -246,7 +257,7 @@ public: { auto thread = threadFromHandle(hActiveThread); if (!thread) - return false; + __debugbreak(); //return false; if(mIsRunning) thread->RegReadContext(); thread->registers.Set(registerFromDword(IndexOfRegister), NewRegisterValue); @@ -255,11 +266,13 @@ public: return true; } - bool GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext) const + bool GetFullContextDataEx(HANDLE hActiveThread, TITAN_ENGINE_CONTEXT_t* titcontext) { + if(!hActiveThread) + return false; auto thread = threadFromHandle(hActiveThread); if (!thread || !titcontext) - return false; + __debugbreak(); //return false; if(mIsRunning) thread->RegReadContext(); memset(titcontext, 0, sizeof(TITAN_ENGINE_CONTEXT_t)); @@ -303,7 +316,7 @@ public: { auto thread = threadFromHandle(hActiveThread); if (!thread || !titcontext) - return false; + __debugbreak(); //return false; if(mIsRunning) thread->RegReadContext(); thread->registers.Gax = titcontext->cax; @@ -357,77 +370,149 @@ public: memset(x87FPURegisters, 0, sizeof(x87FPURegister_t) * 8); } + struct MappedPe + { + FileMap* file; + BufferFile* buffer; + Pe* pe; + }; + + std::unordered_map mappedFiles; + //PE bool StaticFileLoadW(const wchar_t* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) { - //TODO - return false; + auto file = new ::FileMap; + if(!file->Map(szFileName, DesiredAccess == UE_ACCESS_ALL)) + __debugbreak(); //return false; + *FileHandle = file->hFile; + *LoadedSize = file->size; + *FileMap = file->hMap; + *FileMapVA = ULONG_PTR(file->data); + MappedPe mappedPe; + mappedPe.file = std::move(file); + mappedPe.buffer = new BufferFile(mappedPe.file->data, mappedPe.file->size); + mappedPe.pe = new Pe(*mappedPe.buffer); + if(mappedPe.pe->Parse(true) != Pe::ErrorOk) + __debugbreak(); + mappedFiles.insert({ *FileMapVA, mappedPe }); + return true; } bool StaticFileUnloadW(const wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA) { - //TODO - return false; + auto found = mappedFiles.find(FileMapVA); + if(found == mappedFiles.end()) + __debugbreak(); //return false; + delete found->second.pe; + delete found->second.buffer; + delete found->second.file; + mappedFiles.erase(found); + return true; } ULONG_PTR ConvertFileOffsetToVA(ULONG_PTR FileMapVA, ULONG_PTR AddressToConvert, bool ReturnType) { - //TODO - return 0; + auto found = mappedFiles.find(FileMapVA); + if(found == mappedFiles.end()) + __debugbreak(); //return 0; + if(!found->second.pe->IsValidPe()) + __debugbreak(); //return 0; + return found->second.pe->ConvertOffsetToRva(uint32(AddressToConvert)); } ULONG_PTR ConvertVAtoFileOffsetEx(ULONG_PTR FileMapVA, DWORD FileSize, ULONG_PTR ImageBase, ULONG_PTR AddressToConvert, bool AddressIsRVA, bool ReturnType) { - //TODO - return 0; + auto found = mappedFiles.find(FileMapVA); + if(found == mappedFiles.end()) + __debugbreak(); //return 0; + if(!found->second.pe->IsValidPe()) + __debugbreak(); //return 0; + return found->second.pe->ConvertRvaToOffset(uint32(AddressToConvert)); } ULONG_PTR GetPE32DataFromMappedFile(ULONG_PTR FileMapVA, DWORD WhichSection, DWORD WhichData) { - //TODO + auto found = mappedFiles.find(FileMapVA); + if(found == mappedFiles.end()) + __debugbreak(); //return 0; + if(!found->second.pe->IsValidPe()) + __debugbreak(); //return 0; +#ifdef _WIN64 + if(!found->second.pe->IsPe64()) __debugbreak(); //return 0; + auto headers = found->second.pe->GetNtHeaders64(); +#else + if(found->second.pe->IsPe64()) __debugbreak(); //return 0; + auto headers = found->second.pe->GetNtHeaders32(); +#endif //_WIN64 + const auto & sections = found->second.pe->GetSections(); switch(WhichData) { case UE_PE_OFFSET: - break; + return headers.Offset(); case UE_IMPORTTABLEADDRESS: - break; + return headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; case UE_IMPORTTABLESIZE: - break; + return headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size; + case UE_EXPORTTABLEADDRESS: + return headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + case UE_EXPORTTABLESIZE: + return headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size; case UE_CHARACTERISTICS: - break; + return headers->FileHeader.Characteristics; case UE_DLLCHARACTERISTICS: - break; + return headers->OptionalHeader.DllCharacteristics; case UE_OEP: - break; + return headers->OptionalHeader.AddressOfEntryPoint; case UE_SECTIONNUMBER: - break; + return sections.size(); case UE_SECTIONVIRTUALOFFSET: //WhichSection: IMAGE_DIRECTORY_ENTRY_EXCEPTION - break; + return WhichSection < sections.size() ? sections[WhichSection].GetHeader().VirtualAddress : 0; case UE_SECTIONVIRTUALSIZE: //WhichSection: IMAGE_DIRECTORY_ENTRY_EXCEPTION - break; + return WhichSection < sections.size() ? sections[WhichSection].GetHeader().Misc.VirtualSize : 0; case UE_SECTIONNAME: - break; + return WhichSection < sections.size() ? ULONG_PTR(§ions[WhichSection].GetHeader().Name[0]) : 0; + default: + __debugbreak(); } return 0; } ULONG_PTR GetPE32DataW(const wchar_t* szFileName, DWORD WhichSection, DWORD WhichData) { - //TODO + FileMap file; + if(!file.Map(szFileName)) + __debugbreak(); //return 0; + BufferFile buf(file.data, file.size); + Pe pe(buf); + if(pe.Parse(true) != Pe::ErrorOk) + __debugbreak(); //return 0; + if(!pe.IsValidPe()) + __debugbreak(); //return 0; +#ifdef _WIN64 + if(!pe.IsPe64()) __debugbreak(); //return 0; + auto headers = pe.GetNtHeaders64().Data(); +#else + if(pe.IsPe64()) __debugbreak(); //return 0; + auto headers = pe.GetNtHeaders32().Data(); +#endif //_WIN64 switch(WhichData) { + case UE_CHARACTERISTICS: + return headers->FileHeader.Characteristics; case UE_IMAGEBASE: - break; + return headers->OptionalHeader.ImageBase; case UE_OEP: - break; + return headers->OptionalHeader.AddressOfEntryPoint; + default: + __debugbreak(); } return 0; } bool IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA) { - //TODO - return false; + return (GetPE32DataW(szFileName, NULL, UE_CHARACTERISTICS) & IMAGE_FILE_DLL) == IMAGE_FILE_DLL; } bool TLSGrabCallBackDataW(const wchar_t* szFileName, LPVOID ArrayOfCallBacks, LPDWORD NumberOfCallBacks) @@ -663,20 +748,26 @@ private: //functions } } - Thread* threadFromHandle(HANDLE hThread) const + Thread* threadFromHandle(HANDLE hThread) { - if(!hThread) - return mThread; - //TODO: properly implement this - return mThread; + THREAD_BASIC_INFORMATION tbi; + if(!getThreadInfo(hThread, tbi)) + return nullptr; + auto foundP = mProcesses.find(uint32(tbi.ClientId.UniqueProcess)); + if(foundP == mProcesses.end()) + return nullptr; + auto foundT = foundP->second.threads.find(uint32(tbi.ClientId.UniqueThread)); + if(foundT == foundP->second.threads.end()) + return nullptr; + return &foundT->second; } - Process* processFromHandle(HANDLE hProcess) const + Process* processFromHandle(HANDLE hProcess) { - if(!hProcess) - return mProcess; - //TODO: properly implement this - return mProcess; + auto foundP = mProcesses.find(GetProcessId(hProcess)); + if(foundP == mProcesses.end()) + return nullptr; + return &foundP->second; } static HardwareType hwtypeFromTitan(DWORD type) diff --git a/TitanEngineEmulator/FileMap.h b/TitanEngineEmulator/FileMap.h new file mode 100644 index 0000000..bb78125 --- /dev/null +++ b/TitanEngineEmulator/FileMap.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +template +struct FileMap +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hMap = nullptr; + T* data = nullptr; + unsigned int size = 0; + + FileMap() { } + + ~FileMap() + { + Unmap(); + } + + FileMap(const FileMap &) = delete; + + FileMap(FileMap && other) + { + other.hFile = hFile; + other.hMap = hMap; + other.data = data; + other.size = size; + } + + bool Map(const wchar_t* szFileName, bool write = false) + { + hFile = CreateFileW(szFileName, GENERIC_READ | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if(hFile != INVALID_HANDLE_VALUE) + { + size = GetFileSize(hFile, nullptr); + hMap = CreateFileMappingW(hFile, nullptr, write ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr); + if(hMap) + data = (T*)MapViewOfFile(hMap, write ? FILE_MAP_WRITE : FILE_MAP_READ, 0, 0, 0); + } + return data != nullptr; + } + + void Unmap() + { + if(data) + UnmapViewOfFile(data); + if(hMap) + CloseHandle(hMap); + if(hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + + hFile = INVALID_HANDLE_VALUE; + hMap = nullptr; + data = nullptr; + size = 0; + } +}; \ No newline at end of file diff --git a/TitanEngineEmulator/TitanEngineEmulator.cpp b/TitanEngineEmulator/TitanEngineEmulator.cpp index 8c910d1..26dbbb2 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.cpp +++ b/TitanEngineEmulator/TitanEngineEmulator.cpp @@ -159,11 +159,6 @@ __declspec(dllexport) bool TITCALL StaticFileLoadW(const wchar_t* szFileName, DW return emu.StaticFileLoadW(szFileName, DesiredAccess, SimulateLoad, FileHandle, LoadedSize, FileMap, FileMapVA); } -__declspec(dllexport) bool TITCALL StaticFileLoad(const char* szFileName, DWORD DesiredAccess, bool SimulateLoad, LPHANDLE FileHandle, LPDWORD LoadedSize, LPHANDLE FileMap, PULONG_PTR FileMapVA) -{ - return StaticFileLoadW(Utf8ToUtf16(szFileName).c_str(), DesiredAccess, SimulateLoad, FileHandle, LoadedSize, FileMap, FileMapVA); -} - __declspec(dllexport) bool TITCALL StaticFileUnloadW(const wchar_t* szFileName, bool CommitChanges, HANDLE FileHandle, DWORD LoadedSize, HANDLE FileMap, ULONG_PTR FileMapVA) { return emu.StaticFileUnloadW(szFileName, CommitChanges, FileHandle, LoadedSize, FileMap, FileMapVA); @@ -194,11 +189,6 @@ __declspec(dllexport) ULONG_PTR TITCALL GetPE32DataW(const wchar_t* szFileName, return emu.GetPE32DataW(szFileName, WhichSection, WhichData); } -__declspec(dllexport) ULONG_PTR TITCALL GetPE32Data(const char* szFileName, DWORD WhichSection, DWORD WhichData) -{ - return GetPE32DataW(Utf8ToUtf16(szFileName).c_str(), WhichSection, WhichData); -} - __declspec(dllexport) bool TITCALL IsFileDLLW(const wchar_t* szFileName, ULONG_PTR FileMapVA) { return emu.IsFileDLLW(szFileName, FileMapVA); diff --git a/TitanEngineEmulator/TitanEngineEmulator.vcxproj b/TitanEngineEmulator/TitanEngineEmulator.vcxproj index 10fd16b..9b85c59 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.vcxproj +++ b/TitanEngineEmulator/TitanEngineEmulator.vcxproj @@ -154,6 +154,7 @@ + diff --git a/TitanEngineEmulator/TitanEngineEmulator.vcxproj.filters b/TitanEngineEmulator/TitanEngineEmulator.vcxproj.filters index ee93720..e973e70 100644 --- a/TitanEngineEmulator/TitanEngineEmulator.vcxproj.filters +++ b/TitanEngineEmulator/TitanEngineEmulator.vcxproj.filters @@ -22,5 +22,8 @@ Header Files + + Header Files + \ No newline at end of file