Skip to content

Commit dbcd6c3

Browse files
committed
Better Suspender
1 parent ad11b45 commit dbcd6c3

File tree

2 files changed

+109
-13
lines changed

2 files changed

+109
-13
lines changed

Detours.cpp

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5694,24 +5694,37 @@ namespace Detours {
56945694
// Suspender
56955695
// ----------------------------------------------------------------
56965696

5697+
56975698
Suspender::~Suspender() {
5699+
if (m_Mutex.Lock()) {
5700+
if (m_unSuspendDepth > 0) {
5701+
m_unSuspendDepth = 1;
5702+
}
5703+
5704+
m_Mutex.UnLock();
5705+
}
5706+
56985707
Resume();
56995708
}
57005709

5701-
bool Suspender::Suspend() {
5710+
bool Suspender::Suspend(bool bSweepThreads) {
57025711
if (!m_Mutex.Lock()) {
57035712
return false;
57045713
}
57055714

5706-
const auto& hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, NULL);
5715+
if (m_unSuspendDepth > 0) {
5716+
++m_unSuspendDepth;
5717+
m_Mutex.UnLock();
5718+
return true;
5719+
}
5720+
5721+
const auto& hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
57075722
if (!hSnap || (hSnap == INVALID_HANDLE_VALUE)) {
57085723
m_Mutex.UnLock();
57095724
return false;
57105725
}
57115726

5712-
THREADENTRY32 te;
5713-
memset(&te, 0, sizeof(te));
5714-
5727+
THREADENTRY32 te {};
57155728
te.dwSize = sizeof(THREADENTRY32);
57165729

57175730
if (!Thread32First(hSnap, &te)) {
@@ -5727,19 +5740,19 @@ namespace Detours {
57275740
return false;
57285741
}
57295742

5743+
m_SuspendedTIDs.clear();
5744+
57305745
do {
57315746
if ((pTEB->ClientId.UniqueProcess == te.th32OwnerProcessID) && (pTEB->ClientId.UniqueThread != te.th32ThreadID)) {
57325747
HANDLE hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, FALSE, te.th32ThreadID);
57335748
if (hThread && (hThread != INVALID_HANDLE_VALUE)) {
57345749
if (SuspendThread(hThread) == static_cast<DWORD>(-1)) {
5750+
CloseHandle(hThread);
57355751
continue;
57365752
}
57375753

5738-
CONTEXT ctx;
5739-
memset(&ctx, 0, sizeof(CONTEXT));
5740-
5754+
CONTEXT ctx {};
57415755
ctx.ContextFlags = CONTEXT_FULL;
5742-
57435756
if (!GetThreadContext(hThread, &ctx)) {
57445757
ResumeThread(hThread);
57455758
CloseHandle(hThread);
@@ -5753,14 +5766,40 @@ namespace Detours {
57535766

57545767
CloseHandle(hSnap);
57555768

5756-
if (!m_Mutex.UnLock()) {
5757-
return false;
5769+
if (bSweepThreads) {
5770+
const DWORD64 unStartTick = GetTickCount64();
5771+
5772+
while (true) {
5773+
size_t unAdded = SuspendNewThreadsSnapshot();
5774+
5775+
if (GetTickCount64() - unStartTick >= 1000) {
5776+
break;
5777+
}
5778+
5779+
if (unAdded == 0) {
5780+
Sleep(50);
5781+
}
5782+
}
57585783
}
57595784

5785+
m_unSuspendDepth = 1;
5786+
m_Mutex.UnLock();
57605787
return true;
57615788
}
57625789

57635790
void Suspender::Resume() {
5791+
if (!m_Mutex.Lock())
5792+
return;
5793+
5794+
if (m_unSuspendDepth == 0) {
5795+
m_Mutex.UnLock();
5796+
return;
5797+
}
5798+
5799+
if (--m_unSuspendDepth > 0) {
5800+
m_Mutex.UnLock();
5801+
return;
5802+
}
57645803

57655804
for (auto& thread : m_Threads) {
57665805
SetThreadContext(thread.m_hHandle, &thread.m_CTX);
@@ -5769,6 +5808,9 @@ namespace Detours {
57695808
}
57705809

57715810
m_Threads.clear();
5811+
m_SuspendedTIDs.clear();
5812+
5813+
m_Mutex.UnLock();
57725814
}
57735815

57745816
bool Suspender::IsRegionExecuting(void* pAddress, size_t unSize) {
@@ -5817,7 +5859,7 @@ namespace Detours {
58175859
}
58185860

58195861
void Suspender::FixExecutionAddress(void* pAddress, void* pNewAddress) {
5820-
if (!pAddress || pNewAddress) {
5862+
if (!pAddress || !pNewAddress) {
58215863
return;
58225864
}
58235865

@@ -5844,6 +5886,56 @@ namespace Detours {
58445886
}
58455887
}
58465888

5889+
size_t Suspender::SuspendNewThreadsSnapshot() {
5890+
size_t unAdded = 0;
5891+
5892+
const auto& pTEB = GetTEB();
5893+
if (!pTEB) {
5894+
return 0;
5895+
}
5896+
5897+
const auto& hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
5898+
if (!hSnap || (hSnap == INVALID_HANDLE_VALUE)) {
5899+
return 0;
5900+
}
5901+
5902+
THREADENTRY32 te {};
5903+
te.dwSize = sizeof(THREADENTRY32);
5904+
5905+
if (!Thread32First(hSnap, &te)) {
5906+
CloseHandle(hSnap);
5907+
return 0;
5908+
}
5909+
5910+
do {
5911+
if ((pTEB->ClientId.UniqueProcess == te.th32OwnerProcessID) && (pTEB->ClientId.UniqueThread != te.th32ThreadID) && (m_SuspendedTIDs.find(te.th32ThreadID) == m_SuspendedTIDs.end())) {
5912+
HANDLE hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION | THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_SET_CONTEXT, FALSE, te.th32ThreadID);
5913+
if (!hThread || (hThread == INVALID_HANDLE_VALUE))
5914+
continue;
5915+
5916+
if (SuspendThread(hThread) == static_cast<DWORD>(-1)) {
5917+
CloseHandle(hThread);
5918+
continue;
5919+
}
5920+
5921+
CONTEXT ctx {};
5922+
ctx.ContextFlags = CONTEXT_FULL;
5923+
if (!GetThreadContext(hThread, &ctx)) {
5924+
ResumeThread(hThread);
5925+
CloseHandle(hThread);
5926+
continue;
5927+
}
5928+
5929+
m_Threads.emplace_back(te.th32ThreadID, hThread, ctx);
5930+
m_SuspendedTIDs.insert(te.th32ThreadID);
5931+
++unAdded;
5932+
}
5933+
} while (Thread32Next(hSnap, &te));
5934+
5935+
CloseHandle(hSnap);
5936+
return unAdded;
5937+
}
5938+
58475939
Suspender g_Suspender;
58485940
} // namespace Sync
58495941

Detours.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2293,7 +2293,7 @@ namespace Detours {
22932293
~Suspender();
22942294

22952295
public:
2296-
bool Suspend();
2296+
bool Suspend(bool bSweepThreads = true);
22972297
void Resume();
22982298
bool IsRegionExecuting(void* pAddress, size_t unSize);
22992299
bool IsRegionInCallStacks(void* pAddress, size_t unSize);
@@ -2314,6 +2314,10 @@ namespace Detours {
23142314

23152315
std::deque<SUSPENDER_DATA> m_Threads;
23162316
Mutex m_Mutex;
2317+
size_t m_unSuspendDepth;
2318+
std::unordered_set<DWORD> m_SuspendedTIDs;
2319+
2320+
size_t SuspendNewThreadsSnapshot();
23172321
};
23182322

23192323
extern Suspender g_Suspender;

0 commit comments

Comments
 (0)