【发布时间】:2018-02-08 21:37:29
【问题描述】:
我正在尝试使用锁 xcmpchg16b 挂钩一个函数。我已经尝试了大约 20 种不同的方法。
预期结果:
In real func
In hook func
调试构建结果:
Exception thrown at 0x..: 0xC0000005 Access violation reading 0xFFFFFFFFFFFFFFFF
我不知道为什么它试图从 0xFFFFFFFFFFFFFFFF 读取,没有指针到那里。
在发布构建中,它不会崩溃!但它也没有钩子函数。
来源:
#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/en-us/library/windows/desktop/hh972640(v=vs.85).aspx
【问题讨论】:
-
您应该尝试两件事: (1) 确保 ICE128 在普通数据存储器上的行为符合您的预期。 (2) 在修改代码之前尝试将页面保护设置为
PAGE_READWRITE,然后在调用之前设置PAGE_EXECUTE。 Windows 可能默默地拒绝使页面同时可写和可执行(也就是说,我想知道 VirtualProtect(..., PAGE_EXECUTE_READWRITE, ...) 是否可能不报告失败,但不做任何事)。 -
RW+X 页面还有其他问题,比如数据和指令缓存之间的不一致。您的代码修改可能永远不会超出 L1 数据缓存。
-
@zwol 我不能这样做
PAGE_READWRITE因为那样main()将无法执行。但是,我可以以非原子方式覆盖内存,因此页面正在获得 RWX 权限。我也无法使用ICE128更改普通数据。 -
@BenVoigt 好点,但似乎不是根本原因。我添加了
FlushInstructionCache(GetCurrentProcess(), &RealFunc, 0x1000);,但仍然失败。 -
InterlockedCompareExchange 仅在 *(最后一个参数)等于 *(第一个参数)时执行交换。如果所有参数都不是 16 字节对齐的,它也会严重崩溃,这在您的情况下是不必要的,并且可以解释为什么它在发布版本中不会崩溃