
Implementazione di Detours (x64/x86) che utilizza solo l'import di ntdll.
rendi scrivibile la IAT.
vedi simple.cpp
TimedSleepEx chiama la vera API SleepEx tramite il puntatore a funzione TrueSleepEx.``` static DWORD (WINAPI * TrueSleepEx)(DWORD dwMilliseconds, BOOL bAlertable) = SleepEx;
DWORD WINAPI TimedSleepEx(DWORD dwMilliseconds, BOOL bAlertable) { ... DWORD ret = TrueSleepEx(dwMilliseconds, bAlertable); ... }
**_non fare questo !_** linker già definito```
EXTERN_C PVOID __imp_SleepEx = SleepEx;
variabile ( per x86 questo sarà __imp__SleepEx@8 e bisogna usare``` __pragma(comment(linker, "/alternatename:___imp_SleepEx=__imp__SleepEx@8"))
quindi usa ***__imp_SleepEx*** invece di ***TrueSleepEx*** e chiama semplicemente l'API nel modo solito e comodo.
qualsiasi API importata SomeApi invocata tramite ***__imp_SomeApi*** ( caricamento ritardato tramite ***__imp_load_SomeApi*** ) puntatore. usalo !
esempio```
//EXTERN_C extern PVOID __imp_SleepEx;
DECLARE_T_HOOK(SleepEx, 8)
DWORD WINAPI hook_SleepEx( _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable )
{
ULONG ret = SleepEx(dwMilliseconds, bAlertable);
DbgPrint("%s(%x, %x) = %x\n", __FUNCTION__, dwMilliseconds, bAlertable, ret);
return ret;
}
void DetoursDemo()
{
DBG_PRINT_ON();
if (0 <= TrInit())
{
ThreadInfo* pti;
SuspendAll(&pti);
DbgPrint("before: SleepEx = 0x%p\n", SleepEx);
TrHook(&__imp_SleepEx, hook_SleepEx, pti);
DbgPrint("after: SleepEx = 0x%p\n", SleepEx);
ResumeAndFree(pti);
union {
PVOID pv;
DWORD (WINAPI * fn_SleepEx)( _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable );
};
if (pv = GetProcAddress(GetModuleHandleW(L"kernel32"), "SleepEx"))
{
if (QueueUserAPC((PAPCFUNC)OutputDebugStringA, GetCurrentThread(), (ULONG_PTR)"asynchronous procedure call...\n"))
{
fn_SleepEx(INFINITE, TRUE);
}
}
}
}
output di debug tipico:``` NT::ThreadInfo::ThreadInfo<000002196427D6A0>(0000000000000814) NT::ThreadInfo::ThreadInfo<000002196427DBC0>(0000000000000128) NT::ThreadInfo::ThreadInfo<000002196427E0E0>(00000000000023D0) before: SleepEx = 0x00007FFED3DB06B0 0x00007FFED3DB06B0 -> 0x00007FF78BEB06C0 -> 0x00007FFE5394FFB8 [0x00007FFE5394FF98] after: SleepEx = 0x00007FFE5394FFB8 NT::ThreadInfo::~ThreadInfo<000002196427E0E0>(00000000000023D0) NT::ThreadInfo::~ThreadInfo<000002196427DBC0>(0000000000000128) NT::ThreadInfo::~ThreadInfo<000002196427D6A0>(0000000000000814) asynchronous procedure call... NT::hook_SleepEx(ffffffff, 1) = c0
un altro esempio, con unhook:```
DWORD WINAPI hook_SleepEx( _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable )
{
// don't use any [TrueSleepEx](https://github.com/microsoft/Detours/blob/main/samples/simple/simple.cpp#L23) !!
ULONG ret = SleepEx(dwMilliseconds, bAlertable);
DbgPrint("%s(%x, %x) = %x\n", __FUNCTION__, dwMilliseconds, bAlertable, ret);
return ret;
}
int
WINAPI
hook_MessageBoxW(
_In_opt_ HWND hWnd,
_In_opt_ PCWSTR lpText,
_In_opt_ PCWSTR lpCaption,
_In_ UINT uType)
{
// don't use any [Real_MessageBoxW](https://raw.githubusercontent.com/microsoft/Detours/main/samples/traceapi/_win32.cpp) !!
int ret = MessageBoxW(hWnd, lpText, __FUNCTIONW__, uType);
DbgPrint("%s(\"%S\", \"%S\") = %x\n", __FUNCTION__, lpText, lpCaption, ret);
return ret;
}
DECLARE_T_HOOK(SleepEx, 8)
DECLARE_T_HOOK(MessageBoxW, 16)
T_HOOKS_BEGIN(gHooks)
T_HOOK(SleepEx),
T_HOOK(MessageBoxW),
T_HOOKS_END()
void DemoApiCalls()
{
union {
PVOID pv;
DWORD (WINAPI * fn_SleepEx)( _In_ DWORD dwMilliseconds, _In_ BOOL bAlertable );
int (WINAPI * fn_MessageBoxW)( _In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);
};
if (pv = GetProcAddress(GetModuleHandleW(L"kernel32"), "SleepEx"))
{
if (QueueUserAPC((PAPCFUNC)OutputDebugStringA, GetCurrentThread(), (ULONG_PTR)"asynchronous procedure call...\n"))
{
fn_SleepEx(INFINITE, TRUE);
}
}
if (pv = GetProcAddress(GetModuleHandleW(L"user32"), "MessageBoxW"))
{
fn_MessageBoxW(0, L"[some text]", 0, MB_ICONINFORMATION);
}
}
void DetoursDemo()
{
DBG_PRINT_ON();
if (0 <= TrInit())
{
ThreadInfo* pti;
SuspendAll(&pti);
TrHook(gHooks, _countof(gHooks), pti);
ResumeAndFree(pti);
DemoApiCalls();
SuspendAll(&pti);
TrUnHook(gHooks, _countof(gHooks), pti);
ResumeAndFree(pti);
DemoApiCalls();
}
}
NT::ThreadInfo::ThreadInfo<0000026DEA5AD6D0>(00000000000017E8)
NT::ThreadInfo::ThreadInfo<0000026DEA5ADBF0>(00000000000013E0)
NT::ThreadInfo::ThreadInfo<0000026DEA5AE110>(00000000000002D4)
0x00007FFED3DB06B0 -> 0x00007FF693E10790 -> 0x00007FFE5394FFB8 [0x00007FFE5394FF98]
0x00007FFED41CA160 -> 0x00007FF693E10720 -> 0x00007FFE5430FFB8 [0x00007FFE5430FF98]
NT::ThreadInfo::~ThreadInfo<0000026DEA5AE110>(00000000000002D4)
NT::ThreadInfo::~ThreadInfo<0000026DEA5ADBF0>(00000000000013E0)
NT::ThreadInfo::~ThreadInfo<0000026DEA5AD6D0>(00000000000017E8)
asynchronous procedure call...
NT::hook_SleepEx(ffffffff, 1) = c0
---------------------------
NT::hook_MessageBoxW
---------------------------
[some text]
---------------------------
OK
---------------------------
NT::hook_MessageBoxW("[some text]", "(null)") = 1
NT::ThreadInfo::ThreadInfo<0000026DEA5C7370>(0000000000001A84)
NT::ThreadInfo::ThreadInfo<0000026DEA5C7890>(0000000000000D1C)
NT::ThreadInfo::ThreadInfo<0000026DEA5E2950>(00000000000020C8)
NT::ThreadInfo::ThreadInfo<0000026DEA5E2E70>(0000000000000D18)
NT::ThreadInfo::ThreadInfo<0000026DEA5E3390>(0000000000001974)
NT::ThreadInfo::ThreadInfo<0000026DEA5DD3D0>(00000000000023E0)
NT::ThreadInfo::ThreadInfo<0000026DEA5DD8F0>(0000000000001C58)
NT::ThreadInfo::~ThreadInfo<0000026DEA5DD8F0>(0000000000001C58)
NT::ThreadInfo::~ThreadInfo<0000026DEA5DD3D0>(00000000000023E0)
NT::ThreadInfo::~ThreadInfo<0000026DEA5E3390>(0000000000001974)
NT::ThreadInfo::~ThreadInfo<0000026DEA5E2E70>(0000000000000D18)
NT::ThreadInfo::~ThreadInfo<0000026DEA5E2950>(00000000000020C8)
NT::ThreadInfo::~ThreadInfo<0000026DEA5C7890>(0000000000000D1C)
NT::ThreadInfo::~ThreadInfo<0000026DEA5C7370>(0000000000001A84)
asynchronous procedure call...
---------------------------
Error
---------------------------
[some text]
---------------------------
OK
---------------------------
abilita / disabilita l'output di debug ( di default è disabilitato )
enumera i thread nel processo tramite NtGetNextThread
controlla se è il thread corrente ( ZwQueryInformationThread(ThreadBasicInformation) )
sospende il thread ZwSuspendThread
salva il suo contesto ZwGetContextThread
collega le informazioni del thread (handle/contesto) alla lista
scorre la lista dei thread ( pti )
riprende il thread
chiude il suo handle
libera la memoria
{ T_HOOK_ENTRY entry = { p__imp, hook }; return TrHook(&entry, 1, pti); }
versione semplificata, per agganciare una singola API e quando non serve sganciarla
quasi identica a [DetourAttach](https://github.com/microsoft/Detours/wiki/DetourAttach)
unica differenza - TrHook esegue la patch effettiva subito, mentre DetourAttach - dopo DetourTransactionCommit
*****************************************************************************************************
###### void NTAPI TrHook(_In_ T_HOOK_ENTRY* entry, _In_ ULONG n, _In_opt_ ThreadInfo* pti = 0);
*****************************************************************************************************
tenta di allocare un trampoline nel range -/+ 2GB (in modalità 32 bit qualsiasi indirizzo è valido) dalla regione patchata
aggancia l'API impostando un hook JMP all'inizio e salvando le istruzioni originali dentro il trampoline
scorre la lista dei thread (opzionale) e, se necessario (Pc in JMP), regola il contesto dei thread
esistono diversi casi:```
////////////////////////////////////////////////////////////////////////////////////////////////////////
// typical case:
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_RtlDispatchAPC = RtlDispatchAPC;
RtlDispatchAPC:
00007FFAB20AF6D0 mov r11,rsp
00007FFAB20AF6D3 mov qword ptr [r11+8],rbx
00007FFAB20AF6D7 mov qword ptr [r11+10h],rsi
--------------------------------------------------------------------------
after: TrHook(&__imp_RtlDispatchAPC, hook_RtlDispatchAPC);
--------------------------------------------------------------------------
RtlDispatchAPC:
00007FFB876AF6D0 jmp hook_RtlDispatchAPC
00007FFB876AF6D7 mov qword ptr [r11+10h],rsi
trampoline:
00007FFA3225FFB8 mov r11,rsp
00007FFA3225FFBB mov qword ptr [r11+8],rbx
00007FFA3225FFBF jmp RtlDispatchAPC + 7 (7FFB876AF6D7h)
__imp_RtlDispatchAPC = trampoline;
////////////////////////////////////////////////////////////////////////////////////////////////////////
// x86 mov edi,edi:
#pragma comment(linker, "/alternatename:___imp_RtlActivateActivationContextUnsafeFast=__imp_@RtlActivateActivationContextUnsafeFast@8")
EXTERN_C PVOID __imp_RtlActivateActivationContextUnsafeFast = RtlActivateActivationContextUnsafeFast;
771F6FBB int 3
771F6FBC int 3
771F6FBD int 3
771F6FBE int 3
771F6FBF int 3
RtlActivateActivationContextUnsafeFast:
771F6FC0 mov edi,edi
771F6FC2 push ebp
--------------------------------------------------------------------------
after: TrHook(&__imp_RtlActivateActivationContextUnsafeFast, hook_RtlActivateActivationContextUnsafeFast);
--------------------------------------------------------------------------
__imp_RtlActivateActivationContextUnsafeFast = 771F6FC2 ( RtlActivateActivationContextUnsafeFast + 2 )
771F6FBB jmp hook_RtlActivateActivationContextUnsafeFast
RtlActivateActivationContextUnsafeFast:
771F6FC0 jmp 771F6FBB
771F6FC2 push ebp
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case 1: data access relocated
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_CsrFreeCaptureBuffer = CsrFreeCaptureBuffer;
CsrFreeCaptureBuffer:
00007FFAB20A4980 sub rsp,28h
00007FFAB20A4984 cmp byte ptr [7FFAB21B43ECh],0
00007FFAB20A498B jne CsrFreeCaptureBuffer+1Eh (7FFAB20A499Eh)
--------------------------------------------------------------------------
after: TrHook(&__imp_CsrFreeCaptureBuffer, hook_CsrFreeCaptureBuffer);
--------------------------------------------------------------------------
CsrFreeCaptureBuffer:
00007FFAB20A4980 jmp hook_CsrFreeCaptureBuffer
00007FFAB20A498B jne CsrFreeCaptureBuffer+1Eh (7FFAB20A499Eh)
trampoline:
00007FFA3225F878 sub rsp,28h
00007FFA3225F87C cmp byte ptr [7FFAB21B43ECh],0
00007FFA3225F883 jmp CsrFreeCaptureBuffer+0Bh (7FFAB20A498Bh)
__imp_CsrFreeCaptureBuffer = trampoline;
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case 7: - Jcc rel8 (2 bytes) extended to Jcc rel32 (6 bytes) inside trampoline
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_CsrFreeCaptureBuffer = CsrAllocateMessagePointer;
CsrAllocateMessagePointer:
00007FFAB20A46A0 test edx,edx
00007FFAB20A46A2 je CsrAllocateMessagePointer+2Eh (7FFAB20A46CEh)
00007FFAB20A46A4 mov rax,qword ptr [rcx+18h]
00007FFAB20A46A8 mov qword ptr [r8],rax
--------------------------------------------------------------------------
after: TrHook(&__imp_CsrAllocateMessagePointer, hook_CsrAllocateMessagePointer);
--------------------------------------------------------------------------
CsrAllocateMessagePointer:
00007FFAB20A46A0 jmp hook_CsrAllocateMessagePointer
00007FFAB20A46A8 mov qword ptr [r8],rax
trampoline:
00007FFA3225FA38 test edx,edx
00007FFA3225FA3A je CsrAllocateMessagePointer+2Eh (7FFAB20A46CEh)
00007FFA3225FA40 mov rax,qword ptr [rcx+18h]
00007FFA3225FA44 jmp CsrAllocateMessagePointer+8 (7FFAB20A46A8h)
__imp_CsrAllocateMessagePointer = trampoline;
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case 8: function too small ( < 5 bytes )
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_CsrIdentifyAlertableThread = CsrIdentifyAlertableThread;
CsrIdentifyAlertableThread:
00007FFAB20BE480 xor eax,eax
00007FFAB20BE482 ret
00007FFAB20BE483 int 3
00007FFAB20BE484 int 3
00007FFAB20BE485 int 3
--------------------------------------------------------------------------
after: TrHook(&__imp_CsrIdentifyAlertableThread, hook_CsrIdentifyAlertableThread);
--------------------------------------------------------------------------
CsrIdentifyAlertableThread:
00007FFAB20BE480 jmp hook_CsrIdentifyAlertableThread
trampoline:
00007FFA3225F7F8 xor eax,eax
00007FFA3225F7FA ret
__imp_CsrIdentifyAlertableThread = trampoline;
note - no JMP at the end of trampoline !
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case JMP_rel32: function begin with 5 bytes relative JMP
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_DbgQueryDebugFilterState = DbgQueryDebugFilterState;
DbgQueryDebugFilterState:
00007FFAB211B160 jmp NtQueryDebugFilterState (7FFAB20D1720h)
--------------------------------------------------------------------------
after: TrHook(&__imp_DbgQueryDebugFilterState, hook_DbgQueryDebugFilterState);
--------------------------------------------------------------------------
DbgQueryDebugFilterState:
00007FFAB211B160 jmp hook_DbgQueryDebugFilterState(7FFAB20D1720h)
__imp_DbgQueryDebugFilterState = NtQueryDebugFilterState;
no trampoline used here ! __imp_DbgQueryDebugFilterState redirected from DbgQueryDebugFilterState to NtQueryDebugFilterState
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case 2: CALL/JMP/Jcc rel32 relocated
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_DbgQueryDebugFilterState = DbgUiConvertStateChangeStructure;
DbgUiConvertStateChangeStructure:
00007FFAB21080E0 xor r8d,r8d
00007FFAB21080E3 jmp DbgUiConvertStateChangeStructureEx+10h (7FFAB2108100h)
--------------------------------------------------------------------------
after: TrHook(&__imp_DbgUiConvertStateChangeStructure, hook_DbgUiConvertStateChangeStructure);
--------------------------------------------------------------------------
DbgUiConvertStateChangeStructure:
00007FFAB20A46A0 jmp hook_DbgUiConvertStateChangeStructure
trampoline:
00007FFA3225F4F8 xor r8d,r8d
00007FFA3225F4FB jmp DbgUiConvertStateChangeStructureEx+10h (7FFAB2108100h)
__imp_DbgUiConvertStateChangeStructure = trampoline;
////////////////////////////////////////////////////////////////////////////////////////////////////////
for x86:
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_RtlGetActiveConsoleId = RtlGetActiveConsoleId;
RtlGetActiveConsoleId:
7721FDA0 call RtlGetCurrentServiceSessionId (771FF310h)
7721FDA5 test eax,eax
--------------------------------------------------------------------------
after: TrHook(&__imp_RtlGetActiveConsoleId, hook_RtlGetActiveConsoleId);
--------------------------------------------------------------------------
RtlGetActiveConsoleId:
7721FDA0 jmp hook_RtlGetActiveConsoleId
7721FDA5 test eax,eax
trampoline:
02902A94 call RtlGetCurrentServiceSessionId (771FF310h)
02902A99 jmp RtlGetActiveConsoleId+5 (7721FDA5h)
__imp_RtlGetActiveConsoleId = trampoline;
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case 9: Too few instructions !
RtlIsZeroMemory:
7FFB85F5C130 xor eax,eax
7FFB85F5C132 jmp 00007FFB85F5C143 ↓
7FFB85F5C134 test rdx,rdx
7FFB85F5C137 je 00007FFB85F5C157 ↓
7FFB85F5C139 cmp byte ptr [rcx],al
7FFB85F5C13B jne 00007FFB85F5C171 ↓
7FFB85F5C13D inc rcx
7FFB85F5C140 dec rdx
7FFB85F5C143 test cl,7
7FFB85F5C146 jne 00007FFB85F5C134 ↑
7FFB85F5C148 jmp 00007FFB85F5C157 ↓
7FFB85F5C14A cmp qword ptr [rcx],rax
7FFB85F5C14D jne 00007FFB85F5C171 ↓
7FFB85F5C14F add rcx,8
7FFB85F5C153 sub rdx,8
7FFB85F5C157 cmp rdx,8
7FFB85F5C15B jae 00007FFB85F5C14A ↑
7FFB85F5C15D test rdx,rdx
7FFB85F5C160 je 00007FFB85F5C16F ↓
7FFB85F5C162 cmp byte ptr [rcx],al
7FFB85F5C164 jne 00007FFB85F5C171 ↓
7FFB85F5C166 inc rcx
7FFB85F5C169 sub rdx,1
7FFB85F5C16D jne 00007FFB85F5C162 ↑
7FFB85F5C16F mov al,1
7FFB85F5C171 ret
we can not hook such api - only 4 bytes exist
note
7FFB85F5C146 jne 00007FFB85F5C134 ↑
if we set JMP in [7FFB85F5C130, 7FFB85F5C135) - this will be jmp to instruction body
////////////////////////////////////////////////////////////////////////////////////////////////////////
// skip import jump
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_NtdllDefWindowProc_W = NtdllDefWindowProc_W;
NtdllDefWindowProc_W:
7FFAB20CEAD0 jmp qword ptr [DefWindowProcW(7FFF55F9A760)]
DefWindowProcW
7FFF55F9A760 mov rax,rsp
7FFF55F9A763 mov qword ptr [rax+8],rbx
7FFF55F9A767 mov qword ptr [rax+10h],rsi
--------------------------------------------------------------------------
after: TrHook(&__imp_NtdllDefWindowProc_W, hook_NtdllDefWindowProc_W);
--------------------------------------------------------------------------
NtdllDefWindowProc_W:
7FFAB20CEAD0 jmp qword ptr [DefWindowProcW(7FFF55F9A760)]
DefWindowProcW
7FFF55F9A760 jmp hook_NtdllDefWindowProc_W
7FFF55F9A767 mov qword ptr [rax+10h],rsi
trampoline:
7FFED78555F8 mov rax,rsp
7FFED78555FB mov qword ptr [rax+8],rbx
7FFED78555FF jmp DefWindowProcW + 7 (7FFF55F9A767h)
__imp_NtdllDefWindowProc_W = trampoline;
so we set hook on DefWindowProcW instead on NtdllDefWindowProc_W
////////////////////////////////////////////////////////////////////////////////////////////////////////
// case JMP_rel8: function begin with short JMP
-------------------------------------------------------------------------
before:
-------------------------------------------------------------------------
EXTERN_C PVOID __imp_uaw_wcschr = uaw_wcschr;
uaw_wcschr:
7FFF562C6A10 jmp uaw_wcschr+0Bh (7FFF562C6A1B)
7FFF562C6A12 test ax,ax
7FFF562C6A15 je uaw_wcschr+18h (7FFF562C6A28)
7FFF562C6A17 add rcx,2
7FFF562C6A1B movzx eax,word ptr [rcx]
7FFF562C6A1E cmp ax,dx
7FFF562C6A21 jne uaw_wcschr+2 (7FFF562C6A12)
7FFF562C6A23 mov rax,rcx
7FFF562C6A26 ret
7FFF562C6A27 int 3
7FFF562C6A28 xor eax,eax
7FFF562C6A2A ret
--------------------------------------------------------------------------
after: TrHook(&__imp_uaw_wcschr, hook_uaw_wcschr);
--------------------------------------------------------------------------
uaw_wcschr:
7FFF562C6A10 jmp uaw_wcschr+0Bh (7FFF562C6A1B)
7FFF562C6A12 test ax,ax
7FFF562C6A15 je uaw_wcschr+18h (7FFF562C6A28)
7FFF562C6A17 add rcx,2
7FFF562C6A1B jmp hook_uaw_wcschr
7FFF562C6A21 jne uaw_wcschr+2 (7FFF562C6A12)
7FFF562C6A23 mov rax,rcx
7FFF562C6A26 ret
7FFF562C6A27 int 3
7FFF562C6A28 xor eax,eax
7FFF562C6A2A ret
trampoline:
FFED786A338 movzx eax,word ptr [rcx]
FFED786A33B cmp ax,dx
FFED786A33E jmp uaw_wcschr+11h (7FFF562C6A21)
__imp_uaw_wcschr = trampoline;
usual all such functions ( with short JMP at begin) consist from do-while optimized loop
( uaw_wcschr, SHSearchMapInt, FixSlashesAndColonW)
problem here - that hook function can be recursive called in loop
example of uaw_wcschr hook:
PUWSTR
__cdecl
hook_uaw_wcschr(
_In_ PCUWSTR String,
_In_ WCHAR Character
)
{
DbgPrint("%p: %p> uaw_wcschr(\"%S\", '%c')...\n", _AddressOfReturnAddress(), _ReturnAddress(), String, Character);
PUWSTR pw = uaw_wcschr(String, Character);
DbgPrint("%p: %p> uaw_wcschr(\"%S\", '%c') = \"%S\"\n", _AddressOfReturnAddress(), _ReturnAddress(), String, Character, pw);
return pw;
}
TrInit();
TrHook(&__imp_uaw_wcschr, hook_uaw_wcschr);
uaw_wcschr(L"123*567", '*');
and debug output:
000000459910F978: 00007FF6E5FEFCAB> uaw_wcschr("23*567", '*')...
000000459910F928: 00007FF6E5FF086E> uaw_wcschr("3*567", '*')...
000000459910F8D8: 00007FF6E5FF086E> uaw_wcschr("*567", '*')...
000000459910F8D8: 00007FF6E5FF086E> uaw_wcschr("*567", '*') = "*567"
000000459910F928: 00007FF6E5FF086E> uaw_wcschr("3*567", '*') = "*567"
000000459910F978: 00007FF6E5FEFCAB> uaw_wcschr("23*567", '*') = "*567"
////////////////////////////////////////////////////////////////////////////////////////////////////////
// "micro" jmp
case when JMP/Jcc/LOOP/JRCX point to first 5 bytes offunction ( where JMP must be placed )
probably only hypothetical case, but for correct handle, require many extra code.
before:
someapi:
7FF64B5096CF jrcxz someapi+4 (7FF64B5096D3)
7FF64B5096D1 jnp someapi+6 (7FF64B5096D5)
7FF64B5096D3 loop someapi (7FF64B5096CF)
7FF64B5096D5 ...
after:
someapi:
7FF64B5096CF jmp NT::hook_someapi (7FF64B510F14h)
7FF64B5096D5 ...
trampoline:
7FF5CB53FFB8 jrcxz 7FF5CB53FFC0
7FF5CB53FFBA jnp someapi+6 (7FF64B5096D5)
7FF5CB53FFC0 loop 7FF5CB53FFB8
7FF5CB53FFC2 jmp someapi+6 (7FF64B5096D5)
all'inizio dell'API agganciata, impostiamo un JMP diretto all'hook se possibile oppure un JMP a un JMP indiretto [hook_someapi] all'interno del trampoline ( se la distanza tra someapi e hook_someapi è superiore a 2GB )
quindi, dopo l'hook sarà o``` someapi: jmp hook_someapi ; JMP rel32
o```
someapi:
jmp tramp ; JMP rel32
tramp:
jmp [hook_someapi] ; JMP [m64]
alla fine del trampoline di solito ci sarà un JMP relativo al codice dopo il JMP nel corpo della funzione tranne nel caso 8 - quando la funzione hookata è troppo piccola (istruzione ret o JMP già nel trampoline)