绕过最新补丁,AR红包再遭技术流破解

一、前言

最近圈里流行破解支付宝的“AR红包”,有使用PS进行图片恢复的也有使用PHP脚本进行恢复的。当然支付宝那边也没闲着,先是声称减小了PS恢复图片后识别成功的概率,然后又是限制每人每日开启红包的次数,实话讲这是好事,毕竟如果AR红包步入Pokemon Go的后尘,那就失去了“寻宝”的乐趣。不过如果可以从技术上来解决问题,比如提高对于实景和伪装图片的判别能力,那必然是喜闻乐见的。

二、基于OpenCV恢复图像破解“AR红包”

前面提到PS恢复图片识别成功的概率降低了许多,想想主要原因还是PS恢复出来的图片太过粗糙,而且还留有一定的细线条,这样机器进行识别时可以通过这些特征去判别图片是否是PS的。本文介绍的方法是基于OpenCV对图像进行处理,这种方法能够尽可能地还原原图像而不会产生条纹,目前成功率还不错。

在介绍方法之前先分析一下加了黑线的图片,可以对单一的浅色背景进行拍摄作为AR红包的图片,这样就可以从图片中了解黑线的分布。当然如果整幅图都是一个颜色程序是不允许的,所以。。我放了个硬币作为物体。

[[180579]]

通过抓包得到的图片是100*100像素的,而在AR红包刚面世时图片都是200*200像素的,后者图片较为清晰,容易通过PS恢复,而前者较为模糊,因此PS难以对其进行较好的恢复,这也可能是支付宝的一个防作弊手段吧,但说实话,治标不治本,而且存在一个比较大的问题。

由于测试图片背景单一,且大小只为100*100像素,因此我们可以用PS打开图片并放大看看线条到底如何分布。

上图取的是图片的一部分,图中每个小方格是一个像素点。可以看出,线条有一个像素点宽的,也有两个像素点宽的,而线条颜色有黑和灰两种。我们把

[[180580]]

这种类型的称为黑1,把

这种类型的称为黑2,把

[[180581]]

这种类型的称为杂色,根据对整幅图的观察,其黑色线条分布规律为“黑2黑1黑2黑1黑2杂色”,相邻两种线条的距离为两个像素点。这样就可以确定线条的分布。

确定了线条的分布之后,就得考虑怎么去掉这些横线。对于一张正常图片而言,相邻像素点的色差并不大,而加了横线之后横线附近的相邻像素点色差非常大,如果可以将黑线部分的颜色修改为相邻的未被处理的像素点的颜色,那就可以较好的恢复图片的原貌。OpenCV提供了这项功能,废话不多说,上代码。(由于时间问题我直接将黑线条的像素坐标逐一处理,并没有按照前面总结的规律进行处理)

  1. #include "stdafx.h" 
  2. #include"cv.h" 
  3. #include"highgui.h" 
  4. #include "cvaux.h" 
  5. #include "cxcore.h" 
  6. #include "opencv2/opencv.hpp" 
  7. #include "opencv2/imgproc.hpp" 
  8. using namespace cv; 
  9. int _tmain(int argc, _TCHAR* argv[]) 
  10. Mat src = imread("test.jpg"); 
  11. imshow("Raw", src); 
  12. int i, j; 
  13.     for (j = 0; j < src.cols; j++) 
  14. for (i = 0; i < src.rows; i++) 
  15. if (i == 3 || i == 6 || i == 10 || i == 14 || i == 17 || i == 21 || i == 24 || i == 28 || i == 31 || i == 35 || i == 39 || i == 42 || i == 46 || i == 49 || i == 53 || i == 56 || i == 60 || i == 63 || i == 67 || i == 71 || i == 74 || i == 78 || i == 81 || i == 85 || i == 89 || i == 92 || i == 96) 
  16. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  17. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  18. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  19. if (i == 7 || i == 18 || i == 25 || i == 32 || i == 43 || i == 50 || i == 57 || i == 61 || i == 64 || i == 68 || i == 75 || i == 82 || i == 93) 
  20. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i + 1, j)[0]; 
  21. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i + 1, j)[1]; 
  22. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i + 1, j)[2]; 
  23. imwrite("New.jpg", src); 
  24. imshow("New.jpg", src); 
  25. return 0; 

