好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 wmsuper 于 2016-9-26 16:47 编辑
1.前言
flyme一般都自带开放系统权限的功能,输入用户密码后就可以执行root功能 root后的手机会把/system/xbin/lu 改为su 并赋予S位(讨论的是flyme5.1.8.0A 下同)
2.应用层分析
找到设置的apk,Settings.apk没混淆,很容易定位关键函数
[Java] 纯文本查看 复制代码 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
}
}
[Java] 纯文本查看 复制代码 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 的内容:
[XML] 纯文本查看 复制代码 //查看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的内容
[Java] 纯文本查看 复制代码
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的内容
[Java] 纯文本查看 复制代码
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
[C] 纯文本查看 复制代码
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[1124]; // [sp+10h] [bp-64h]@1
char v16; // [sp+474h] [bp+400h]@1
int v17; // [sp+874h] [bp+800h]@1
v4 = a4;
v5 = a3;
v6 = a1;
v17 = _stack_chk_guard;
j_j_memset(&v15[100], 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[v11] = 1515870810;
v11 += 4;
}
while ( v11 != 64 );
*(_DWORD *)&v15[64] = j_j_j__ZN7android20get_platform_versionEv((android *)0x40);
*(_DWORD *)&v15[68] = v5;
j_j___memcpy_chk(&v15[100], v8, v9, 1024);
j_j_memcpy(&v15[v9 + 100], v15, 0x64u);
v12 = j_j_syscall(0xF0067, 16, 2, &v15[100], &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
[Asm] 纯文本查看 复制代码 :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, [SP,#0x110]
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, [X28]
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, [X27,X26,LSL#3]
ROM:FFFFFFC0000844CC BR X16 ; switch jump
继续往下跟踪
[Asm] 纯文本查看 复制代码 :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, [SP,#-0x10+var_20]!
ROM:FFFFFFC00008FF18 MOV X3, X0
ROM:FFFFFFC00008FF1C MOV W0, #0x67
ROM:FFFFFFC00008FF20 MOV X29, SP
ROM:FFFFFFC00008FF24 STP X19, X20, [SP,#0x20+var_10]
ROM:FFFFFFC00008FF28 STP X21, X22, [SP,#0x20+var_s0]
ROM:FFFFFFC00008FF2C MOVK W0, #0xF,LSL#16
ROM:FFFFFFC00008FF30 LDR X1, [X3,#0x38]
ROM:FFFFFFC00008FF34 CMP W1, W0 ;sysno是否为0xf0067 是的话就调用do_private_entry()
ROM:FFFFFFC00008FF38 B.NE loc_FFFFFFC00008FF64
ROM:FFFFFFC00008FF3C LDR W0, [X3]
ROM:FFFFFFC00008FF40 LDR W1, [X3,#8]
ROM:FFFFFFC00008FF44 LDR X2, [X3,#0x10]
ROM:FFFFFFC00008FF48 LDR X3, [X3,#0x18]
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, [SP,#0x20+var_10]
ROM:FFFFFFC00008FF58 LDP X21, X22, [SP,#0x20+var_s0]
ROM:FFFFFFC00008FF5C LDP X29, X30, [SP+0x20+var_20],#0x30
ROM:FFFFFFC00008FF60 RET
接下来是验证数据内容,并对mmc进行写操作
4.结语
由于本人能力有限和内核动态调试十分困难,只能找到大概的流程,但是内核是如何更改lu为su 并赋予s位的过程还不是十分清楚,欢迎大牛一起分析。
|
免费评分
-
参与人数 6 | 威望 +1 |
吾爱币 +1 |
热心值 +6 |
收起
理由
|
i-ii
| |
+ 1 |
+ 1 |
谢谢@Thanks! |
lawlier
| |
|
+ 1 |
用心讨论,共获提升! |
灌汤包
| |
|
+ 1 |
我很赞同! |
昧光
| |
|
+ 1 |
鼓励转贴优秀软件安全工具和文档! |
yyhf
| |
|
+ 1 |
没有看到跟踪 do_private_entry的过程,猜测是厂商自行添加了一个系统调用. |
Hmily
| + 1 |
|
+ 1 |
感谢发布原创作品,吾爱破解论坛因你更精彩! |
查看全部评分
|