[英]Read access violation using lock xcmpchg16b _InterlockedCompareExchange128
我正在嘗試使用xcmpchg16b鎖定鈎子函數。 我已經嘗試了大約20種不同的方法。
預期結果:
In real func
In hook func
調試生成的結果:
Exception thrown at 0x..: 0xC0000005 Access violation reading 0xFFFFFFFFFFFFFFFF
我不確定為什么要嘗試從0xFFFFFFFFFFFFFFFFFF讀取,沒有指針去那里。
在發布版本中,它不會崩潰! 但是它也沒有鈎住函數。
資源:
#include <stdio.h>
#include <Windows.h>
int RealFunc()
{
printf("In real func\n");
return 2;
}
int HookFunc()
{
printf("In hook func\n");
return 1;
}
int main()
{
DWORD dwOld;
if (!VirtualProtect(&RealFunc, 0x1000, PAGE_EXECUTE_READWRITE, &dwOld))
{
printf("Unable to make mem RWX.\n");
return 0;
}
RealFunc();
__declspec(align(16)) PVOID ProcAddress = &RealFunc;
__declspec(align(16)) LONG64 Restore[2];
Restore[0] = 0x0000000025ff9090; // nop, nop, jmp [rip + 0]
Restore[1] = (LONG64)&HookFunc;
_InterlockedCompareExchange128((LONG64*)ProcAddress, Restore[0], Restore[1], Restore);
RealFunc();
system("PAUSE");
return 0;
}
以下是功能文檔: https : //msdn.microsoft.com/zh-cn/library/windows/desktop/hh972640(v=vs.85).aspx
_InterlockedCompareExchange128((LONG64*)ProcAddress,
Restore[0], Restore[1], Restore);
這當然是錯誤的。 如果尋找功能簽名
unsigned char __cdecl InterlockedCompareExchange128(
_Inout_ LONGLONG volatile *Destination,
_In_ LONGLONG ExchangeHigh,
_In_ LONGLONG ExchangeLow,
_Inout_ LONGLONG *ComparandResult
);
第二個操作數是ExchangeHigh和第三是ExchangeLow -因此必須Restore[1], Restore[0]
但不Restore[0], Restore[1]
並且ComparandResult
必須包含原始函數數據。 因此它不能Restore
。
還要注意下一個來自MSDN的內容:
此函數的參數必須在16字節邊界上對齊; 否則,該功能在x64系統上將無法正常運行。
但是哪些參數呢? 全部? 顯然沒有。 例如, ExchangeHigh
和ExchangeLow
通過值傳遞。 我們可以在這里使用完全沒有任何地址的直接值。 因此,對於第二和第三參數,談論對齊是毫無意義的。 真正將InterlockedCompareExchange128
轉換為lock cmpxchg16b
指令。 從英特爾手冊
請注意,
CMPXCHG16B
要求目標(存儲器)操作數為16字節對齊。
因此只有Destination
必須是16字節對齊的。 ComparandResult
不(它將移至RCX:RBX
寄存器對)
所以__declspec(align(16)) LONG64 Restore[2];
您完全不需要-您可以將直接值傳遞給InterlockedCompareExchange128
。 然后
__declspec(align(16)) PVOID ProcAddress = &RealFunc;
與_InterlockedCompareExchange128((LONG64*)ProcAddress..
錯誤和毫無意義。 ProcAddress
哪個對齊不同? ProcAddress
指向的內存必須對齊16個字節。 但不是ProcAddress
本身。 同樣,我們在這里不需要任何臨時變量。 我們可以直接使用
_InterlockedCompareExchange128((LONG64*)RealFunc, ...)
當然, RealFunc
必須對齊16字節。 否則,我們將獲得0xC0000005 Access violation reading 0xFFFFFFFFFFFFFFFF
異常。
所以我想在調試模式下RealFunc
不是16字節對齊的。
在發布版本中,它不會崩潰! 但是它也沒有鈎住函數。
不會鈎,因為您在原位使用ComparandResult
Restore
,也沒有異常,因為RealFunc
是隨機的16字節對齊。
因為一般情況下函數可以有任何地址,並且不能以16個字節對齊_InterlockedCompareExchange128
在這里_InterlockedCompareExchange128
沒有用。 這也僅適用於x64 ,不適用於x86
代碼(如果RealFunc
未對齊16個字節,則無論如何都不具有鈎子功能)看起來像
int RealFunc()
{
printf("In real func\n");
return 2;
}
int HookFunc()
{
printf("In hook func\n");
return 1;
}
int xxx()
{
DWORD dwOld;
if (VirtualProtect(RealFunc, 2*sizeof(PVOID), PAGE_EXECUTE_READWRITE, &dwOld))
{
RealFunc();
#if defined(_M_X64)
if (!((LONG_PTR)RealFunc & 15))
{
LONG64 Comparand[2] = { ((LONG64*)RealFunc)[0], ((LONG64*)RealFunc)[1] };
InterlockedCompareExchange128((LONG64*)RealFunc, (LONG64)HookFunc, 0x0000000025ff9090, Comparand);
}
else
{
printf("bad function address %p\n", RealFunc);
}
#elif defined(_M_IX86)
static PVOID pvHookFunc = HookFunc;
LARGE_INTEGER Exchange = { 0x25ff9090, (LONG)&pvHookFunc };
LONG64 Comparand;
memcpy(&Comparand, RealFunc, sizeof(Comparand));
InterlockedCompareExchange64((LONG64*)RealFunc, Exchange.QuadPart, Comparand);
#else
#error not implemented
#endif
FlushInstructionCache(NtCurrentProcess(), RealFunc, 2*sizeof(PVOID));
if (dwOld != PAGE_EXECUTE_READWRITE)
{
VirtualProtect(RealFunc, 2*sizeof(PVOID), dwOld, &dwOld);
}
RealFunc();
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.