C# winform 魔獸MH全圖制作教程(2):創建項目與關鍵類


C# winform 魔獸MH全圖制作教程(2):創建項目與關鍵類

 

 

一、開發開始:

  1. 准備好VS,新建一個winform項目,窗體命名為WarMapHack 如圖:

  2. 開始寫代碼,上一章講到把魔獸游戲窗體和進程等信息看做一個對象,用來保存所有信息,且屬性為封裝靜態.
    War.cs
    using System; using System.Collections.Generic; using System.Linq; using System.Text;
    namespace WarMacpHack { /// <summary>/// 魔獸游戲信息 /// </summary> class War { //初始化.. public static void WarInit() { War.GameName = "Warcraft III"; War.ProcessName = "War3"; War.DllName = "game.dll"; War.State = "未運行"; War.BaseAddre = IntPtr.Zero; War.HWnd = IntPtr.Zero; War.PId = 0; War.Version = ""; }
    //游戲名稱 private static string gameName;
    //進程名稱 private static string processName;
    //進程id private static int pId;
    //版本信息 private static string version;
    //游戲主要進程模塊名稱 private static string dllName;
    //窗體句柄 private static IntPtr hWnd;
    //游戲內存基址 private static IntPtr baseAddre;
    //游戲狀態提示信息 private static string state;
    public static string GameName { get { return War.gameName; } set { War.gameName = value; } }
    public static string ProcessName { get { return War.processName; } set { War.processName = value; } }
    public static int PId { get { return War.pId; } set { War.pId = value; } }
    public static string Version { get { return War.version; } set { War.version = value; } }
    public static string DllName { get { return War.dllName; } set { War.dllName = value; } }
    public static IntPtr HWnd { get { return War.hWnd; } set { War.hWnd = value; } }
    public static IntPtr BaseAddre { get { return War.baseAddre; } set { War.baseAddre = value; } }
    public static string State { get { return War.state; } set { War.state = value; } }
    } }
  3. 有了魔獸實體,剩下就是獲得信息,根據上一章的結構圖可以看到我們主要寫內存的API函數,這個函數位於Kernel32.dll 庫文件中,這個文件位於:C:\WINDOWS\system32

  4. 那么我們如何在C#中調用這個API:WriteProcessMemory

 

 

 

