Skip to content

Commit e46faaa

Browse files
committed
Add SlimDetoursDetachEx to allow to free the trampoline manually
Usage example: SlimDetoursTransactionBegin(); PVOID pTrampoline = NULL; DETOUR_DETACH_OPTIONS Options; Options.ppTrampolineToFreeManually = &pTrampoline; SlimDetoursDetachEx(pPointer, pDetour, &Options); SlimDetoursTransactionCommit(); Sleep(1000); SlimDetoursFreeTrampoline(pTrampoline);
1 parent 06bcb22 commit e46faaa

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-7
lines changed

Source/SlimDetours/SlimDetours.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,35 @@ SlimDetoursAttach(
6262
_Inout_ PVOID* ppPointer,
6363
_In_ PVOID pDetour);
6464

65+
typedef struct _DETOUR_DETACH_OPTIONS
66+
{
67+
PVOID *ppTrampolineToFreeManually;
68+
} DETOUR_DETACH_OPTIONS, *PDETOUR_DETACH_OPTIONS;
69+
70+
typedef const DETOUR_DETACH_OPTIONS* PCDETOUR_DETACH_OPTIONS;
71+
6572
HRESULT
6673
NTAPI
74+
SlimDetoursDetachEx(
75+
_Inout_ PVOID* ppPointer,
76+
_In_ PVOID pDetour,
77+
_In_ PCDETOUR_DETACH_OPTIONS pOptions);
78+
79+
FORCEINLINE
80+
HRESULT
6781
SlimDetoursDetach(
6882
_Inout_ PVOID* ppPointer,
69-
_In_ PVOID pDetour);
83+
_In_ PVOID pDetour)
84+
{
85+
DETOUR_DETACH_OPTIONS Options;
86+
Options.ppTrampolineToFreeManually = NULL;
87+
return SlimDetoursDetachEx(ppPointer, pDetour, &Options);
88+
}
89+
90+
HRESULT
91+
NTAPI
92+
SlimDetoursFreeTrampoline(
93+
_In_ PVOID pTrampoline);
7094

7195
PVOID
7296
NTAPI

Source/SlimDetours/SlimDetours.inl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ struct _DETOUR_OPERATION
117117
PBYTE pbTarget;
118118
PDETOUR_TRAMPOLINE pTrampoline;
119119
ULONG dwPerm;
120+
PVOID* ppTrampolineToFreeManually;
120121
};
121122

122123
/* Memory management */

Source/SlimDetours/Transaction.c

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,14 @@ SlimDetoursTransactionCommit(VOID)
194194
NtFlushInstructionCache(NtCurrentProcess(), o->pbTarget, o->pTrampoline->cbRestore);
195195
} else
196196
{
197-
// Don't remove in this case, put in bypass mode and leak trampoline.
197+
// Don't remove and leak trampoline in this case.
198198
o->dwOperation = DETOUR_OPERATION_NONE;
199-
o->pTrampoline->pbDetour = o->pTrampoline->rbCode;
200199
DETOUR_TRACE("detours: Leaked hook on pbTarget=%p due to external hooking\n", o->pbTarget);
201200
}
202201

202+
// Put hook in bypass mode.
203+
o->pTrampoline->pbDetour = o->pTrampoline->rbCode;
204+
203205
*o->ppbPointer = o->pbTarget;
204206
} else if (o->dwOperation == DETOUR_OPERATION_ADD)
205207
{
@@ -270,9 +272,16 @@ SlimDetoursTransactionCommit(VOID)
270272
NtProtectVirtualMemory(NtCurrentProcess(), &pMem, &sMem, o->dwPerm, &dwOld);
271273
if (o->dwOperation == DETOUR_OPERATION_REMOVE)
272274
{
273-
detour_free_trampoline(o->pTrampoline);
275+
if (!o->ppTrampolineToFreeManually)
276+
{
277+
detour_free_trampoline(o->pTrampoline);
278+
freed = TRUE;
279+
} else
280+
{
281+
// The caller is responsible for freeing the trampoline.
282+
*o->ppTrampolineToFreeManually = o->pTrampoline;
283+
}
274284
o->pTrampoline = NULL;
275-
freed = TRUE;
276285
}
277286

278287
n = o->pNext;
@@ -505,9 +514,10 @@ SlimDetoursAttach(
505514

506515
HRESULT
507516
NTAPI
508-
SlimDetoursDetach(
517+
SlimDetoursDetachEx(
509518
_Inout_ PVOID* ppPointer,
510-
_In_ PVOID pDetour)
519+
_In_ PVOID pDetour,
520+
_In_ PCDETOUR_DETACH_OPTIONS pOptions)
511521
{
512522
NTSTATUS Status;
513523
PVOID pMem;
@@ -560,12 +570,66 @@ SlimDetoursDetach(
560570
o->pTrampoline = pTrampoline;
561571
o->pbTarget = pbTarget;
562572
o->dwPerm = dwOld;
573+
o->ppTrampolineToFreeManually = pOptions->ppTrampolineToFreeManually;
563574
o->pNext = s_pPendingOperations;
564575
s_pPendingOperations = o;
565576

566577
return HRESULT_FROM_NT(STATUS_SUCCESS);
567578
}
568579

580+
HRESULT
581+
NTAPI
582+
SlimDetoursFreeTrampoline(
583+
_In_ PVOID pTrampoline)
584+
{
585+
if (pTrampoline == NULL)
586+
{
587+
return HRESULT_FROM_NT(STATUS_SUCCESS);
588+
}
589+
590+
NTSTATUS Status;
591+
592+
// This function can be called as part of a transaction or outside of a transaction.
593+
BOOL bInTransaction = FALSE;
594+
if (_InterlockedCompareExchange(&s_nPendingThreadId, NtCurrentThreadId(), 0) == 0)
595+
{
596+
bInTransaction = TRUE;
597+
}
598+
599+
if (!bInTransaction)
600+
{
601+
// Make sure the trampoline pages are writable.
602+
Status = detour_writable_trampoline_regions();
603+
if (!NT_SUCCESS(Status))
604+
{
605+
goto fail;
606+
}
607+
}
608+
609+
detour_free_trampoline((PDETOUR_TRAMPOLINE)pTrampoline);
610+
detour_free_trampoline_region_if_unused((PDETOUR_TRAMPOLINE)pTrampoline);
611+
612+
if (!bInTransaction)
613+
{
614+
detour_runnable_trampoline_regions();
615+
}
616+
617+
Status = STATUS_SUCCESS;
618+
619+
fail:
620+
if (!bInTransaction)
621+
{
622+
#ifdef _MSC_VER
623+
#pragma warning(disable: __WARNING_INTERLOCKED_ACCESS)
624+
#endif
625+
s_nPendingThreadId = 0;
626+
#ifdef _MSC_VER
627+
#pragma warning(default: __WARNING_INTERLOCKED_ACCESS)
628+
#endif
629+
}
630+
return HRESULT_FROM_NT(Status);
631+
}
632+
569633
HRESULT
570634
NTAPI
571635
SlimDetoursUninitialize(VOID)

0 commit comments

Comments
 (0)