• (转)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;
    .....
  • 相关阅读:
    asp .net 文件浏览功能
    Angular组件间的数据传输
    Angular自定义表单验证
    asp .net Cookies
    带参跳转其他controller
    asp .net 页面跳转
    发送邮件
    ubuntu之Matlab安装
    清华宿舍楼
    ubuntu窗口打开指定文件夹
  • 原文地址:https://www.cnblogs.com/toosuo/p/979975.html
Copyright © 2020-2023  润新知