Delphi新手跟我学写CALL,附完整原程序
在开始进入正题前先罗嗦几句:
1、本人也刚学Delphi不久,也刚通过《诛仙》游戏的绝大部分CALL不久。所以在以下所说所列举的例子并不算是名门正中的写法,如有不当,请各位原谅。
2、本人所学基本都是在“漆黑一片”中自己摸索出来的。也正因如此,因而深感各位新手想入门但又无处可问的无奈心情。所以将在下面为各位新手较详细地列举2个CALL的应用例子。希望大家不要象我一样走那么多的弯路。更希望论坛的各位老大能多多开源,多点无私的奉献。
抗日时期,中国之所以能屡屡打败强大的帝国,就是因为有大多数国人的无私奉献和团结一致的精神!
......
废话一堆后进入正题,下面我将会通过《诛仙》游戏分几段讲述有参数CALL、无参数CALL的调用;CALL在游戏更新后,自己如何找回入口地址;以及《诛仙》游戏中几个基址间的关系。
第一讲 --- 《诛仙》的基址
在论坛中看过相关帖子的朋友不难发现《诛仙》有三个所谓的基址:基址1:$12F82C 基址2:$9045EC 基址3:$900ADC
其中它们之间的关系如下:[$12F82C]=$9045EC 、 $9045EC=[$900ADC+1C]
之所以一开始就先说这个,是想希望大家学会在游戏更新后,如何快速地找到新的,适合自己习惯的有用基址。从上面关系不难看出。$12F82C是三个基址中最为稳定的一个,事实上在6.19、7.3更新时它就没,而其他2个都变了。当然如果你本身是用$12F82C这个做基址的也就免去了不少麻烦。不过我可以证实这个基址1并不能在大部分的环境下(WinXP、Win2000等)通过,如果不是只做给自己一个用的,最好不用这基址。
我就选用了基址2:$9045EC。因为[$12F82C]=$9045EC,所以当游戏更新了基址时,只要用CE看看[$12F82C]=?就OK了,明白了吗?(当然这并不绝对,但大部分是可行的啦,除非游戏真的动大手术啦)
而基址3:$900ADC则是用于CALL里面的(大家看看《诛仙》CALL地址公布就知道这地址的重要性了),所以一定要学会怎找到这基址。
方法就是用CE跟踪[$12F82C]=?这个“?”地址是啥(现在是$9045EC),再根据“mov ecx, [eax+1c]”查看 eax的值(现在是$9045D0),最后查找$9045D0 得到 $900ADC,OK?
第二讲 --- 《诛仙》的死亡回城CALL(无参数CALL)
为了大家方便学习,我一次性把整个讲解的实例程序打包贴出来,里面包括了角色基本信息的读取(含名字);无参数CALL(死亡回城)调用;有参数CALL(技能攻击)调用(仅以重击为例)。
许多新手也象我当初一样,会问论坛怎没有一个无参数CALL的例子。其实有参数和无参数CALL的调用是一样的。我就用《诛仙》的死亡回城CALL作为无参数CALL的实例,其中关键过程如下:
......
// ---- 定义参数指针
type
P1_STR = packed record
Param1: DWORD;
Param2: DWORD;
end;
PP1_STR = ^P1_STR;
......
//打开游戏进程并一次性申请注入空间
procedure TForm1.FormCreate(Sender: TObject);
begin
MyHwnd:=findwindow(nil, 'Element Client');
GetWindowThreadProcessId(MyHwnd, @ThreadID);
hProcess_N := OpenProcess(PROCESS_ALL_ACCESS, False, ThreadID);
if hProcess_N = 0 then
begin
Messagebox(handle, ' 请退出先登录运行《诛仙》游戏。 ','提示',MB_OK+MB_IconError);
exit;
end;
Base0:=$9045EC; // 基址
MemSize:=128; // 128的空间已足够,无须4096这么浪费
ThreadAdd := VirtualAllocEx(hProcess_N, nil, MemSize, MEM_COMMIT, PAGE_READWRITE);
ParamAdd := VirtualAllocEx(hProcess_N, nil, 20, MEM_COMMIT, PAGE_READWRITE);
end;
.....
//一次性释放空间
procedure TForm1.FormDestroy(Sender: TObject);
begin
VirtualFreeEx(hProcess_N, ThreadAdd, MemSize, MEM_RELEASE);
VirtualFreeEx(hProcess_N, ParamAdd, 20, MEM_RELEASE);
CloseHandle(hProcess_N);
end;
.....
//CALL注入
procedure InjectFunc(Func: Pointer; Param: Pointer; ParamSize: DWORD);
var
hThread: THandle;
lpNumberOfBytes: DWORD;
begin
if hProcess_N<>0 then
begin
WriteProcessMemory(hProcess_N, ThreadAdd, Func, MemSize, lpNumberOfBytes);
WriteProcessMemory(hProcess_N, ParamAdd, Param, ParamSize, lpNumberOfBytes);
hThread := CreateRemoteThread(hProcess_N, nil, 0, ThreadAdd, ParamAdd, 0, lpNumberOfBytes);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
end;
end;
.....
// ---- 死亡回城 CALL 注意,下面只有一个Address的CALL入口地址,没其他参数
procedure MyCall1; Stdcall;
var
Address:=Pointer($5A1F70);
asm
pushad
call Address
popad
end;
.....
// --- 调用CALL 回城 注意,下面MyParam没其具体赋值,因为是无参数CALL
procedure TForm1.RetCity;
var
MyParam : P1_STR;
ParamSum: DWORD;
begin
ParamSum:=0;
if MyHwnd<>0 then
begin
injectfunc(@MyCall1, @MyParam, ParamSum);
end;
end;
.....
//死亡后按这按钮能回城
procedure TForm1.Button2Click(Sender: TObject);
begin
RetCity;
end;
.....
第三讲 --- 《诛仙》的技能攻击CALL(有参数CALL)
有了上面无参数CALL做基础,有参数CALL就好做了,下面以《诛仙》“重击”技能攻击CALL为例,其中关键过程如下:
......
// ---- 定义参数指针
type
P1_STR = packed record
Param1: DWORD;
Param2: DWORD;
end;
PP1_STR = ^P1_STR;
......
//打开游戏进程并一次性申请注入空间
procedure TForm1.FormCreate(Sender: TObject);
begin
MyHwnd:=findwindow(nil, 'Element Client');
GetWindowThreadProcessId(MyHwnd, @ThreadID);
hProcess_N := OpenProcess(PROCESS_ALL_ACCESS, False, ThreadID);
if hProcess_N = 0 then
begin
Messagebox(handle, ' 请退出先登录运行《诛仙》游戏。 ','提示',MB_OK+MB_IconError);
exit;
end;
Base0:=$9045EC; // 基址
MemSize:=128; // 128的空间已足够,无须4096这么浪费
ThreadAdd := VirtualAllocEx(hProcess_N, nil, MemSize, MEM_COMMIT, PAGE_READWRITE);
ParamAdd := VirtualAllocEx(hProcess_N, nil, 20, MEM_COMMIT, PAGE_READWRITE);
end;
.....
//一次性释放空间
procedure TForm1.FormDestroy(Sender: TObject);
begin
VirtualFreeEx(hProcess_N, ThreadAdd, MemSize, MEM_RELEASE);
VirtualFreeEx(hProcess_N, ParamAdd, 20, MEM_RELEASE);
CloseHandle(hProcess_N);
end;
.....
//CALL注入
procedure InjectFunc(Func: Pointer; Param: Pointer; ParamSize: DWORD);
var
hThread: THandle;
lpNumberOfBytes: DWORD;
begin
if hProcess_N<>0 then
begin
WriteProcessMemory(hProcess_N, ThreadAdd, Func, MemSize, lpNumberOfBytes);
WriteProcessMemory(hProcess_N, ParamAdd, Param, ParamSize, lpNumberOfBytes);
hThread := CreateRemoteThread(hProcess_N, nil, 0, ThreadAdd, ParamAdd, 0, lpNumberOfBytes);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
end;
end;
.....
// ---- 技能 CALL 注意,下面只有一个Address的CALL入口地址,还有个P1 ---- 技能ID号的参数
procedure MyCall8(P:PP1_STR); Stdcall;
var
Address: pointer;
P1: DWORD;
begin
Address:=Pointer($4656F0);
P1:=P^.Param1; // ---- 技能ID号
asm
pushad
push -1
push 0
push 0
push P1
mov ecx,DWORD PTR DS:[$900adc]
mov edx,DWORD PTR DS:[ecx+$1c]
mov ecx,DWORD PTR DS:[edx+$28]
call address
popad
end;
end;
.....
// ---- 调用CALL 技能 注意,下面MyParam.Param1(第一个参数)具体赋值为JNID(技能ID号)
procedure TForm1.JiNeng;
var
MyParam : P1_STR;
ParamSum: DWORD;
begin
MyParam.Param1:=JNID;
ParamSum:=SizeOf(MyParam);
if MyHwnd<>0 then
begin
injectfunc(@MyCall8, @MyParam, ParamSum);
end;
end;
.....
//按这按钮能用“重击”技能攻击怪
procedure TForm1.Button3Click(Sender: TObject);
begin
JNID:=$DA; // 这里举例用“重击”的ID号为例
JiNeng;
end;
http://www.cnblogs.com/toosuo/archive/2007/12/02/979975.html
Delphi新手跟我学写CALL,附完整原程序的更多相关文章
- delphi使用outputdebugstring调试程序和写系统日志
delphi使用outputdebugstring调试程序和写系统日志 procedure TForm1.btn1Click(Sender: TObject); begin OutputDebugSt ...
- 跟我一起学写jQuery插件开发方法(转载)
jQuery如此流行,各式各样的jQuery插件也是满天飞.你有没有想过把自己的一些常用的JS功能也写成jQuery插件呢?如果你的答案是肯定的,那么来吧!和我一起学写jQuery插件吧! 很 ...
- 我要带徒弟学写JAVA架构,引路架构师之路(Jeecg开源社区)
带徒弟学JAVA架构(Jeecg社区) Java程序员如何打破工作2,3年的瓶颈问题,如何更上一层楼? 太多的巧合,让我接触到了开源,通过JEECG与很多朋友交流后,让我有了帮助别 ...
- canvas知识03:学写一个字案例
效果
- 一点一点学写Makefile(3)-增加第三方库和头文件
我们在写代码的时候不一定都是有自己来完成,一个工程中会大量使用一些比较优秀的动态库.静态库等,我们在使用这些库完成所有的代码后,需要在编译的时候将这些库使用的头文件添加到我们的工程上,将他的库文件也添 ...
- 一点一点学写Makefile-1
相信很多Linux开发者 都得自己来写Makefile,刚开始学习学写这个的时候都会碰到很多困难,我之前没有自己独立完成过Makefile,都是在公司已有的模板上添加.现在突然有一个很大的想法就是从零 ...
- 学写jQuery插件开发方法
jQuery如此流行,各式各样的jQuery插件也是满天飞.你有没有想过把自己的一些常用的JS功能也写成jQuery插件呢?如果你的答案是肯定的,那么来吧!和我一起学写jQuery插件吧! 很多公 ...
- 你必须学写 Python 装饰器的五个理由
你必须学写Python装饰器的五个理由 ----装饰器能对你所写的代码产生极大的正面作用 作者:Aaron Maxwell,2016年5月5日 Python装饰器是很容易使用的.任何一个会写Pytho ...
- canvas学写一个字
第一步:画一个米字格,先画一个矩形,再画中间的米字. <script> window.onload = function(){ var canvas = document.getEleme ...
随机推荐
- 小贝_redis web管理界面工具安装
RedisWEB管理界面工具安装 一.概述 二.文件下载 三.安装过程 一.概述 1.因为redis是基于C/S的方式开发.也就是说,仅仅要满足于redis的client通信要求的,都能够作为redi ...
- (转)Oracle EXP-00091解决方法
转自:http://blog.csdn.net/dracotianlong/article/details/8270136 EXP-: 正在导出有问题的统计信息. . . 正在导出表 WF_GENER ...
- PythonOOP面向对象编程2
编程语言的特征: 继承 封装 多态 如:C++ / Java / Python / Swift / C# inheritance 继承 drived 派生 概念: 继承是指从已有的类中衍生出新类,新类 ...
- jmeter--基本组件介绍
一.JMeter 介绍 Apache JMeter是100%纯Java桌面应用程序,被设计为用于测试客户端/服务端结构的软件(例如web应用程序).它可以用来测试静态和动态资源的性能,例如:静态文件, ...
- [D3] Make D3 v4 Charts Responsive with the viewBox attribute
Making SVGs responsive is unfortunately not as simple as adding some media queries. This lesson intr ...
- JavaFX2 - 文本可复制的Label
背景介绍 我的公司和我个人一直都使用JavaFX2来编写client应用程序,同一时候也作为Applet在浏览器中执行. 我们的客户以前拿我们的产品和网页对照,然后向我们提过两个需求: (1) 希望界 ...
- spark源码解析之基本概念
从两方面来阐述spark的组件,一个是宏观上,一个是微观上. 1. spark组件 要分析spark的源码,首先要了解spark是如何工作的.spark的组件: 了解其工作过程先要了解基本概念 官方罗 ...
- POJ 1364 King (UVA 515) 差分约束
http://poj.org/problem?id=1364 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemi ...
- (转)yum & wget代理设置
转自 http://www.cnblogs.com/windows/archive/2012/12/14/2817533.html yum 配置代理服务器访问要设置所有 yum 操作都使用代理服 ...
- 11.1 Android显示系统框架_framebuffer原理及改进
1. Android显示系统框架Android Graphic UI with GPU Hardware Accelerationhttps://community.nxp.com/docs/DOC- ...