wmsuper 发表于 2016-9-23 22:33

记一次对flyme自带root的功能的逆向

本帖最后由 wmsuper 于 2016-9-26 16:47 编辑

1.前言
flyme一般都自带开放系统权限的功能,输入用户密码后就可以执行root功能root后的手机会把/system/xbin/lu 改为su 并赋予S位(讨论的是flyme5.1.8.0A 下同)


2.应用层分析
找到设置的apk,Settings.apk没混淆,很容易定位关键函数

   private void handleRootPermissionPreferenceClick() {
      if(this.isRootPermissionOpened()) {
            this.startFragment(this, RootPermissionSettingsFragment.class.getName(), 2131430221, -1, null);
      }
      else if(this.isFlymeAccountLogined()) {
            this.startActivity(new Intent("com.meizu.action.ROOT"));//执行一个intent
      }
    }

    private boolean needShowRootPreference() {
      boolean v0 = true;
      if(MzUtils.isGuestUser(this.getActivity())) {
            v0 = false;
      }
      else if(!this.isRootPermissionOpened()) {
            if((this.isFlymeAccountLogined()) && (MzUtils.isPackageExistAndHasAction(this.getActivity(), "com.meizu.account", "com.meizu.action.ROOT"))) { //这里可以知道com.meizu.action.ROOT在MzAccount.apk有实现
                return v0;
            }

            v0 = false;
      }

      return v0;
    }





MzAccount.apk 的内容:
//查看MzAccount.apk的AndroidManifest.xml搜索com.meizu.action.ROOT定位到一个activity

      <activity android:label="@string/app_name" android:name="com.meizu.root.OpenSystemRightActivity" android:screenOrientation="portrait" android:theme="@style/AccountTheme.Gray">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <action android:name="com.meizu.action.ROOT" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
      </activity>


com.meizu.root.OpenSystemRightActivity的内容

protected void onCreate(Bundle arg5) {
      super.onCreate(arg5);
      ap.a(((Activity)this), null, this.getResources().getString(2131296648), 0);
      this.setContentView(2130903077);
      this.c = this.findViewById(2131755221);
      this.c.setOnCheckedChangeListener(((CompoundButton$OnCheckedChangeListener)this));
      this.a = new SystemRootHelper(((Context)this));//看名称很特别 到这个类里面看看
      this.e = this.findViewById(2131755244);
      this.e.setEnabled(false);
      this.e.setText(this.getString(2131296645));
      this.e.setVisibility(0);
      this.e.setOnClickListener(new a(this));
    }


SystemRootHelper的内容
    public boolean a(String arg5) {//root操作
      boolean v0 = false;
      if(this.b.b(DeviceStateManagerEx.a("Root"), Base64.decode(arg5, 0)) == 0) {//DeviceStateManagerEx.a("Root")映射一个数字 arg5是输入密码后服务器返回的值
            v0 = true;
      }

      return v0;
    }
    public boolean b(String arg5) {   //uroot操作这个调用没有公开
      boolean v0 = false;
      if(this.b.b(DeviceStateManagerEx.a("Unroot"), Base64.decode(arg5, 0)) == 0) {
            v0 = true;
      }

      return v0;
    }

    public int b(int arg8, byte[] arg9) {
      int v0 = -1;
      try {
            Object v1_1 = a.a(this.b, "doCommand", new Class[]{Integer.TYPE, byte[].class}, new Object[]{Integer.valueOf(arg8), arg9});//执行服务命令doCommand
            if(v1_1 == null) {
                return v0;
            }

            v0 = Integer.parseInt(v1_1.toString());
      }
      catch(Exception v1) {
            v1.printStackTrace();
      }

      return v0;
    }
    public DeviceStateManagerEx(Context arg2) {
      super();
      this.b = arg2.getSystemService("device_states"); //使用了device_states的服务
    }


找到系统服务下面是services.jar的内容


static {
      System.loadLibrary("android_servers");
    }
    private native int nativeDoCheckState(int arg1) {
    }

    private native int nativeDoCommand(int arg1, byte[] arg2) {   //这就是我们找的 实现在libandroid_servers.so 里面
    }

    private native int nativeDoGetInitNo(int arg1, byte[] arg2) {
    }

    private native int nativeLockRecoveryUnchecked() {
    }

    private native int nativeLockRecoveryUncheckedByHandle(int arg1) {
    }



