首页
社区
课程
招聘
[原创]x加密流程分析
发表于: 15小时前 969

[原创]x加密流程分析

15小时前
969

声明

本文仅限于技术讨论,不得用于非法途径,后果自负。

入口

如果说apk的在启动的时候最早的运行的时候可能很多人会下意思的认为是application中name这个类中的attachBaseContext,然而这个包很特别,如果你使用frida hook这个name(s.h.e.l.l.S) 你会发现根本hook不到,但是你hookdlopen你会发现libexec确实加载了,所以一定有比这更早的时候,在jadx中搜索加载libexec的代码,打印堆栈 最后定位到了application 中的android:appComponentFactory这个类中的instantiateApplication,观察逻辑,如果这个s.h.e.l.l.S被加载,那么他的名称会被替换。
图片描述
图片描述
继续观察剩下代码发现classLoader 也被替换,那么loader.al 就是重中之重
图片描述
查看a1发现是so的函数
图片描述
可以看到libexec已经被加载了
图片描述

initproc

使用ida打开apk中的libexec.so发现被加密了,那么动态dump,定位initproc,简单看了下 大致是一个压缩壳,那么在initarraydump下来,sofix修复
图片描述

initarray

查看initarray不得不说,函数是真的多 看了前半部分全部是解密字符串 那么定位到initarray最后一项,重新dump
图片描述
定位后半部分

大致行为

获取了手机基本信息和libc中的pthread_create ,还有就是反调试检查,最重要的行为是填充了一个全局结构体,我叫做jni_data(懒得改,实际上应该叫IJM_Global),这个结构体贯穿所有行为逻辑,考验结构体逆向的功底
图片描述

jni_onload

jni_onload 只做了2件事情

1.获取apk全面信息

大致上获取了apk的路径 如 base.apk的路径 files路径等,其他根据版本获取了手机的能获取到的信息,所有需要的东西
图片描述
图片描述

jni_fast_call

jni_data 引用了一组函数指针结构体的指针,用于快速调用jni函数
图片描述
图片描述

2.RegisterNatives