二、WriteProcessMemory最主要參數來源:

 

    1. 引入命名空間:
      using System.Runtime.InteropServices;
      導入方式為:
      [DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]
      在上面代碼的下一行聲明接口函數定義:
      public static extern bool WriteProcessMemory(IntPtr hProcess, int lpBaseAddress, Byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten);
    2. 想要成功必需知道參數的意義,WriteProcessMemory返回為true的話代表方法寫入內存成功。

    3. 第一個參數:IntPtr 類型的 hProcess , 我們需要打開一個進程句柄,那么這個句柄的值從何而來?會百度或MSDN的就會知道:由 OpenProcess 返回的進程句柄。而OpenProcess這個函數也為系統中的API,所以我們一下子用到兩個API。因此Api.cs中聲明如下:
             /// <summary>
             
      /// 寫內存byte[]
             
      /// </summary>
             
      /// <param name="hProcess"></param>
             
      /// <param name="lpBaseAddress"></param>
             
      /// <param name="lpBuffer"></param>
             
      /// <param name="nSize"></param>
             
      /// <param name="lpNumberOfBytesWritten"></param>
             
      /// <returns></returns>
              [DllImport("kernel32.dll", EntryPoint = "WriteProcessMemory")]
              public static extern bool WriteProcessMemory(IntPtr hProcess, int lpBaseAddress, Byte[] lpBuffer, int nSize, out int lpNumberOfBytesWritten);


              /// <summary>
             
      /// 進程提權
             
      /// </summary>
             
      /// <param name="dwDesiredAccess"></param>
             
      /// <param name="bInheritHandle"></param>
             
      /// <param name="dwProcessId"></param>
             
      /// <returns></returns>
              [DllImport("kernel32.dll", EntryPoint = "OpenProcess")]
              public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    4. 參數介紹: dwDesiredAccess        //渴望得到的訪問權限(標志) 最大權限為:0x1F0FFF ; 為了方便可以聲明變量為:                                 //int PROCESS_ALL_ACCESS = 0x1F0FFF;
      bInheritHandle            //是否繼承句柄,傳值為:false
      dwProcessId:        // 進程標示符(也就是我們在War.cs中定義的變量pId,關於獲得會在以后的章節中講到)
      如果成功的話兩個函數就可以被正常的調用,並且返回正確有效的值,其實這些API還不能滿足我們的需要,比如我們還需要在后進行關閉句柄:CloseHandle 因為它不會被C#垃圾回收,所以還需要聲明:
              /// <summary>
             
      /// 關閉一個內核對象
             
      /// </summary>
             
      /// <param name="hObject"></param>
              [DllImport("kernel32.dll", EntryPoint = "CloseHandle")]
              public static extern void CloseHandle(IntPtr hObject);
      只有一個參數,就是OpenProcess方法返回的值。
    5. 有了以上API,基本上可以完成WriteProcessMemory的第一參數,下面看第二參數,也就是lpBaseAddress內存基本地址,因為它需要從魔獸的進程中獲得Game.dll的信息,Game.dll包含游戲的版本信息,內存基址...這些信息對於我們完成全圖功能很重要。
              /// <summary>
             
      /// 進程快照
             
      /// </summary>
             
      /// <param name="flags"></param>
             
      /// <param name="processid"></param>
             
      /// <returns></returns>
              [DllImport("Kernel32.dll", EntryPoint = "CreateToolhelp32Snapshot")]
              public static extern IntPtr CreateToolhelp32Snapshot(uint flags, uint processid);

              /// <summary>
             
      /// 得到進程信息
             
      /// </summary>
             
      /// <param name="Handle"></param>
             
      /// <param name="Me"></param>
             
      /// <returns></returns>
              [DllImport("Kernel32.dll", EntryPoint = "Module32First")]
              public static extern int Module32First(IntPtr Handle, ref   MODULEENTRY32 Me);

              [DllImport("Kernel32.dll", EntryPoint = "Module32Next")]
              public static extern int Module32Next(IntPtr Handle, ref   MODULEENTRY32 Me);
      CreateToolhelp32Snapshot進程快照。這三個函數的所用也很簡單,只是寫起來比較麻煩。
      第一個參數:flags 表示要獲取快照中的哪類信息,有以下值:

      我們只用到: TH32CS_SNAPMODULE - 在快照中包含在processid中指定的進程的所有的模塊,processid也就是第二個參數。 值: TH32CS_SNAPMODULE = 8;
      第二個參數:processid (同樣是進程id,也就是War.cs中的字段pId)
      Module32First 和 Module32Next:
      兩個函數的第一個參數都為:CreateToolhelp32Snapshot返回的數據類型IntPtr的值
      Module32First 和 Module32Next 兩個函數像一對兄弟組合取出我們想要的Module模塊信息,當然它們不只能獲得這些,所以兩個函數的第二個參數。數據結構體:MODULEENTRY32 用來存儲兩個兄弟拿到的所有信息。而且是ref 引用傳遞,ref的參數會在方法中更改其值以后反應到作為參數值的變量上,就是說會將獲得信息直接設置到結構中。 將此結構同樣定義到Api.cs:
              /// <summary>
             
      /// 枚舉進程信息
             
      /// </summary>
              [StructLayoutAttribute(LayoutKind.Sequential)]
              public struct MODULEENTRY32
              {
                  public uint dwSize;
                  public uint th32ModuleID;
                  public uint th32ProcessID;
                  public uint GlblcntUsage;
                  public uint ProccntUsage;
                  IntPtr modBaseAddr;
                  public uint modBaseSize;
                  public IntPtr hModule;
                  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                  public string szModule;
                  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                  public string szExePath;
              }
      退出方法前CreateToolhelp32Snapshot返回的句柄同樣需要關閉。
      好,截止到目前我們的Api.cs所需要的寫內存函數聲明完畢,這一節也講解了WriteProcessMemory函數最主要的前兩個參數,關於第三個參數也就是byte[]類型,它代表內存基址的偏移數值,關於全圖等功能的偏移會在以后章節中全部貼出,包括顯示單位,清除迷霧,分辨幻想.等.....
      結構圖更新如下:


      下一章將講解:WriteProcessMemory 的調用和其他函數的實現方式。
      該章節源代碼下載:

      W.je(zlawliet)作品,轉載注明出處: http://www.cnblogs.com/tango/articles/2409329.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM