@@ -160,12 +160,14 @@ SlimDetoursTransactionCommit(VOID)
160160 NtFlushInstructionCache (NtCurrentProcess (), o -> pbTarget , o -> pTrampoline -> cbRestore );
161161 } else
162162 {
163- // Don't remove in this case, put in bypass mode and leak trampoline .
163+ // Don't remove and leak trampoline in this case .
164164 o -> dwOperation = DETOUR_OPERATION_NONE ;
165- o -> pTrampoline -> pbDetour = o -> pTrampoline -> rbCode ;
166165 DETOUR_TRACE ("detours: Leaked hook on pbTarget=%p due to external hooking\n" , o -> pbTarget );
167166 }
168167
168+ // Put hook in bypass mode.
169+ o -> pTrampoline -> pbDetour = o -> pTrampoline -> rbCode ;
170+
169171 * o -> ppbPointer = o -> pbTarget ;
170172 } else if (o -> dwOperation == DETOUR_OPERATION_ADD )
171173 {
@@ -236,9 +238,16 @@ SlimDetoursTransactionCommit(VOID)
236238 NtProtectVirtualMemory (NtCurrentProcess (), & pMem , & sMem , o -> dwPerm , & dwOld );
237239 if (o -> dwOperation == DETOUR_OPERATION_REMOVE )
238240 {
239- detour_free_trampoline (o -> pTrampoline );
241+ if (!o -> ppTrampolineToFreeManually )
242+ {
243+ detour_free_trampoline (o -> pTrampoline );
244+ freed = TRUE;
245+ } else
246+ {
247+ // The caller is responsible for freeing the trampoline.
248+ * o -> ppTrampolineToFreeManually = o -> pTrampoline ;
249+ }
240250 o -> pTrampoline = NULL ;
241- freed = TRUE;
242251 }
243252
244253 n = o -> pNext ;
@@ -471,9 +480,10 @@ SlimDetoursAttach(
471480
472481HRESULT
473482NTAPI
474- SlimDetoursDetach (
483+ SlimDetoursDetachEx (
475484 _Inout_ PVOID * ppPointer ,
476- _In_ PVOID pDetour )
485+ _In_ PVOID pDetour ,
486+ _In_ PCDETOUR_DETACH_OPTIONS pOptions )
477487{
478488 NTSTATUS Status ;
479489 PVOID pMem ;
@@ -526,12 +536,67 @@ SlimDetoursDetach(
526536 o -> pTrampoline = pTrampoline ;
527537 o -> pbTarget = pbTarget ;
528538 o -> dwPerm = dwOld ;
539+ o -> ppTrampolineToFreeManually = pOptions -> ppTrampolineToFreeManually ;
529540 o -> pNext = s_pPendingOperations ;
530541 s_pPendingOperations = o ;
531542
532543 return HRESULT_FROM_NT (STATUS_SUCCESS );
533544}
534545
546+ HRESULT
547+ NTAPI
548+ SlimDetoursFreeTrampoline (
549+ _In_ PVOID pTrampoline )
550+ {
551+ if (pTrampoline == NULL )
552+ {
553+ return HRESULT_FROM_NT (STATUS_SUCCESS );
554+ }
555+
556+ // This function can be called as part of a transaction or outside of a transaction.
557+ ULONG nPrevPendingThreadId = _InterlockedCompareExchange (& s_nPendingThreadId , NtCurrentThreadId (), 0 );
558+ BOOL bInTransaction = nPrevPendingThreadId != 0 ;
559+ if (bInTransaction && nPrevPendingThreadId != NtCurrentThreadId ())
560+ {
561+ return HRESULT_FROM_NT (STATUS_TRANSACTIONAL_CONFLICT );
562+ }
563+
564+ NTSTATUS Status ;
565+
566+ if (!bInTransaction )
567+ {
568+ // Make sure the trampoline pages are writable.
569+ Status = detour_writable_trampoline_regions ();
570+ if (!NT_SUCCESS (Status ))
571+ {
572+ goto fail ;
573+ }
574+ }
575+
576+ detour_free_trampoline ((PDETOUR_TRAMPOLINE )pTrampoline );
577+ detour_free_trampoline_region_if_unused ((PDETOUR_TRAMPOLINE )pTrampoline );
578+
579+ if (!bInTransaction )
580+ {
581+ detour_runnable_trampoline_regions ();
582+ }
583+
584+ Status = STATUS_SUCCESS ;
585+
586+ fail :
587+ if (!bInTransaction )
588+ {
589+ #ifdef _MSC_VER
590+ #pragma warning(disable: __WARNING_INTERLOCKED_ACCESS)
591+ #endif
592+ s_nPendingThreadId = 0 ;
593+ #ifdef _MSC_VER
594+ #pragma warning(default: __WARNING_INTERLOCKED_ACCESS)
595+ #endif
596+ }
597+ return HRESULT_FROM_NT (Status );
598+ }
599+
535600HRESULT
536601NTAPI
537602SlimDetoursUninitialize (VOID )
0 commit comments