Skip to content

Commit 6e5792c

Browse files
committed
Add SlimDetoursDetachEx to allow to free the trampoline manually
Usage example: SlimDetoursTransactionBegin(); PVOID pTrampoline = pPointer; DETOUR_DETACH_OPTIONS Options; Options.fFreeTrampoline = FALSE; SlimDetoursDetachEx(pPointer, pDetour, &Options); SlimDetoursTransactionCommit(); Sleep(1000); SlimDetoursFreeTrampoline(pTrampoline);
1 parent 67b9e57 commit 6e5792c

File tree

4 files changed

+75
-9
lines changed

4 files changed

+75
-9
lines changed

Source/SlimDetours/SlimDetours.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,34 @@ SlimDetoursAttach(
4545
_Inout_ PVOID* ppPointer,
4646
_In_ PVOID pDetour);
4747

48+
typedef struct _DETOUR_DETACH_OPTIONS
49+
{
50+
BOOL fFreeTrampoline;
51+
} DETOUR_DETACH_OPTIONS, *PDETOUR_DETACH_OPTIONS;
52+
53+
typedef const DETOUR_DETACH_OPTIONS* PCDETOUR_DETACH_OPTIONS;
54+
4855
HRESULT
4956
NTAPI
57+
SlimDetoursDetachEx(
58+
_Inout_ PVOID* ppPointer,
59+
_In_ PVOID pDetour,
60+
_In_ PCDETOUR_DETACH_OPTIONS pOptions);
61+
62+
FORCEINLINE
63+
HRESULT
5064
SlimDetoursDetach(
5165
_Inout_ PVOID* ppPointer,
52-
_In_ PVOID pDetour);
66+
_In_ PVOID pDetour)
67+
{
68+
DETOUR_DETACH_OPTIONS Options;
69+
Options.fFreeTrampoline = TRUE;
70+
return SlimDetoursDetachEx(ppPointer, pDetour, &Options);
71+
}
72+
HRESULT
73+
NTAPI
74+
SlimDetoursFreeTrampoline(
75+
_In_ PVOID pTrampoline);
5376

5477
PVOID
5578
NTAPI

Source/SlimDetours/SlimDetours.inl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ enum
105105
DETOUR_OPERATION_NONE = 0,
106106
DETOUR_OPERATION_ADD,
107107
DETOUR_OPERATION_REMOVE,
108+
DETOUR_OPERATION_REMOVE_AND_FREE,
108109
};
109110

110111
typedef struct _DETOUR_OPERATION DETOUR_OPERATION, *PDETOUR_OPERATION;

