@@ -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
506515HRESULT
507516NTAPI
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,67 @@ 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+ // This function can be called as part of a transaction or outside of a transaction.
591+ ULONG nPrevPendingThreadId = _InterlockedCompareExchange (& s_nPendingThreadId , NtCurrentThreadId (), 0 );
592+ BOOL bInTransaction = nPrevPendingThreadId != 0 ;
593+ if (bInTransaction && nPrevPendingThreadId != NtCurrentThreadId ())
594+ {
595+ return HRESULT_FROM_NT (STATUS_TRANSACTIONAL_CONFLICT );
596+ }
597+
598+ NTSTATUS Status ;
599+
600+ if (!bInTransaction )
601+ {
602+ // Make sure the trampoline pages are writable.
603+ Status = detour_writable_trampoline_regions ();
604+ if (!NT_SUCCESS (Status ))
605+ {
606+ goto fail ;
607+ }
608+ }
609+
610+ detour_free_trampoline ((PDETOUR_TRAMPOLINE )pTrampoline );
611+ detour_free_trampoline_region_if_unused ((PDETOUR_TRAMPOLINE )pTrampoline );
612+
613+ if (!bInTransaction )
614+ {
615+ detour_runnable_trampoline_regions ();
616+ }
617+
618+ Status = STATUS_SUCCESS ;
619+
620+ fail :
621+ if (!bInTransaction )
622+ {
623+ #ifdef _MSC_VER
624+ #pragma warning(disable: __WARNING_INTERLOCKED_ACCESS)
625+ #endif
626+ s_nPendingThreadId = 0 ;
627+ #ifdef _MSC_VER
628+ #pragma warning(default: __WARNING_INTERLOCKED_ACCESS)
629+ #endif
630+ }
631+ return HRESULT_FROM_NT (Status );
632+ }
633+
569634HRESULT
570635NTAPI
571636SlimDetoursUninitialize (VOID )
0 commit comments