diff --git a/src/creatwth.cpp b/src/creatwth.cpp index c2819aff..2a9c659c 100644 --- a/src/creatwth.cpp +++ b/src/creatwth.cpp @@ -1153,7 +1153,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, goto Cleanup; } - rlpDlls = new NOTHROW LPCSTR [s_pHelper->nDlls]; + rlpDlls = DetourCreateObjectArray(s_pHelper->nDlls); cSize = s_pHelper->cb - sizeof(DETOUR_EXE_HELPER); for (DWORD n = 0; n < s_pHelper->nDlls; n++) { size_t cchDest = 0; @@ -1177,7 +1177,7 @@ VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, Cleanup: if (rlpDlls != NULL) { - delete[] rlpDlls; + DetourDestroyObjectArray(rlpDlls); rlpDlls = NULL; } @@ -1251,7 +1251,7 @@ BOOL WINAPI AllocExeHelper(_Out_ PDETOUR_EXE_HELPER *pHelper, cSize += (DWORD)cchDest + 1; } - Helper = (PDETOUR_EXE_HELPER) new NOTHROW BYTE[sizeof(DETOUR_EXE_HELPER) + cSize]; + Helper = (PDETOUR_EXE_HELPER)DetourCreateObjectArray(sizeof(DETOUR_EXE_HELPER) + cSize); if (Helper == NULL) { goto Cleanup; } @@ -1316,7 +1316,7 @@ BOOL WINAPI AllocExeHelper(_Out_ PDETOUR_EXE_HELPER *pHelper, Cleanup: if (Helper != NULL) { - delete[] (PBYTE)Helper; + DetourDestroyObjectArray((PBYTE&)Helper); Helper = NULL; } return Result; @@ -1326,7 +1326,7 @@ static VOID WINAPI FreeExeHelper(PDETOUR_EXE_HELPER *pHelper) { if (*pHelper != NULL) { - delete[] (PBYTE)*pHelper; + DetourDestroyObjectArray((PBYTE&)*pHelper); *pHelper = NULL; } } diff --git a/src/detours.cpp b/src/detours.cpp index c1138dca..e90e6d61 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -10,6 +10,9 @@ //#define DETOUR_DEBUG 1 #define DETOURS_INTERNAL +typedef long NTSTATUS; +#include +#define WIN32_NO_STATUS #include "detours.h" #if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH @@ -21,23 +24,18 @@ ////////////////////////////////////////////////////////////////////////////// // -#ifdef _DEBUG -extern "C" IMAGE_DOS_HEADER __ImageBase; -int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg) +extern "C" void __cdecl _assert(const char* expr, const char* filename, unsigned lineno); +void DetourAssert(const char* expr, const char* filename, unsigned lineno) { - int nRet = 0; DWORD dwLastError = GetLastError(); - CHAR szModuleNameWithFunctionName[MAX_PATH * 2]; - szModuleNameWithFunctionName[0] = 0; - GetModuleFileNameA((HMODULE)&__ImageBase, szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName)); - StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), ",", ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1); - StringCchCatNA(szModuleNameWithFunctionName, ARRAYSIZE(szModuleNameWithFunctionName), FunctionName, ARRAYSIZE(szModuleNameWithFunctionName) - strlen(szModuleNameWithFunctionName) - 1); SetLastError(dwLastError); - nRet = _CrtDbgReport(reportType, filename, linenumber, szModuleNameWithFunctionName, msg); + int last_error_mode = _set_error_mode(_OUT_TO_MSGBOX); + _assert(expr, filename, lineno); + if (last_error_mode != _OUT_TO_MSGBOX) { + _set_error_mode(last_error_mode); + } SetLastError(dwLastError); - return nRet; } -#endif// _DEBUG ////////////////////////////////////////////////////////////////////////////// // @@ -1531,6 +1529,23 @@ struct DetourThread { DetourThread * pNext; HANDLE hThread; + BOOL fCloseThreadHandleOnDestroyDetourThreadObject; +public: + DetourThread() + { + pNext = NULL; + hThread = NULL; + fCloseThreadHandleOnDestroyDetourThreadObject = FALSE; + } + ~DetourThread() + { + if (fCloseThreadHandleOnDestroyDetourThreadObject) { + if (hThread) { + CloseHandle(hThread); + hThread = NULL; + } + } + } }; struct DetourOperation @@ -1591,16 +1606,30 @@ PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound) } LONG WINAPI DetourTransactionBegin() +{ + return DetourTransactionBeginEx(FALSE); +} + +LONG WINAPI DetourTransactionBeginEx(_In_ BOOL fWait) { // Only one transaction is allowed at a time. _Benign_race_begin_ + Check__s_nPendingThreadId: if (s_nPendingThreadId != 0) { + if (fWait) { + Sleep(10); + goto Check__s_nPendingThreadId; + } return ERROR_INVALID_OPERATION; } _Benign_race_end_ // Make sure only one thread can start a transaction. if (InterlockedCompareExchange(&s_nPendingThreadId, (LONG)GetCurrentThreadId(), 0) != 0) { + if (fWait) { + Sleep(10); + goto Check__s_nPendingThreadId; + } return ERROR_INVALID_OPERATION; } @@ -1635,7 +1664,7 @@ LONG WINAPI DetourTransactionAbort() } DetourOperation *n = o->pNext; - delete o; + DetourDestroyObject(o); o = n; } s_pPendingOperations = NULL; @@ -1649,7 +1678,7 @@ LONG WINAPI DetourTransactionAbort() ResumeThread(t->hThread); DetourThread *n = t->pNext; - delete t; + DetourDestroyObject(t); t = n; } s_pPendingThreads = NULL; @@ -1920,7 +1949,7 @@ typedef ULONG_PTR DETOURS_EIP_TYPE; } DetourOperation *n = o->pNext; - delete o; + DetourDestroyObject(o); o = n; } s_pPendingOperations = NULL; @@ -1939,7 +1968,7 @@ typedef ULONG_PTR DETOURS_EIP_TYPE; ResumeThread(t->hThread); DetourThread *n = t->pNext; - delete t; + DetourDestroyObject(t); t = n; } s_pPendingThreads = NULL; @@ -1953,6 +1982,11 @@ typedef ULONG_PTR DETOURS_EIP_TYPE; } LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread) +{ + return DetourUpdateThreadEx(hThread, FALSE); +} + +LONG WINAPI DetourUpdateThreadEx(_In_ HANDLE hThread, _In_ BOOL fCloseThreadHandleOnDestroyDetourThreadObject) { LONG error; @@ -1966,12 +2000,12 @@ LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread) return NO_ERROR; } - DetourThread *t = new NOTHROW DetourThread; + DetourThread *t = DetourCreateObject(); if (t == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; fail: if (t != NULL) { - delete t; + DetourDestroyObject(t); t = NULL; } s_nPendingError = error; @@ -1987,12 +2021,199 @@ LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread) } t->hThread = hThread; + t->fCloseThreadHandleOnDestroyDetourThreadObject = fCloseThreadHandleOnDestroyDetourThreadObject; t->pNext = s_pPendingThreads; s_pPendingThreads = t; return NO_ERROR; } +// winternl.h is different in each version of the Windows SDK, +// and some fields or types we need are missing in the lower version, +// so we do not use winternl.h in the current compilation environment by default. +#ifdef __USE_WINTERNL_H__ +#include +#else // __USE_WINTERNL_H__ +// Excerpted from "C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um\winternl.h" +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING; +typedef UNICODE_STRING* PUNICODE_STRING; +typedef const UNICODE_STRING* PCUNICODE_STRING; + +typedef LONG KPRIORITY; + +typedef struct _CLIENT_ID { + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID; + +typedef struct _SYSTEM_THREAD_INFORMATION { + LARGE_INTEGER Reserved1[3]; + ULONG Reserved2; + PVOID StartAddress; + CLIENT_ID ClientId; + KPRIORITY Priority; + LONG BasePriority; + ULONG Reserved3; + ULONG ThreadState; + ULONG WaitReason; +} SYSTEM_THREAD_INFORMATION, * PSYSTEM_THREAD_INFORMATION; + +typedef struct _SYSTEM_PROCESS_INFORMATION { + ULONG NextEntryOffset; + ULONG NumberOfThreads; + BYTE Reserved1[48]; + UNICODE_STRING ImageName; + KPRIORITY BasePriority; + HANDLE UniqueProcessId; + PVOID Reserved2; + ULONG HandleCount; + ULONG SessionId; + PVOID Reserved3; + SIZE_T PeakVirtualSize; + SIZE_T VirtualSize; + ULONG Reserved4; + SIZE_T PeakWorkingSetSize; + SIZE_T WorkingSetSize; + PVOID Reserved5; + SIZE_T QuotaPagedPoolUsage; + PVOID Reserved6; + SIZE_T QuotaNonPagedPoolUsage; + SIZE_T PagefileUsage; + SIZE_T PeakPagefileUsage; + SIZE_T PrivatePageCount; + LARGE_INTEGER Reserved7[6]; +} SYSTEM_PROCESS_INFORMATION, * PSYSTEM_PROCESS_INFORMATION; + +typedef enum _SYSTEM_INFORMATION_CLASS { + SystemBasicInformation = 0, + SystemPerformanceInformation = 2, + SystemTimeOfDayInformation = 3, + SystemProcessInformation = 5, + SystemProcessorPerformanceInformation = 8, + SystemInterruptInformation = 23, + SystemExceptionInformation = 33, + SystemRegistryQuotaInformation = 37, + SystemLookasideInformation = 45, + SystemCodeIntegrityInformation = 103, + SystemPolicyInformation = 134, +} SYSTEM_INFORMATION_CLASS; + +// +// Generic test for success on any status value (non-negative numbers +// indicate success). +// + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) +#endif + +#endif // __USE_WINTERNL_H__ + +static +NTSTATUS +(NTAPI* +pfnNtQuerySystemInformation)( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength OPTIONAL +); + +BOOL WINAPI DetourUpdateAllOtherThreads() +{ + LONG bResult = FALSE; + + if (!pfnNtQuerySystemInformation) { + HMODULE hmod_ntdll = GetModuleHandle(TEXT("ntdll.dll")); + DETOUR_ASSERT(hmod_ntdll); + if (!hmod_ntdll) { + return bResult; + } + pfnNtQuerySystemInformation = (NTSTATUS(NTAPI*)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG))GetProcAddress(hmod_ntdll, "NtQuerySystemInformation"); + DETOUR_ASSERT(pfnNtQuerySystemInformation); + if (!pfnNtQuerySystemInformation) { + return bResult; + } + } + + ULONG data_size = 1024 * 1024; + for (int i = 0; i < 10; i++) { + PBYTE data = DetourCreateObjectArray(data_size); + if (data == NULL) { + break; + } + + NTSTATUS status = pfnNtQuerySystemInformation(SystemProcessInformation, data, data_size, NULL); + if (NT_SUCCESS(status)) { + __if_not_exists(SYSTEM_PROCESS_INFORMATION::Threads) { + struct MySYSTEM_PROCESS_INFORMATION :public SYSTEM_PROCESS_INFORMATION { + SYSTEM_THREAD_INFORMATION Threads[1]; + }; + } + __if_exists(SYSTEM_PROCESS_INFORMATION::Threads) { + struct MySYSTEM_PROCESS_INFORMATION :public SYSTEM_PROCESS_INFORMATION { + }; + } + MySYSTEM_PROCESS_INFORMATION* pSYSTEM_PROCESS_INFORMATIONs = (MySYSTEM_PROCESS_INFORMATION*)data; + DWORD pid = GetCurrentProcessId(); + while (pSYSTEM_PROCESS_INFORMATIONs) { + if (pSYSTEM_PROCESS_INFORMATIONs->UniqueProcessId == (HANDLE)(DWORD_PTR)pid) { + DWORD tid = GetCurrentThreadId(); + for (ULONG threadIdx = 0; threadIdx < pSYSTEM_PROCESS_INFORMATIONs->NumberOfThreads; threadIdx++) { + DWORD threadId = (DWORD)(DWORD_PTR)pSYSTEM_PROCESS_INFORMATIONs->Threads[threadIdx].ClientId.UniqueThread; + + if (threadId != tid) { + HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION | THREAD_SET_CONTEXT, FALSE, threadId); + if (hThread) { + LONG error = DetourUpdateThreadEx(hThread, TRUE); + DETOUR_ASSERT(error == NO_ERROR || error == ERROR_ACCESS_DENIED); + if (error) { + DETOUR_TRACE(("DetourUpdateThreadEx failed, error=%ld\n", error)); + // Reset s_nPendingError so that subsequent threads can continue to try to call the DetourUpdateThreadEx function + DETOUR_ASSERT(error == s_nPendingError); + // When the console program is terminated, s_nPendingError == ERROR_ACCESS_DENIED may be caused when the SuspendThread is called in DetourUpdateThreadEx + DETOUR_ASSERT(s_nPendingError == ERROR_ACCESS_DENIED); + s_nPendingError = NO_ERROR; + } + } + } + } + bResult = TRUE; + break; + } + else if (pSYSTEM_PROCESS_INFORMATIONs->NextEntryOffset) { + pSYSTEM_PROCESS_INFORMATIONs = (MySYSTEM_PROCESS_INFORMATION*)(((LPBYTE)pSYSTEM_PROCESS_INFORMATIONs) + pSYSTEM_PROCESS_INFORMATIONs->NextEntryOffset); + } + else { + pSYSTEM_PROCESS_INFORMATIONs = NULL; + } + } + + DetourDestroyObjectArray(data); + data = NULL; + break; + } + else { + DetourDestroyObjectArray(data); + data = NULL; + + DETOUR_ASSERT(status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_BUFFER_TOO_SMALL); + if (status == STATUS_INFO_LENGTH_MISMATCH || status == STATUS_BUFFER_TOO_SMALL) { + data_size *= 2; + } + else { + break; + } + } + }; + + return bResult; +} + ///////////////////////////////////////////////////////////// Transacted APIs. // LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, @@ -2087,7 +2308,7 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, *ppRealDetour = pDetour; } - o = new NOTHROW DetourOperation; + o = DetourCreateObject(); if (o == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; fail: @@ -2102,7 +2323,7 @@ LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, } } if (o != NULL) { - delete o; + DetourDestroyObject(o); o = NULL; } if (ppRealDetour != NULL) { @@ -2389,7 +2610,7 @@ LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, return error; } - DetourOperation *o = new NOTHROW DetourOperation; + DetourOperation *o = DetourCreateObject(); if (o == NULL) { error = ERROR_NOT_ENOUGH_MEMORY; fail: @@ -2397,7 +2618,7 @@ LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, DETOUR_BREAK(); stop: if (o != NULL) { - delete o; + DetourDestroyObject(o); o = NULL; } s_ppPendingError = ppPointer; diff --git a/src/detours.h b/src/detours.h index f3738af0..9dd514d2 100644 --- a/src/detours.h +++ b/src/detours.h @@ -48,7 +48,9 @@ #include #pragma warning(pop) #endif -#include + +#include +#include // Allow Detours to cleanly compile with the MingW toolchain. // @@ -381,10 +383,10 @@ extern const GUID DETOUR_EXE_RESTORE_GUID; extern const GUID DETOUR_EXE_HELPER_GUID; #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! -typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; - -#ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS -#define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 +typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; + +#ifndef DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS +#define DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS 32 #endif // !DETOUR_MAX_SUPPORTED_IMAGE_SECTION_HEADERS /////////////////////////////////////////////////////////// Binary Structures. @@ -557,12 +559,21 @@ typedef VOID * PDETOUR_LOADED_BINARY; //////////////////////////////////////////////////////////// Transaction APIs. // LONG WINAPI DetourTransactionBegin(VOID); +LONG WINAPI DetourTransactionBeginEx(_In_ BOOL fWait /*= TRUE*/); LONG WINAPI DetourTransactionAbort(VOID); LONG WINAPI DetourTransactionCommit(VOID); LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); +// DetourUpdateThread is no longer recommended to be called by users, please use DetourUpdateAllOtherThreads for safer HOOK LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); +// After calling DetourUpdateAllOtherThreads, you should call DetourTransactionCommit(Ex) or DetourTransactionAbort as soon as possible. +// In addition to the DetourAttach(Ex)\DetourDetach(Ex) call, other user operations should not be included between them, +// because other user operations may cause CRT lock competition, and at this time CRT lock may be owned by other threads. +// Other threads have been suspended at this time, so that may cause deadlock problems +LONG WINAPI DetourUpdateThreadEx(_In_ HANDLE hThread, _In_ BOOL fCloseThreadHandleOnDestroyDetourThreadObject /*= TRUE*/); +BOOL WINAPI DetourUpdateAllOtherThreads(); + LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, _In_ PVOID pDetour); @@ -594,8 +605,8 @@ PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, _In_ BOOL fLimitReferencesToModule); PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, - _Out_ PDWORD pcbAllocatedSize); -BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode, + _Out_ PDWORD pcbAllocatedSize); +BOOL WINAPI DetourIsFunctionImported(_In_ PBYTE pbCode, _In_ PBYTE pbAddress); ///////////////////////////////////////////////////// Loaded Binary Functions. @@ -991,17 +1002,10 @@ PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); #endif #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 +void DetourAssert(const char* expr, const char* filename, unsigned lineno); +#define Detour_Assert(_Expression) (void)( (!!(_Expression)) || (DetourAssert(#_Expression, __FILE__, __LINE__), 0) ) #ifdef _DEBUG - -int Detour_AssertExprWithFunctionName(int reportType, const char* filename, int linenumber, const char* FunctionName, const char* msg); - -#define DETOUR_ASSERT_EXPR_WITH_FUNCTION(expr, msg) \ - (void) ((expr) || \ - (1 != Detour_AssertExprWithFunctionName(_CRT_ASSERT, __FILE__, __LINE__,__FUNCTION__, msg)) || \ - (_CrtDbgBreak(), 0)) - -#define DETOUR_ASSERT(expr) DETOUR_ASSERT_EXPR_WITH_FUNCTION((expr), #expr) - +#define DETOUR_ASSERT(expr) Detour_Assert(expr) #else// _DEBUG #define DETOUR_ASSERT(expr) #endif// _DEBUG @@ -1219,6 +1223,375 @@ BOOL WINAPI DetourAreSameGuid(_In_ REFGUID left, _In_ REFGUID right); } #endif // __cplusplus +//////////////////////////////////////////////////////////// Memory management APIs. +// use these APIs can avoid Use-after-free, Double-free and Over-bound-access memory errors. +struct DetourMemory +{ +private: + DWORD_PTR dwpHead; + size_t nObjectSize; + // T object; + // DWORD_PTR dwpTail[]; +private: + DetourMemory(size_t nObjectSize, BOOL bOnlyForGetNeedAllocateSize) + { + dwpHead = 0; + this->nObjectSize = nObjectSize; + if (!bOnlyForGetNeedAllocateSize) { + Fill(); + } + } +private: + size_t GetNeedAllocateSize() const + { + size_t nNeedAllocedSize = sizeof(DetourMemory) + nObjectSize; + return nNeedAllocedSize; + } +private: + PBYTE GetStructPtr() const + { + PBYTE pStruct = (PBYTE)this; + return pStruct; + } + size_t GetStructSize() const + { + PBYTE pStruct = GetStructPtr(); + size_t nStructSize = DetourMemSize(pStruct); + Detour_Assert(nStructSize); + return nStructSize; + } + PBYTE GetHeadPtr() const + { + PBYTE pHead = (PBYTE)&dwpHead; + return pHead; + } + size_t GetHeadSize() const + { + size_t nHeadSize = sizeof(dwpHead); + return nHeadSize; + } +public: + PBYTE GetObjectPtr() + { + PBYTE pStruct = GetStructPtr(); + PBYTE pObject = pStruct + sizeof(DetourMemory); + return pObject; + } + size_t GetObjectSize() const + { + return nObjectSize; + } +private: + PBYTE GetTailPtr() + { + PBYTE pObject = GetObjectPtr(); + PBYTE pTail = pObject + nObjectSize; + return pTail; + } + size_t GetTailSize() const + { + size_t nTailSize = 0; + size_t nStructSize = GetStructSize(); + if (nStructSize) { + nTailSize = nStructSize - sizeof(DetourMemory) - nObjectSize; + // nTailSize equal to 0 is allowed + } + return nTailSize; + } +private: + BOOL ValidateOrFillFlagPart_Internal(PBYTE pFlagPart, size_t nFlagPartSize, const DWORD_PTR dwpFlagPart_Per, BOOL bValidate) + { + BOOL bIsValid = TRUE; + DWORD_PTR* dwpFlagPart_Ptr = (DWORD_PTR*)pFlagPart; + size_t dwpFlagPart_Size = nFlagPartSize / sizeof(dwpFlagPart_Per); + for (size_t i = 0; i < dwpFlagPart_Size; i++) { + if (bValidate) { + if (dwpFlagPart_Ptr[i] != dwpFlagPart_Per) { + bIsValid = FALSE; + Detour_Assert(bIsValid); + break; + } + } + else { + dwpFlagPart_Ptr[i] = dwpFlagPart_Per; + } + } + return bIsValid; + } + BOOL ValidateOrFillFlagPart_Head(BOOL bValidate) + { + PBYTE pFlagPart = GetHeadPtr(); + size_t nFlagPartSize = GetHeadSize(); + const DWORD_PTR dwpFlagPart_Per = *(DWORD_PTR*)"HeadPart"; + BOOL bIsValid = ValidateOrFillFlagPart_Internal(pFlagPart, nFlagPartSize, dwpFlagPart_Per, bValidate); + Detour_Assert(bIsValid); + return bIsValid; + } + BOOL ValidateOrFillFlagPart_Tail(BOOL bValidate) + { + PBYTE pFlagPart = GetTailPtr(); + size_t nFlagPartSize = GetTailSize(); + const DWORD_PTR dwpFlagPart_Per = *(DWORD_PTR*)"TailPart"; + BOOL bIsValid = ValidateOrFillFlagPart_Internal(pFlagPart, nFlagPartSize, dwpFlagPart_Per, bValidate); + return bIsValid; + } + BOOL Fill() + { +#ifdef __ENABLE_DETOUR_MEMORY_VALIDATE__ + return ValidateOrFillFlagPart_Head(FALSE) && ValidateOrFillFlagPart_Tail(FALSE); +#else + return TRUE; +#endif + } + BOOL Validate() + { +#ifdef __ENABLE_DETOUR_MEMORY_VALIDATE__ + return ValidateOrFillFlagPart_Head(TRUE) && ValidateOrFillFlagPart_Tail(TRUE); +#else + return TRUE; +#endif + } +private: + static inline PVOID DetourMemAlloc(size_t size) + { + PVOID pDetourMemBlock = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE); + return pDetourMemBlock; + } + static inline PVOID DetourMemReAlloc(PVOID pDetourMemBlock_Old, size_t size_New) + { + PVOID pDetourMemBlock_New = VirtualAlloc(pDetourMemBlock_Old, size_New, MEM_COMMIT, PAGE_READWRITE); + if (pDetourMemBlock_New == NULL) { + pDetourMemBlock_New = VirtualAlloc(NULL, size_New, MEM_COMMIT, PAGE_READWRITE); + } + return pDetourMemBlock_New; + } + static inline size_t DetourMemSize(PVOID pDetourMemBlock) + { + MEMORY_BASIC_INFORMATION mbi; + mbi.RegionSize = 0; + BOOL bResult = VirtualQuery(pDetourMemBlock, &mbi, sizeof(mbi)) == sizeof(mbi); + Detour_Assert(bResult); + if (bResult) { + bResult = mbi.BaseAddress == mbi.AllocationBase; + Detour_Assert(bResult); + if (!bResult) { + mbi.RegionSize = 0; + } + } + return mbi.RegionSize; + } + static inline BOOL DetourMemFree(PVOID pDetourMemBlock) + { + BOOL bResult = VirtualFree(pDetourMemBlock, 0, MEM_RELEASE); + Detour_Assert(bResult); + return bResult; + } +public: + static DetourMemory* Create(size_t nObjectSize) + { + DetourMemory m(nObjectSize, TRUE); + DetourMemory* pm = (DetourMemory*)DetourMemAlloc(m.GetNeedAllocateSize()); + if (pm) { + ::new(pm) DetourMemory(m.GetObjectSize(), FALSE); + } + return pm; + } + static DetourMemory* ReCreate(DetourMemory* pm_Old, size_t nObjectSize_New) + { + DetourMemory m(nObjectSize_New, TRUE); + DetourMemory* pm_New = (DetourMemory*)DetourMemReAlloc(pm_Old, m.GetNeedAllocateSize()); + if (pm_New) { + ::new(pm_New) DetourMemory(m.GetObjectSize(), FALSE); + } + return pm_New; + } + static BOOL Destroy(DetourMemory*& pm) + { + BOOL bResult = FALSE; + if (pm) { + bResult = DetourMemFree((PVOID)pm); + if (bResult) { + pm = NULL; + } + } + return bResult; + } +public: + static DetourMemory* FromObjectPtr(PBYTE p) + { + DetourMemory* pm = NULL; + if (p) { + pm = (DetourMemory*)(p - sizeof(DetourMemory)); + if (!pm->Validate()) { + pm = NULL; + } + } + return pm; + } +}; + +inline PVOID __cdecl DetourObjectByteArray_Alloc(size_t size) +{ + DetourMemory* pm = DetourMemory::Create(size); + BYTE* p = NULL; + if (pm) { + p = pm->GetObjectPtr(); + } + return p; +} +inline void __cdecl DetourObjectByteArray_Free(PVOID p) +{ + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm) { + DetourMemory::Destroy(pm); + } +} +inline size_t __cdecl DetourObjectByteArray_Size(PVOID p) +{ + size_t size = 0; + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + Detour_Assert(pm); + if (pm) { + size = pm->GetObjectSize(); + } + return size; +} +inline PVOID __cdecl DetourObjectByteArray_ReAlloc(PVOID p_Old, size_t size_New) +{ + if (p_Old == NULL) { + return DetourObjectByteArray_Alloc(size_New); + } + + if (size_New == 0) { + DetourObjectByteArray_Free(p_Old); + return NULL; + } + + DetourMemory* pm_Old = DetourMemory::FromObjectPtr((PBYTE)p_Old); + if (pm_Old == NULL) { + // p_Old is a invalid memory block! + return NULL; + } + DetourMemory* pm_New = DetourMemory::ReCreate(pm_Old, size_New); + BYTE* p_New = NULL; + if (pm_New) { + p_New = pm_New->GetObjectPtr(); + if (p_New != p_Old) { + size_t copy_size = __min(pm_Old->GetObjectSize(), pm_New->GetObjectSize()); + memcpy(p_New, p_Old, copy_size); + DetourObjectByteArray_Free(p_Old); + p_Old = NULL; + } + } + + return p_New; +} + +template +T* DetourCreateObject() +{ + T* p = (T*)DetourObjectByteArray_Alloc(sizeof(T)); + if (p) { + ::new(p) T; + // Revalidate DetourMemory object after call its constructor + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm == NULL) { + // overwrite error + Detour_Assert(pm); + p = NULL; + } + } + return p; +} +template +T* DetourCreateObject(P1 p1) +{ + T* p = (T*)DetourObjectByteArray_Alloc(sizeof(T)); + if (p) { + ::new(p) T(p1); + // Revalidate DetourMemory object after call its constructor + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm == NULL) { + // overwrite error + Detour_Assert(pm); + p = NULL; + } + } + return p; +} +template +T* DetourCreateObject(P1 p1, P2 p2) +{ + T* p = (T*)DetourObjectByteArray_Alloc(sizeof(T)); + if (p) { + ::new(p) T(p1, p2); + // Revalidate DetourMemory object after call its constructor + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm == NULL) { + // overwrite error + Detour_Assert(pm); + p = NULL; + } + } + return p; +} +template +void DetourDestroyObject(T*& p) +{ + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm) { + size_t MemSize = pm->GetObjectSize(); + Detour_Assert(MemSize == sizeof(T)); + if (MemSize != sizeof(T)) { + return; + } + + p->~T(); + // validate and release DetourMemory object after call their destructor + DetourObjectByteArray_Free((PVOID)p); + p = NULL; + } +} +template +T* DetourCreateObjectArray(size_t size) +{ + T* p = (T*)DetourObjectByteArray_Alloc(sizeof(T) * size); + if (p) { + for (size_t i = 0; i < size; i++) { + ::new(&p[i]) T; + } + // Revalidate DetourMemory object after call their constructor + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm == NULL) { + // overwrite error + Detour_Assert(pm); + p = NULL; + } + } + return p; +} +template +void DetourDestroyObjectArray(T*& p) +{ + DetourMemory* pm = DetourMemory::FromObjectPtr((PBYTE)p); + if (pm) { + size_t MemSize = pm->GetObjectSize(); + Detour_Assert(MemSize % sizeof(T) == 0); + if (MemSize % sizeof(T) != 0) { + return; + } + + size_t _Size = MemSize / sizeof(T); + // _Size equal to 0 is allowed + for (size_t i = 0; i < _Size; i++) { + (&p[i])->~T(); + } + // validate and release DetourMemory object after call their destructor + DetourObjectByteArray_Free((PVOID)p); + p = NULL; + } +} + ////////////////////////////////////////////////////////////////////////////// #define MM_ALLOCATION_GRANULARITY 0x10000 diff --git a/src/image.cpp b/src/image.cpp index 897df4eb..4a415ff0 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -323,7 +323,7 @@ static LPCSTR DuplicateString(_In_ LPCSTR pszIn) return NULL; } - PCHAR pszOut = new NOTHROW CHAR [cch + 1]; + PCHAR pszOut = DetourCreateObjectArray(cch + 1); if (pszOut == NULL) { SetLastError(ERROR_OUTOFMEMORY); return NULL; @@ -331,7 +331,7 @@ static LPCSTR DuplicateString(_In_ LPCSTR pszIn) hr = StringCchCopyA(pszOut, cch + 1, pszIn); if (FAILED(hr)) { - delete[] pszOut; + DetourDestroyObjectArray(pszOut); return NULL; } @@ -341,7 +341,7 @@ static LPCSTR DuplicateString(_In_ LPCSTR pszIn) static VOID ReleaseString(_In_opt_ LPCSTR psz) { if (psz != NULL) { - delete[] psz; + DetourDestroyObjectArray(psz); } } @@ -366,20 +366,20 @@ CImageImportFile::CImageImportFile() CImageImportFile::~CImageImportFile() { if (m_pNextFile) { - delete m_pNextFile; + DetourDestroyObject(m_pNextFile); m_pNextFile = NULL; } if (m_pImportNames) { - delete[] m_pImportNames; + DetourDestroyObjectArray(m_pImportNames); m_pImportNames = NULL; m_nImportNames = 0; } if (m_pszName) { - delete[] m_pszName; + DetourDestroyObjectArray(m_pszName); m_pszName = NULL; } if (m_pszOrig) { - delete[] m_pszOrig; + DetourDestroyObjectArray(m_pszOrig); m_pszOrig = NULL; } } @@ -396,11 +396,11 @@ CImageImportName::CImageImportName() CImageImportName::~CImageImportName() { if (m_pszName) { - delete[] m_pszName; + DetourDestroyObjectArray(m_pszName); m_pszName = NULL; } if (m_pszOrig) { - delete[] m_pszOrig; + DetourDestroyObjectArray(m_pszOrig); m_pszOrig = NULL; } } @@ -422,7 +422,7 @@ CImageData::~CImageData() m_pbData = NULL; } if (m_pbData) { - delete[] m_pbData; + DetourDestroyObjectArray(m_pbData); m_pbData = NULL; } m_cbData = 0; @@ -437,7 +437,7 @@ BOOL CImageData::SizeTo(DWORD cbData) return TRUE; } - PBYTE pbNew = new NOTHROW BYTE [cbData]; + PBYTE pbNew = DetourCreateObjectArray(cbData); if (pbNew == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -446,7 +446,7 @@ BOOL CImageData::SizeTo(DWORD cbData) if (m_pbData) { CopyMemory(pbNew, m_pbData, m_cbData); if (m_cbAlloc > 0) { - delete[] m_pbData; + DetourDestroyObjectArray(m_pbData); } m_pbData = NULL; } @@ -789,13 +789,13 @@ CImage::~CImage() BOOL CImage::Close() { if (m_pImportFiles) { - delete m_pImportFiles; + DetourDestroyObject(m_pImportFiles); m_pImportFiles = NULL; m_nImportFiles = 0; } if (m_pImageData) { - delete m_pImageData; + DetourDestroyObject(m_pImageData); m_pImageData = NULL; } @@ -810,7 +810,7 @@ BOOL CImage::Close() } if (m_pbOutputBuffer) { - delete[] m_pbOutputBuffer; + DetourDestroyObjectArray(m_pbOutputBuffer); m_pbOutputBuffer = NULL; m_cbOutputBuffer = 0; } @@ -869,7 +869,7 @@ BOOL CImage::SizeOutputBuffer(DWORD cbData) } cbData = FileAlign(cbData); - PBYTE pOutput = new NOTHROW BYTE [cbData]; + PBYTE pOutput = DetourCreateObjectArray(cbData); if (pOutput == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; @@ -878,7 +878,7 @@ BOOL CImage::SizeOutputBuffer(DWORD cbData) if (m_pbOutputBuffer) { CopyMemory(pOutput, m_pbOutputBuffer, m_cbOutputBuffer); - delete[] m_pbOutputBuffer; + DetourDestroyObjectArray(m_pbOutputBuffer); m_pbOutputBuffer = NULL; } @@ -1150,7 +1150,7 @@ BOOL CImage::Read(HANDLE hFile) goto fail; } - CImageImportFile *pImportFile = new NOTHROW CImageImportFile; + CImageImportFile *pImportFile = DetourCreateObject(); if (pImportFile == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto fail; @@ -1210,7 +1210,7 @@ BOOL CImage::Read(HANDLE hFile) if (pAddrThunk && nNames) { pImportFile->m_nImportNames = nNames; - pImportFile->m_pImportNames = new NOTHROW CImageImportName [nNames]; + pImportFile->m_pImportNames = DetourCreateObjectArray(nNames); if (pImportFile->m_pImportNames == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto fail; @@ -1320,7 +1320,7 @@ BOOL CImage::Read(HANDLE hFile) } } - m_pImageData = new NOTHROW CImageData(pbData, cbData); + m_pImageData = DetourCreateObject(pbData, cbData); if (m_pImageData == NULL) { SetLastError(ERROR_OUTOFMEMORY); } @@ -1397,7 +1397,7 @@ BOOL CImage::CheckImportsNeeded(DWORD *pnTables, DWORD *pnThunks, DWORD *pnChars // CImageImportFile * CImage::NewByway(_In_ LPCSTR pszName) { - CImageImportFile *pImportFile = new NOTHROW CImageImportFile; + CImageImportFile *pImportFile = DetourCreateObject(); if (pImportFile == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto fail; @@ -1422,7 +1422,7 @@ CImageImportFile * CImage::NewByway(_In_ LPCSTR pszName) fail: if (pImportFile) { - delete pImportFile; + DetourDestroyObject(pImportFile); pImportFile = NULL; } return NULL; @@ -1484,7 +1484,7 @@ BOOL CImage::EditImports(PVOID pContext, else { // Delete Byway *ppLastFile = pImportFile->m_pNextFile; pImportFile->m_pNextFile = NULL; - delete pImportFile; + DetourDestroyObject(pImportFile); m_nImportFiles--; continue; // Retry after delete. } @@ -1547,7 +1547,7 @@ BOOL CImage::EditImports(PVOID pContext, pImportName->m_nOrdinal = nOrdinal; if (pImportName->m_pszName != NULL) { - delete[] pImportName->m_pszName; + DetourDestroyObjectArray(pImportName->m_pszName); pImportName->m_pszName = NULL; } } @@ -1684,7 +1684,7 @@ BOOL CImage::Write(HANDLE hFile) m_nNextFileAddr = Max(m_SectionHeaders[n].PointerToRawData + m_SectionHeaders[n].SizeOfRawData, m_nNextFileAddr); - // Old images have VirtualSize == 0 as a matter of course, e.g. NT 3.1. + // Old images have VirtualSize == 0 as a matter of course, e.g. NT 3.1. // In which case, use SizeOfRawData instead. m_nNextVirtAddr = Max(m_SectionHeaders[n].VirtualAddress + (m_SectionHeaders[n].Misc.VirtualSize @@ -2031,15 +2031,14 @@ BOOL CImage::Write(HANDLE hFile) // PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile) { - Detour::CImage *pImage = new NOTHROW - Detour::CImage; + Detour::CImage *pImage = DetourCreateObject(); if (pImage == NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } if (!pImage->Read(hFile)) { - delete pImage; + DetourDestroyObject(pImage); return FALSE; } @@ -2207,7 +2206,7 @@ BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary) } BOOL bSuccess = pImage->Close(); - delete pImage; + DetourDestroyObject(pImage); pImage = NULL; return bSuccess; diff --git a/src/modules.cpp b/src/modules.cpp index 52fc2cfb..e62f5dee 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -229,7 +229,7 @@ PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, // and have to convert it to a wrapped [code pointer, global pointer]. // PPLABEL_DESCRIPTOR pldEntry = (PPLABEL_DESCRIPTOR)DetourGetEntryPoint(hModule); - PPLABEL_DESCRIPTOR pldSymbol = new PLABEL_DESCRIPTOR; + PPLABEL_DESCRIPTOR pldSymbol = DetourCreateObject(); pldSymbol->EntryPoint = symbol.Address; pldSymbol->GlobalPointer = pldEntry->GlobalPointer; diff --git a/src/uimports.cpp b/src/uimports.cpp index ed43d659..65826c27 100644 --- a/src/uimports.cpp +++ b/src/uimports.cpp @@ -40,7 +40,7 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess, finish: if (pbNew != NULL) { - delete[] pbNew; + DetourDestroyObjectArray(pbNew); pbNew = NULL; } return fSucceeded; @@ -178,9 +178,13 @@ static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess, goto finish; } } - pbNew = new BYTE [cbNew]; + + _Analysis_assume_(cbNew > + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (nDlls + nOldDlls) + + sizeof(DWORD_XX) * 4 * nDlls); + pbNew = DetourCreateObjectArray(cbNew); if (pbNew == NULL) { - DETOUR_TRACE(("new BYTE [cbNew] failed.\n")); + DETOUR_TRACE(("DetourCreateObjectArray(cbNew) failed.\n")); goto finish; } ZeroMemory(pbNew, cbNew);