你的位置:首页 > ASP.net教程

[ASP.net教程]【原创开源】自己用C#写的一款“托管”FPS射击网游辅助开源,给大家参考~


写在前面:

 

1.本博文只是用来给大家参考,学习的,本人不建议大家去写外挂破坏游戏,影响他人正常游戏体验,以下暂称“助手”。

2.本博文写的比较菜,因为第一次写,而且表达方面可能比较难理解。希望大家见谅。

3.本博文侧重 描述一下 菜单的功能 和 内存 读写以及 一些 其他 注意事项,给大家以参考。

4.本人还是个.Net 老菜鸟,如果代码写的存在问题或者不足的,请 评论指出 ,我非常 感谢。

5.助手特性:

可以从服务器端控制 菜单 显示文字,

控制菜单 功能快捷键 ,

控制菜单 功能是否启用,

控制菜单 功能基址和偏移和写入值,

控制菜单 功能实现方式(时钟控制与否)

等..

助手效果:

登陆:

 

 

登陆成功效果:


 

正文:

1. 助手 菜单类 定义:

 public partial class MenuFnClass  {    public delegate void fn(int bassaddress, int[] offsetlist, string value);     fn fntemp;    ///构造函数,传入委托方法名    public MenuFnClass( fn fn1)    {      fntemp = fn1;     }    public string menuName=string.Empty;//功能名    public bool isMenuOpen=false;//菜单是否正在被使用    public bool isMenuVisiable=false;//菜单是否可用,控制标签显示与快捷键调用    public int baseAddress=0;//基址    public int[] multiLevel=null;//偏移队列    public string value=string.Empty;//写入值     public bool isUsetimer=false;//是否时钟控制,,如果只需修改一次的功能,则不去除效果. 默认 假    public Label myLabel;//菜单标签控件    public Keys myKeys;//快捷键    public void DoWork()    {      fntemp(baseAddress, multiLevel,value);    }  }

 

2.菜单 功能对象申明:

    #region (功能)类定义/初始化    private MenuFactory mnFactory;//从登陆类获取 基址偏移解密密码,并初始化菜单工厂类    private List<MenuFnClass> MenuList=new List<MenuFnClass>();    private ArrayList nameList =new ArrayList();//同房玩家昵称数组    private ArrayList playIdList = new ArrayList();//同房玩家Id数组    private MenuFnClass CS_AntiReport;//防止举报    private MenuFnClass CS_QuickAmo;//子弹加速    private MenuFnClass CS_SuperGun;//无限散弹    private MenuFnClass CS_SuperKnief;//刀加速    //private MenuFnClass CS_NoJingZi;//去除瞄准镜    //private MenuFnClass CS_HuanDan;//换弹加速    private MenuFnClass CS_GaiVip;//模拟vip    private MenuFnClass CS_GaiRank;//改等级    private MenuFnClass CS_GaiMing;//改游戏昵称    private MenuFnClass CS_DuckModel;//鸭子模式    private MenuFnClass CS_MaxAmo;//无限子弹    private MenuFnClass CS_FangShan;//去除闪光弹效果    private MenuFnClass CS_HouZuo;//去除后座力    private MenuFnClass CS_ZhunXin; //准心    private MenuFnClass CS_MoNi;//盗名昵称    private MenuFnClass CS_MoNi2;//模拟角色    //private MenuFnClass CS_KaiJing;//0秒开镜    //private MenuFnClass CS_QieQiang;//狙击切枪    //private MenuFnClass CS_AutoFire;//自动开火    private MenuFnClass CS_ShootDist_Add;    private MenuFnClass CS_ShootDist_Des;//减少射程    private MenuFnClass CS_RandomMove;//视觉飞天    private MenuFnClass CS_PinbgMuBH;//屏幕不晃    private MenuFnClass CS_WuHouZuo;//无后座力    #endregion

 

3. 

这边我自己定义了一个 MenuFactory 类,用于 和数据库交互 取菜单数据。

 /// <summary>  /// 注意 要想实例化本帮助类,必须传入正确参数。本帮助类解析加密基址字符串  /// </summary>  public partial class MenuFactory  {     private string JieMiMiMa;    /// <summary>    /// 构造函数,存入基址解密密码    /// </summary>    /// <param name="keydata"></param>    public MenuFactory(string keydata)    {      JieMiMiMa = keydata;    }    #region 数据库相关    private  string GetConStr()    {      return "server=.;database=DB_AVA_TEST;integrated security=true;";    }    /// <summary>    ///从数据库获取 【解密密码keydata】解密数据 ,处理数据 ,直接返回类 供前台调用    /// </summary>    /// <returns></returns>    public MenuFnClass GetOneMenu(int? mid, MenuFnClass.fn fn1)    {      MenuFnClass retMfc= new MenuFnClass(fn1);      if (mid == null) { return retMfc; }      // return des.DecryptDES(GetDESData(jzid), JieMiMiMa);       SqlParameter[] spa = new SqlParameter[]      {        new SqlParameter("@tid",SqlDbType.Int,4),        new SqlParameter("@tusername",SqlDbType.NVarChar,4000),         new SqlParameter("@tpassword",SqlDbType.NVarChar,4000)      };      spa[0].Value = mid;      spa[1].Value = Login_.login_name;      spa[2].Value = Login_.login_pwd;      DataSet dsTemp= DbHelperSQL.QueryProcedure("OFS_Get_ById_UserInfoDate", spa);//自定义存储过程用于从DB取数据      if(dsTemp==null|| dsTemp.Tables[0].Rows.Count==0)      {        retMfc.isMenuVisiable = false;        retMfc.menuName = "tip:function here locked";      }      else      {        //验证数据有效性? 取出时间参数校验        DataTable dt=dsTemp.Tables[0];         //bool isok=CheckData(dt.Rows[0]["m"].ToString(),dt.Rows[0]["d"].ToString());        //if(!isok){ return null;}        retMfc.baseAddress = Other.HexToInt(des.DESJIE(dt.Rows[0]["BASEADD"].ToString(), JieMiMiMa));        retMfc.isUsetimer=(dt.Rows[0]["ISTIMER"].ToString()=="1")?true:false;        retMfc.menuName=dt.Rows[0]["MENUNAME"].ToString();        retMfc.value=dt.Rows[0]["WVALUE"].ToString();//可以不用从数据库取        retMfc.multiLevel = Other.StringToIntSZ(des.DESJIE(dt.Rows[0]["OFFSETSLIST"].ToString(), JieMiMiMa), ','); //偏移字符串转换为int[],偏移分隔符',',16进制字符串数组到整型数组        retMfc.isMenuVisiable = (dt.Rows[0]["ISUSED"].ToString() =="1") ? true : false;              }      return retMfc;    }     /// <summary>    /// 时间校验,同月,北京日-美国日 <2    /// </summary>    /// <param name="strm"></param>    /// <param name="strd"></param>    /// <returns></returns>    private bool CheckData(string strm,string strd)    {      //int mon = int.Parse(strm);      //int day = int.Parse(strd);      //if (mon == (DateTime.Now.Month + DateTime.Now.Month) && (DateTime.Now.Day - day) < 2)      // {      //   return true;      // }      // return false;      return true;    }    /// 根据基址编号id,用户账号密码,从数据库获取 已开启 的基址和偏移 ,返回数据 解密 ,进行数据是否过期验证    private string GetDESData(int id)    {      return null;    }    #endregion  }

 

4. 窗口 Load事件里 去 从数据库 取菜单 数据 以及 助手 内存地址 等信息,做 初始化 操作。

Load事件里 补下一个 键盘hook 注册代码

        KeyboardHook kh;//声明为全局        kh = new KeyboardHook();        kh.SetHook();        kh.OnKeyDownEvent += kh_OnKeyDownEvent; 

 

  /// <summary>    /// 主窗体Load事件    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void Main_frm_vip_Load(object sender, EventArgs e)    {       try      {         timr_checkava.Start();//安全        timr_now.Start();        //  Login_.Isused = Other.CheckMd5();//如果校验MD5成功,改变改变量为 true        // if (!Login_.Isused) { Application.Exit(); return; }         this.Text = "请求数据...";        lab_Msg.Text = "[Msg]请求数据...";        Thread tr_fillmenu = new Thread(new ThreadStart(FillMenuList));//开一个线程去 初始化 菜单 集合        tr_fillmenu.Start();// tr_fillmenu时钟用于 动态从 menuList 菜单集合 里面去 显示 菜单信息到 窗口。       }
}

 #region 菜单集合初始化/核心代码    /// <summary>    /// 核心代码-填充菜单集    /// </summary>    /// <returns></returns>    private void FillMenuList()    {      MenuFactory mnFactory;//从登陆类获取 基址偏移解密密码,并初始化菜单工厂类      mnFactory = new MenuFactory(des.desjiemi(Login_.datakey));//初始化 从数据库拿基址的帮助类

