网站建设的方向和任务,开发网站监控工具,wordpress typecho 大数据库,株洲发布前言
只是普通的单机手游#xff0c;广告比较多#xff0c;所以分析处理了下#xff0c;校验流程蛮有意思的#xff0c;所以就分享出来了
1.重打包崩溃处理
样本进行了加固#xff0c;对其dump出dex后重打包出现崩溃 ida分析地址发现为jni函数引起
利用Xposed直接替换…前言
只是普通的单机手游广告比较多所以分析处理了下校验流程蛮有意思的所以就分享出来了
1.重打包崩溃处理
样本进行了加固对其dump出dex后重打包出现崩溃 ida分析地址发现为jni函数引起
利用Xposed直接替换该函数崩溃问题解决 1 2 3 4 5 6 XposedHelpers.findAndHookMethod(com.unity3d.player.UnityPlayerActivity, classLoader, IsHDR_DisplayBoot, java.lang.String.class, java.lang.String.class, new XC_MethodReplacement() { Override protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable { return null; } });
2.卡加载界面处理
但是出现了新的问题游戏卡在了加载页面 对该类的其他jni函数进行分析发现supportVulkan很明显进行了签名读取对其去除签名校验。
此处参考项目ApkSignatureKillerEx
3.地图无法进入问题分析基于原包
去除完签名校验后游戏能正常进入主页面但是点击游戏地图没有任何反应。
在对原包进行多次测试发现在首次启动游戏时如果断网也会出现无法正常进入地图的问题怀疑是游戏首次启动进行了网络请求进行数据校验
经过抓包对比定位到可疑数据包
利用Frida的算法通杀脚本没有定位到相关内容怀疑是so层进行了请求
3.1 hook send函数进行调用栈分析
通过调用栈可以很清晰看到请求是从unity引擎相关的so中发出的。
3.2 il2cppTrace对请求调用栈分析
查阅资料在unity中网络请求主要通过UnityWebRequest 类来执行网络请求利用frida-il2cpp-bridge对UnityWebRequest进行trace打印调用栈得 1 2 3 4 5 6 7 8 9 10 0x0247db9c ┌─UnityEngine.Networking.UnityWebRequest::.ctor(this UnityEngine.Networking.UnityWebRequest, url http://106.54.194.167:8077/CheckUpdate, method POST) 0x0247db00 │ ┌─UnityEngine.Networking.UnityWebRequest::set_url(this UnityEngine.Networking.UnityWebRequest, value http://106.54.194.167:8077/CheckUpdate) 0x0247ef38 │ │ ┌─UnityEngine.Networking.UnityWebRequest::InternalSetUrl(this UnityEngine.Networking.UnityWebRequest, url http://106.54.194.167:8077/CheckUpdate) 0x0247ef38 │ │ └─UnityEngine.Networking.UnityWebRequest::InternalSetUrl 0x0247db00 │ └─UnityEngine.Networking.UnityWebRequest::set_url 0x0247dc1c │ ┌─UnityEngine.Networking.UnityWebRequest::set_method(this UnityEngine.Networking.UnityWebRequest, value POST) 0x0247e4e0 │ │ ┌─UnityEngine.Networking.UnityWebRequest::InternalSetMethod(this UnityEngine.Networking.UnityWebRequest, methodType Post) 0x0247e4e0 │ │ └─UnityEngine.Networking.UnityWebRequest::InternalSetMethod 0x0247dc1c │ └─UnityEngine.Networking.UnityWebRequest::set_method 0x0247db9c └─UnityEngine.Networking.UnityWebRequest::.ctor
在IDA中进行交叉引用分析定位到UnitySDKManager类 1 2 3 追踪调用定位到 class UnitySDK.UnitySDKManager.PostDatad__25 : System.Object, System.Collections.Generic.IEnumeratorSystem.Object, System.Collections.IEnumerator, System.IDisposable private Boolean MoveNext() { }
增加UnitySDKManager类重新对其trace因为出现报错把参数输出关了 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 0x00b15b44 ┌─UnitySDK.UnitySDKManager::ServerVerifyApk 0x00b04b3c │ ┌─UnitySDK.UnitySDKManager::GetFileInfoList 0x00b04b3c │ └─UnitySDK.UnitySDKManager::GetFileInfoList 0x00b06ec0 │ ┌─UnitySDK.UnitySDKManager::GetGamePackageName 0x00b06ec0 │ └─UnitySDK.UnitySDKManager::GetGamePackageName 0x00b06204 │ ┌─UnitySDK.UnitySDKManager::GetSDKVersion 0x00b06204 │ └─UnitySDK.UnitySDKManager::GetSDKVersion 0x00b06278 │ ┌─UnitySDK.UnitySDKManager::HexStringToHex 0x00b06278 │ └─UnitySDK.UnitySDKManager::HexStringToHex 0x00b10fcc │ ┌─UnitySDK.UnitySDKManager::EncryptString 0x00b10fcc │ └─UnitySDK.UnitySDKManager::EncryptString 0x00b100a4 │ ┌─UnitySDK.UnitySDKManager::PostData 0x00a341fc │ │ ┌─UnitySDK.UnitySDKManager.PostDatad__25::.ctor 0x00a341fc │ │ └─UnitySDK.UnitySDKManager.PostDatad__25::.ctor 0x00b100a4 │ └─UnitySDK.UnitySDKManager::PostData 0x00a3422c │ ┌─UnitySDK.UnitySDKManager.PostDatad__25::MoveNext 0x00b12be4 │ │ ┌─UnitySDK.UnitySDKManager::GetUrl 0x00b12be4 │ │ └─UnitySDK.UnitySDKManager::GetUrl 0x0247db9c │ │ ┌─UnityEngine.Networking.UnityWebRequest::.ctor 0x0247db00 │ │ │ ┌─UnityEngine.Networking.UnityWebRequest::set_url 0x0247ef38 │ │ │ │ ┌─UnityEngine.Networking.UnityWebRequest::InternalSetUrl 0x0247ef38 │ │ │ │ └─UnityEngine.Networking.UnityWebRequest::InternalSetUrl 0x0247db00 │ │ │ └─UnityEngine.Networking.UnityWebRequest::set_url 0x0247dc1c │ │ │ ┌─UnityEngine.Networking.UnityWebRequest::set_method 0x0247e4e0 │ │ │ │ ┌─UnityEngine.Networking.UnityWebRequest::InternalSetMethod 0x0247e4e0 │ │ │ │ └─UnityEngine.Networking.UnityWebRequest::InternalSetMethod 0x0247dc1c │ │ │ └─UnityEngine.Networking.UnityWebRequest::set_method 0x0247db9c │ │ └─UnityEngine.Networking.UnityWebRequest::.ctor 0x0247e0f4 │ │ ┌─UnityEngine.Networking.UnityWebRequest::set_uploadHandler 0x0247e0f4 │ │ └─UnityEngine.Networking.UnityWebRequest::set_uploadHandler 0x0247dfdc │ │ ┌─UnityEngine.Networking.UnityWebRequest::set_downloadHandler 0x0247dfdc │ │ └─UnityEngine.Networking.UnityWebRequest::set_downloadHandler 0x0247f66c │ │ ┌─UnityEngine.Networking.UnityWebRequest::SetRequestHeader 0x0247f66c │ │ └─UnityEngine.Networking.UnityWebRequest::SetRequestHeader 0x0247e42c │ │ ┌─UnityEngine.Networking.UnityWebRequest::Send 0x0247e430 │ │ │ ┌─UnityEngine.Networking.UnityWebRequest::SendWebRequest 0x0247e42c │ │ │ └─UnityEngine.Networking.UnityWebRequest::Send 0x0247e430 │ │ └─UnityEngine.Networking.UnityWebRequest::SendWebRequest 0x00a3422c │ └─UnitySDK.UnitySDKManager.PostDatad__25::MoveNext 0x00a34cd4 │ ┌─UnitySDK.UnitySDKManager.PostDatad__25::System.Collections.IEnumerator.get_Current 0x00a34cd4 │ └─UnitySDK.UnitySDKManager.PostDatad__25::System.Collections.IEnumerator.get_Current 0x00b15b44 └─UnitySDK.UnitySDKManager::ServerVerifyApk
通过调用栈可以初步对校验流程进行了解主要通过ServerVerifyApk函数进行校验经过一系列字符串加解密最后进行网络请求
3.3 加解密函数hook分析
对关键函数进行hook分析 1 2 3 4 5 6 0x00b10fcc │ UnitySDK.UnitySDKManager::EncryptString 0x00b0b13c │ UnitySDK.UnitySDKManager::DecryptString il2cpp: EncryptString:{appid:com.meta.peopleground.dream,appName:com.meta.peopleground.dream,appVer:1.0.1,sdkVer:2,appFileList:981lDpbObvjRn/3yI74fI1S5cr08qKLGq0xg7TcfFOA7hRePAQjXPCgIzECp58RThRtl4PIsPEgiJZVYn1e2oZl06jeKGD6C0Zy6lQaDiAVaOtO5szilZxfmN2j8XtlBmBaOzOVBBi6ctJamGsfM2XbkGqYtf/TlNyvOZ8p5YDdOgnhGWonkjG1sGEbuqc4smhkCxOC7dX1rEM4/5S6wT1erPL5iWJoRpiTuHok15zCQjdNFCXn97Vwg/h8eXrtxrDvkkLqqCff2D0WrAISmIOi4fY97ulhpz5Pey2vJlkLK5MdSApENx4exv3t4Q1sVfoPojwDueXAW9T1RTOc1LeK0cYMrBjsE1W8} il2cpp: EncryptString result:xoJRLdGOAd21Q0JEIDiJqlciJFWy0jtiSLU7lNue9ZLAOxsuEkWvJwP8o3ub4CfcIjulssJCocK0ai3lkr1XfNXlLi2QJ0iTtYzbCDQqYmqXr7uTTdOrAK3Y6NKkdmYgFFJ2w7tY/rl5NBPPlwRWWbvw45CRp3JX34BkKTA2KEXiWywj90T3Qw72AnpWgBOo1rD3USuAVQeN8EOhxVc1jTjsBn2qSfZX38tNC73wvceexa4w5wOea9rzaRshViPWjFkNko/BDuaAyWDJbB656FNatES6/WA3f7qMlQmEU4BGrX72StLzsNQYcQZ4KDFnWwqfhuH1zCudxxDoNpi53fqvDavLwmRRE19e1clgW5ANilhelSIGi9U9nq2BcNr3GMJ8eI2FAV76U1FHONbyMUggUYr6cDc9Vo9l5Wc4UVD4tqDmulUW1L1s8NTkieyVDEJxb1o6166fVVWdUKNBlrIXDfbWjE6gLheTHfp1/ywUy4EcVSklERsEkdufZrdKM57XVkXcKFnA0hutpuKqCbbkthULifwkAtwyQ/qSdcZHIh6pNYGuLOFF5NiCsHhJ6D/O03/uUgsR/V5WwRGuOeZFsM2NKNcyYjHDkoKh6SjoEnZZ/yfg1M4kOUJy5qG/V1jR8IqOmZ84w il2cpp: DecryptString:CVWCEji2Lgf4nUTWb7J/Q il2cpp: DecryptString result:100
发现之前抓包获得的请求体相对应其中appFileList还是密文继续分析
3.4 追EncryptString函数 与dump.cs中的函数进行对照发现v14 由字符串转hex转base64获得 1 System.Byte[] HexStringToHex(System.String inputHex); // 0x00b06278
hook HexStringToHex 函数获得参数 1 il2cpp: inputHex:f7cd650e96ce6febe3467ff7c88ef87c8fb54b972bd3ca8a2c6ab4c60ed371f14e03b85178f0108d73c2808cc40bea79f114e146d9783c8b0f120889655627d5eda8665d3a8de2860faf82d19cba95068388055a3ad3b9b338a56717e63768fc5ed94198168ecce541062e9cb496a61ac7ccd976e41aa62d7ff4e5372bce67ca7960374e827846f96a279231b5b0611bbaa738b26fa1902c4e0bb757d6b10ce3fe52eb04f57ab3cbe7e896268469893b87a24d79cc242374d1425e7f7b57083efe1f1e5ebb71ac3be490baaa09f7f60f45ab0084a620e8b87d8f7bba5869cf93decb6bc99642cae4c75202910dc787b1bf7b78435b157e83e88f00ee797016f53d514ce7352de2b471832b063b04d56f
IDA继续查找调用发现其中字符串由GetFileInfoList函数获得 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // static System.IntPtr GetFileInfoList(); // 0x00b04b3c __int64 sub_B04B3C() { __int64 (*v0)(void); // x8 __int64 v2[5]; // [xsp0h] [xbp-40h] BYREF int v3; // [xsp28h] [xbp-18h] char v4; // [xsp2Ch] [xbp-14h] v0 (__int64 (*)(void))qword_30365A0; if ( !qword_30365A0 ) { v3 0; v2[0] (__int64)UnitySDK; v2[1] 8LL; v2[2] (__int64)GetFileInfoList; v2[3] 15LL; v2[4] 0x200000000LL; v4 0; v0 (__int64 (*)(void))sub_812FB4(v2); qword_30365A0 (__int64)v0; } return v0(); }
很明显调用了libUnitySDK.so中的GetFileInfoList函数获得
3.5 libUnitySDK.so分析 1 2 3 4 __int64 GetFileInfoList() { return FileInfoListStr; }
FileInfoListStr在writeFileJson函数中被赋值而writeFileJson则是由java函数上文中的IsHDR_DisplayBoot调用该函数首个参数为base.apk路径 很明显ll11l1l1ll函数 对之前的明文字符串进行了加密frida hook打印参数 1 2 3 4 5 6 7 8 9 10 11 12 13 args: { HashList : { AndroidManifest.xml : c72b1d2, assets/bin/Data/Managed/Metadata/game.dat : a34a757d, classes.dex : 58b6cf21, lib/arm64-v8a/libUnitySDK.so : b56d5af4, lib/armeabi-v7a/libUnitySDK.so : 3d548ba2 }, fileCount : 1620 } returnResult: f7cd650e96ce6febe3467ff7c88ef87c8fb54b972bd3ca8a2c6ab4c60ed371f14e03b85178f0108d73c2808cc40bea79f114e146d9783c8b0f120889655627d5eda8665d3a8de2860faf82d19cba95068388055a3ad3b9b338a56717e63768fc5ed94198168ecce541062e9cb496a61ac7ccd976e41aa62d7ff4e5372bce67ca7960374e827846f96a279231b5b0611bbaa738b26fa1902c4e0bb757d6b10ce3fe52eb04f57ab3cbe7e896268469893b87a24d79cc242374d1425e7f7b57083efe1f1e5ebb71ac3be490baaa09f7f60f45ab0084a620e8b87d8f7bba5869cf93decb6bc99642cae4c75202910dc787b1bf7b78435b157e83e88f00ee797016f53d514ce7352de2b471832b063b04d56f
其中 HashList 中文件对应的值为文件的 crc 至此除了具体的字符串加密算法游戏的校验流程已经很清晰
4.校验流程归纳
签名校验读取base.apk进行关键文件crc读取进行服务器请求对关键文件crc校验
5.后记
对该校验去除的思路
对读取安装包的函数 zip_open 或java层的 IsHDR_DisplayBoot 函数进行hook进行参数替换进行io重定向基于il2cpp中的ServerVerifyApk函数进行更详细的分析直接对其检测去除