您的位置:首页 > 移动开发 > Android开发

Android中使用"hacker"方式解决ServiceManager的权限限制问题(1)

2016-08-02 10:59 519 查看

缘由

有一个系统,需要我们的解决方案,但是却没有提供BSP的源码。

我们的方案有一个So文件,并在其中有注册service,但是启动后发现service并没有注册成功,查询log发现是:

<span style="font-family:Microsoft YaHei;font-size:18px;">E/ServiceManager﹕ add_service('XXXX',0x48) uid=YYY - PERMISSION DENIED</span>
看起来是我们不具备权限,然后确定了一下SElinux的状态,发现是没有开启的,而servicemanager对添加service的权限的检查是位于其代码中的。

关于ServiceManager是如何检查权限的可以参考一下stackoverflow中的答案,或者自己看看servicemanager的源码。

参考的链接为这个,从这里面我们可以得知权限的检查写死在了对应的source code中(Android 4.4),暂时没有配置文件,这个和SeLinux不一样。

判断逻辑

ServiceManager的判断逻辑为:

1. uid判断是否为system
2. 是否在可信任的表格中

如果两个都不是,那么就认为没有权限,然后打印出前面的话来。这个对应的代码为:

int svc_can_register(unsigned uid, uint16_t *name)
{
unsigned n;

if ((uid == 0) || (uid == AID_SYSTEM))
return 1;

for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
if ((uid == allowed
.uid) && str16eq(name, allowed
.name))
return 1;

return 0;
}
另外这个allowed的数组为:

/* TODO:
* These should come from a config file or perhaps be
* based on some namespace rules of some sort (media
* uid can register media.*, etc)
*/
static struct {
unsigned uid;
const char *name;
} allowed[] = {
{ AID_MEDIA, "media.audio_flinger" },
{ AID_MEDIA, "media.log" },
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
{ AID_MEDIA, "media.audio_policy" },
{ AID_DRM,   "drm.drmManager" },
{ AID_NFC,   "nfc" },
{ AID_BLUETOOTH, "bluetooth" },
{ AID_RADIO, "radio.phone" },
{ AID_RADIO, "radio.sms" },
{ AID_RADIO, "radio.phonesubinfo" },
{ AID_RADIO, "radio.simphonebook" },
/* TODO: remove after phone services are updated: */
{ AID_RADIO, "phone" },
{ AID_RADIO, "sip" },
{ AID_RADIO, "isms" },
{ AID_RADIO, "iphonesubinfo" },
{ AID_RADIO, "simphonebook" },
{ AID_MEDIA, "common_time.clock" },
{ AID_MEDIA, "common_time.config" },
{ AID_KEYSTORE, "android.security.keystore" },
};


从里面的注释可以看出,以后这个可能会变成使用通配符方式,或者是配置文件的方式,但是现在还是直接写死了。

如果要让我们的service可以成功注册,那么可以:

直接将前面的return 0改成return 1即可
将我们的service添加到allowed数组中

我们先使用第一种方式来完成。

反汇编完成

获取servicemanager elf文件

这个非常容易,直接adb pull即可,这个servicemanager位于/system/bin下面。

定位需要更改的位置

我们使用反汇编工具,加载这个ELF文件,然后根据前面的log提示,搜索这个位置即可:



然后jump进去:



然后其伪代码为:

