最近经朋友介绍开始玩 密传 网络游戏
升级升级,突然觉得太费键盘,于是自己用C#写了一个程序,想代替我的操作,自己去打怪物,自己升级
用这个东西升了好多级了,现在把源码贴出来,和大家共享,欢迎大家批评指正,感激不尽。
程序大概分成两个部分,一个部分是类库,一个是应用程序
大概的思路就是找到游戏进程的主窗口句柄,然后发送游戏按键消息(模拟按键)。
XDF.GamePlugInCommon 类库项目//API.cs 文件,定义一些常用API函数及常量using System;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;namespace XDF.GamePlugInCommon
{
/// <summary>
/// API 的摘要说明。
/// </summary>
public sealed class API
{
public static int WM_KEYDOWN = 0x0100;
public static int WM_KEYUP = 0x0101;
public static int WM_SYSKEYDOWN = 0x0104;
public static int WM_SYSKEYUP = 0x0105; public static int WM_MOUSEMOVE = 0x0200;
public static int WM_LBUTTONDOWN = 0x0201;
public static int WM_LBUTTONUP = 0x0202;
public static int WM_LBUTTONDBLCLK = 0x0203;
public static int WM_RBUTTONDOWN = 0x0204;
public static int WM_RBUTTONUP = 0x0205;
public static int WM_RBUTTONDBLCLK = 0x0206;
public static int WM_USER = 0x0400; public static int MK_LBUTTON = 0x0001;
public static int MK_RBUTTON = 0x0002;
public static int MK_SHIFT = 0x0004;
public static int MK_CONTROL = 0x0008;
public static int MK_MBUTTON = 0x0010; public static int MK_XBUTTON1 = 0x0020;
public static int MK_XBUTTON2 = 0x0040; [DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd,int Msg,int wParam,int lParam); //此处主要用来让窗口置于最前(SetWindowPos(this.Handle,-1,0,0,0,0,0x4000|0x0001|0x0002);)
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd,
int hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
int uFlags
); /// <summary>
/// 窗口置前
/// </summary>
/// <param name="hWnd"></param>
public static void SetWindowPos(IntPtr hWnd)
{
SetWindowPos(hWnd,-1,0,0,0,0,0x4000|0x0001|0x0002);
}
/// <summary>
///
/// </summary>
/// <param name="processName"></param>
/// <returns></returns>
public static Process GetGameProcess(string processName)
{
Process pro = null;
Process[] pros = Process.GetProcessesByName(processName);
if(pros.Length > 0)
{
pro = pros[0];
}
return pro;
}
}
}
升级升级,突然觉得太费键盘,于是自己用C#写了一个程序,想代替我的操作,自己去打怪物,自己升级
用这个东西升了好多级了,现在把源码贴出来,和大家共享,欢迎大家批评指正,感激不尽。
程序大概分成两个部分,一个部分是类库,一个是应用程序
大概的思路就是找到游戏进程的主窗口句柄,然后发送游戏按键消息(模拟按键)。
XDF.GamePlugInCommon 类库项目//API.cs 文件,定义一些常用API函数及常量using System;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;namespace XDF.GamePlugInCommon
{
/// <summary>
/// API 的摘要说明。
/// </summary>
public sealed class API
{
public static int WM_KEYDOWN = 0x0100;
public static int WM_KEYUP = 0x0101;
public static int WM_SYSKEYDOWN = 0x0104;
public static int WM_SYSKEYUP = 0x0105; public static int WM_MOUSEMOVE = 0x0200;
public static int WM_LBUTTONDOWN = 0x0201;
public static int WM_LBUTTONUP = 0x0202;
public static int WM_LBUTTONDBLCLK = 0x0203;
public static int WM_RBUTTONDOWN = 0x0204;
public static int WM_RBUTTONUP = 0x0205;
public static int WM_RBUTTONDBLCLK = 0x0206;
public static int WM_USER = 0x0400; public static int MK_LBUTTON = 0x0001;
public static int MK_RBUTTON = 0x0002;
public static int MK_SHIFT = 0x0004;
public static int MK_CONTROL = 0x0008;
public static int MK_MBUTTON = 0x0010; public static int MK_XBUTTON1 = 0x0020;
public static int MK_XBUTTON2 = 0x0040; [DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd,int Msg,int wParam,int lParam); //此处主要用来让窗口置于最前(SetWindowPos(this.Handle,-1,0,0,0,0,0x4000|0x0001|0x0002);)
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd,
int hWndInsertAfter,
int X,
int Y,
int cx,
int cy,
int uFlags
); /// <summary>
/// 窗口置前
/// </summary>
/// <param name="hWnd"></param>
public static void SetWindowPos(IntPtr hWnd)
{
SetWindowPos(hWnd,-1,0,0,0,0,0x4000|0x0001|0x0002);
}
/// <summary>
///
/// </summary>
/// <param name="processName"></param>
/// <returns></returns>
public static Process GetGameProcess(string processName)
{
Process pro = null;
Process[] pros = Process.GetProcessesByName(processName);
if(pros.Length > 0)
{
pro = pros[0];
}
return pro;
}
}
}
XDF.TantraPlugIn
//ControlItem.cs
using System;
using System.IO;
using System.Xml.Serialization;namespace XDF.TantraPlugIn
{
/// <summary>
/// ControlItem 的摘要说明。
/// </summary>
[Serializable]
public sealed class ControlItem
{
private string m_Name = "";
public string Name
{
get
{
return this.m_Name;
}
set
{
this.m_Name = value;
}
}
private char m_KeyChar = 'a';
public char KeyChar
{
get
{
return this.m_KeyChar;
}
set
{
this.m_KeyChar = value;
}
}
private int m_DelayTime = 100;
public int DelayTime
{
get
{
return this.m_DelayTime;
}
set
{
this.m_DelayTime = value;
}
}
public ControlItem()
{
}
}
[Serializable]
public sealed class ControlItemCollection : System.Collections.CollectionBase
{
public ControlItem this[int index]
{
get
{
return (ControlItem)List[index];
}
set
{
List[index] = value;
}
}
public ControlItemCollection()
{
}
public int Add(ControlItem item)
{
return List.Add(item);
}
public void Remove(ControlItem item)
{
List.Remove(item);
}
}
}
using System;
using System.IO;
using System.Xml.Serialization;namespace XDF.TantraPlugIn
{
/// <summary>
/// TantraConfig 的摘要说明。
/// </summary>
[Serializable]
public class TantraConfig
{
private ControlItemCollection m_KillControls = new ControlItemCollection();
public ControlItemCollection KillControls
{
get
{
return this.m_KillControls;
}
set
{
this.m_KillControls = value;
}
}
private ControlItemCollection m_BloodControls = new ControlItemCollection();
public ControlItemCollection BloodControls
{
get
{
return this.m_BloodControls;
}
set
{
this.m_BloodControls = value;
}
} private int m_BloodRate = 25; public int BloodRate
{
get
{
return this.m_BloodRate;
}
set
{
this.m_BloodRate = value;
}
} private string m_ProcessName = "HTLauncher"; public string ProcessName
{
get
{
return this.m_ProcessName;
}
set
{
this.m_ProcessName = value;
}
} public TantraConfig()
{
} public bool Save(string file)
{
bool result = false;
try
{
FileStream fs = new FileStream(file,FileMode.Create,FileAccess.Write);
XmlSerializer xsl = new XmlSerializer(this.GetType());
xsl.Serialize(fs,this);
fs.Close();
result = true;
}
catch
{
result = false;
}
return result;
}
public static TantraConfig LoadFromFile(string file)
{
TantraConfig config = null;
try
{
FileStream fs = new FileStream(file,FileMode.Open,FileAccess.Read);
XmlSerializer xsl = new XmlSerializer(typeof(TantraConfig));
config = (TantraConfig)xsl.Deserialize(fs);
fs.Close();
}
catch
{
}
return config;
}
}
}
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;using XDF.GamePlugInCommon;namespace XDF.TantraPlugIn
{
/// <summary>
/// Form1 的摘要说明。
/// </summary>
public class Frmmain : System.Windows.Forms.Form
{
private System.Windows.Forms.Button btnSetup;
private System.Windows.Forms.Timer timerMain;
private System.Windows.Forms.Button btnStart;
private System.ComponentModel.IContainer components; public Frmmain()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();
this.Closing +=new CancelEventHandler(Frmmain_Closing);
} /// <summary>
/// 清理所有正在使用的资源。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
} #region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Frmmain));
this.btnStart = new System.Windows.Forms.Button();
this.btnSetup = new System.Windows.Forms.Button();
this.timerMain = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// btnStart
//
this.btnStart.Location = new System.Drawing.Point(8, 16);
this.btnStart.Name = "btnStart";
this.btnStart.Size = new System.Drawing.Size(65, 22);
this.btnStart.TabIndex = 0;
this.btnStart.Text = "开始(&S)";
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
//
// btnSetup
//
this.btnSetup.Location = new System.Drawing.Point(152, 16);
this.btnSetup.Name = "btnSetup";
this.btnSetup.Size = new System.Drawing.Size(65, 22);
this.btnSetup.TabIndex = 1;
this.btnSetup.Text = "设置(&C)";
this.btnSetup.Click += new System.EventHandler(this.btnSetup_Click);
//
// Frmmain
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(226, 55);
this.Controls.Add(this.btnSetup);
this.Controls.Add(this.btnStart);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Frmmain";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Tantra PlugIn beta1";
this.ResumeLayout(false); }
#endregion /// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Frmmain());
} private TantraConfig m_TantraConfig = null;
private Thread m_Thread = null;
private bool m_Stop = true;
private IntPtr m_GameMainWindowHandle = IntPtr.Zero; private void btnSetup_Click(object sender, System.EventArgs e)
{
TantraConfig config = new TantraConfig(); ControlItemCollection items = config.KillControls; ControlItem item_e = new ControlItem();
item_e.DelayTime = 50;
item_e.KeyChar = 'E';
item_e.Name = "选择最近的攻击目标";
items.Add(item_e);
ControlItem item_r = new ControlItem();
item_r.DelayTime = 6000;
item_r.KeyChar = 'R';
item_r.Name = "攻击选定的目标";
items.Add(item_r); ControlItem item_f = new ControlItem();
item_f.DelayTime = 500;
item_f.KeyChar = 'F';
item_f.Name = "捡起打完怪物掉下的物品";
items.Add(item_f); ControlItem item_f2 = new ControlItem();
item_f2.DelayTime = 500;
item_f2.KeyChar = 'F';
item_f2.Name = "捡起打完怪物掉下的金币";
items.Add(item_f2); ControlItem item_blood = new ControlItem();
item_blood.DelayTime = 1000;
item_blood.KeyChar = '1';
item_blood.Name = "自动增加体能秘技";
config.BloodControls.Add(item_blood); config.Save("c:\\tantra.xml"); } private void btnStart_Click(object sender, System.EventArgs e)
{
if(this.m_Stop)
{
this.StartControl();
}
else
{
this.StopControl();
}
this.btnStart.Text = (this.m_Stop)?"开始(&S)":"停止(&S)";
} private void StartControl()
{
string file = Environment.CurrentDirectory + "\\tantra.xml";
this.m_TantraConfig = TantraConfig.LoadFromFile(file);
if(this.m_TantraConfig == null)
{
MessageBox.Show("配置文件未找到,无法启动!");
return;
} //HTLauncher
//string proname = "TantraPlugIn";
System.Diagnostics.Process pro = API.GetGameProcess(this.m_TantraConfig.ProcessName);
if(pro == null)
{
MessageBox.Show("游戏进程 "+this.m_TantraConfig.ProcessName+" 未找到,无法启动!");
return;
}
this.m_GameMainWindowHandle = pro.MainWindowHandle;
this.Text = "Game name:" + pro.ProcessName;
this.m_Stop = false;
this.m_Thread = new Thread(
new ThreadStart(TantraControl));
this.m_Thread.Start();
} private void StopControl()
{
if(this.m_Thread != null)
{
this.m_Stop = true;
this.m_Thread.Abort();
}
} private void TantraControl()
{
int count = 0;
while(!this.m_Stop)
{
for(int i=0;i<this.m_TantraConfig.KillControls.Count;i++)
{
API.SendMessage(this.m_GameMainWindowHandle,API.WM_KEYDOWN,
Convert.ToInt32(this.m_TantraConfig.KillControls[i].KeyChar),0);
Thread.Sleep(this.m_TantraConfig.KillControls[i].DelayTime);
}
count ++;
if(count >= this.m_TantraConfig.BloodRate)
{
count = 0;
for(int i=0;i<this.m_TantraConfig.BloodControls.Count;i++)
{
API.SendMessage(this.m_GameMainWindowHandle,API.WM_KEYDOWN,
Convert.ToInt32(this.m_TantraConfig.BloodControls[i].KeyChar),0);
Thread.Sleep(this.m_TantraConfig.BloodControls[i].DelayTime);
}
}
}
}
protected override void WndProc(ref Message m)
{
base.WndProc (ref m);
if(m.Msg == API.WM_KEYDOWN)
{
this.Text = m.WParam.ToInt32().ToString();
if(this.Text == "1")
{
MessageBox.Show("blood");
}
}
} private void Frmmain_Closing(object sender, CancelEventArgs e)
{
try
{
this.StopControl();
}
catch
{
}
} }
}以上是全部代码
设置功能未完善,可以通过手动修改XML配置文件实现其他类似游戏的外挂
附带典型(12级)外挂配置,配置文件随着各人级别不同和技能不同自己做修改。
<TantraConfig xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<KillControls>
<ControlItem>
<Name>选择最近的攻击目标</Name>
<KeyChar>69</KeyChar>
<DelayTime>50</DelayTime>
</ControlItem>
<ControlItem>
<Name>攻击选定的目标</Name>
<KeyChar>82</KeyChar>
<DelayTime>5000</DelayTime>
</ControlItem>
<ControlItem>
<Name>捡起打完怪物掉下的物品</Name>
<KeyChar>70</KeyChar>
<DelayTime>500</DelayTime>
</ControlItem>
<ControlItem>
<Name>捡起打完怪物掉下的金币</Name>
<KeyChar>70</KeyChar>
<DelayTime>500</DelayTime>
</ControlItem>
</KillControls>
<BloodControls>
<ControlItem>
<Name>自动增加体能秘技</Name>
<KeyChar>49</KeyChar>
<DelayTime>1000</DelayTime>
</ControlItem>
</BloodControls>
<BloodRate>20</BloodRate>
<ProcessName>HTLauncher</ProcessName>
</TantraConfig>严重推荐兄弟们累的时候,玩玩这个游戏,号称永久免费的哦
我用bcb写的键盘模拟工具 hp和地图坐标可以从内存中读取
通过hook call的方法可以作的更多 比如地上掉落物品的提示,110出现的提示
最近工作忙没时间弄它了
我已经解开几个消息的格式了
没想到几天不见xiongchen(二氧化鬼) ( ) 升成猩猩了
没想到几天不见xiongchen(二氧化鬼) ( ) 升成猩猩了
另外你这个程序是不是只能打开一次运行到底?那个线程abort以后还能启动么?
加血的功能需要将快捷键加到快捷栏里面
比如我有两种加血,一种自动加血,持续3分钟,一种每次都加血
第一个快捷键1,第二个快捷键2
致命一击我定义为3,那个XML文件自己根据情况手动修改即可如果真想判断自己的血在什么状况,我的想法是截取血那部分的图片(局部截图,速度很快的)
然后用象素计算的方式能算出血损失了多少,还剩下多少(百分比)
但是我要提醒的是,网络状况不好的情况下,往往你的血是满的,突然一下子就挂了
没有办法
另外也可以用RAWSOCKET 截获数据包,分析自己的血的状况,当然处理的方法比较麻烦
需要摸索出数据包的格式,你有兴趣可以自己研究一下哦注意我的标题(朋友定义为外挂,按键精灵)
是否外挂不重要,重要的是写程序的那种乐趣,那种可以动作的快感,然否?
注册热键用registerhotkey unregisterhotkey就可以,好像没问题
这位仁兄,你看看这个帖子,我就是用这两个API,有时候就是没法激活,不知道什么问题
现在想想可能是因为我把窗体隐藏了,可是为啥有时候又行呢?http://community.csdn.net/Expert/topic/3852/3852784.xml?temp=.989895
呵呵,我也在做这个,把游戏隐藏起来,然后对他发消息,现在遇到一个问题,隐藏了以后按一些键,游戏里会有反应。。现在准备用钩子试试看。各位有没有好方法?
前段时间玩了一下钩子,发现加了钩子比较耗CPU时间,尤其是全局钩子
隐藏游戏的窗口应该还是能够接到消息的,感觉可以用热键试试看,用钩子感觉耗资源
向太傅。终于找到你了。我是请操啊。啥意思啊?我好久不来这里了,老友我忘记了,真是汗~!==============================================================
看看寻秦记就知道了
至于keybd_event很简单的。比如这就是天霸封神斩的发招方法:
[DllImport("user32.dll", EntryPoint="keybd_event")]
public static extern void keybd_event (
byte bVk,
byte bScan,
int dwFlags,
int dwExtraInfo
);
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_KEYDOWN = 0x00; private const int KEY_A = 0x41;
private const int KEY_S = 0x53;
private const int KEY_D = 0x44;
private const int KEY_W = 0x57; private const int KEY_J = 0x4A;
private const int KEY_K = 0x4B;
private const int KEY_L = 0x4C; private const int KEY_U = 0x55;
private const int KEY_I = 0x49;
private const int KEY_O = 0x4F; #region SimulateKey
private void OneKey(byte VirtualKey, int _interval, int KeyUpDown)
{
keybd_event(VirtualKey, 0, KeyUpDown, 0);
Thread.Sleep(_interval);
} private void TowKey(byte VirtualKey1, byte VirtualKey2, int _interval, int KeyUpDown)
{
keybd_event(VirtualKey1, 0, KeyUpDown, 0);
keybd_event(VirtualKey2, 0, KeyUpDown, 0);
Thread.Sleep(_interval);
}
#endregion SimulateKey #region Actions
private void ToRight_Action01(int Interval)
{
int _interval = Interval; OneKey(KEY_D, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_D, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_A, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_A, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_D, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_D, _interval, KEYEVENTF_KEYUP); OneKey(KEY_A, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_A, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_A, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_A, _interval, KEYEVENTF_KEYUP);
TowKey(KEY_K, KEY_U,_interval, KEYEVENTF_KEYDOWN);
TowKey(KEY_K, KEY_U,_interval, KEYEVENTF_KEYUP);
} private void ToLeft_Action01(int Interval)
{
int _interval = Interval; OneKey(KEY_A, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_A, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_D, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_D, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_A, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_A, _interval, KEYEVENTF_KEYUP); OneKey(KEY_D, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_D, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_S, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_D, _interval, KEYEVENTF_KEYDOWN);
OneKey(KEY_S, _interval, KEYEVENTF_KEYUP);
OneKey(KEY_D, _interval, KEYEVENTF_KEYUP);
TowKey(KEY_K, KEY_U,_interval, KEYEVENTF_KEYDOWN);
TowKey(KEY_K, KEY_U,_interval, KEYEVENTF_KEYUP);
}
#endregion Actions