PMR = new ProcessMemoryReader(); PMR.ReadProcess = Other.GetAvAProcessId();//获取游戏进程标识 CS_AntiReport = mnFactory.GetOneMenu(2, AntiReport); //26,参数1:菜单在数据库的ID 参数2:专属功能名 此处用到了 委托 CS_AntiReport.myKeys = Keys.NumPad8;//设定该项菜单 快捷键 CS_AntiReport.myLabel = lab_AntiReport;// 设定该项菜单 对应的label CS_AntiReport.myLabel.Text = CS_AntiReport.menuName;//设定该项菜单 对应的label的显示文字 CS_TSRoom.isUsetimer = true; //true持续修改,默认为false;实际从数据库取值判断 设定该项功能 是否启用时钟 控制还是只执行一次 MenuList.Add(CS_AntiReport); //MenuList定义为 List<MenuFnClass> CS_QuickAmo = mnFactory.GetOneMenu(9, QuickAmo); // 子弹加速 CS_QuickAmo.myKeys = Keys.NumPad1; CS_QuickAmo.myLabel = lab_N1; CS_QuickAmo.myLabel.Text=CS_QuickAmo.menuName; MenuList.Add(CS_QuickAmo); CS_SuperGun = mnFactory.GetOneMenu(11,SuperGun);//N+弹 CS_SuperGun.myKeys = Keys.NumPad2; CS_SuperGun.myLabel = lab_N2; CS_SuperGun.myLabel.Text = CS_SuperGun.menuName; MenuList.Add(CS_SuperGun); CS_SuperKnief = mnFactory.GetOneMenu(13,SuperKnief);//右刀加速 CS_SuperKnief.myKeys = Keys.NumPad3; CS_SuperKnief.myLabel = lab_N8; CS_SuperKnief.myLabel.Text = CS_SuperKnief.menuName; MenuList.Add(CS_SuperKnief); //.....省略一些无关的 或 重复的代码 Win32.Beep(833, 220);//菜单 初始化完毕, 声音提示 ,都保存在集合里面}

 

 /// <summary>    /// 用于动态加载 菜单到 窗口 的时钟    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void timr_DisplayMenu_Tick(object sender, EventArgs e)    {       if (!IsInitDataOk)      {        this.Text = "绘制菜单...";        lab_Msg.Text = "[Msg]绘制菜单...";        lab_Msg.ForeColor = Color.Red;        Thread.Sleep(300);        JudegVisiable(); //根据 menulist 集合去 隐藏/显示 功能对应的 label      }      else      {         this.Text = "Enjoy Ur Game!!";        lab_Msg.Visible = false;        timr_main.Start();       }      lab_Msg.Text = "[Msg]接收,解析数据...";      lab_Msg.ForeColor = Color.White;    }

 /// <summary>    /// 初始化菜单项,不可用的设置不可见 或 杠线    /// </summary>    private void JudegVisiable()    {      foreach(MenuFnClass mfc in MenuList)      {        if (mfc.myLabel == null) return;        mfc.myLabel.Visible = true;        if(!mfc.isMenuVisiable)        {          if (Login_.labelUnableStyle == "0")          { mfc.myLabel.Font = new Font("宋体", 9, FontStyle.Strikeout); }          else { mfc.myLabel.Visible = false; }        }        }     }

 #region 界面UI特效集合/UI代码    /// <summary>    /// 按下快捷键后的菜单效果以及声音提示,参数1目标控件,参数2是否打开    /// </summary>    private void AddEffect(Label lbl,bool isBeep=true)    {      lbl.Text = lbl.Text.ToString().Replace('关', '开').Replace("OFF", "ON").Replace("False", "True").Replace("F", "T");       lbl.ForeColor = Color.Red;       if (isBeep) Win32.Beep(800, 180);     }    /// <summary>    /// 按下快捷键后的菜单效果以及声音提示,参数1目标控件     /// </summary>    private void ClearEffect(Label lbl, bool isBeep = true)    {      lbl.Text = lbl.Text.ToString().Replace('开', '关').Replace("ON", "OFF").Replace("True", "False").Replace("T", "F");      lbl.ForeColor = Color.Lime;      lbl.BackColor = Color.Transparent;      if (isBeep) Win32.Beep(1000, 100);    }    #endregion

 

 

 