signed int __fastcall sub_87C(int a1, void *a2, unsigned int a3, int a4, int a5, int a6)
{
int v6; // r9@1
void *v7; // r7@1
int v8; // r6@1
int v9; // r5@1
_BYTE *v10; // r3@5
const char *v11; // r1@5
const char *v12; // r2@5
int v13; // r0@6
int v14; // r4@6
_BYTE *v15; // r0@8
void *v16; // r0@10
int v17; // r2@13
int v19; // [sp+0h] [bp-28h]@5
int v20; // [sp+4h] [bp-24h]@5

v6 = a1;
v7 = a2;
v8 = a3;
v9 = a4;
if ( !a4 || !a3 || a3 > 0x7F )
return -1;
if ( sub_7D4(a5, (int)a2) )
{
v13 = sub_80C(v7, v8);
v14 = v13;
if ( v13 )
{
if ( *(_DWORD *)(v13 + 4) )
{
v15 = sub_73C((int)v7);
_android_log_print(
6,
"ServiceManager",
"add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
v15,
v9,
a5);
sub_774(v6, v14);
}
*(_DWORD *)(v14 + 4) = v9;
}
else
{
v16 = malloc(2 * (v8 + 13));
v14 = (int)v16;
if ( !v16 )
{
v19 = v9;
v20 = a5;
v10 = sub_73C((int)v7);
v11 = "ServiceManager";
v12 = "add_service('%s',%p) uid=%d - OUT OF MEMORY\n";
goto LABEL_12;
}
*((_DWORD *)v16 + 5) = v8;
*((_DWORD *)v16 + 1) = v9;
memcpy((char *)v16 + 24, v7, 2 * (v8 + 1));
*(_WORD *)(v14 + 2 * (v8 + 12)) = 0;
v17 = dword_30B8;
*(_DWORD *)(v14 + 8) = sub_774;
*(_DWORD *)(v14 + 12) = v14;
*(_DWORD *)(v14 + 16) = a6;
*(_DWORD *)v14 = v17;
dword_30B8 = v14;
}
sub_CFC(v6, v9);
sub_D2C(v6, v9, v14 + 8);
return 0;
}
v10 = sub_73C((int)v7);
v19 = v9;
v20 = a5;
v11 = "ServiceManager";
v12 = "add_service('%s',%p) uid=%d - PERMISSION DENIED\n";
LABEL_12:
_android_log_print(6, v11, v12, v10, v19, v20);
return -1;
}


根据if判断,知道我们需要到sub_7D4中修改
我们先在function/symbol list中找到这symbol:



然后再jump过去:



框中就是我们前面提到的return 0,这个就是我们需要更改的位置。

其伪代码和前面的ServiceManager中的判断非常类似:



修改

在修改之前我们需要找到其对应instruction,这个在IDA Pro中非常容易,直接在hex view中sync对应的窗口过来即可:



在这里其对应对位置为:



因为ARM是小端模式,所以高低字节序相反,因此前面MOVS R0, 0对应的指令是0x2000。

指令说明

我们非常清楚根据APCS(arm procedure call standard), 此文档可以google或者baidu,也可以到我的资源中下载(http://download.csdn.net/detail/sy373466062/9592421), R0是作为返回值,因此直接改这一条就够了。

显然0x200是2个Byte,因此是Thumb指令,我们可以查询一下这个指令,然后将其改成MOVS R0, 1 

对此,我们参考Thumb指令的说明文档非常容易更改。

在Thumb指令文档中(下载地址:http://download.csdn.net/detail/sy373466062/9592423),可以看到:



从这个指令可以看出前面的Rd就是我们这里面的R0, 后面的offset8立即数,为0,我们这里需要改成1,因此,重新拼接一下就是:0x2001。 

关于指令的修改可以参考:

http://stackoverflow.com/questions/9279451/armv7-word-patch-cbnz

如果觉得要找这些比较麻烦,那么可以使用ARM ASM Converter软件来转换,直接在软件的底下输入指令,然后点击convert即可:



这个软件业给出了Thumb指令为2001,这个软件可以从我的资源下载(http://download.csdn.net/detail/sy373466062/9592450

修改

我们使用010Editor或者UE等一些软件来修改比较合适,例如在010Editor中找到对应的位置(0x800),然后直接更改即可:



修改完成后保存,为了确保我们修改正确,可以比较一下:



然后就可以push进去测试了。

测试

因为我们是add_service,因此可以先在log中看是否还有Permission Denied的提示,同时也可以使用下面的命令来查看我的service注册成功没有:

service list | grep XXX
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  IDA Pro ARM ServiceManager
相关文章推荐