本帖最后由 霖韵嫣然 于 2016-7-23 06:28 编辑
浅析编程制作EXE内存补丁 -By 霖韵嫣然 前记 瘫在沙发上一天了,为了防止白活一天,那总得做点什么。刚申请上论坛的账号,为了庆祝,就发一篇文章吧。专门针对小白,大神请飘过。过。过。。然而我。。快要疯了。。。平板怎么这么难编辑帖子。也罢。不编辑了。word文档链接:https://yunpan.cn/cBaWCKPziAIiH 1.用易语言写一个简单的CRACK ME。 我们可以清晰地看到,它简单到让小白都呕吐的算法。如图: 2.OD查找到关键代码处。 注意:由于我的系统是WINDOWS10有ASLR保护机制,所以,把它丢到 虚拟机里面测试(WINDWOS XP)。为了简单,也为了编程时不过于复杂。(非我懒) 轻易找出关键跳后,作出如下分析: 1. 我们需要修改的地址:00401271 |. /0F84 41000000 je CRACKME.004012B8
2. 这一行中,我们只要将00401271和00401272的数据更改为9090或者将00401272的数据更改为85即可。
3. 打开强大无比的VS编程解决这个问题。
3.编程打内存补丁 使用FindWindow函数来查找窗口以确认它正在运行。 函数原型: HWND FindWindow( LPCTSTR lpClassName,
| // pointer to class name
| LPCTSTR lpWindowName
| // pointer to window name
| );
|
|
第一个参数是窗口类名,第二个参数则是窗口名,用spy++可以轻松获取。(VS自带工具,在工具菜单可以找到)。 标题:CrackME -BY ZZZ 类名:ZZZ 这样,这个函数就可以工作了。 HWND 目标程序句柄 = FindWindowA("ZZZ", " CrackME -BY ZZZ "); (注意:VS支持中文名变量!) 我们继续,获取了这个窗口的句柄,我们就可以对它干一些事情………… DWORD 接受PID; GetWindowThreadProcessId(目标程序句柄, &接受PID); 定义一个DWORD类型变量来接收PID。因为我们需要PID来完成一些工作。 使用GetWindowThreadProcessId 函数原型: DWORD GetWindowThreadProcessId( HWND hWnd,
| // handle of window
| LPDWORD lpdwProcessId
| // address of variable for process identifier
| );
|
|
很简单的一个WIN32 API,在此不作过多赘述。 接着,我们需要获取一个打开程序的句柄。 HANDLE 打开文件句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 接受PID); 函数原型: HANDLE OpenProcess( DWORD dwDesiredAccess,
| // access flag
| BOOL bInheritHandle,
| // handle inheritance flag
| DWORD dwProcessId
| // process identifier
| );
|
|
第一个参数就是权限,我们要所有权限,因为我们需要写内存! 第二个参数是是否继承,直接填否即可。 第三个参数是PID,刚才获取的东西,终于派上了用场。 现在,我们回顾一下刚才需要修改的地方: 我们需要用WriteProcessMemory这个函数来修改内存。 函数原型: BOOL WriteProcessMemory( HANDLE hProcess,
| // handle to process whose memory is written to
| LPVOID lpBaseAddress,
| // address to start writing to
| LPVOID lpBuffer,
| // pointer to buffer to write data to
| DWORD nSize,
| // number of bytes to write
| LPDWORD lpNumberOfBytesWritten
| // actual number of bytes written
| );
|
|
这个函数初次用可能会很茫然,我们来简单了解一下它。 第一个参数是我们刚才打开的文件句柄,这个不用多说,直接填进去就可以。 第二个参数是我们需要写的内存地址。我们在这里填入地址 00401272。为了让程序稳定一些,我们只修改一个字节。将84修改为85。(注意:在汇编码中,JE/JZ是84,JNE/JNZ是85)观察一下,类型是LPVOID。这样我们可以这样写:(LPVOID)0x401272,强制转换一下即可。由于这个地址是十六进制,所以我们加0x表示。 第三个参数是数据。这里我们定义一下数据:int 数据 = 0x85;看一下类型,又是LPVOID,这次我们不用强转,直接取地址数据即可。在此注意0x不可省去! 第四个参数是写入的大小,我们写了一个字节,当然填入1。 第五个参数我们可以不用写了,直接填入NULL。 这样,这个函数可以写出来了。 int 写内存返回值 = WriteProcessMemory(打开文件句柄, (LPVOID)0x401266, &数据, 1, NULL); 他的返回值如果是0,那么函数就是执行失败,我们可以接收来判断一下。 这样最终的源码就是这样了: #include <Windows.h>
int main() { MessageBoxA(NULL, "准备开始补丁!", "提示:", MB_ICONINFORMATION); HWND 目标程序句柄 = FindWindowA("ZZZ", "CrackME -BY ZZZ"); if (目标程序句柄 == 0) { MessageBoxA(NULL, "未找到目标程序!", "提示:", MB_ICONINFORMATION); return 0; } else { DWORD 接受PID; GetWindowThreadProcessId(目标程序句柄, &接受PID); HANDLE 打开文件句柄 = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 接受PID); int 数据 = 0x85; int 写内存返回值 = WriteProcessMemory(打开文件句柄, (LPVOID)0x401272, &数据, 1, NULL); if (写内存返回值 != 0) { MessageBoxA(NULL, "补丁成功!", "提示:", MB_ICONINFORMATION); return 1; } else { MessageBoxA(NULL, "补丁失败!", "提示:", MB_ICONEXCLAMATION); return -1; } } }
在编译时,注意要设置一下兼容,确保XP能够运行补丁。(按理说我的WIN10不能运行,但是奇异的一幕出现了…………望大神告知这是怎么回事。居然成功补丁上了。只是卡了几秒。) 效果如图: 这样,一个简单的内存补丁就制作完成了。 后记 为了防止其他某些编译器不识别汉字变量,我在附件中将汉字变量全部改了名称。(用拼音来祭奠我那悲催的英语成绩) 最后,大家暑假愉快! 360云盘链接: https://yunpan.cn/cBi4eDerIWjYB 度盘已废,不要问我为什么。。。
|