诛仙外挂学习一
unit Unit1; //文件名
interface //接口
uses //引用单元文件,包含的库文件 相当于c里面的include
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type //定义一个窗体类,包含各种控件及事件过程。以下是你再form中方的控件申明,系统自动生成,不用管的
TForm1 = class(TForm)
PageControl1: TPageControl;
TabSheet1: TTabSheet;
GroupBox1: TGroupBox;
TabSheet2: TTabSheet;
TabSheet3: TTabSheet;
TabSheet4: TTabSheet;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
EditName: TEdit;
EditHP: TEdit;
EditMP: TEdit;
Label4: TLabel;
EDIT1: TEdit;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private //私有变量声明
{ Private declarations }
public //公共变量声明
{ Public declarations }
end;
var //定义全局变量
Form1: TForm1;
Base0,Base1,BaseT1:Integer; //内存地址
HP,MP:Integer; //血、魔法量
MYHwnd:Hwnd; //Hwnd:窗口的句柄 handle of window
hProcess_N:Thandle; //线程号
ThreadAdd,ParamAdd:pointer;
ThreadID:DWORD; //双字节变量
MemSize,JNID:DWORD;
ByteRead:Cardinal;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
myHwnd:=FindWindow(nil,'诛仙'); //找到游戏
GetWindowThreadProcessID(MYHwnd,@ThreadID); //获取进程ID
hProcess_N:=openprocess(process_all_access,false,threadid); //打开进程
if hProcess_N=0 then
begin //以下错误提示
Messagebox(handle, '游戏未运行,请退出本程序。','提示',MB_OK+MB_IconError);
exit;
end
else
begin
Edit1.TEXT:=inttostr(myhwnd)
end;
Base0:=$A43D84; // 基址
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;
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;
begin
address:=pointer($d2293d4);
asm
pushad
call Address
popad
end;
end;
end.
总结:
通过网上的外挂实例,得出以下思路
首先,要取得游戏窗口句柄、线程;
其次,注入,在目标线程中获得内存空间,并具有最高权限;
然后开始注入,使用CALL;
感觉查找地址难度比较大,需要耐心,而之后的CALL的方法在网上都有,
目前疑惑的是,如何应对游戏的更新比较方便(如写出自动找地址的程序)、防止游戏封挂具体是怎么回事,以上问题待深入后希望能得到答案。
浙公网安备 33010602011771号