逆向篇:解决快牙不能扫码问题
2022-9-4 18:0:19 Author: 看雪学苑(查看原文) 阅读量:18 收藏


本文为看雪论坛优秀文章

看雪论坛作者ID:hjhjl222

由于我们的设备需要集成快牙,快牙有扫码功能,但是扫码功能出现了异常,能扫描,但是不能正确的识别二维码。大概率还是我们虚拟摄像头导致的。有过扫码开发的同学都比较清楚,扫码一般是集成zxing或者zbar的sdk(当然也有自己写的,比如淘宝)。废话不多说,直接开整。从界面入手,获取到当前界面信息。打开扫码界面,过滤Camera日志。


由于我们在摄像头在framework层给Camera传参的时候带上了界面信息,方便虚拟摄像头做特殊用途判断,故此很容易拿到当前是GroupScanQrcodeFragment。然后我们打开反编译后的快牙源码找到这个类。然后大致搜索下result关键字,看看有没有可用信息。

那么也很明显了,这里就是处理结果的地方,无论成功还是失败都会sendMessage到这个handle上进行处理。这里有处理成功的结果,那我们就找找这个message.what为R.id.decode_succeeded是在哪里发送的。

通过全局搜索也找到了这个发送的关键函数,并且看到ZbarManager.decode这个关键解码函数,由此可知这货应该是用Zbar的sdk进行扫码的,那接下来就用frida插桩探测一下。


首先分享下我加载类的方式:


• framework中的类我们直接使用


• 一般情况下,我们都用这个方法来获取classloader,这种情况适合使用默认的classloader来加载的类

对于app自定义的类,我通常通过插桩Application的onCreate函数,来拿到application实例,并调用其getClassLoader函数来拿到classloader来loadClass。当然也可以hook ClassLoader的构造函数,并且保存下来,用到的时候遍历容器来loadClass。这样加载类的成功率更高。

这种方法必须通过spawn启动,因为Application.onCreate的时机比较早,并且这样不会漏过任何一个application,比如加载特定模块时才会创建的application。

回到正题,我们hook了a类的a方法,并且hook了ZbarManager的decode方法,看看这两个方法有没有被调用,如果调用到这个字节数组是否有数据,返回结果是否为空。

以下是输出的日志:

通过日志我们可以发现ZbarMananger的decode方法被调用了,但是结果为null,然后入参的字节数组长度不为0,我们先不深究这些数据正不正确,至少是有输入,但是没输出,很明显问题出在解码这块了。那么继续分析这个decode方法。

直接就是个native函数,那就导出这个libzbar.so,用ida看看吧。

exports面板搜索decode找到这个函数,然后shift+f11导入64位Android Arm,然后修改结构体,并且对其进行一番解读后,得到下图:

直接去hook解析图像信息的函数,看看有没有走到。


找到函数偏移,然后frida hook,我这里对hookNative的地址做了简单的封装,方便代码复用。

通过日志可以看到函数已经被调用了,这是不能正常解析的情况。

接下来再试试正常的手机,并且hook 得到结果的函数,也就是zbar_symbol_get_data。

通过这个函数我们很容易找到了结果:

然后再切换回我们真正开发的设备看看。

很遗憾,没有任何输出,说明根本没走到这里,也就是说在zbar_image_first_symbol函数时的返回值不满足要求,继续hook。

得到如下日志,也就验证了我的猜想,应该是图像解析函数出来问题。

再进到zbar_image_first_symbol函数里去看看。




只是取了convert_image的字段里的某个值(注意convert_image+104的偏移),那咱就去看看这个值是在解析图像信息的哪里赋的值。

v11是通过上面的zbar_symbol_set_ref函数和v16的值换算过来的,于是hook下这个函数。


可以看到这个v16的值是1,也就确定了是从下图的代码块过来的。

再来看看zbar_symbol_set_ref内部逻辑。

因为a2 = 1所以 a2 <= 0 必然条件不满足,不会走到条件成立的代码块,所以不做任何操作,从上面的日志也验证了入参和返回值的指针没有任何变化,能正常识别的pixel也是一样。


推演分析到这我感觉我的思路可能错了,既然是已经到解析图片信息这里了,那么问题很可能出现在图片本身,而非流程。
于是我又回到ZbarManager.decode函数,把参数里的字节数组保存下来,并且转化一份成jpg格式的图片看看,pixel和我们的设备到底有什么不同。

下面是将yuv420sp格式的数据转成jpg后的图片,左图是pixel,右图为我们的设备,两个相反。嗯…至少图像上除了颠倒也没啥区别。


这个是经过zbar算法处理后的图片,那我们在把相机抛上来的原始数据再保存成图片看看,找到如下源码。

hook一下,并且保存bArr吧。

得到如下两张图,左图pixel,右图我们的设备。

原图和zbar处理过的图片对比好像做了旋转90度,然后去掉一个通道色值数据。好像也没别的太大区别。上面我们说倒除了保存图片以外,还保存了一份decode的bArr原始数据。既然没有很好的办法,那我们就抛开设备因素,拿着手机和开发设备的数据,通过unidbg主动解析这个函数,看看结果咋样。在通过unidbg调用前,我们必须拿到这个函数的其他参数。


pixel:


开发设备:

然后把两份decode前的数据文件、apk,so等拷贝到unidbg工程里。

这里我对unidbg做了模块化封装,所以代码看起来比较简洁,并且能支持Spring,服务器部署。

运行的结果和在设备中一样,pixel的能识别出结果,而我们的开发设备结果null。

所以也就排除了设备本身环境的影响。那么结合上面本身图片数据完整,但是旋转了180度,所以猜测很可能就是识别区域导致的,重新再省视下byteArray后面的那几个参数。1080,1920肯定是图片的宽高,而后面这几个225、247、630、743参数应该就是识别区域相关的。于是去找源码。

这似乎就是我们之前没注意过的细节。

再结合这张图片(左pixel、右开发设备)和这几个数据,(pixel:225、247、630、743;开发设备:300、166、480、500)
妥妥的开发设备是从x=300、y=160的位置开始识别的,这个位置哪有二维码的数据。于是我估算了一组起始识别的坐标x=220,y=1200,也就是如下图运行。


运行结果:

果然都正常识别了。

总结一下:因为我们的虚拟摄像头给的预览数据,经zbar计算后旋转了180度导致原先的识别区域没有二维码信息,导致了识别失败,所以只需要让开发人员适配下快牙扫码时预览数据在原先旋转90度的基础上再旋转180度,到270度(和pixel一样),就能通过扫码了。

看雪ID:hjhjl222

https://bbs.pediy.com/user-home-926631.htm

*本文由看雪论坛 hjhjl222 原创,转载请注明来自看雪社区

# 往期推荐

1.WhatsApp私信协议实现记录

2.Android4.4和8.0 DexClassLoader加载流程分析之寻找脱壳点

3.实战DLL注入

4.某车联网APP加固分析

5.逆向篇:解决tiktok切换前后置虚拟摄像头卡住问题

6.House of cat新型glibc中IO利用手法解析 & 第六届强网杯House of cat详解

球分享

球点赞

球在看

点击“阅读原文”,了解更多!


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458467651&idx=1&sn=e9a570d6ea3a58058ecbecff914afbe5&chksm=b18e0dc986f984df3306ca2bcb353f69ff29accdbed4156b10cd231a1348710f6d9e056b0c6b#rd
如有侵权请联系:admin#unsafe.sh