C++,python,热爱算法和机器学习
全部博文(1214)
分类: 网络与安全
2016-10-08 18:35:44
上一篇文章里我们已经成功地模拟了前三个包并下载了两张至关重要的图片,今天我们将完成这两张图片的还原。如果你还没成功下载bg和fullbg两张图片,请先阅读此文:
接下来我们正式开始图片的还原,首先回忆我们之前找到的GeeTest自己计算图片偏移坐标的相关JavaScript代码。这行代码用于产生偏移量:
k = "-" + (n[i] % 26 * 12 + 1) + "px " + (n[i] > 25 ? -f.config.height / 2 : 0) + "px"
至于这里面用到的n数组,则由以下函数a产生:
function (){for(var a,b="6_11_7_10_4_12_3_1_0_5_2_9_8".split("_"),c=[],d=0,e=52;e>d;d++)a=2*parseInt(b[parseInt(d%26/2)])+d%2,parseInt(d/2)%2||(a+=d%2?-1:1),a+=26>d?26:0,c.push(a);return c}
我们将其改写,赋予它一个函数名a并把里面的双引号替换为单引号:
function a(){for(var a,b='6_11_7_10_4_12_3_1_0_5_2_9_8'.split('_'),c=[],d=0,e=52;e>d;d++)a=2*parseInt(b[parseInt(d%26/2)])+d%2,parseInt(d/2)%2||(a+=d%2?-1:1),a+=26>d?26:0,c.push(a);return c;}
把这行代码添加到Scripts.cs中用来储存JS代码的JSCODE常量中,并且添加如下C#函数供使用:
public int[] a() { Microsoft.JScript.ArrayObject jsArray = jsObject.a(); int[] a = new int[System.Convert.ToInt32(jsArray.length)]; for (int i = 0; i < a.Length; i++) a[i] = System.Convert.ToInt32(jsArray[i]); return a; }
这里我们把从JS里面返回的ArrayObject转换成了int[]以方便我们后面的调用。
再看一遍JS中计算偏移值的代码:
k = "-" + (n[i] % 26 * 12 + 1) + "px " + (n[i] > 25 ? -f.config.height / 2 : 0) + "px"
x和y的偏移值都是负数(或者0),因为这是背景的偏移值。想要显示背景图片右侧的内容,就要把图片向左移,因此偏移值为负数。
然而我们想要的偏移值刚好与其相反,我们需要的是向右取的偏移值,因此直接取它的相反数即可。所以:
x偏移值:(n[i] % 26 * 12 + 1)
y偏移值:(n[i] > 25 ? f.config.height / 2 : 0)
这样,我们既有了n,又有了xy偏移值计算方法,我们已经可以完成图片的还原了。
首先,把我们上次下载的图片格式从Image改为Bitmap,原因是Bitmap才可以直接GetPixel和SetPixel,比较方便:
Bitmap bg = new Bitmap(await netHandler.GETRequestAsImageAsync( bgUrl, false, null, false, "")); Bitmap fullbg = new Bitmap(await netHandler.GETRequestAsImageAsync( fullbgUrl, false, null, false, ""));
接着,我们知道整个图片由2行26列的10*58的方格组成:
int rows = 2, columns = 26, sliceWidth = 10, sliceHeight = 58;
新建两个Bitmap对象用于储存被还原的图像:
Bitmap realBg = new Bitmap(columns * sliceWidth, rows * sliceHeight); Bitmap realFullbg = new Bitmap(columns * sliceWidth, rows * sliceHeight);
另外,我们留意到,JavaScript中GeeTest产生div的顺序是先第一行从左到右,再第二行从左到右。因此我们也模拟这个顺序:
for (int row = 0; row<rows; row++) for (int column = 0; column<columns; column++) { }
在内层for里,我们可以计算出该方块左上角的位置:
int startingX = column * sliceWidth, startingY = row * sliceHeight;
同时,按照上面得出的偏移值计算公式,我们可以计算出xy的偏移值:
int offsetX = n[row * columns + column] % 26 * 12 + 1; int offsetY = n[row * columns + column] > 25 ? config.height / 2 : 0;
其中的row * columns + column即为目前方块的序号(从0开始)。
这些值都计算好之后,我们就要开始把这个方块的内容从原图复制到新图里了。还是在内层for里:
for (int x = 0; x<sliceWidth; x++) for (int y = 0; y<sliceHeight; y++) { realBg.SetPixel(startingX + x, startingY + y, bg.GetPixel(offsetX + x, offsetY + y)); realFullbg.SetPixel(startingX + x, startingY + y, fullbg.GetPixel(offsetX + x, offsetY + y)); }
当中starting开头的是新图中的开始位置,而offset开头的则是原图中的开始位置。完成这些之后,我们就要把两个pictureBox的Image属性设为新的Bitmap对象了:
pictureBox1.Image = realBg;
pictureBox2.Image = realFullbg;
运行,结果如下:
成功!我们完美地还原了两张图片。下一篇文章里我们将计算偏移值,这看起来很简单,但是实际上有一些值得注意的问题:
下一篇文章里我们将对付这三个问题,写出代码计算完美的移动值。这个移动值对于我们最后构造4号包完成验证至关重要。
喜欢我的文章的话记得关注和点赞!(我的专栏关注人数终于突破了100!谢谢你们的支持!)