车机OTA包解密

admin 2025年2月5日23:03:57评论25 views字数 3814阅读12分42秒阅读模式
我的车二代车机系统终于更新了,上了高德新版,有了红绿灯倒计时,盼了很久,终于更新了。
我就想着将OTA包里面的apk,直接提取出来,升级就行了,不需要更新车机系统了,结果失败!
拿到了心心念的OTA升级包,一打开。
哦豁~~~~
车机OTA包解密
它竟然做了加密的,好惨。
我就想着,既然这里做了加密,那么车机系统在拿到包后,肯定也需要进行解密才能去安装呀,于是带着好奇去看了看。


获取升级apk

在车机交流群里面,顺利拿到了负责车机升级的apk,拖进jadx 里面,找关键字,HuOs。
还真找到了:
车机OTA包解密
这不就是我升级的路径,和包格式嘛 .zip
跟着调用栈一路静态分析,结果追到了解密方法:
车机OTA包解密
这里发现 包被进行了 "AES/CBC/PKCS5Padding" 的加密,车机系统拿到文件,进行解密后,再安装。


获取解密Key

又上一个步骤发现,是通过获取 "/system/bin/sd_ivi_data/ckey"  的值,然后使用 未宸 解密,对这个文件进行解密,获取前16 字节,作为系统包的aes key。
车机OTA包解密
想要解密这个就得两个步骤:
1、获取到这个ckey 这个文件 (万能的车友群 把文件给了我)
2、拿到 whiteBox.decrypt 的代码实现逻辑 (万能的车友群 把文件给了我)
步骤2走了一些弯路。起初以为 whiteBox.decrypt  这个代码的实现是放在 boot-framework.vdex 、最后通过搜索,发现是放在boot-ext.vdex 里面的。
车机OTA包解密
这里就需要使用两个工具:
1.vdex 转为cdex
2.再将 cdex 转为dex
最终打开:
车机OTA包解密
解密方法则是将文件的值,与一个key ,进到native 里面计算出来。
车机OTA包解密
那么我们还需要获取到这个token。


获取解密Key的解密token

