@@ -194,12 +194,14 @@ SlimDetoursTransactionCommit(VOID)
194
194
NtFlushInstructionCache (NtCurrentProcess (), o -> pbTarget , o -> pTrampoline -> cbRestore );
195
195
} else
196
196
{
197
- // Don't remove in this case, put in bypass mode and leak trampoline .
197
+ // Don't remove and leak trampoline in this case .
198
198
o -> dwOperation = DETOUR_OPERATION_NONE ;
199
- o -> pTrampoline -> pbDetour = o -> pTrampoline -> rbCode ;
200
199
DETOUR_TRACE ("detours: Leaked hook on pbTarget=%p due to external hooking\n" , o -> pbTarget );
201
200
}
202
201
202
+ // Put hook in bypass mode.
203
+ o -> pTrampoline -> pbDetour = o -> pTrampoline -> rbCode ;
204
+
203
205
* o -> ppbPointer = o -> pbTarget ;
204
206
} else if (o -> dwOperation == DETOUR_OPERATION_ADD )
205
207
{
@@ -270,9 +272,16 @@ SlimDetoursTransactionCommit(VOID)
270
272
NtProtectVirtualMemory (NtCurrentProcess (), & pMem , & sMem , o -> dwPerm , & dwOld );
271
273
if (o -> dwOperation == DETOUR_OPERATION_REMOVE )
272
274
{
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
+ }
274
284
o -> pTrampoline = NULL ;
275
- freed = TRUE;
276
285
}
277
286
278
287
n = o -> pNext ;
@@ -505,9 +514,10 @@ SlimDetoursAttach(
505
514
506
515
HRESULT
507
516
NTAPI
508
- SlimDetoursDetach (
517
+ SlimDetoursDetachEx (
509
518
_Inout_ PVOID * ppPointer ,
510
- _In_ PVOID pDetour )
519
+ _In_ PVOID pDetour ,
520
+ _In_ PCDETOUR_DETACH_OPTIONS pOptions )
511
521
{
512
522
NTSTATUS Status ;
513
523
PVOID pMem ;
@@ -560,12 +570,67 @@ SlimDetoursDetach(
560
570
o -> pTrampoline = pTrampoline ;
561
571
o -> pbTarget = pbTarget ;
562
572
o -> dwPerm = dwOld ;
573
+ o -> ppTrampolineToFreeManually = pOptions -> ppTrampolineToFreeManually ;
563
574
o -> pNext = s_pPendingOperations ;
564
575
s_pPendingOperations = o ;
565
576
566
577
return HRESULT_FROM_NT (STATUS_SUCCESS );
567
578
}
568
579
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
+
569
634
HRESULT
570
635
NTAPI
571
636
SlimDetoursUninitialize (VOID )
0 commit comments