Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4564962
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: 网络与安全

2016-10-09 14:13:20

原文地址:
作者:Jonathan LEI
链接:
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇文章中我们已经顺利完成了bg和fullbg两张图片的还原,而在文章的最后我提出了3个问题。在这篇文章里,我们将一一解决这三个问题,并计算出正确的横向移动距离。

首先我们要决定计算距离的方法。这个并不太难,大致想法是从左到右对比realBg和realFullbg两张图片的每一列,如果发现不同,则立刻判断出这就是缺块处的x坐标。

然而,上一次我们已经提到,在还原后的realBg中,除了真正的缺块位置,还会有一个浅浅的印干扰计算。因此我们不能直接要求两张图片的列完全相同,而应该允许一定程度的差异。为此,我首先编写了一个函数来判断两个像素点是否相似

private bool ColorSimilar(Color col1, Color col2) { int max = 30; int diffR = Math.Abs(col1.R - col2.R); int diffG = Math.Abs(col1.G - col2.G); int diffB = Math.Abs(col1.B - col2.B); return diffR < max && diffG < max && diffB < max; } 

这里的max是容忍值,如果最后发现经常把浅印判断为缺块,则说明容忍值太小,就需要将它设置地更大。目前先设置为30看看如何。

然后,利用这个函数,再编写一个函数判断两张图片的同一列是否相似

private bool ColumnSimilar(Bitmap pic1, Bitmap pic2, int columnIndex) { for (int y = 0; y < pic1.Height; y++) if (!ColorSimilar(pic1.GetPixel(columnIndex, y), pic2.GetPixel(columnIndex, y))) return false; return true; } 

有了这个函数,我们就可以计算目标位置的x值了:

int destinationIndex = -1; for (int x = 0; x<columns* sliceWidth; x++) if (!ColumnSimilar(realBg, realFullbg, x)) { destinationIndex = x; break; } if (destinationIndex == -1) throw new Exception("Cannot find"); 

将结果用MessageBox.Show()输出,看看如何:

算出来结果是105,如果我们把这张图片放到MSPaint中手动计算距离:

可以看到自动计算的结果和我们手动计算的是一样的。为了方便检验结果,我们把realBg的这一列设为黑色:

for (int y = 0; y < rows * sliceHeight; y++) realBg.SetPixel(destinationIndex, y, Color.Black); 

重复实验,发现有这样的情况:

果然容忍值30太过小了,将其改为60并再次重复试验,该问题消失。

现在我们计算出的x值是整个缺块最最左边的值,包括突出的部分。那我们到底需要哪个?是突出的部分左侧x值,还是竖直边缘的x值?

要解决这个问题,我们要看看一直被我们忽略的slice图片。这是一个png格式的图片,如果我们发现slice的竖直边缘总是固定在一个位置,那么我们需要的就是竖直边缘的x值。相反,如果slice的边缘是整个缺块最最左边的部分,那我们也就相应地选取最左边的x值。

下载几个slice图片(和下载bg与fullbg同理),在MSpaint中打开:

如此一来,答案已经相当明显了。slice的左侧竖直边缘并不是固定的,真正固定的是整个slice的最最左侧的位置。因此我们现在用的计算destinationIndex的方法是正确的,不需要进行修改。(读者可以思考,如果发现竖直边缘固定,我们要怎么修改代码计算正确的x值?)

三个问题剩下最后一个。这个计算出来的距离并不是我们最终传送的距离,原因是我们并不是从0开始滑动。这个问题的答案也在slice中:

框选slice左侧的部分,发现宽度为5px。意思是我们还没开始滑动的时候,slice的实体部分已经有5px的偏移了。因此在最后计算移动距离的时候,我们要减去这5px:

int startIndex = 5; int moveDistance = destinationIndex - startIndex; 

伴随着三个问题的解决,我们得到了moveDistance变量,这个变量里储存了将拼图完美拼合的横向移动距离。这样一来,整个破解过程就只剩最后一步了:构造4号包完成验证。

这个步骤看上去容易,实际上这是GeeTest把关最为严格的一环。在这里,GeeTest对传送的参数进行多种验证,以至于有时真人去拉动滑块,也显示失败:

“怪物吃了拼图”所对应的错误代码是forbidden,表示所传送的参数不被服务器认可。

人手拉也无法达到100%的通过率,这对我们完成最后一步造成了极大的困难。我们要如何完成破解?当然实际上我已经完成了破解,大家可以放心学习:

这看似最轻松的一步其实困难重重,接下来我们将逐步剖析4号包,了解其防破解措施,并最终实现代码模拟。

最近比较忙,应该是无法再一天一更了,如果有兴趣的读者可以先自行尝试模拟4号包。如果你想第一时间收到更新,就要关注我的专栏啦!

喜欢我的文章的话记得关注和点赞!谢谢你们!

阅读(3648) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~