通过静态分析,获取token的 通过获取升级 apk 下的一些文件值,在native 里面进行判断,最后返回出结果。
车机OTA包解密
起初,我以为需要在native 里面进行计算,最后反编译进去一看。
好家伙只是将获取的数据进行了对比,然后直接返回token,想复杂了。
int __fastcall Java_com_weichen_whitebox_encrytion_WhiteBoxNativeImpl_connectionToNativeVerifyDigest(JNIEnv *a1, int a2, int a3, size_t a4, int a5, int a6, size_t a7, int a8, int a9, int a10, int a11)
{
_DWORD *v13; // r9
const char *v14; // r5
const char *v15; // r10
int v16; // r0
const char *v17; // r5
jbyte *v18; // r4
jbyte *v19; // r6
jstring (*v20)(JNIEnv *, const char *); // r2
const char *v21; // r1
const char *v23; // r4
void *v24; // r9
const char *v25; // r10
jbyte *v26; // r4
jbyte *v27; // r5
const char *v28; // [sp+1Ch] [bp-2Ch]
const char *v29; // [sp+24h] [bp-24h]

v13 = malloc(0x20u);
v14 = (*a1)->GetStringUTFChars(a1, a9, 0);
v15 = (*a1)->GetStringUTFChars(a1, a5, 0);
if ( !j_readFileFromApk(v14, v15, v13) )
{
_android_log_print(4, "LeosinAcsctl: digest", "can't find file, LINE = %d", 275);
LABEL_8:
v20 = (*a1)->NewStringUTF;
v21 = "can't find file";
return (int)v20(a1, v21);
}
v29 = v14;
v16 = j_calculateDigest(a1, v13, a10);
if ( !v16 || (v17 = (const char *)v16, !v13[4]) )
{
_android_log_print(4, "LeosinAcsctl: digest", "unsupproted signAlg, LINE = %d", 281);
v20 = (*a1)->NewStringUTF;
v21 = "unsupproted signAlg";
return (int)v20(a1, v21);
}
v18 = (*a1)->GetByteArrayElements(a1, a3, 0);
v19 = (jbyte *)malloc(a4);
qmemcpy(v19, v18, a4);
if ( strncmp(v17, v19, a4) )
{
_android_log_print(4, "LeosinAcsctl: digest", "mainfiestFileDigest is wrong, LINE = %d", 290);
v20 = (*a1)->NewStringUTF;
v21 = "mainfiestFileDigest is wrong";
return (int)v20(a1, v21);
}
(*a1)->ReleaseByteArrayElements(a1, (jbyteArray)a3, v18, 2);
(*a1)->ReleaseStringUTFChars(a1, (jstring)a5, v15);
free(v19);
free(v13);
v23 = (*a1)->GetStringUTFChars(a1, a8, 0);
v24 = malloc(0x20u);
if ( !j_readFileFromApk(v29, v23, v24) )
{
_android_log_print(4, "LeosinAcsctl: digest", "can't find file, LINE = %d", 301);
goto LABEL_8;
}
v28 = v23;
v25 = (const char *)j_calculateDigest(a1, v24, a11);
v26 = (*a1)->GetByteArrayElements(a1, a6, 0);
v27 = (jbyte *)malloc(a4);
qmemcpy(v27, v26, a7);
__android_log_print(4, "LeosinAcsctl: digest", "dexClassDigestLen is %d", a7);
__android_log_print(4, "LeosinAcsctl: digest", "dexClassDigestArr is %s", v27);
__android_log_print(4, "LeosinAcsctl: digest", "dexClassDigest is %s", v25);
if ( !strncmp(v27, v25, a7) )
{
(*a1)->ReleaseByteArrayElements(a1, (jbyteArray)a6, v26, 2);
(*a1)->ReleaseStringUTFChars(a1, (jstring)a8, v28);
free(v27);
free(v24);
(*a1)->ReleaseStringUTFChars(a1, (jstring)a9, v29);
v20 = (*a1)->NewStringUTF;
v21 = "@ABCDEFG";
}
else
{
_android_log_print(4, "LeosinAcsctl: digest", "can't find file, LINE = %d", 313);
v20 = (*a1)->NewStringUTF;
v21 = "dexclass digest is wrong";
}
return (int)v20(a1, v21);
}


解密Key

前面既然已经拿到了 token ,那我们直接使用Unidbg 将 token 值,和ckey 的值传入,计算出结果即可。

public byte[] key() {
String y2 = "decryptUsingNative([BLjava/lang/String;)[B";
//参数1 ckey的值,参数2 token 值
DvmObject<?> dvmObject = UmeJni.callStaticJniMethodObject(emulator, y2, Base64.getDecoder().decode("j3AR4u/J4hedDbN8gkrqbbj7ibVPSX695NCfhVxSQWc="), "@ABCDEFG");
return (byte[]) dvmObject.getValue();
}
车机OTA包解密


解密

拿到key 了,返回第一步,使用AES/CBC/PKCS5Padding 解密,获得ota包。
车机OTA包解密
然后使用 开源工具payload-dumper-go  将 payload.bin 提取出 system.img 即可:就拿到了高德地图。
车机OTA包解密


总结

整体弄下来,花了一下午的时间,最开始想的太难了,动手起来,多亏了万能的车群提供了相应的文件进行分析,万事开头难,做起来就顺了。整体分析难道不大,都是一些基础的调用,和简单的知识点结合就行。

车机OTA包解密

看雪ID:ty1937

https://bbs.kanxue.com/user-home-857508.htm

*本文为看雪论坛优秀文章,由 ty1937 原创,转载请注明来自看雪社区

原文始发于微信公众号(看雪学苑):车机OTA包解密

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月5日23:03:57
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   车机OTA包解密https://cn-sec.com/archives/3702070.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息