异常处理单元:

 #region 异常统一处理/异常处理代码    /// <summary>    /// 该页面统一 处理 提交错误信息到贴吧    /// </summary>    private void ReportBug(string exceptionMsg)    {      timr_main.Stop();      uhelp.MyMsg("Sorry!An Exception Throwed!");      FRM_BUGREPORT fbg = new FRM_BUGREPORT(exceptionMsg);      fbg.ShowDialog();      this.Hide();    }    #endregion

 

5.助手 功能单元

#region 外挂功能实现模块/核心代码 /// <summary>    /// 一秒子弹数(散弹数)子函数     /// </summary>    private void SuperGun(int _baddress,int[] _offsetslist,string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress,4,_offsetslist);      PMR.WriteByte(address,byte.Parse(_value));    }    /// <summary>    /// 子弹加速/左刀加速    /// </summary>    private void QuickAmo(int _baddress, int[] _offsetslist, string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress, 4, _offsetslist);      PMR.WriteFloat(address,float.Parse(_value)); //这儿也可以写字节型    }   /// <summary>    /// 无限子弹子函数,0x6E9-701-g_AmoNum    /// </summary>    private void MaxAmo(int _baddress, int[] _offsetslist, string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress, 4, _offsetslist);      PMR.WriteByte(address, byte.Parse(_value));    }    //注: 这些参数都是 从数据里里 取出来的, 在 菜单 初始化 那里 进行了 配置复制 给对应的 菜单 对象。    //..........省略一些 无关 或 重复代码

 

 //<summary>     //防闪     //</summary>    private void FangShan(int _baddress, int[] _offsetslist, string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress, 4, _offsetslist);      int tempBoxCount = PMR.ReadInt(address);      if (tempBoxCount == 1)      {        PMR.WriteInt(address, int.Parse(_value));      }    }    //<summary>    //后座    //</summary>    private void HouZuo(int _baddress, int[] _offsetslist, string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress, 4, _offsetslist);      int tempBoxCount = PMR.ReadByte(address);      if (tempBoxCount > 0 && tempBoxCount<=255)      {        PMR.WriteByte(address, byte.Parse(_value));      }    }    //<summary>    //准心    //</summary>    private void ZhunXin(int _baddress, int[] _offsetslist, string _value)    {      int address = PMR.ReadMultiLevelPointer(_baddress, 4, _offsetslist);      int tempBoxCount = PMR.ReadByte(address);      if (tempBoxCount > 0 && tempBoxCount <= 255)      {        PMR.WriteFloat(address, float.Parse(_value));      }    }
}

 

