电信网络诈骗中,犯罪分子使用的“共享屏幕”类视频会议软件不断升级演变(如图1)。从“手机QQ”、“腾讯会议”等市面上常见的网络会议软件,到自研的“会议”、“云服务”软件,再到更具隐蔽性的“云视听”软件。
近期出现的一款名为“微服务”的视频会议软件,更是能绕过大狗平台线索分析脚本的检测,让追踪调查愈发困难。此 APP 最早出现时间为2024年6月,目前大狗平台发现的样本已有200余个。
图1 “屏幕共享”骗局中涉案APP的演变过程
大狗涉网线索分析平台专家团队研究员@yyy 针对“微服务”APP 样本展开深入研究,以下是他分享的一些技术研判思路,希望能为解决这一问题提供新的见解。
分析过程
1►
了解APP样本
将 APK 文件上传至大狗平台进行自动化分析,从解析出的 APK 专业报告中可以发现:
1、应用名称和图标较之前“云服务”类 APP 已经发生了改变,但是界面截图和 APP 提供的功能依然具有极大的相似性,初步判断为同团伙样本;
2、在 SDK 信息栏同样识别出了“实时音视频”类开发工具包。不同之处在于:变更了 SDK 提供商,同时关键 ID 中只识别到了文件路径,需要进一步逆向分析来获取调证 ID、KEY。
图2 APK专业报告
了解完样本之后,将 APK 文件放入 Jadx 中,进行反编译,获取程序源代码。
2►
通过Jadx分析
● 2.1. 分析思路
1、这里已经明确了,要分析的实时音视频 SDK 在源码中的文件路径为:lib/armeabi-v7a/libliteavsdk.so。所以,直接去资源文件 lib 中查看相关的 so 文件信息,进行确认。
2、找到 so 文件后,可以在网上搜索库文件的名字,查找相关的文章或信息。这个样本中,第三方库文件名称为 libliteavsdk.so ,搜索结果显示为国内某厂商提供的 实时音视频SDK。
可以先搜全名, 如果没有结果可以进行拆分搜索(如: liteavsdk, liteav)。
3、接下来,去看该 SDK 提供商的开发者文档,查看它是如何初始化的。初始化过程中是否需要Key,或者某些ID等标识,我们需要获取的就是这个 ,了解后便可以开始进行下一步了。
由于 SDK 初始化过程中用到的 Key 或者某些 ID,是区别不同用户身份的唯一标识,因此也会作为向相关 SDK 提供商发起数据调证时,需要提取的关键 ID。
● 2.2. 找SDK初始化位置
阅读开发者文档可以发现, 当调用 enterRoom时需要传递一个叫 TRTCParams的参数,里面有一个字段叫SDKAppID(如图3),这个就是我们要找的,继续下一步。
图3 SDK开发者文档
当知道在调用哪个函数会携带 SDK ID 信息时,就可以在 Jadx 中全局搜索这个函数名字,帮助我们快速定位该函数在哪些位置发生了调用,这里搜索 enterRoom (如图4)。
图4 全局搜索 enterRoom 函数
可以看到,匹配到很多结果,可以检查调用, 查看有哪些地方调用了SDK。不过种方式很难定位并找到 APP ID,因此尝使用 Frida Hook 来查找。
3►
使用Frida分析
● 3.1. 分析思路
1、首先,在 Jadx 中查找 SDK 文档提供的初始化函数,明确目标。除个别定制的情况外,进行初始化操作必定会调用第三方 SDK 厂商提供的初始化函数。
2、此外,要明确需要 Hook 的具体函数,因为 Java 中存在多态的情况,Hook 后可能并不会被触发。因此,需要明确 Hook 的是被调用的类,而不是接口或被继承的类。
● 3.2. 开始Hook
尝试直接 Hook enterRoom 函数的代码如下:
let TrtcCloudJni = Java.use("com.tencent.liteav.trtc.TrtcCloudJni");
TrtcCloudJni["nativeEnterRoom"].implementation = function (j, enterRoomParams, i) {
console.log(`TrtcCloudJni.nativeEnterRoom is called: j=${j}, enterRoomParams=${enterRoomParams}, i=${i}`);
this["nativeEnterRoom"](j, enterRoomParams, i);
};
图5 直接Hook enterRoom 函数
从运行结果可以看出,Hook 后并没有按预期来执行,尝试在界面上点击加入房间并输入任意房间号之后,提示: 网络错误, 请检查网络! 猜想可能的原因如下:
1、是因为网络不通?
但是进行抓包后,在云真机操作台中分析网络请求,发现所有的网络都是通的。
2、是因为是模拟器的原因?
用真机打开该APP,仍然报一样的错误,甚至换了好几部手机都是一样的错误……
说明真正的错误并不是由上述问题导致的,于是换了个分析思路:能否直接将按钮 Hook 掉,来追踪到底是什么原因导致发出这个错误的?有没有可能直接把这个报错给跳过?
于是开始进行 Java 层上的 Hook,刚开始认为按钮虽然在前端实现,具体按下事件处理程序应该是在 Java 层上。找到这个具体的位置,上面的问题就能解决了,但是结果却恰恰相反。
4►
分析uni-app
结合之前 APK 分析报告中,识别到数字天堂(DCloud)开发工具SDK,查看 AndroidManifest.xml 发现其入口是 DCloud-uniapp 平台下的前端应用的框架(如图6)。
我们可以将一些特殊的名称拿到搜索引擎上去查一下, 在这里就是通过搜索知道这是基于DCloud Uniapp框架开发出来的,给后续分析提供很大的帮助。
图6 AndroidManifest.xml 文件
查看 uni-app 平台的开发文档发现,具体业务逻辑可以通过编写 JS 代码来实现,整个框架都是基于 H5 来做的。接着,通过搜索找到这个框架打包出来的 APK 结构信息(如图7)。
图7 uni-app框架打包的APK结构信息
或者也可以不用搜 APK 结构信息,直接在Jadx上将所有可疑的文点开来看, 也能够找到想要的内容。
之后开始着手看这些文件,发现真实业务逻辑代码经过了混淆,让其难以看懂和理解。
于是就想到,既然这样有没有可能使用到 WebView,带着这个问题,通过编写 Frida 脚本来 Hook WebView 的loadUrl 函数,发现确实使用到了 WebView(如图8)。
let WebView = Java.use("android.webkit.WebView");
WebView.loadUrl.overload("java.lang.String").implementation = function (url) {
console.log(url)
return this.loadUrl(...arguments);
};
图8 Hook WebView 的 loadUrl 函数
紧接着,开始分析前端代码。做法比较简单:通过 Frida 把 loadUrl 的参数改写,直接访问自己起的服务,这样就可以达到调试的效果。
结果还是不行,因为这些并不是业务代码,还需要继续分析,对错误提示的字符串进行全局搜索(如图9)。
图9 全局搜索
发现错误提示的字符串在 app-service.js 中,WebView 中并没有加载这个 js 文件。既然 WebView 中没有加载,那是不是在 java 代码中加载的呢?带着这个问题,继续回到 Java 代码中查找。由于程序加载文件必然会读文件,所以直接 Hook 读文件那个函数,然后打印堆栈就可以实现,代码如下:
function traceStack() {
let stackString = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
console.log(stackString);
}
Java.use("java.io.File").$init.overload("java.lang.String").implementation = function () {
// console.log('call ', arguments[0])
if (arguments[0].endsWith("app-service.js")) {
traceStack();
}
return this.$init(...arguments);
};
运行结果显示,程序确实加载了 app-service.js 文件(如图10)。
图10 打印读文件函数堆栈
let WXViewWrapper = Java.use("io.dcloud.feature.weex.WXViewWrapper");
WXViewWrapper["render"].implementation = function (template, options, jsonInitData) {
console.log(
`WXViewWrapper.render is called: template=${template}, options=${options}, jsonInitData=${jsonInitData}`
);
this["render"](template, options, jsonInitData);
};
图11 最终调用函数位置
现在的问题是:如何修改这个 JS 代码?由于代码是混淆无法读懂,更别说修改了。再次去网上查找相关反混淆的工具,功夫不负有心人,找到一个可以用的 Github – kuizuo/js-deobfuscator。解密后,所有逻辑一目了然, 可以不用继续 Hook 下去了。
图12 检查函数
请求时会调用 isTrueVersion 这个函数来检查(图12),里面检测的并不是网络错误, 网络错误只是一个误导。这里检查的是当前日期,需要的日期是 “20240701” 。由于分析的时候已经是第二天了,时间不匹配,因此就会报这个错误。然后将其它几个函数也还原了,最后发现 APP ID 是从服务器返回的(图13)。
图13 从服务器返回 APP ID
传递的参数是 SDK 最后转化为 APP ID,只要加入房间都会调用 enterRoom 函数(图14、图15)。
图14 传递SDK转化为 APP ID
图15 加入房间触发 enterRoom 函数调用
说明按照上面直接Hook enterRoom 函数的方式是可以行的,至此,分析结束。
总结:’微服务’ 视频会议
APP线索核查建议
1►
分析结论
针对最新样本“微服务”视频会议 APP 样本的分析,揭示了以下关键信息:
-
应用程序采用了代码混淆技术,以掩盖其真实业务逻辑。要进行业务逻辑分析,需要先使用反混淆工具还原相应的代码。
-
同时,该 APP 会对系统时间进行检测,当时间超出预设范围时,操作 APP 将会触发“网络错误,请检查网络!”的提示。
-
要想在不修改代码的情况下获取 SDKAppID,需要确保 APK 文件在有效时间内。
2►
线索核查建议
建议大家在案件发生后,及时对相关 APK 和网站进行固证。在调查过程中,可以尝试通过大狗平台进行关联分析,获取相关团伙的最新样本。
如果涉案 APP 仍在有效时间内,可以通过下面的 Frida 脚本 Hook enterRoom 函数,获取 APP 中实时音视频 SDK 的 AppID 线索。
let TrtcCloudJni = Java.use("com.tencent.liteav.trtc.TrtcCloudJni");
TrtcCloudJni["nativeEnterRoom"].implementation = function (j, enterRoomParams, i) {
console.log(`TrtcCloudJni.nativeEnterRoom is called: j=${j}, enterRoomParams=${enterRoomParams}, i=${i}`);
this["nativeEnterRoom"](j, enterRoomParams, i);
};
此外,根据还原的 JS 代码,我们了解到 APP ID 是从服务器返回的。感兴趣的朋友,可以进一步研究该样本 API 网站。
最后,当遇到复杂的APP、网站线索分析问题时,欢迎大家咨询无糖信息专家服务进行处理~
原文始发于微信公众号(无糖反网络犯罪研究中心):剖析‘共享屏幕骗局’最新样本:某视频会议软件 SDK 线索分析