场景1
调用目标call 需要跳过某些判断或者函数
场景2
目标call 只需要部分指令执行
大概实现技术
设置线程上下文设置drX寄存器 实现硬件执行断点
主动调用目标call
通过硬件断点获取寄存器或修改eip
以上实现不改变crc且不通过驱动实现。只对当前执行线程有效,不使用线程句柄
调用call 的过程中有4个硬件断点随意修改call内部流程,适合在游戏主循环中使用.
---------------------------------------------------------------------------
已经通过hook方法 把所有读写call均在目标主线程调用。
通过主动调用1050F7A0这个call 但是不执行1050F805
1050F805 此时的 ECX则是我需要得到的值
void __declspec(naked) _stdcall hook_handleEIP()
{
_asm
{
//E
popeax //目标地址有push,先平盏
moveax,ecx //得到数据后修改eax作为返回值 然后ret掉目标函数
retn 4
}
}
EXCEPTION_DISPOSITION
__cdecl
_except_handler(
struct _EXCEPTION_RECORD *ExceptionRecord,
void * EstablisherFrame,
struct _CONTEXT *ContextRecord,
void * DispatcherContext )
{
EXCEPTION_DISPOSITION ERet = ExceptionContinueSearch;
//判断异常是否为单步异常,硬件断点也是单步异常
if (ExceptionRecord->ExceptionCode==EXCEPTION_SINGLE_STEP)
{
//判断异常地址,不是目标地址则是第一次的单步
if ((DWORD)ExceptionRecord->ExceptionAddress != 0x1050F805)
{
//B
SetHardwareBreakpoint(ContextRecord,0x32D3F805,DR_3,CODE,SIZE_1);//设置硬件断点相关标志位
ERet = ExceptionContinueExecution;//告诉系统异常已处理
}else if ((DWORD)ExceptionRecord->ExceptionAddress == 0x1050F805)
{
//D
RemoveHardwareBreakpoint(ContextRecord,DR_3);//删除硬件寄存器标志位
//修改eip到自己的函数上
ContextRecord->Eip = (DWORD)hook_handleEIP;
ERet = ExceptionContinueExecution;//告诉系统异常已处理
}
}
return ERet;
}
DWORD ExecutionFunction()
{
//A
DWORD handler = (DWORD)_except_handler;//异常处理函数
_asm
{
pushhandler//注册异常处理函数
pushFS:[0]
movFS:[0],ESP
pushfd
pushfd
orDWORD PTR[esp],0x100//设置dr7单步标志
popfd //执行到这里会触发单步异常
nop
popfd
}
//以上是注册异常处理函数
//以下是主动调用目标函数
DWORD dwRet;
_asm
{
pushad
push0
moveax,1050F7A0h
calleax //C
mov[dwRet],eax
popad
}
//F
//删除异常接收函数
_asm
{
moveax,[ESP]
movFS:[0], EAX
addesp, 8
}
return dwRet;
}
//以上函数执行过程有标注 A-B-C-D-E-F顺序
描述完毕。
设置drX寄存器可以参阅
https://blog.csdn.net/binhualiu1983/article/details/51646094
非常详细.
需要注意的是目前这个函数有逻辑跳转,如果没正确执行到1050F805就会离开这个函数,然后dr3寄存器未清理,导致被保护检测
所以执行完call 后主动清理drX寄存器一次就完整了。