zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    C语言 realloc为什么要有返回值,realloc返回值具体解释/(解决随意长度字符串输入问题)。
    opencv中的vs框架中的Blob Tracking Tests的中文注释。
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 棋盘多项式
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
    Java实现 蓝桥杯VIP 算法提高 分苹果
  • 原文地址:https://www.cnblogs.com/findumars/p/4690294.html
Copyright © 2011-2022 走看看