Source/SlimDetours/Thread.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,8 @@ detour_thread_update(
188188
bUpdateContext = FALSE;
189189
for (o = PendingOperations; o != NULL && !bUpdateContext; o = o->pNext)
190190
{
191-
if (o->dwOperation == DETOUR_OPERATION_REMOVE)
191+
if (o->dwOperation == DETOUR_OPERATION_REMOVE ||
192+
o->dwOperation == DETOUR_OPERATION_REMOVE_AND_FREE)
192193
{
193194
if (cxt.CONTEXT_PC >= (ULONG_PTR)o->pTrampoline->rbCode &&
194195
cxt.CONTEXT_PC < ((ULONG_PTR)o->pTrampoline->rbCode + RTL_FIELD_SIZE(DETOUR_TRAMPOLINE, rbCode)))

Source/SlimDetours/Transaction.c

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ SlimDetoursTransactionCommit(VOID)
169169
o = s_pPendingOperations;
170170
do
171171
{
172-
if (o->dwOperation == DETOUR_OPERATION_REMOVE)
172+
if (o->dwOperation == DETOUR_OPERATION_REMOVE ||
173+
o->dwOperation == DETOUR_OPERATION_REMOVE_AND_FREE)
173174
{
174175
// Check if the jmps still points where we expect, otherwise someone might have hooked us.
175176
BOOL hookIsStillThere =
@@ -186,12 +187,14 @@ SlimDetoursTransactionCommit(VOID)
186187
NtFlushInstructionCache(NtCurrentProcess(), o->pbTarget, o->pTrampoline->cbRestore);
187188
} else
188189
{
189-
// Don't remove in this case, put in bypass mode and leak trampoline.
190+
// Don't remove and leak trampoline in this case.
190191
o->dwOperation = DETOUR_OPERATION_NONE;
191-
o->pTrampoline->pbDetour = o->pTrampoline->rbCode;
192192
DETOUR_TRACE("detours: Leaked hook on pbTarget=%p due to external hooking\n", o->pbTarget);
193193
}
194194

195+
// Put hook in bypass mode.
196+
o->pTrampoline->pbDetour = o->pTrampoline->rbCode;
197+
195198
*o->ppbPointer = o->pbTarget;
196199
} else if (o->dwOperation == DETOUR_OPERATION_ADD)
197200
{
@@ -260,7 +263,7 @@ SlimDetoursTransactionCommit(VOID)
260263
pMem = o->pbTarget;
261264
sMem = o->pTrampoline->cbRestore;
262265
NtProtectVirtualMemory(NtCurrentProcess(), &pMem, &sMem, o->dwPerm, &dwOld);
263-
if (o->dwOperation == DETOUR_OPERATION_REMOVE)
266+
if (o->dwOperation == DETOUR_OPERATION_REMOVE_AND_FREE)
264267
{
265268
detour_free_trampoline(o->pTrampoline);
266269
o->pTrampoline = NULL;
@@ -496,9 +499,10 @@ SlimDetoursAttach(
496499

497500
HRESULT
498501
NTAPI
499-
SlimDetoursDetach(
502+
SlimDetoursDetachEx(
500503
_Inout_ PVOID* ppPointer,
501-
_In_ PVOID pDetour)
504+
_In_ PVOID pDetour,
505+
_In_ PCDETOUR_DETACH_OPTIONS pOptions)
502506
{
503507
NTSTATUS Status;
504508
PVOID pMem;
@@ -546,7 +550,9 @@ SlimDetoursDetach(
546550
goto fail;
547551
}
548552

549-
o->dwOperation = DETOUR_OPERATION_REMOVE;
553+
o->dwOperation = pOptions->fFreeTrampoline
554+
? DETOUR_OPERATION_REMOVE_AND_FREE
555+
: DETOUR_OPERATION_REMOVE;
550556
o->ppbPointer = (PBYTE*)ppPointer;
551557
o->pTrampoline = pTrampoline;
552558
o->pbTarget = pbTarget;
@@ -557,6 +563,41 @@ SlimDetoursDetach(
557563
return HRESULT_FROM_NT(STATUS_SUCCESS);
558564
}
559565

566+
HRESULT
567+
NTAPI
568+
SlimDetoursFreeTrampoline(
569+
_In_ PVOID pTrampoline)
570+
{
571+
NTSTATUS Status;
572+
573+
// Make sure only one thread can start a transaction.
574+
if (_InterlockedCompareExchange(&s_nPendingThreadId, NtCurrentThreadId(), 0) != 0)
575+
{
576+
return HRESULT_FROM_NT(STATUS_TRANSACTIONAL_CONFLICT);
577+
}
578+
579+
// Make sure the trampoline pages are writable.
580+
Status = detour_writable_trampoline_regions();
581+
if (!NT_SUCCESS(Status))
582+
{
583+
goto fail;
584+
}
585+
586+
detour_free_trampoline((PDETOUR_TRAMPOLINE)pTrampoline);
587+
detour_free_trampoline_region_if_unused((PDETOUR_TRAMPOLINE)pTrampoline);
588+
589+
detour_runnable_trampoline_regions();
590+
591+
fail:
592+
#ifdef _MSC_VER
593+
#pragma warning(disable: __WARNING_INTERLOCKED_ACCESS)
594+
#endif
595+
s_nPendingThreadId = 0;
596+
#ifdef _MSC_VER
597+
#pragma warning(default: __WARNING_INTERLOCKED_ACCESS)
598+
#endif
599+
}
600+
560601
#if (NTDDI_VERSION >= NTDDI_WIN6)
561602

562603
static

0 commit comments

Comments
 (0)