最近接到个项目,头大了很一阵,今天终于有时间写写自己喜欢的东西了。前几日和同学玩大家来找茬,老是输……于是终于决定发挥程序员的优势,编写一个大家来找茬的外挂,或者说作弊器更贴切点。
首先我们理清思路,我们如何才能比较出两张图片的区别之处呢?首先我们知道图片是有像素组成的(就算是矢量图片传入显示器也会变成像素的吧)。大方向上我们就靠每个像素的分析来解决这个问题吧。
既然是针对QQ游戏的作弊器,那么我们就要分析QQ游戏中“大家来找茬”的界面了。直接在QQ游戏上动手脚是不行的,所以我们需要把“大家来找茬”的两张图片截获下来。这有两种方法,捕获网络传输和对QQ游戏截图。我选择了后者,因为后者比较不容易被QQ游戏发现,而且上手也简单。
那么我们就来看看如何截图。从《Programming Windows》中我们看到有一个叫BitBlt的函数。可以对指定设备的像素进行捕获。没错就是这个API了。但是一用到.net没提供的函数就是一件头大的事,这次也不例外。BitBlt函数要求有被截图的窗体的设备驱动器句柄,这就涉及到另外两个API函数,GetDC(hwnd),ReleaseDC()的调用了。GetDC()可以获得指定窗体句柄的设备驱动器句柄,但是要求有被获取窗体的窗体句柄,然后我们又要用FindWindow()函数,=_=||
{
[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
private static extern bool BitBlt(
IntPtr hdcDest, // 目标 DC的句柄
int nXDest,
int nYDest,
int nWidth,
int nHeight,
IntPtr hdcSrc, // 源DC的句柄
int nXSrc,
int nYSrc,
System.Int32 dwRop // 光栅的处理数值
);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static IntPtr FindWindow(string lpClassName,string lpWindowName);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static IntPtr GetDC( IntPtr hWnd);
[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static int ReleaseDC( IntPtr hWnd,IntPtr hDC);
}
有了这些API就能开始截图了....
{
//获得当前窗体的大小
Rectangle rect = this.ClientRectangle;
//创建一个以当前屏幕为模板的图象
Graphics g1 = this.CreateGraphics();
//创建以此为大小的标准位图
Image MyImage = new Bitmap(rect.Width, rect.Height, g1);
Graphics g2 = Graphics.FromImage(MyImage);
//得到屏幕的DC
IntPtr dc1 = g1.GetHdc();
//得到Bitmap的DC
IntPtr dc2 = g2.GetHdc();
//调用此API函数,实现屏幕捕获
BitBlt(dc2, 0, 0, rect.Width, rect.Height, dc1, 0, 0, 13369376);
//释放掉屏幕的DC
g1.ReleaseHdc(dc1);
//释放掉Bitmap的DC
g2.ReleaseHdc(dc2);
//以JPG文件格式来保存
MyImage.Save("Capture.jpg", ImageFormat.Jpeg);
MessageBox.Show("当前屏幕已经保存为当前目录的capture.jpg文件!");
g1.DrawImage(MyImage, this.ClientRectangle);//在窗体上画出被捕获的图片
}
将以上代码复制到你的方法中就能进行截图了,只不过这里截的图是自己窗体的,所以就没有用到GetDC,FindWindow两个API。
接下来是分析图片了。QQ游戏中左边那张图片位置是在X=10左右随机的,右边那张图在X=407的位置(在分辨率为1440*900条件下测试)。估计是反作弊用的。左边的位置我们可以让用户自己去确定。比如设个快捷键,让用户移到左边那张图片后按下快捷键。
分析图片用如下代码:
p1,p2是两个坐标,用于标记两张图片的起始位置。
bmp2是一个Bitmap类型。就是当初截图截下来后用基类Image来指向的。
出于效率考虑,这里之从起点坐标开始横向比较190个像素,纵向比较300个像素。此处请自己修改,否则会抛出IndexOutofRange异常的。
{
Point p1,p2;
Color c1 = Color.Blue;
Color c2 = Color.Red;
int i = Convert.ToInt32(p1.x), j;
Graphics g = this.CreateGraphics();
int i2 = Convert.ToInt32(p2.x);
int iS = i + 190, js;
for (; i < iS; i++)
{
for (j = Convert.ToInt32(p1.y), js = j + 300; j < js; j++)
{
c1 = bmp2.GetPixel(i, j);
c2 = bmp2.GetPixel(i2, j);
if (c1 != c2)
bmp2.SetPixel(i, j, Color.FromArgb(c1.ToArgb() - c2.ToArgb()));
bmp2.SetPixel(i2, j, Color.Blue);
g.DrawImage(bmp2, 0, 0);
}
i2++;
}
g.DrawImage(bmp2, 0, 0);
}
循环中,如果发现两者颜色不同就就像不同处用红色代替。
程序就是这么简单了,本来是想写的好点的,但是这个程序分析图片的速度真是……完全没有想法,竟然要8秒!整个游戏都只有14秒……看来还是得用C++写比较好啊....=_=||
代码贴出来仅供娱乐。欢迎大家提出意见。