主要的助手 控制时钟:

#region 主功能控制区/核心代码    /// <summary>    /// 主功能时钟,动态调用功能    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void timr_main_Tick(object sender, EventArgs e)    { ‘        foreach (MenuFnClass fn in MenuList)//该线程时钟控制 无限子弹/N+弹/无后座 等等功能        {          if (fn.isUsetimer && fn.isMenuOpen)          {            fn.DoWork();          }        }    }

 

补充一部分,上面忘记写出来了:

全局快捷键 控制 功能 开关 以及效果显示:

 

 #region 全局快捷键/事件代码    KeyboardHook kh;    /// <summary>    /// 键盘事件    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    void kh_OnKeyDownEvent(object sender, KeyEventArgs e)    {
tempKey = e.KeyData; try { foreach(MenuFnClass mfc in MenuList) { if (mfc.myKeys == Keys.None) return; if (e.KeyData == mfc.myKeys && mfc.isMenuVisiable) //isMenuVisiable控制热键是否有效以及菜单小时与否 { if (mfc.isUsetimer)//用时钟控制,则dowork()写在时钟函数里面 { //以下 给菜单 添加开/关效果 以及 改变 菜单 开/关状态 if (!mfc.isMenuOpen) { AddEffect(mfc.myLabel); mfc.isMenuOpen = true; } else { ClearEffect(mfc.myLabel); mfc.isMenuOpen = false; } } else//不用时钟控制,则dowork()执行一次,此处只显示效果 { mfc.DoWork();//运用委托 触发该 菜单内含的 功能。 AddEffect(mfc.myLabel); mfc.isMenuOpen = true; } } } } //------------------------------------- 功能控制 End------------------------------------- catch (Exception ex) { ReportBug(ex.ToString()); } } #endregion

 

尾记:

1.因为C#是托管语言,受限于无法直接读写 目标进程游戏 内存,所以只能通过外部调用API形式 去远程读写内存,这样存在一个 不太好的地方就是,别人可以轻而易举的 Hook 那个Win32 读写远程进程 内存的函数,从而 当你每次调用 那几个api, 别人能够 拦截到 你要修改的 基址 偏移 和 读写值 。已有的现成的盗取基址偏移的工具"外挂无间道" (http://www.52pojie.cn/thread-118235-1-1.html)

2.虽然技术上可以 将C# dll“注入到” 游戏进程,但 这必须 用到一个 vc dll去先 注入到 游戏进程, 从而  让 首先注入到 游戏进程的 vc dll 先去根据clr版本 去系统目录 启动 CLR托管环境,然后 在托管环境里面 去 执行 我们的 C# dll代码,这样 一系列的 操作 存在一定的 未知性 以及 诸多bug 问题需要解决。

故 推荐 各位 写游戏 助手 还是 用VC 比较好。

 

 

由于时间比较长了以及篇幅所限,暂时贴这么些关键代码,可能比较乱,自己看源码吧大家。

QQ : 844125365 有问题联系我。

源代码下载:

 1.C#  读写远进程 内存帮助类:http://www.cnblogs.com/SparkOng/p/4881072.html

 2. 整个解决方案 源代码写的比较栏,有需要的 问我要把,就先不发出来献丑了。主要的 代码已经贴在上面了。