Skip to content

Commit 9fa3011

Browse files
m417zRatinCN
authored andcommitted
When unhooking, verify that the function wasn't changed
If for some reason the function was changed, e.g. if somebody else placed a hook on top of ours, don't restore the original bytes over it, which will remove the other hook and will likely cause a crash when that other library will remove its hook. Instead, leak the allocated trampoline and patch it such that it will jump straight to the original code.
1 parent f187686 commit 9fa3011

File tree

4 files changed

+119
-13
lines changed

4 files changed

+119
-13
lines changed

Source/SlimDetours/Instruction.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,20 @@ detour_gen_jmp_immediate(
120120
return pbCode + sizeof(INT32);
121121
}
122122

123+
BOOL
124+
detour_is_jmp_immediate_to(
125+
_In_ PBYTE pbCode,
126+
_In_ PBYTE pbJmpVal)
127+
{
128+
PBYTE pbJmpSrc = pbCode + 5;
129+
if (*pbCode++ != 0xe9) // jmp +imm32
130+
{
131+
return FALSE;
132+
}
133+
INT32 offset = *((INT32*)pbCode);
134+
return offset == (INT32)(pbJmpVal - pbJmpSrc);
135+
}
136+
123137
_Ret_notnull_
124138
PBYTE
125139
detour_gen_jmp_indirect(
@@ -139,6 +153,30 @@ detour_gen_jmp_indirect(
139153
return pbCode + sizeof(INT32);
140154
}
141155

156+
BOOL
157+
detour_is_jmp_indirect_to(
158+
_In_ PBYTE pbCode,
159+
_In_ PBYTE* ppbJmpVal)
160+
{
161+
#if defined(_AMD64_)
162+
PBYTE pbJmpSrc = pbCode + 6;
163+
#endif
164+
if (*pbCode++ != 0xff) // jmp [+imm32]
165+
{
166+
return FALSE;
167+
}
168+
if (*pbCode++ != 0x25)
169+
{
170+
return FALSE;
171+
}
172+
INT32 offset = *((INT32*)pbCode);
173+
#if defined(_AMD64_)
174+
return offset == (INT32)((PBYTE)ppbJmpVal - pbJmpSrc);
175+
#else
176+
return offset == (INT32)((PBYTE)ppbJmpVal);
177+
#endif
178+
}
179+
142180
_Ret_notnull_
143181
PBYTE
144182
detour_gen_brk(
@@ -488,6 +526,37 @@ detour_gen_jmp_indirect(
488526
return pbCode;
489527
}
490528

529+
BOOL
530+
detour_is_jmp_indirect_to(
531+
_In_ PBYTE pbCode,
532+
_In_ PULONG64 pbJmpVal)
533+
{
534+
const struct ARM64_INDIRECT_JMP* pIndJmp;
535+
union ARM64_INDIRECT_IMM jmpIndAddr;
536+
537+
jmpIndAddr.value = (((LONG64)pbJmpVal) & 0xFFFFFFFFFFFFF000) -
538+
(((LONG64)pbCode) & 0xFFFFFFFFFFFFF000);
539+
540+
pIndJmp = (const struct ARM64_INDIRECT_JMP*)pbCode;
541+
542+
return pIndJmp->ardp.Rd == 17 &&
543+
pIndJmp->ardp.immhi == (ULONG)jmpIndAddr.adrp_immhi &&
544+
pIndJmp->ardp.iop == 0x10 &&
545+
pIndJmp->ardp.immlo == (ULONG)jmpIndAddr.adrp_immlo &&
546+
pIndJmp->ardp.op == 1 &&
547+
548+
pIndJmp->ldr.Rt == 17 &&
549+
pIndJmp->ldr.Rn == 17 &&
550+
pIndJmp->ldr.imm == (((ULONG64)pbJmpVal) & 0xFFF) / 8 &&
551+
pIndJmp->ldr.opc == 1 &&
552+
pIndJmp->ldr.iop1 == 1 &&
553+
pIndJmp->ldr.V == 0 &&
554+
pIndJmp->ldr.iop2 == 7 &&
555+
pIndJmp->ldr.size == 3 &&
556+
557+
pIndJmp->br == 0xD61F0220;
558+
}
559+
491560
_Ret_notnull_
492561
PBYTE
493562
detour_gen_jmp_immediate(

Source/SlimDetours/SlimDetours.inl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ typedef struct _DETOUR_OPERATION DETOUR_OPERATION, *PDETOUR_OPERATION;
105105
struct _DETOUR_OPERATION
106106
{
107107
PDETOUR_OPERATION pNext;
108-
BOOL fIsRemove;
108+
BOOL fIsAdd : 1;
109+
BOOL fIsRemove : 1;
109110
PBYTE* ppbPointer;
110111
PBYTE pbTarget;
111112
PDETOUR_TRAMPOLINE pTrampoline;
@@ -158,12 +159,22 @@ detour_gen_jmp_immediate(
158159
_In_ PBYTE pbCode,
159160
_In_ PBYTE pbJmpVal);
160161

162+
BOOL
163+
detour_is_jmp_immediate_to(
164+
_In_ PBYTE pbCode,
165+
_In_ PBYTE pbJmpVal);
166+
161167
_Ret_notnull_
162168
PBYTE
163169
detour_gen_jmp_indirect(
164170
_In_ PBYTE pbCode,
165171
_In_ PBYTE* ppbJmpVal);
166172

173+
BOOL
174+
detour_is_jmp_indirect_to(
175+
_In_ PBYTE pbCode,
176+
_In_ PBYTE* ppbJmpVal);
177+
167178
#elif defined(_ARM64_)
168179

169180
_Ret_notnull_
@@ -179,6 +190,11 @@ detour_gen_jmp_indirect(
179190
_In_ PBYTE pbCode,
180191
_In_ PULONG64 pbJmpVal);
181192

193+
BOOL
194+
detour_is_jmp_indirect_to(
195+
_In_ PBYTE pbCode,
196+
_In_ PULONG64 pbJmpVal);
197+
182198
#endif
183199

184200
_Ret_notnull_

Source/SlimDetours/Thread.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ detour_thread_update(
153153
return Status;
154154
}
155155

156-
for (o = PendingOperations; o != NULL; o = o->pNext)
156+
bUpdateContext = FALSE;
157+
for (o = PendingOperations; o != NULL && !bUpdateContext; o = o->pNext)
157158
{
158-
bUpdateContext = FALSE;
159159
if (o->fIsRemove)
160160
{
161161
if (cxt.CONTEXT_PC >= (ULONG_PTR)o->pTrampoline->rbCode &&
@@ -172,7 +172,7 @@ detour_thread_update(
172172
bUpdateContext = TRUE;
173173
}
174174
#endif
175-
} else
175+
} else if (o->fIsAdd)
176176
{
177177
if (cxt.CONTEXT_PC >= (ULONG_PTR)o->pbTarget &&
178178
cxt.CONTEXT_PC < ((ULONG_PTR)o->pbTarget + o->pTrampoline->cbRestore))
@@ -182,11 +182,11 @@ detour_thread_update(
182182
bUpdateContext = TRUE;
183183
}
184184
}
185-
if (bUpdateContext)
186-
{
187-
Status = NtSetContextThread(ThreadHandle, &cxt);
188-
break;
189-
}
185+
}
186+
187+
if (bUpdateContext)
188+
{
189+
Status = NtSetContextThread(ThreadHandle, &cxt);
190190
}
191191

192192
return Status;

Source/SlimDetours/Transaction.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ SlimDetoursTransactionAbort(VOID)
111111
pMem = o->pbTarget;
112112
sMem = o->pTrampoline->cbRestore;
113113
NtProtectVirtualMemory(NtCurrentProcess(), &pMem, &sMem, o->dwPerm, &dwOld);
114-
if (!o->fIsRemove)
114+
if (o->fIsAdd)
115115
{
116116
detour_free_trampoline(o->pTrampoline);
117117
o->pTrampoline = NULL;
@@ -165,10 +165,29 @@ SlimDetoursTransactionCommit(VOID)
165165
{
166166
if (o->fIsRemove)
167167
{
168-
RtlCopyMemory(o->pbTarget, o->pTrampoline->rbRestore, o->pTrampoline->cbRestore);
169-
NtFlushInstructionCache(NtCurrentProcess(), o->pbTarget, o->pTrampoline->cbRestore);
168+
// Check if the jmps still points where we expect, otherwise someone might have hooked us.
169+
BOOL hookIsStillThere =
170+
#if defined(_X86_) || defined(_AMD64_)
171+
detour_is_jmp_immediate_to(o->pbTarget, o->pTrampoline->rbCodeIn) &&
172+
detour_is_jmp_indirect_to(o->pTrampoline->rbCodeIn, &o->pTrampoline->pbDetour);
173+
#elif defined(_ARM64_)
174+
detour_is_jmp_indirect_to(o->pbTarget, (ULONG64*)&(o->pTrampoline->pbDetour));
175+
#endif
176+
177+
if (hookIsStillThere)
178+
{
179+
RtlCopyMemory(o->pbTarget, o->pTrampoline->rbRestore, o->pTrampoline->cbRestore);
180+
NtFlushInstructionCache(NtCurrentProcess(), o->pbTarget, o->pTrampoline->cbRestore);
181+
} else
182+
{
183+
// Don't remove in this case, put in bypass mode and leak trampoline.
184+
o->fIsRemove = FALSE;
185+
o->pTrampoline->pbDetour = o->pTrampoline->rbCode;
186+
DETOUR_TRACE("detours: Leaked hook on pbTarget=%p due to external hooking\n", o->pbTarget);
187+
}
188+
170189
*o->ppbPointer = o->pbTarget;
171-
} else
190+
} else if (o->fIsAdd)
172191
{
173192
DETOUR_TRACE("detours: pbTramp =%p, pbRemain=%p, pbDetour=%p, cbRestore=%u\n",
174193
o->pTrampoline,
@@ -457,6 +476,7 @@ SlimDetoursAttach(
457476
pTrampoline->rbCode[8], pTrampoline->rbCode[9],
458477
pTrampoline->rbCode[10], pTrampoline->rbCode[11]);
459478

479+
o->fIsAdd = TRUE;
460480
o->fIsRemove = FALSE;
461481
o->ppbPointer = (PBYTE*)ppPointer;
462482
o->pTrampoline = pTrampoline;
@@ -520,6 +540,7 @@ SlimDetoursDetach(
520540
goto fail;
521541
}
522542

543+
o->fIsAdd = FALSE;
523544
o->fIsRemove = TRUE;
524545
o->ppbPointer = (PBYTE*)ppPointer;
525546
o->pTrampoline = pTrampoline;

0 commit comments

Comments
 (0)