首页
社区
课程
招聘
[原创]XX找茬的研究(非截屏,非对比像素,源码)
发表于: 2010-10-5 22:16 19690

[原创]XX找茬的研究(非截屏,非对比像素,源码)

2010-10-5 22:16
19690

【文章标题】: XX找茬的研究(非截屏,非对比像素,源码)
【文章作者】: Sam.com[CCG]
【下载地址】: 自己搜索下载
【使用工具】: Delphi 2007
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
      对找茬的辅助工具并不感冒,但也接触过,先说下废话,本文文字比较多,重点在讲思路
      由于经常在某论坛混,论坛每天会有找茬活动,就是版主发张像找茬那样的图片,然后圈出来回复图片就可以了,因为图片
  是人手处理,有时也有很难找的时候,所以就会用工具把右半的图片复制到左边去,然后把这个图层改变下透明就能看出来不
  同的地方,顺便推荐个在线处理图片的网页,感觉比较强大 http://www.pixlr.com/editor/?loc=zh-cn
  
      因为每天要在这花些时间,所以想自己做个程序能帮我把图片不同处自动找出来,因为我接触的辅助工具都是像素比较的
  方法,所以开始我也这样做了,原理很简单,因为论坛发布的图片是一张的,包括了左右两部分,所以只要把图片分成两半,然后
  逐个像素比较颜色,颜色不同的话就把这个像素点改成红色,这样效果是不错,简单不过有点慢,但经过几次使用问题就来了,
  因为原图是人手制作的,所以左右两图有时会坐标有点偏差,或者两图间有空白,导致这样简单的对比法几乎所有像素都对不
  上坐标的,结果相当于整张图都标上了红色.
  
      上面的方法行不通,也是找茬辅助的难点所在,找了些资料,好像比较难的都是在确定两图的坐标上,当然应该也有其它
  方法或者优秀的算法来解决这个问题,但是我不会,其实两图的不同处都是比较大的一块区域,对比的要求并不用严格到每一
  个像素,像用透明的方法,坐标偏差比较大都能用肉眼判断出来,那就换个思路,也是简单的方法,不用把不同处标记出来了,
  就直接把右边的图片做为一个图层放在最左边,然后用个定时器把这个图层前置和隐藏,这样一个视觉差就能很明显的看出
  不同处.这个源码在下面提供,里面有个测试图片,直接拖图片进程序窗口就可以了,双击图片选择颜色后可以用像素对比的
  方法来显示.
  
  
  
      然后,回想以前玩XX找茬时经常被人虐,虐人的这个看你点得快有威胁还要把你踢出去,实在是理解不了这种人的心理,
  既然我的这种方法简单有效,能不能运用到XX找茬里去呢?于是动手研究XX找茬,思路是这样,找到游戏的图片源,找个地方
  Hook把图片取出来,按上面的其中一个方法把不同处显示出来,先不考虑效率,也不考虑截屏,只要达到目的
  
      先找找图片是怎么来的,XX找茬有练习模式,比较方便调试,先拦下封包,看看会不会是每次从服务器传过来,如果是的话
  说不定包里还有不同处的坐标之类,但结果很失望,收到的包很少,仔细想想,如果从封包入手也挺麻烦的,还要解密封包什么
  的,初步来看应该也不像是从服务器发过来的,最多可能也就只有坐标而已,也或者封包数据是从XXGame.exe这个进程传过来,
  反正这个方法要处理起来要花比较多时间去处理,先暂时放弃.
  
      图片是找茬游戏重要的保护对象,无论图片是在本地或者服务器传过来,压缩或者加密是必要的,看看游戏目录,有个
  zlib1.dll,这个不用说了,ZIP的模块,有个导出函数uncompress,在这入手看看.启动游戏后附加然后下断,只要一加载图片就
  断下来了,来看看uncompress的参数,共4个参数
  
  004604B5  |.  52            push edx
  004604B6  |.  8B51 10       mov edx, dword ptr [ecx+10]
  004604B9  |.  03C2          add eax, edx
  004604BB  |.  8B5424 08     mov edx, dword ptr [esp+8]
  004604BF  |.  8D4C24 10     lea ecx, dword ptr [esp+10]
  004604C3  |.  50            push eax
  004604C4  |.  51            push ecx
  004604C5  |.  52            push edx
  004604C6  |.  E8 A1730000   call <jmp.&zlib1.uncompress>
  004604CB  |.  83C4 10       add esp, 10
  
  
  0012F044   05D8D6F8    <---输出缓冲
  0012F048   0012F060    <---返回解压后的实际长度
  0012F04C   00F90010    <---输入缓冲
  0012F050   0000C904    <---输入长度
  
      函数执行过后,到05D8D6F8看看,一看内容就知道是个JPG,JPG的文件头很容易看出来.堆栈往下拉就能看到文件名如
  "res\chaBig\xxx\origin.JPG", xxx是个数字,按实际长度把二进制保存为JPG文件,打开看正好就是找茬的图,那么我的猜
  想就没错了,所有图片资源都用ZIP压缩的,那么只要把两个图取出来就大功告成了.
  
      先继续中断看看,当游戏换一次图时,共会中断7,8次,前两次是"res\chaBig\xxx\origin.JPG",后面的都是类似
  "res\chaBig\xxx\cha1.JPG"的,把所有图片都保存下来看看,傻眼了,一直认为找茬每次都是两个图片,一个是原图一个是
  改过的,但XX找茬不是,他是用两张原图,然后5张小图放在其中一个原图的上面,这5个小图就是找茬的地方,想想这种游戏
  要保证最小的传输量又要保证找茬的地方每次不同,这个方法也许是最有效的,那么情况麻烦了,我无法得到修改过的图片,
  只有5块碎图,游戏应该是根据内设的坐标把这5个小图重绘在原图上,或者先处理完再显示,那么如果要用之前的方法来处理
  的话就必须得找到他处理完的地方才行,但是一想到处理的代码可能非常复杂,又或者根本不是我想像的那样,启不是浪费
  我宝贵的时间?
  
      本来想开始这么简单顺利,现在一下就把这个方法推翻了,我可真不想花太多时间在它身上,在放弃前再考虑下有没有
  什么简单的方法来达到目的,换个思路,在uncompress这个地方Hook应该是最合适的了,既然解压后JPG就直接在内存中取得
  到,那么我把5个小图换成其它的图片行吗?比如一个笑脸,那么显示出来后这5个地方就一目了然了,那光是简单的替换,就
  考虑用LPK来做吧,反正我也想试试LPK,代码很简单,只要判断一下文件名,把所有小图都统一换成同一个图,果然有效了.
  
      但是,显示是显示出来了,使用中有问题,最明显的是替换的小图显示有问题,几乎所有小图的右下角都是显示灰色的,
  还有就是所有不同处都显示一样大小的图片,那么有效的点击范围就出问题了,只有点击左上角比较小的范围才能100%正确,
  也许点击范围也是根据小图的XY来确定的,显示问题虽然不美观,但也不影响使用,这样的话替换的图片太大又会画面乱,太小
  又会有时点不正确,真是有点郁闷了.
  
      本人比较追求完美,虽然现在这样能用,但效果实在有些接受不了.再想办法改,首先考虑的是不要改变小图的大小,以
  免影响点击的判断区域,比如动态生成一个一样大小的图片来替换,那既然要做到这份上了,不如我就直接修改小图,在小图
  上做个标记好了,要做到这个效果光是LPK就不行了,因为要引用jpeg这些单元,所以生成的LPK会出错
  
      具体请参考下面的源码ZhaoCha.rar,LPK借用的是Tee_lpk_Delphi_APIHOOK.rar,谢谢Tee8088分享,不过还是没解决
  显示灰色的问题,由于时间关系就不处理了,期待高手指点,对于图像的处理不熟悉,大部分是现找现写的,代码比较粗糙,
  好处是不用区分找茬的版本,美女或者卡通都通用(两者只是图片和大小不同而已),2个Dll复制到游戏目录下即可,下面注
  释下核心代码.
  
  LPK部分:
  procedure uncompressCallback(out OutBuf: Pointer; out OutBytes: Integer; const InBuf: Pointer; InBytes: Integer);cdecl;
  var
    TmpStr: array [0..1023] of char;
    DllHandle: THandle;
  begin
    //引用zlib1的uncompress直接调用它,先解压再处理
    uncompress(OutBuf, OutBytes, InBuf, InBytes);
    //取文件名,版本更新后有可能要调整
    asm
      pushad
      push dword ptr [ebp+$48]
      lea eax, TmpStr
      push eax
      call lstrcpy
    end;
  
    //由于LPK中不能用VCL,所以要另外写个Dll,在这里才加载
    if not assigned(@ChangeJpg) then
    begin
      DllHandle := LoadLibrary(PChar('CJpg.dll'));
      if DllHandle = 0 then
      begin
        asm
          popad
        end;
        Exit;
      end else
        @ChangeJpg:= GetProcAddress(DllHandle, 'ChangeJpg');
    end;
  
    //判断文件名只处理找茬所需的图片,且只处理小图片
    if (Pos('res\cha\', TmpStr) > 0) or ((Pos('res\chaBig\', TmpStr) > 0)) then
    begin
      if Pos('origin', TmpStr) > 0 then
      else
      begin
        ChangeJpg(OutBuf, OutBytes);
      end;
    end;
  
    asm
      popad
    end;
  
  end;
  
  
  处理图片部分:
  procedure ChangeJpg(out OutBuf: Pointer; out OutBytes: Integer);cdecl;
  var
    Jpg: TJPEGImage;
    Bmp: TBitmap;
    TmpStream: TMemoryStream;
  begin
    Jpg:= TJPEGImage.Create;
    Bmp := TBitmap.Create;
    //为什么要多用个TmpStream?因为Jpg我找不到Size变量,就无法写回文件长度
    TmpStream:= TMemoryStream.Create;
    //从输出缓冲里读出Jpg
    TmpStream.Write(OutBuf, DWORD(OutBytes));
    TmpStream.Position:= 0;
  
    Jpg.LoadFromStream(TmpStream);
    //因为Jpg的像素是只读的,只能转成Bmp来处理,这是网上找到的方法
    Bmp.Assign(jpg);
    //在图片四边画上红线和绿线,一目了然
    Bmp.Canvas.Pen.Width:= 3;
    Bmp.Canvas.Pen.Color:= clRed;
    Bmp.Canvas.Polyline([Point(0, 0), Point(Bmp.Width, 0), Point(Bmp.Width, Bmp.Height),
                         Point(0, Bmp.Height), Point(0, 0)]);
  
    Bmp.Canvas.Pen.Width:= 3;
    Bmp.Canvas.Pen.Color:= clLime;
    Bmp.Canvas.Polyline([Point(0+3, 0+3), Point(Bmp.Width-3, 0+3), Point(Bmp.Width-3, Bmp.Height-3),
                         Point(0+3, Bmp.Height-3), Point(0+3, 0+3)]); 
  
  
    //处理后的图片转成Jpg
    Jpg.Assign(Bmp);
    TmpStream.Position:= 0;
    Jpg.SaveToStream(TmpStream);
    TmpStream.Position:= 0;
    //处理后的图片放回原处
    TmpStream.Read(OutBuf, TmpStream.Size);
    //改成处理后的长度
    DWORD(OutBytes):= TmpStream.Size;
  
    Jpg.Free;
    Bmp.Free;
    TmpStream.Free;
  end;
  
  最后来个未点击的效果图:
  

  源码:
   PicCmp.rar

   ZhaoCha.rar
  
--------------------------------------------------------------------------------
【经验总结】
  LPK不能使用VCL
  换个角度,看似复杂的问题可以简单化
  
--------------------------------------------------------------------------------
【版权声明】: 此文及源码仅限学习研究之用,请勿用于商业用途!

                                                       2010年10月05日 21:17:32


[注意]APP应用上架合规检测服务,协助应用顺利上架!

上传的附件:
收藏
免费 8
支持
分享
最新回复 (33)
雪    币: 225
活跃值: (1251)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
恩,不错.学习了.
2010-10-6 00:26
0
雪    币: 80
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
强贴.......
2010-10-6 00:37
0
雪    币: 2397
活跃值: (2310)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
4
确实是好帖。
2010-10-6 13:27
0
雪    币: 256
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好东西收藏了!
2010-10-6 18:39
0
雪    币: 1829
活跃值: (5410)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
好东西收藏了!
2010-10-7 04:58
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
下载了就支持你!
2010-10-7 22:22
0
雪    币: 488
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
好久不玩Delphi了
2010-10-8 15:11
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
有VC的就安逸了
2010-10-8 16:17
0
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
10
我还在用delphi6,不知道楼主写的jpg和bmp相互转化的在6里面是否也能实现。
2010-10-8 23:10
0
雪    币: 168
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
哇.楼主你- -强悍
2010-10-9 10:56
0
雪    币: 57
活跃值: (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
12
还不错………………
2010-10-9 12:28
0
雪    币: 558
活跃值: (43)
能力值: ( LV12,RANK:220 )
在线值:
发帖
回帖
粉丝
13
Good idea!~~
2010-10-9 14:20
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
学习了逆向思想.
2010-10-9 16:41
0
雪    币: 323
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
真是不错,虽然我没有玩过
2010-10-10 08:50
0
雪    币: 2203
活跃值: (1021)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
XX找茬的挂又要出来了~~
2010-10-10 13:42
0
雪    币: 7325
活跃值: (3803)
能力值: (RANK:1130 )
在线值:
发帖
回帖
粉丝
17
没bin啊。。。
只有src,没编译器。
2010-10-10 15:00
0
雪    币: 1058
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我以前是用像素的
楼主这个方法很好
2010-10-11 14:50
0
雪    币: 177
活跃值: (278)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
怎么又来一个找茬的?前几天我不是发了一个内存的方法么,他的框框的一个角的坐标和框的宽和高都有啊
2010-10-12 14:06
0
雪    币: 65
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
LS发在哪儿的,看雪怎么找不到
2010-10-12 22:11
0
雪    币: 168
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
0 0这怎么编译啊
2010-10-18 22:17
0
雪    币: 177
活跃值: (278)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
我回复在一个讲找茬的帖子里了,具体哪我忘了
2010-10-19 18:06
0
雪    币: 124
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
学习了,谢谢楼主分享经验。
2010-10-20 12:33
0
雪    币: 2538
活跃值: (2208)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
24
真的好不错啊  学习下
2010-10-20 20:29
0
雪    币: 458
活跃值: (41)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
呵呵,求bin版本。
2010-11-7 17:12
0
游客
登录 | 注册 方可回帖
返回
//