图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* TID 28896 */
[+] JNIEnv->RegisterNatives
|- JNIEnv*          : 0x7ce6beb6c0
|- jclass           : 0x101
|- JNINativeMethod* : 0x7fff774e30
|: 0x7bf43d5fe4 - l(Landroid/app/Application;Ljava/lang/String;)Z
|: 0x7bf43d7d54 - r(Landroid/app/Application;Ljava/lang/String;)Z
|: 0x7bf43d840c - ra(Landroid/app/Application;Ljava/lang/String;)Z
|: 0x7bf43d85bc - b2b([BI)[B
|: 0x7bf43d85c4 - m(Ljava/lang/String;I)V
|: 0x7bf43d85c8 - sa(Ljava/lang/String;Ljava/lang/String;)V
|: 0x7bf43d864c - al(Ljava/lang/ClassLoader;Landroid/content/pm/ApplicationInfo;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/ClassLoader;
|- jint             : 7
|= jint             : 0
0x7bf4383000

a1

继续向下看 观察a1 这就应该就是加载dex的函数了 返回classload。
图片描述

下面根据行为大致列出流程

图片描述
检查initarray设下的反调试标志
图片描述
兼容大客户 不过这个不是,有兴趣的去学习学习
图片描述
图片描述
值得注意的是自实现了一组加载解密函数
图片描述
初始化ijm的功能强度配置 通过文件来设置
图片描述
重定向输出流 ,也就是干掉log 不过缺陷是ijm内部加载文件log会在我的frida打印搞不懂
图片描述
计算出包名的md5 这个md5会参与后面的文件解密
图片描述
图片描述
图片描述
图片描述
打开文件解密出包名校验
图片描述
图片描述
图片描述
创建2个线程 一个签名校验,一个校验资源androidmanifest
图片描述
jni检查isdebug
图片描述
检查嫌疑机型
图片描述
检查虚拟机 su root
图片描述
图片描述
检查了看雪上已知的脱壳系统 fart youpk 还有几个super功能没开 应该是得加钱

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
__int64 antiFartYoupkAndAntiFrida()
{
  Jni_Data **v0; // x21
  jclass v1; // x19
  unsigned int v2; // w19
  __int64 v4; // x19
  Jni_Data *v5; // x8
  __int64 v6; // x19
  void *v7; // x0
  Jni_Data *v8; // x8
  __int64 v9; // [xsp+8h] [xbp-B8h] BYREF
  _BYTE v10[8]; // [xsp+10h] [xbp-B0h] BYREF
  char v11[128]; // [xsp+18h] [xbp-A8h] BYREF
  __int64 v12; // [xsp+98h] [xbp-28h]
 
  v12 = *(_QWORD *)(_ReadStatusReg(ARM64_SYSREG(3, 3, 13, 0, 2)) + 40);
  if ( (unsigned int)faccessat("/data/dexname") != -1 )
  {
    return 1;
  }
  v0 = ppjni_data;
  v1 = (*(*ppjni_data)->Env)->FindClass((*ppjni_data)->Env, "cn/youlor/Unpacker");
  (*v0)->jni_func_D5D58->checkException((*v0)->Env);
  if ( v1 )
  {
    return 1;
  }
  if ( (*v0)->androidVersion < 24
    || (v2 = 1,
        !((__int64 (__fastcall *)(const char *, const char *, __int64))(*v0)->hookfunc_D59F8->dlsym)(
           "libart.so",
           "_ZN3art8Unpacker12dumpAllDexesEv",
           1LL))
    && (v2 = 1,
        !((__int64 (__fastcall *)(const char *, const char *, __int64))(*v0)->hookfunc_D59F8->dlsym)(
           "libart.so",
           "_ZN3art4Aupk13aupkArtMethodE",
           1LL)) )
  {
    if ( (unsigned int)faccessat("/data/local/tmp/unpacker.config") != -1 )
    {
      return 1;
    }
    if ( (unsigned int)faccessat("/data/local/tmp/aupk.config") != -1 )
    {
      return 1;
    }
    if ( (unsigned int)faccessat("/data/fart") != -1 )
    {
      return 1;
    }
    v4 = (__int64)(*(*v0)->Env)->FindClass((*v0)->Env, "cn/mik/Fartext");
    (*v0)->jni_func_D5D58->checkException((*v0)->Env);
    if ( v4 )
    {
      return 1;
    }
    if ( (unsigned int)faccessat("/data/system/mik.conf") != -1 )
    {
      return 1;
    }
    v5 = *v0;
    v9 = 0LL;
    v6 = (__int64)(*v5->Env)->NewStringUTF(v5->Env, "mikrom");
    (*v0)->jni_func_D5D58->CallStaticObjectMethodV(
      (*v0)->Env,
      &v9,
      "android/os/ServiceManager",
      aLjava,
      "getService",
      v6);
    (*(*v0)->Env)->DeleteLocalRef((*v0)->Env, (jobject)v6);
    if ( v9 || !strstr(aData, "re.frida.server") )
    {
      return 1;
    }
    if ( (*v0)->androidVersion < 24 )
    {
      v7 = dlopen("libart.so", 0);
      if ( v7 && dlsym(v7, "myfartInvoke") )
      {
        return 1;
      }
    }
    else if ( ((__int64 (__fastcall *)(const char *, const char *, _QWORD))(*v0)->hookfunc_D59F8->dlsym)(
                "libart.so",
                "myfartInvoke",
                0LL) )
    {
      return 1;
    }
    v8 = *v0;
    if ( !(*v0)->isPakeName )
    {
LABEL_25:
      (*(void (__fastcall **)(_BYTE *, _QWORD, _DWORD *(*)(), _QWORD))v8->pthread_create)(v10, 0LL, sub_43D80, 0LL);
      return 0;
    }
    memset(v11, 0, sizeof(v11));
    if ( (int)_system_property_get_1((__int64)"ro.dalvik.vm.native.bridge", (__int64)v11) < 1
      || !strcmp_1(v11, "libriruloader.so") && (unsigned int)faccessat("/system/lib/libriruloader.so") == -1 )
    {
      (*(void (__fastcall **)(_BYTE *, _QWORD, void (__fastcall __noreturn *)(__int64), _QWORD))(*v0)->pthread_create)(
        v10,
        0LL,
        antiFrida,
        0LL);
      v8 = *v0;
      goto LABEL_25;
    }
    return 1;
  }
  return v2;
}

图片描述
图片描述
这里自实现了一组dlsym hook了抽取壳需要的api,如果实在找不到关键api 甚至会对特定机型进行硬编码
图片描述
图片描述
图片描述
图片描述
这里这里dex被解密(需要用到之前的md5)并加载进classload 但是这个是个抽取壳
图片描述
图片描述
图片描述
大致行为就这样

对抗

1.壳并没有使用控制流混淆,但是大量使用了不透明谓词去干扰 还有虚假控制流,这个需要耐心对汇编有一定功底要求
2.ida静态干扰,ida函数识别是错的需要你自己去重新定义 同样需要nop汇编
3.我不知道这个有没有对抗 但是sofix 修复的部分重定位表 是有问题的 会导致ida解析函数调用的时候忽略参数
4.如果你使用frida 打印堆栈 或者DebugSymbol.fromAddress libc的锁会崩溃

回填

这个需要你耐心读一遍android 源码 弄明白loadmethod 这个函数的参数的结构 ,和弄明白new_loadmethod的行为 dump 数据修复


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 3
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
大神,能联系我不V13308782687
14小时前
0
雪    币: 220
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
大佬 我想请问下是怎么个动态dump法 使用了什么工具 真心请教下
13小时前
0
雪    币: 2519
活跃值: (4338)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
7_up 大佬 我想请问下是怎么个动态dump法 使用了什么工具 真心请教下
frida啊
12小时前
0
雪    币: 1963
活跃值: (2417)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
感谢分享
12小时前
0
游客
登录 | 注册 方可回帖
返回
//