为了使用ida6.8的反编译 这里选用了lib里面的32bit的libandroid_servers.so

signed int __fastcall android::nativeDoCommandRoot(int *a1, int a2, int a3, int a4)
{
int v4; // r8@1
int v5; // r6@1
int *v6; // r4@1
int v7; // ST00_4@1
int v8; // r10@1
int v9; // r8@1
signed int result; // r0@3
int v11; // r0@6
__int32 v12; // r0@8
int v13; // ST00_4@8
int v14; // r7@8
char v15; // @1
char v16; // @1
int v17; // @1

v4 = a4;
v5 = a3;
v6 = a1;
v17 = _stack_chk_guard;
j_j_memset(&v15, 0, 0x400u);
j_j_memset(&v16, 0, 0x400u);
j_j_memset(v15, 0, 0x64u);
v7 = *v6;
j_j___android_log_print(4, "DeviceStateService", "Native: nativeDoCommand env=%x,*env=%x, handle=%d.", v6);
v8 = sub_1A984((int)v6);
v9 = sub_10768(v6, v4);
if ( v5 == 1 || v5 == 2 )
{
    v11 = 0;
    do
    {
      *(_DWORD *)&v15 = 1515870810;
      v11 += 4;
    }
    while ( v11 != 64 );
    *(_DWORD *)&v15 = j_j_j__ZN7android20get_platform_versionEv((android *)0x40);
    *(_DWORD *)&v15 = v5;
    j_j___memcpy_chk(&v15, v8, v9, 1024);
    j_j_memcpy(&v15, v15, 0x64u);
    v12 = j_j_syscall(0xF0067, 16, 2, &v15, &v16, v5);//关键系统函数调用 sysno=0xF0067
    v13 = *v6;
    v14 = v12 | (v12 >> 31);
    j_j___android_log_print(
      4,
      "DeviceStateService",
      "Native: nativeDoCommandRoot env=%x,*env=%x, handle=%d, rtx.enable:%d,result:%d.",
      v6);
    result = v14;
}
else
{
    result = -2;
}
if ( v17 != _stack_chk_guard )
    j_j___stack_chk_fail(result);
return result;
}

可以看到这个sysno很大 这里面肯定有猫腻

3.内核浅析
本人参考了以下链接提取了内核 不同的是这是x64的内核
http://www.blogbus.com/riusksk-logs/272240986.html
http://bbs.pediy.com/showthread.php?t=194803

ida6.8对64位的arm代码支持的不是很好(6.9可以完美支持),这里需要注意的是, 内核载入ida后由于不是完美支持,导致分析不出来。

可载入时先处理器改成ARM ,再将基址改为ffffffc000080000,调节段的大小为64位(如下图),全选后再次分析即可反汇编成功


按照链接中的方法提取符号,生成idc执行来给函数命名



定位到el0_svc
:FFFFFFC000084480 el0_svc                                 ; CODE XREF: ROM:FFFFFFC000083F68j
ROM:FFFFFFC000084480               ADRP            X27, #0xFFFFFFC000DEB000
ROM:FFFFFFC000084484               MOV             W26, W8
ROM:FFFFFFC000084488               MOV             X25, #0x116 ;最大的sysno
ROM:FFFFFFC00008448C
ROM:FFFFFFC00008448C el0_svc_naked                           ; CODE XREF: ROM:FFFFFFC000084080j
ROM:FFFFFFC00008448C               STP             X0, X26,
ROM:FFFFFFC000084490               MRS             X16, #0, c0, c2, #2
ROM:FFFFFFC000084494               AND             X16, X16, #0xFFFFFFFFFFFFFFFE
ROM:FFFFFFC000084498               MSR             #0, c0, c2, #2, X16
ROM:FFFFFFC00008449C               ISB
ROM:FFFFFFC0000844A0               MSR             #7, #8
ROM:FFFFFFC0000844A4               MSR             #7, #2
ROM:FFFFFFC0000844A8               MOV             X28, SP
ROM:FFFFFFC0000844AC               AND             X28, X28, #0xFFFFFFFFFFFFC000
ROM:FFFFFFC0000844B0               LDR             X16,
ROM:FFFFFFC0000844B4               TST             X16, #0xF00
ROM:FFFFFFC0000844B8               B.NE            __sys_trace
ROM:FFFFFFC0000844BC               ADR             X30, ret_fast_syscall
ROM:FFFFFFC0000844C0               CMP             X26, X25 ; switch 0 cases;比较大小
ROM:FFFFFFC0000844C4               B.CS            ni_sys; jumptable 000044CC default case;超出范围调用ni_sys()
ROM:FFFFFFC0000844C8               LDR             X16,
ROM:FFFFFFC0000844CC               BR            X16   ; switch jump

