与其说是一个半成品的辅助,不如说一段代码更贴切……
前些天无聊,看到暗黑1贴吧的 TH2 更新了,于是下下来玩了会,说实话,的确有些难度,正常的打连修理费都修理不起来;然后就在贴吧找些修改的贴子,想修改些金币来修理,研究一翻,找到了修改金币的地址,突发奇想,做一个只修改金币的辅助;于是说干就干,代码如下
#include <iostream> #include <stdio.h> #include <windows.h> #include <time.h> // 延时头文件 DWORD rw_base = 0x006BBD18; // 基址 DWORD py_1 = 0x44; // 偏移1 DWORD py_2 = 0x8; // 偏移2 DWORD py_3 = 0x0; // 偏移3 DWORD py_4 = 0x0; // 偏移4 DWORD py_5 = 0x88; // 偏移5 using namespace std; // 延时 void Delay(int sec) { time_t start_time, cur_time; // 声明变量 time(&start_time); do { time(&cur_time); } while((cur_time - start_time) < sec); } // 菜单 void menu() { cout << " ****************************\n"; cout << " * 1 , 获取进程 *\n"; cout << " * 2 , 读取金钱数量 *\n"; cout << " * 3 , 修改金钱数量 *\n"; cout << " * 4 , 其 它 *\n"; cout << " ****************************\n"; } // 进度条 void JinDuBar() { for (int i = 0; i <= 4; i ++) { cout << " . "; Sleep(200); } cout << endl; } // 获取进程 void JinChen() { DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub"));// 窗口句柄 pid = GetWindowThreadProcessId(hWnd, &pid); cout << "进程 ID = " << pid << endl; if (pid == 0) cout << " 请检查游戏...." << endl; else cout << " 游戏进程获取成功, 请输入相应数值开启对应功能。" << endl; } // 读取金币数量 void ReadGoldCount() { DWORD buffer = 0; DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub"));// 获取窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid == 0) cout << " 请检查游戏...." << endl; else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // 打开线程 现在就可以对游戏内存进行操作了 ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL); // 对人物基址进行读取 把读取的值放进buffer里 buffer += py_1;// 把上面读取到的地址 + py_1 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第二次偏移地址进行读取 把读取的值放进buffer里 buffer += py_2;// 把第二次读取到的地址 + py_2 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第三次偏移地址进行读取 把读取的值放进buffer里 buffer += py_3;// 把第三次读取到的地址 + py_3 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第四次偏移地址进行读取 把读取的值放进buffer里 buffer += py_2;// 把第四次读取到的地址 + py_2 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第二次偏移地址进行读取 把读取的值放进buffer里 CloseHandle(hProcss); cout << " 金币的地址是: " << &buffer << ",金币数量是: " << buffer << endl; } } // 修改金币数量 void AddGoldCount() { DWORD buffer = 0; DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub"));// 获取窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid == 0) cout << " 请检查游戏...." << endl; else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); // 打开线程 现在就可以对游戏内存进行操作了 ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL); // 对人物基址进行读取 把读取的值放进buffer里 buffer += py_1;// 把上面读取到的地址 + py_1 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第二次偏移地址进行读取 把读取的值放进buffer里 buffer += py_2;// 把第二次读取到的地址 + py_2 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第三次偏移地址进行读取 把读取的值放进buffer里 buffer += py_3;// 把第三次读取到的地址 + py_3 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第四次偏移地址进行读取 把读取的值放进buffer里 buffer += py_4;// 把第四次读取到的地址 + py_4 赋值给 buffer, ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第五次偏移地址进行读取 把读取的值放进buffer里 buffer += py_5;// 把第五次读取到的地址 + py_5 赋值给 buffer,
// 刚开始这下面还有一次读取,但是实际上不用,否则就出错
//ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); // 对第五次偏移地址进行读取 把读取的值放进buffer里
int ne; cout << "请输入要修改的金币数量,范围 0 < 金币数量 <= 50000...." << endl; cin >> ne; WriteProcessMemory(hProcss, (LPVOID)buffer, &ne, sizeof(ne), NULL); CloseHandle(hProcss); cout << " 金币的地址是: " << &buffer << ",金币数量是: " << buffer << endl; } } int main() { system("color 0B");// system 语句中的 "color‘0‘B‘"分别为系统控制台颜色,黑色背景,绿色前景,具体代码网上查下 menu(); while(1){ int n; cin >> n; if (n == 1) { (void) Delay(0.3); //延时3秒 JinChen(); } else if (n == 2) { (void) Delay(0.3); JinDuBar(); ReadGoldCount(); } else if (n ==3) { cout << "正在修改金币数量。" << endl; JinDuBar(); (void) Delay(0.3); AddGoldCount(); } else { cout << "输入不正确,请重新输入...." << endl; system("pause"); } cin.clear(); cin.ignore(); } return 0; }
其实之前,我修改的并不是HD版暗黑1,我修改的是TH2,由于我找到TH2可以直接修改金钱的数量,刚开始玩TH2的时候,装备的修理费都修得怀疑人生了,于是想到修改,而之前玩TH1的时候也修改过装备的耐久,将耐久修改成100再继续玩,但之前玩那个TH1的时候是个半成品,没有好装备,玩了几层后就没继续玩下去。
隔了这么长时间,我一看TH2也出来了,装备系统也完美得很好,白色,蓝色,黄色等等装备都有了,于是就先修改耐久,后来发现,每打到一个装备就要修改耐久,而且刚几层都垃圾装备都要修改耐久,烦了,想要修改金钱。第一次修改金钱无效,然后去贴吧问了一句,回复是修改金钱不能挪位置,于是我在找到金钱地址后在内存中上下的翻动,终于被我找到一处,金钱修改成功,没有副作用。
然后(人的欲望是无法满足的……)我想到有一件事,之前玩HD版暗黑1的时候借鉴前人的经验修改装备的属性的时候,我通过基址找到物品栏某一个格的基址,然后把要修改的装备放到这个格子上就可以直接修改,而不用每次去找这个装备的地址。还有前不久看到一个视频教程,视频的内容是用CE找DNF的基址教程,于是我就想到,我可以找到TH2的人物基址或者物品栏第一个格的基址,把金钱放到第一个格子里,然后直接用C++编写一段修改金钱数量的代码进行修改金钱数量。因为几年前我也是照着视频学着写人生第一个辅助,DNF之无敌霸体,评分,三速效果,我想我只要得到金钱的基址,然后把基址把在的值修改应该就OK了吧,(昨天写半天没保存,我列个大艹)。
好了,继续,先运行TH2,进入游戏,再运行CE,先加载TH2进程,类型选择“未知的初始数值”,
找到3千多W条信息,然后随便移动人物,或是点买卖NPC,或是进入地下城打几个怪,再点
这里可以多点几次,但效果不大,然后退出游戏到选择人物界面,这时人物基址的值为0,所以设置为
这次过滤了一半左右,也可多点几次,可以菜单界面换个扫描类型,再扫描
然后换个人物进入游戏,
这次过滤了好多了,不过仍然有太多的结果,继续重复以上的步骤,最后找到1W多个,基本上就不会动了
我看到左边的地址有黑色也有绿色的,把黑色的地址删除,然后就只剩下10个绿色的地址了
看这几个地址都隔不远的,点第一个,右键,先浏览相关内存区域
发现了两个有用的信息
这正是我人物的名字,不过却不知道怎么用,看来得换个方法找,找物品栏的基址,把金币放第一格
同样查找未知的数值,然后把金币移到其它格子上
搜索0,又找到N多
继续反复查找,最终找到一个地址:
点地址右键,选择“什么访问了这个地址”
我艹,游戏崩了,又得重新找。。。。,找到一个,右键访问地址
出现这个界面:
把鼠标放到物品栏第一格晃动下鼠标,刚才界面就改变了”
选第四个,再点右边详细信息:
出现下面窗口
在红框处点右键复制:
把地址复制到搜索框里:
搜索到一个绿色的地址01C28608,然后就用到
遍历出了人物名字了:
用 CE 验证一下:
正确,我金币的数量是 133,用遍历工具往下找
这里有一个133
用 CE 验证下,
改变上述红框的值试下,
改了没有恢复,退出游戏。
再进入游戏,加速 进程:
基址和偏移是找对了,然后就是用 C++ 编写修改金币的代码了。好了,明天继续......
好了,继续,昨天已经通过CE找到了修改金币的基址,现在开始用C++ 编写修改金币的代码,因为之前在 CE 贴吧里学了一个 C++ 编写 毒奶粉 的无敌、霸体、评分等最基本功能的辅助,那个也是找到基址后进行修改,现在基址已经找到了,于是拿出 VC6++,把之前毒奶粉的代码稍微的改下基址,连下面的菜单都没有改,
然后发现一个问题,为何系统进程里显示的ID和我用代码获取的ID数值不一样?,但好歹能够读出来。继续获取人物名字
继续获取人物名字
将String[10]改成4字节
人物名字的地址貌似显示不对,先不管了,继续显示金币数量
金币数量和地址读取都是正常的,我显示地址是10进制的,代码以后再改,再来就是修改金币数量
虽然提示修改完成,但是金币数量还是266,而且金币的地址这里就不对了,这是之前写的代码
由于和网上教程的代码是差不多的,之前修改毒奶粉没问题,怎么到这里就不行了,反复研究半天无果,原以为是TH2不支持C++修改,
// 首先 得到人物基址的值 放进buffer里 ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL); // 人物基址的值 // 然后 再得到 人物基址的值 + 物品栏第一列第七格物品数量偏移 后的地址 buffer += bag61_count_de1; // 人物基址的值 + 物品栏第一列第七格物品名称偏移 // 首先 得到人物基址的值 + 物品栏第一列第七格物品数量偏移 后的地址的值 放进buffer里 ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL); std::cout<<"请输入金币数值,1 - 50000."<<std::endl; // 修改金钱真正地址的值 cin >> n; // 修改金钱的值 WriteProcessMemory(hProcss, (LPVOID)buffer, &n, sizeof(n), NULL);//写入 cout << "正在修改"; jd(); cout << " 金币地址 = " << &buffer << ", " << " 金币数量 = " << n << endl; cout << "修改完成." << endl; CloseHandle(hProcss);
于是我就想到之前玩暗黑1HD版的时候也找到过物品栏的基址,不过那个版本不大好修改,想着先用这个代码修改HD版,看看是代码问题还是游戏机制问题,然后代码如下
#include <iostream> #include <stdio.h> #include <windows.h> #include <time.h> // 延时头文件 #include <Windows.h> DWORD rw_base = 0x006BBD18;// 人物基址1023 DWORD rw_1 = 0x44;// 偏移1 DWORD rw_2 = 0x8;// 偏移2 DWORD rw_3 = 0x0;// 偏移3 DWORD rw_4 = 0x0;// 偏移4 DWORD rw_5 = 0x88;// 偏移5 //写内存 DWORD WriteMemory(DWORD Address,DWORD n,HANDLE hProcss) { WriteProcessMemory(hProcss, (LPVOID)Address, &n, sizeof(n), NULL); return 0; } //读内存 DWORD ReadMemory(DWORD Address,HANDLE hProcss) { DWORD tmp=0; ReadProcessMemory(hProcss, (LPCVOID)Address, &tmp, sizeof(tmp), NULL);//读取人物基址 return tmp; } void delay(int sec) { time_t start_time, cur_time; // 变量声明 time(&start_time); do { time(&cur_time); } while((cur_time - start_time) < sec ); } //菜单 void menu() { std::cout<<" ***************************\n"; std::cout<<" * 1 , 获取进程 *\n"; std::cout<<" * 2 , 读取金钱数量 *\n"; std::cout<<" * 3 , 修改金钱数量 *\n"; std::cout<<" * 4 , 其它 *\n"; std::cout<<" ***************************\n"; } //进度条 void jd() { int i =0; for (i=0;i<=4;i++) { std::cout<<"."; Sleep(200); } std::cout << std::endl; } //获取进程 void jinchen() { DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 pid = GetWindowThreadProcessId(hWnd,&pid); std::cout<<"进程ID="<<pid<<std::endl; //std::cout<<pid<<std::endl; if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { std::cout<<"游戏进程获取成功,输入相应数值开启对应功能\n"<<std::endl; } } void ReadGold() { DWORD buffer=0; DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_1; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_2; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_3; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_4; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_5; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 // DWORD bt = 1; // WriteProcessMemory(hProcss, (LPVOID)buffer, &bt, sizeof(bt), NULL); CloseHandle(hProcss); std::cout<< " 金钱数量 = " << buffer << std::endl; } } void AddGold() { DWORD buffer=0; DWORD pid = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_1; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_2; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_3; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_4; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_5; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 DWORD bt = 100; WriteProcessMemory(hProcss, (LPVOID)buffer, &bt, sizeof(bt), NULL); CloseHandle(hProcss); std::cout<< " 金钱数量 = " << bt << std::endl; } } int main() { system("color 0B");//system语句中的"color‘0‘‘A‘"分别为系统控制台颜色,黑色背景,绿色前景.具体颜色代号表上网查一下就可以了. menu(); while(1){ std::cout<<"请输入出相应数值 \n"; int n; std::cin>>n; if (n==1) { (void) delay(0.3); //延时3秒 jinchen(); } else if (n==2) { (void) delay(0.3); //延时3秒 jd(); ReadGold(); } else if (n==3) { std::cout<<"正在修改金钱数量\n"; jd(); (void) delay(0.3); //延时3秒 AddGold(); } else { std::cout<<"输入不正确,请重新输入"; system("pause"); } std::cin.clear(); std::cin.ignore(); } return 0; }
能获取进程和金币数量,但就是不能修改。。。。
于是第二天我就在一个暗黑1的企鹅群里求教,我 copy 代码到群里问,立马就有人回了,但后来我发现他回答的是修改会被系统回收的问题,而非我的代码不能修改金币数量问题,回到正题后,他让我把每次偏移后的地址也用代码读取,然后看看读取的地址,于是我加了相关读取地址的代码后,发现,
添加显示地址的代码:
void AddGold() { DWORD buffer=0; DWORD pid = 0; DWORD ne = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_1; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_2; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_3; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_4; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 buffer += rw_5; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL)//人物基址的值 cin.get(); DWORD ne = 100; cout << "输入数量:"; cin >> ne; WriteProcessMemory(hProcss, (LPVOID)buffer, &ne, sizeof(ne), NULL); CloseHandle(hProcss); std::cout<< " 金钱数量 = " << ne << " 金钱地址 = " << buffer << std::endl; } }
运行代码
这金币的地址明显不对
基址找的没问题,怎么最后读取的地址不对,于是在每次偏移都加上读取地址
void AddGold() { DWORD buffer=0; DWORD pid = 0; DWORD ne = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 人物基址 = " << std:: hex << rw_base << std::endl; buffer += rw_1; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址1 = " << buffer << std::endl; buffer += rw_2; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址2 = " << std:: hex << buffer << std::endl; buffer += rw_3; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址3 = " << std:: hex << buffer << std::endl; buffer += rw_4; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址4 = " << std::hex <<buffer << std::endl; buffer += rw_5; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL)//人物基址的值 std::cout<< " 金钱地址5 = " << buffer << std::endl; cin.get(); DWORD ne = 100; cout << "输入数量:"; cin >> ne; WriteProcessMemory(hProcss, (LPVOID)buffer, &ne, sizeof(ne), NULL); CloseHandle(hProcss); std::cout<< " 金钱数量 = " << ne << " 金钱地址 = " << buffer << std::endl; } }
运行代码后
前五次读取的地址都是正确,最后修改要读取的地址却跑偏了,最后次没有加偏移,为何读取的地址会跑偏了呢,看到这里应该这样改,把第五次 ReadProcessMemory()这行代码删除,第五次的偏移,直接加要修改的数量直接写入
void AddGold() { DWORD buffer=0; DWORD pid = 0; DWORD ne = 0; HWND hWnd = FindWindow(NULL, TEXT("Belzebub")); //窗口句柄 GetWindowThreadProcessId(hWnd, &pid); if (pid==0) { std::cout<<"请检查游戏"<<std::endl; } else { HANDLE hProcss = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); ReadProcessMemory(hProcss, (LPCVOID)rw_base, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 人物基址 = " << std:: hex << rw_base << std::endl; buffer += rw_1; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址1 = " << buffer << std::endl; buffer += rw_2; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址2 = " << std:: hex << buffer << std::endl; buffer += rw_3; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址3 = " << std:: hex << buffer << std::endl; buffer += rw_4; ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL);//人物基址的值 std::cout<< " 金钱地址4 = " << std::hex <<buffer << std::endl; buffer += rw_5; //ReadProcessMemory(hProcss, (LPCVOID)buffer, &buffer, sizeof(buffer), NULL)//人物基址的值 //std::cout<< " 金钱地址5 = " << buffer << std::endl; cin.get(); DWORD ne = 100; cout << "输入数量:"; cin >> ne; WriteProcessMemory(hProcss, (LPVOID)buffer, &ne, sizeof(ne), NULL); CloseHandle(hProcss); std::cout<< " 金钱数量 = " << ne << " 金钱地址 = " << buffer << std::endl; } }
运行代码:
这次地址是正确的,然后游戏就...
修改的金币被删除了,到这里问题总算是解决了,后来群里有个大S告诉我可以直接用VC的调试模式来调试,不用每次都加代码来显示地址进行调试,真是一语惊醒啊,学习的时候经常用F10进行调试,写辅助的时候却忘了这么好的东西了....
原文:https://www.cnblogs.com/hsoftk/p/12588163.html