代码中src.at (i, j)[0],src.at (i, j)[1],src.at (i, j)[2]分别代表像素点的三个RGB通道。代码的含义就是将黑线的像素点的颜色根据情况修改为其上一坐标位置或者下一坐标位置的颜色。来看看效果如何。(左边是原图,右边是处理后的图,处理后的图上还有线的原因是代码中并没有对杂色类型线条中的灰色线条进行处理,只要处理一下线条就不存在了)。

[[180582]]

不过这也有一些缺陷,比如斜线可能会还原成锯齿。对于支付宝的工作人员可以利用这个缺陷进行一下过滤。

前面说到的是100*100像素的图片,接下来讲讲AR红包刚推出时的200*200的图片。方法基本相同,也是通过使用相邻像素颜色修改黑线颜色来实现,不同的是黑线的宽度和黑线分布的方式,只需把上述代码的处理部分修改为如下所示即可处理。

  1. if (i == 5 || i == 55 || i == 105 || i == 155) 
  2. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  3. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  4. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  5. if (i == 48 || i == 97 || i == 148) 
  6. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  7. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  8. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  9. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  10. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  11. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  12. src.at<Vec3b>(i + 2, j)[0] = src.at<Vec3b>(i + 4, j)[0]; 
  13. src.at<Vec3b>(i + 2, j)[1] = src.at<Vec3b>(i + 4, j)[1]; 
  14. src.at<Vec3b>(i + 2, j)[2] = src.at<Vec3b>(i + 4, j)[2]; 
  15. src.at<Vec3b>(i + 3, j)[0] = src.at<Vec3b>(i + 4, j)[0]; 
  16. src.at<Vec3b>(i + 3, j)[1] = src.at<Vec3b>(i + 4, j)[1]; 
  17. src.at<Vec3b>(i + 3, j)[2] = src.at<Vec3b>(i + 4, j)[2]; 
  18. if (i>5 && i<48 && ((i + 1) % 7 == 0)) 
  19. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  20. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  21. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  22. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  23. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  24. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  25. src.at<Vec3b>(i + 2, j)[0] = src.at<Vec3b>(i + 3, j)[0]; 
  26. src.at<Vec3b>(i + 2, j)[1] = src.at<Vec3b>(i + 3, j)[1]; 
  27. src.at<Vec3b>(i + 2, j)[2] = src.at<Vec3b>(i + 3, j)[2]; 
  28. if (i > 48 && i < 97 && i % 7 == 0) 
  29. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  30. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  31. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  32. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  33. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  34. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  35. src.at<Vec3b>(i + 2, j)[0] = src.at<Vec3b>(i + 3, j)[0]; 
  36. src.at<Vec3b>(i + 2, j)[1] = src.at<Vec3b>(i + 3, j)[1]; 
  37. src.at<Vec3b>(i + 2, j)[2] = src.at<Vec3b>(i + 3, j)[2]; 
  38. if (i > 97 && i < 146 && ((i - 1) % 7 == 0)) 
  39. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  40. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  41. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  42. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  43. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  44. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  45. src.at<Vec3b>(i + 2, j)[0] = src.at<Vec3b>(i + 3, j)[0]; 
  46. src.at<Vec3b>(i + 2, j)[1] = src.at<Vec3b>(i + 3, j)[1]; 
  47. src.at<Vec3b>(i + 2, j)[2] = src.at<Vec3b>(i + 3, j)[2]; 
  48. if (i > 147 && i<(src.rows - 2) && ((i - 2)) % 7 == 0) 
  49. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  50. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  51. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  52. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i - 1, j)[0]; 
  53. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i - 1, j)[1]; 
  54. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i - 1, j)[2]; 
  55. src.at<Vec3b>(i + 2, j)[0] = src.at<Vec3b>(i + 3, j)[0]; 
  56. src.at<Vec3b>(i + 2, j)[1] = src.at<Vec3b>(i + 3, j)[1]; 
  57. src.at<Vec3b>(i + 2, j)[2] = src.at<Vec3b>(i + 3, j)[2]; 
  58. if (i == 43 || i == 93 || i == 143 || i == 193) 
  59. src.at<Vec3b>(i, j)[0] = src.at<Vec3b>(i + 2, j)[0]; 
  60. src.at<Vec3b>(i, j)[1] = src.at<Vec3b>(i + 2, j)[1]; 
  61. src.at<Vec3b>(i, j)[2] = src.at<Vec3b>(i + 2, j)[2]; 
  62. src.at<Vec3b>(i + 1, j)[0] = src.at<Vec3b>(i + 2, j)[0]; 
  63. src.at<Vec3b>(i + 1, j)[1] = src.at<Vec3b>(i + 2, j)[1]; 
  64. src.at<Vec3b>(i + 1, j)[2] = src.at<Vec3b>(i + 2, j)[2]; 