继续往下跟踪
:FFFFFFC00008FF14 compat_arm_syscall                      ; CODE XREF: ROM:FFFFFFC000089238p
ROM:FFFFFFC00008FF14
ROM:FFFFFFC00008FF14 var_20          = -0x20
ROM:FFFFFFC00008FF14 var_10          = -0x10
ROM:FFFFFFC00008FF14 var_s0          =0
ROM:FFFFFFC00008FF14
ROM:FFFFFFC00008FF14               STP             X29, X30, !
ROM:FFFFFFC00008FF18               MOV             X3, X0
ROM:FFFFFFC00008FF1C               MOV             W0, #0x67
ROM:FFFFFFC00008FF20               MOV             X29, SP
ROM:FFFFFFC00008FF24               STP             X19, X20,
ROM:FFFFFFC00008FF28               STP             X21, X22,
ROM:FFFFFFC00008FF2C               MOVK            W0, #0xF,LSL#16
ROM:FFFFFFC00008FF30               LDR             X1,
ROM:FFFFFFC00008FF34               CMP             W1, W0    ;sysno是否为0xf0067 是的话就调用do_private_entry()
ROM:FFFFFFC00008FF38               B.NE            loc_FFFFFFC00008FF64
ROM:FFFFFFC00008FF3C               LDR             W0,
ROM:FFFFFFC00008FF40               LDR             W1,
ROM:FFFFFFC00008FF44               LDR             X2,
ROM:FFFFFFC00008FF48               LDR             X3,
ROM:FFFFFFC00008FF4C               BL            do_private_entry
ROM:FFFFFFC00008FF50               SBFM            X0, X0, #0, #0x1F
ROM:FFFFFFC00008FF54
ROM:FFFFFFC00008FF54 loc_FFFFFFC00008FF54                  ; CODE XREF: compat_arm_syscall+E0j
ROM:FFFFFFC00008FF54                                       ; compat_arm_syscall+E8j ...
ROM:FFFFFFC00008FF54               LDP             X19, X20,
ROM:FFFFFFC00008FF58               LDP             X21, X22,
ROM:FFFFFFC00008FF5C               LDP             X29, X30, ,#0x30
ROM:FFFFFFC00008FF60               RET
接下来是验证数据内容,并对mmc进行写操作
4.结语
由于本人能力有限和内核动态调试十分困难,只能找到大概的流程,但是内核是如何更改lu为su 并赋予s位的过程还不是十分清楚,欢迎大牛一起分析。


月下孤影01 发表于 2016-11-10 06:00

支持下楼主,因为本人用的就是魅族pro5,去手机店的时候随便问问过老板,几个都说无法刷机的,好像貌似这个魅族的root权限与Flyme锁做的好像相比同类稍微牛一点……

qtfreet00 发表于 2016-10-7 17:58

对这些不懂,@Hmily 你评个分吧

IT_K 发表于 2016-10-7 19:06

支持一波!!!!!!1

yege0201 发表于 2016-10-7 21:38

无论结果如何都要支持LZ

xiumao 发表于 2016-10-8 12:43

Loopher 发表于 2016-10-8 19:50

我也有点好奇,楼主在哪里弄的这个东东~不明觉厉

Kali-J 发表于 2016-10-8 23:03

毕设就是要做安卓内核的动态动态调试分析的。一起探讨

__star__ 发表于 2016-10-11 10:42

文章思路很不错,值得进一步挖掘su怎么利用{:17_1062:}

dxdeng 发表于 2016-10-11 14:30

学习了,不过好多不懂

freebuf 发表于 2016-10-15 19:05

支持 还在学习中。
页: [1] 2
查看完整版本: 记一次对flyme自带root的功能的逆向