
Detours-Implementierung (x64/x86), die nur den ntdll-Import verwendet
IAT beschreibbar machen.
siehe simple.cpp
TimedSleepEx ruft die echte SleepEx-API über den TrueSleepEx-Funktionszeiger auf.``` static DWORD (WINAPI * TrueSleepEx)(DWORD dwMilliseconds, BOOL bAlertable) = SleepEx;
DWORD WINAPI TimedSleepEx(DWORD dwMilliseconds, BOOL bAlertable) { ... DWORD ret = TrueSleepEx(dwMilliseconds, bAlertable); ... }
**_Tu das nicht !_** Linker bereits definiert```
EXTERN_C PVOID __imp_SleepEx = SleepEx;
Variable ( für x86 wird dies __imp__SleepEx@8 sein und muss verwendet werden``` __pragma(comment(linker, "/alternatename:___imp_SleepEx=__imp__SleepEx@8"))
Verwende also ***__imp_SleepEx*** anstelle von ***TrueSleepEx*** und rufe die API einfach auf die übliche und bequeme Weise auf.
Jede importierte API SomeApi wird über den ***__imp_SomeApi***-Zeiger aufgerufen (verzögertes Laden über ***__imp_load_SomeApi***). Nutze es!
Beispiel```
//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);
}
}
}
}
typische Debug-Ausgabe:``` 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
ein weiteres Beispiel, mit 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
---------------------------
Debug-Ausgabe aktivieren / deaktivieren ( standardmäßig deaktiviert)
Threads im Prozess mithilfe von NtGetNextThread auflisten prüfen, ob aktueller Thread ( ZwQueryInformationThread(ThreadBasicInformation) ) Thread per ZwSuspendThread anhalten Kontext per ZwGetContextThread speichern Thread-Infos (Handle/Kontext) mit Liste verknüpfen
Thread-Liste durchlaufen ( pti ) Thread fortsetzen Handle schließen Speicher freigeben