HWND hwnd = ::FindWindow(NULL,
"地下城与勇士"
);
if
(!hwnd)
{
MessageBox(
"请先运行游戏!"
);
return
;
}
DWORD processid;
::GetWindowThreadProcessId(hwnd,&processid);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS,
false
,processid);
//
以上过程为套话,窗口名可以下载spy++获取,想知道每个具体函数自行MSDN或百度
LPCVOID base = (LPCVOID)0x0060C6A0;
//base
是要跳转的dnf原程序代码,我们在这里修改代码,使之跳到我们自己的函数中
::ReadProcessMemory(handle,(LPCVOID)0x0060C6A0, (LPVOID)&m_char,6,NULL);
//
设一个char[1000]型类成员变量,保存游戏程序在0060C6A0处原代码,以便不想用外挂时将代码还原
LPVOID newaddr=VirtualAllocEx(handle,NULL,0x256,MEM_COMMIT | MEM_RESERVE,PAGE_EXECUTE_READWRITE);
//
在DNF进程中申请内存以便存放我们自己编写的代码
m_newmem=newaddr;
//
保存新申请的内存地址在LPVOID型类成员变量m_newmem中,以便释放
char ch1={0xe9};
::WriteProcessMemory(handle,(LPVOID)0x0060C6A0,(LPVOID)&ch1,1,NULL);
//
改写0060C6A0地址中DNF源代码,使他“跳”到我们自己的代码中,我们的代码在申请的newaddr内存中,汇编指令跳jmp机器码0xe9
int Jmp1=(int)newaddr-0x0060C6A0-5;
//
汇编中jmp某地址,转成机器码需要用公式转换:
//
机器码中地址=目标地址-e9(jmp)字节所在地址-5
::WriteProcessMemory(handle,(LPVOID)0x0060C6A1,(LPVOID)&Jmp1,4,NULL);
//
将跳转地址即申请的内存地址转成机器码写入内存
char ch2={0x90};
::WriteProcessMemory(handle,(LPVOID)0x0060C6A5,(LPVOID)&ch2,1,NULL);
//
我们改写了源代码的6个字节,而jmp newaddr只用了5个字节,这一字节没有用,用0x90(nop)空代码代替,不改也可以,因为程序不再会执行这里
//
随着DNF的更新,0060C6A0这一地址值将会发生变化,但特征码一般不会变,以后若果发现程序不可用,可以特征码搜出新的地址替换0060C6A0
char ch[15]={0xc7,0x44,0x24,0x04,0x99,0x99,0x00,0x00,0x55,0x8b,0xec,0x8b,0x45,0x10,0xe9};
/*我们自己的代码,汇编代码的机器码,最好你手头有汇编和机器码转换的东东,比如CE里随便写一段就能看见对应的机器码,我这里的汇编是这样的:
mov [esp+04],00009999
因为0060C6A0是call edx跳过来的,所以堆栈中被压入了call edx下一句地址,那我们的当前血值就是栈顶指针+4,即[esp,+4]里的值,把0x9999传入就是设定当前血量0x9999
push ebp
//0060C6A0
源代码 不变
mov ebp,esp
//0060C6A0
源代码 不变
mov eax,[ebp+10]
//0060C6A0
源代码 不变*/
::WriteProcessMemory(handle,newaddr,(LPVOID)&ch,15,NULL);
//
代码写入到e9(jmp),跳转地址仍需要用公式转换
int Jmp2=0x60c6a6-(int)newaddr-14-5;
/*我们改写了源代码从0060C6A0开始的6个字节,所以我们应跳回到0060C6A0+6的位置,而当前e9(jmp)所在地址是newaddr+14*/
::WriteProcessMemory(handle,(LPVOID)((int)newaddr+15),(LPVOID)&Jmp2,4,NULL);
//
写入跳回地址jmp 0060C6A6
CloseHandle(handle);
[CODE]
若果不想用此功能,可将源代码写回0060C6A0
[CODE]
HWND hwnd = ::FindWindow(NULL,
"地下城与勇士"
);
if
(!hwnd)
{
MessageBox(
"请先运行游戏!"
);
return
;
}
DWORD processid;
::GetWindowThreadProcessId(hwnd,&processid);
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS,
false
,processid);
::WriteProcessMemory(handle,(LPVOID)0x0060C6A0,(LPVOID)&m_char,6,NULL);
//
写回我们改写的6个字节,之前已经保存在了类成员变量中
VirtualFreeEx(handle,m_newmem,NULL,0x256);
//
释放内存,可有可无