首页
社区
课程
招聘
[原创]逆向篇二:解决快牙不能扫码问题
发表于: 2022-8-26 17:55 22516

[原创]逆向篇二:解决快牙不能扫码问题

2022-8-26 17:55
22516

背景介绍:本人原先是android逆向工程师,后来因为工作变动,离开了协议分析这类的岗位,目前在做直播机与第三方应用兼容性分析。所以就有了这篇兼容性分析文章。本文篇幅较长,需要跟着思路一直往下看,否则肯定云里雾里。
由于我们的设备需要集成快牙,快牙有扫码功能,但是扫码功能出现了异常,能扫描,但是不能正确的识别二维码。大概率还是我们虚拟摄像头导致的。有过扫码开发的同学都比较清楚,扫码一般是集成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一样),就能通过扫码了


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-8-28 13:04 被hjhjl222编辑 ,原因: 贴图错误
收藏
免费 7
支持
分享
打赏 + 80.00雪花
打赏次数 1 雪花 + 80.00
 
赞赏  Editor   +80.00 2022/09/05 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (5)
雪    币: 1392
活跃值: (5152)
能力值: ( LV13,RANK:240 )
在线值:
发帖
回帖
粉丝
2
摄像头问题在兼容里面就是大坑。
2022-8-29 09:19
0
雪    币: 669
活跃值: (1652)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
是的,尤其是自研设备,我们十个里面五六个都是
2022-8-29 09:43
0
雪    币: 8437
活跃值: (5031)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
4
学到了,感谢分享
2022-8-29 14:24
0
雪    币: 129
活跃值: (4485)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
一开头我就想到是颠倒的问题,之前我就试过一些扫码软件跟浏览器扫码的功能,对着框扫不了,往上挪就可以,但坑太多了
2022-8-30 15:26
0
雪    币: 340
活跃值: (107)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学到了,感谢分享
2022-8-30 20:10
0
游客
登录 | 注册 方可回帖
返回
//