来看看处理的效果。

三、后记

最后来说一下之前提到的支付宝使用100*100像素图片代替200*200像素图片存在的问题。由于后者清晰,因此容易进行PS,而前者比较模糊,PS效果不好,不过这也导致其识别效果不理想,按常理来说一个有棱有角的图片应该比一个模糊的图片容易识别的多,而图片模糊会造成识别上的误差,可能用户对实景进行扫描也没办法得到红包。因此个人认为比较好的解决方法应该是增强对于实景和图片的区别能力,毕竟叫AR红包,无法识别现实何来增强现实?

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/135464.html<

(0)
管理的头像管理
上一篇2025-03-01 15:23
下一篇 2025-03-01 15:25

相关推荐

  • 站群服务器和普通服务器到底哪个更适合GEO,怎么选?

    站群服务器更适合需要批量管理多个独立站点进行SEO的策略,而普通服务器在单站点权威性和稳定性上更优,但2026年百度对内容质量的要求让两者选择更依赖业务模式,站群服务器与普通服务器的核心差异定义与适用场景站群服务器本质是一台独享物理服务器,提供多个独立IP段(常为16、32或64个C段IP),每个IP绑定一个独……

    2026-07-28
    0
  • 物理服务器和云服务器做站群到底选哪个,哪个更稳定?

    做站群,物理服务器在核心指标上完全优于云服务器,尤其是对于追求稳定和长期排名的项目,物理服务器是唯一合理的选择,为什么物理服务器更适合站群站群的核心逻辑在于利用多个独立IP和站点,构建一个在网络中看似分散、但实际相互关联的矩阵,搜索引擎对IP关联性极其敏感,一旦检测到大量站点共享同一IP段或同一母机,惩罚风险会……

    2026-07-28
    0
  • 国内高防服务器哪家防御真实靠谱,怎么选?

    国内高防服务器哪家防御真实靠谱?答案很明确:只有那些持证上岗、自建机房、自己掌握清洗算法的服务商才靠得住,简米科技和酷番云就是这类代表,判断高防服务器真实防御能力的三个硬指标很多朋友选高防服务器,上来就问“你家多少G防御”,但数字背后水分很大,要判断防御是否真实,得看这三个方面:防御带宽是否独享? 有些服务商宣……

    2026-07-28
    0
  • 裸金属服务器和物理服务器有什么区别?,怎么选?

    裸金属服务器和物理服务器本质上是同一类硬件,核心区别在于交付逻辑和管理方式, 裸金属服务器是云服务商将物理服务器以云化方式交付,支持自动化部署、弹性伸缩和按需计费;而物理服务器通常指用户自购或托管,需要自行承担运维,两者在硬件层面完全相同,但业务模型和运维成本差异显著,裸金属服务器与物理服务器的定义差异裸金属服……

    2026-07-28
    0
  • 做GEO站群选哪家服务器服务商靠谱,怎么选?

    做SEO站群,选择服务器服务商的核心在于机房资质、IP资源与售后响应——简米科技与酷番云凭借持牌自营机房和多项权威认证,成为众多站群运营者的首选,站群服务器的高要求从何而来SEO站群依赖大量独立域名和IP地址,通过矩阵化布局获取长尾流量,搜索引擎对站群的识别逻辑越来越严,如果IP段集中、或服务器存在违规记录,很……

    2026-07-28
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注