Android下的permission和gid

Android是在linux基础上构建的,权限的管理即要依赖apk中的permission,也要考虑和linux的uid/gid的方式结合。虽然很多操作可以在java层完成,但诸如设备文件的访问,又要回归到传统的uid/gid管理模式,比如设备文件

crw-rw---- bluetooth net_bt_stack 204,  68 2016-12-07 13:24 ttyAMA4

net_bt_stack组对设备文件是可以操作的,如果查看/system/etc/permissions/platform.xml

<permission name="android.permission.BLUETOOTH_ADMIN" >
    <group gid="net_bt_admin" />
</permission>

<permission name="android.permission.BLUETOOTH" >
    <group gid="net_bt" />
</permission>

<permission name="android.permission.BLUETOOTH_STACK" >
    <group gid="net_bt_stack" />
</permission>

<permission name="android.permission.NET_TUNNELING" >
    <group gid="vpn" />
</permission>

<permission name="android.permission.INTERNET" >
    <group gid="inet" />
</permission>

<permission name="android.permission.READ_LOGS" >
    <group gid="log" />
</permission>

<permission name="android.permission.WRITE_MEDIA_STORAGE" >
    <group gid="media_rw" />
    <group gid="sdcard_rw" />
</permission>
...

可以看到,如果apk申请了android.permission.BLUETOOTH_STACK权限,它的进程将具备linux的uid/gid管理体系下的net_bt_stack组权限

运行该apk,然后查看/proc/pid/status,Groups中也直接阐明了这一点

State:  S (sleeping)
Tgid:   13412
Pid:    13412
PPid:   15316
TracerPid:      0
Uid:    10135   10135   10135   10135
Gid:    10135   10135   10135   10135
FDSize: 64
Groups: 3001 3002 3008 9997 50135

但这并不意味着,直接su app_id得到的shell具备该gid。Android下的su并不是基于/etc/passwd等文件实现的完整权限切换,仅保留了uid的信息。不过Android提供的run-as可以完整切换权限,得到具备该gid的shell

osx下编译android内核

如果是在linux系统下编译android的内核,基本不会有什么大的问题,但osx就稍微顽皮一些。

以nexus 5的内核编译为例,首先下载编译内核用的arm-eabi-gcc工具:

git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/

然后下载内核源代码

git clone https://android.googlesource.com/kernel/msm.git

之后切换代码到需要的branch

$ cd msm/
$ git branch -a

  * master
    remotes/origin/HEAD -> origin/master
    remotes/origin/android-msm-2.6.35
    remotes/origin/android-msm-3.9-usb-and-mmc-hacks
    remotes/origin/android-msm-flo-3.4-jb-mr2
    remotes/origin/android-msm-flo-3.4-kitkat-mr0
    remotes/origin/android-msm-flo-3.4-kitkat-mr1
    remotes/origin/android-msm-hammerhead-3.4-kitkat-mr1
...
$ git checkout origin/android-msm-hammerhead-3.4-kitkat-mr1

以上都是常规步骤,针对osx还有一些必须的改动:


增加两个头文件elf.h和features.h到内核源码的scripts/mod下面,头文件下载

修改scripts/mod/mk_elfconfig.c和scripts/mod/modpost.h两个文件,将<elf.h>改成 “elf.h”

将scripts/recordmcount.c中的<elf.h>修改为 “mod/elf.h”

修改kernel/timeconst.pl,将defined(@array)的修改为@array


最后再编译即可:

export ARCH=arm
export CC=arm-eabi-
export CROSS_COMPILE=arm-eabi-
make hammerhead_defconfig
make menuconfig
make -k

暴力破解Android锁屏口令

JellyBean开始,Android的锁屏口令以hash形式存放,口令通常是4位数字(对于多位复杂口令方法也是一样的),暴力破解完全可行

锁屏口令的hash存放在/data/system/password.key,形如

11 36 65 6D 5C 67 18 C1 DE FC 71 B4 31 B2 CB 56 52 A8 AD 55 0E 20 BD CF 52 B0 00 02 C8 DF 35 C9 63 B7 12 98

共72个字符,包含Sha1和MD5两个hash,参考Android源码

byte[] saltedPassword = (password + getSalt()).getBytes();

byte[] sha1 = MessageDigest.getInstance(algo = “SHA-1”).digest(saltedPassword);

byte[] md5 = MessageDigest.getInstance(algo = “MD5”).digest(saltedPassword);

hashed = (toHex(sha1) + toHex(md5)).getBytes();

前40位是Sha1,后32位是MD5,计算(口令+salt)得到hash

salt的存放位置为/data/system/locksettings.db,使用sqlite3打开数据库,输入

select value from locksettings where name='lockscreen.password_salt'

就得到形如3582477098377895419的salt值了,最后将其转化为小写的16进制64位整数31 b7 83 f0 b0 c9 5d fb

有了这些信息用就可以用hashcat跑了,用MD5部分(0E 20 BD CF 52 B0 00 02 C8 DF 35 C9 63 B7 12 98)爆破的指令为

cudaHashcat64.exe -m 10 0E20BDCF52B00002C8DF35C963B71298:31b783f0b0c95dfb -a 3 ?d?d?d?d

Android下的dropbear编译

dropbear是ssh的一个实现,包含了客户端和服务端以及相关的配置组件

Android下没有包含/etc/passwd等目录结构,并不能直接使用dropbear建立ssh服务

修改及编译过程如下:

安装交叉编译环境

下载0.52版的dropbear

  • 下载dropbear0.52-android.patch到源码上层目录
  • 切换到dropbear的目录执行:
  • patch < ../dropbear0.52-android.patch

准备编译

./configure --host=arm-none-linux-gnueabi 
--disable-zlib 
--disable-largefile 
--disable-loginfunc 
--disable-shadow 
--disable-utmp 
--disable-utmpx 
--disable-wtmp 
--disable-wtmpx 
--disable-pututline 
--disable-pututxline 
--disable-lastlog 
CC=arm-none-linux-gnueabi-gcc
export STATIC=1 MULTI=0 CC=arm-none-linux-gnueabi-gcc SCPPROGRESS=0 PROGRAMS="dropbear dropbearkey scp dbclient"
make strip

生成的dropbear可以理解为就是sshddbclient就是ssh
建立ssh服务

dropbearkey -t rsa -f /system/etc/dropbear/dropbear_rsa_host_key
dropbearkey -t dss -f /system/etc/dropbear/dropbear_dss_host_key
dropbear -A -N <username> -C <password> -E

Android系统下的SUID标记

Android内核基于linux内核开发,但一些安全访问限制有所不同。

如果是Linux系统,可执行文件设置了suid标记,则该程序运行时可以拥有创建者的euid,比如自己编写的一个idpie程序

$ ls -l /system/bin/idpie
-rwsr-xr-x root	shell	651379 2013-10-30 15:21 idpie

这个程序运行时会显示自己的uid和euid,然后尝试利用setuid,seteuid等提权,再输出提权后的uid和euid

$ idpie
uid:2000,euid:0
uid:0,euid:0

目前来看,Android和Linux的情况相同,但Android系统下如果将这个程序放到/data/local/tmp目录执行,执行结果:

$ /data/local/tmp/idpie
uid:2000,euid:2000

结论是:Android下,suid位并不是程序权限提升的唯一因素,程序所在目录也会限制,虽然没有全面测试,但至少/system/bin目录下的suid标记可以生效,/data/local/tmp目录下则不行

Update:

参考Ron的研究

suid程序不能放在nosuid挂载点的文件夹,否则无法获取相应的权限

$ cat /proc/mounts | grep nosuid 可以获取mount挂载文件夹到底支不支持suid

显然 /data 和 /cache 都不行

gdb on Android

临时需要分析一下android下一个so库的崩溃原因,因此需要一个调试环境。经典的方法是用NDK提供的环境实现,当然如果是做jni开发调试的话这个方法无可厚非,无可替代。但如果仅仅是对某个二进制的崩溃迹象进行轻量级分析的话,搞一套NDK就太劳民伤财了。原理上就是Android的gdbserver连接PC端gdb即可,折腾了一大圈,总算找到了编译好的binary,点击下载

Android端:

gdbserver :9999 yourprogram

PC端:

adb forward tcp:9990 tcp:9999

arm-linux-androideabi-gdb

(gdb) target remote:9999

Shake it baby~~

Android模拟器重启后不还原

Android自带的模拟器每次开启都会还原/system等文件系统解决方案很粗暴,但绝对有效~在sdk的目录下找到/sdk/platforms/android-X (比如我的虚拟机基于android 2.1,X取值为7) 这个目录下面的system.img和ramdisk.img就是模拟器每次启动时加载的文件系统了。只要解压他们,按意愿修改再打包,替换原有的文件就OK了


system.img
需要用到mkyaffs2image.exe和unyaffs.exe,用于打包和解包,需要在cygwin环境下使用,可以在这里下载


ramdisk.img
这个稍微麻烦一些,同样我是在cygwin下进行的操作
将ramdisk.img复制到/tmp目录,重命名为ramdisk.img.gz

gunzip ramdisk.img.gz
mkdir ramdisk
cd ramdisk
cpio -i -F ../ramdisk.img

然后开始你想要进行的修改吧,修改完事儿后

cpio -i -t -F ../ramdisk.img > list
cpio -o -H newc -O temp.img > list
gzip -c temp.img < ../ramdisk.img

这样就在/tmp目录下面生成了打包好的ramdisk.img了,替换回去即可

Android内核源码下载

今天下午抽了会儿疯把电脑清理了一遍,删掉了之前的android源码和内核源码。不过事后想想,万一想编译个驱动啥的还是得用,就又切到linux下面开始下载android内核源码(tegra)。

下载的教程按照官方的走就行,

git clone https://android.googlesource.com/kernel/tegra.git

可惜速度是要多慢有多慢,估计又是伟大的GFW在作祟,还好教育网内有些不是特敏感的内容用ipv6都能很好的绕过。

做法就是找到android.googlesource.com的ipv6地址,添加到/etc/hosts,然后用Network manger关闭ipv4出口,仅保留ipv6就可以高速免流量的下载源码了。

具体操作如下:

windows cmd下输入:

nslookup -qt=aaaa android.googlesource.com 2001:470:20::2

-qt用于指定查询类型(a,mx,ns…)

2001:470:20::2 是一个公益组织的dns服务器,仅返回被查域名的ipv6地址

比如我查询结果:2404:6800:4005:c00::52

切回linux,添加到/etc/hosts

2404:6800:4005:c00::52 android.googlesource.com

以此类推,将cache.pack.google.com,www.googlesource.com也添加到hosts中

然后使用Network manager关闭ipv4通道

再git clone就能以4-5M的速度下载内核源码了~ enjoy

Android kernel编译与刷机

RT3070的驱动在交叉编译时发现过程十分纠结,且网上说法不一,但辗转反侧折腾中发现了新的契机。原来Nexus 7的3.1.10内核本身就支持Ralink RT3070,只需要开启后编译产生新内核刷入Nexus 7就可以了,至于能不能让网卡支持混杂模式还有待测试。
编译内核比编译Android本身还容易,源码量小,对系统要求也比较低。参考[这里]下载编译内核有关代码
接下来为了编译内核,需要从Nexus 7下面把/proc/config.gz拽回来,并且解压得到.config放到kernel代码的根目录
cat config.gz | gunzip >.config
直接用git下载回来的Nexus 内核源码里面只有一个.git文件夹,需要使用git checkout才能将特定版本的源码解包释放。版本的选择可以参考下设备上的内核版本标注。比如我的为3.1.10-g009b6d1,就可以使用
git checkout 009b6d1
 
来释放对应版本的内核代码。然后 make menuconfig 可以调整内核模块,开启上述模块
make ARCH=arm CROSS_COMPILE=arm-eabi- menuconfig 
 
Networking support –> Wireless
[*] Generic IEEE 802.11 Networking Stack (mac80211) 
// 只有开启这个选项才能看到RT3070的驱动模块
device drivers –>
network device support ->
wireless lan –>
ralink driver support
 
最后make一下就产生了zImage在arch/arm/boot/下面
接下来需要把这个zImage打包成boot.img然后刷入Nexus 7中
打包方法可以参看[这里] ,所需的解压包工具从[这里]下载
 
我的做法是用Nexus 7 toolkit把系统的boot.img提取,然后用unpackbootimg解包,然后把我的zImage和ramdisk重新打包成成boot.img,就能够刷入系统了。刷入的方法就是用
fastboot flash boot boot.img
 
推荐在做一切前hack工作前,用Nexus-7-toolkit先备份好,fastboot,adb这类工具toolkit里面也提供了

Jelly Bean 编译

由于需要移植RT3070的驱动到Nexus 7,因此Android的源码是必须要有的。为了保证源码的正确性,就先把Android编译出来练练手吧。主要过程看[这里]

我是在LiveUSB模式的Backtrack 5 r3 (ubuntu 10.0.4) 下面进行的代码下载和编译,代码都放在了mount过来的Windows分区(NTFS)下面。

整体思路和参考链接相同,但由于是在mount过来的分区上搞,所以PATH环境变量的设置要有所区别。

再来就是需要sun-java6-jdk安装到位,具体方法:

###############

gedit /ect/apt/sources.list 

添加一行: deb http://us.archive.ubuntu.com/ubuntu/ hardy multiverse

apt-get update

apt-get install sun-java6-jdk 

############### 

另一点就是repo工具的下载,在不同城市测试了一下,原文链接已经被墙了。如果是教育网用ipv6就能绕过这个微墙。否则就在windows下先用代理下载好。repo实际上就是一段python代码。

使用repo下载全部JellyBean过程特别慢,花了有两三天吧,经常有错误产生,可能是dns导致的。如果你也遇到可以考虑修改host文件:

#########

gedit /etc/hosts

然后把 android.googlesource.com 和 googlesource.com 先用 nslookup 查好ip地址添加进来。

#########

这样可以减少代码下载中的DNS请求数量

至于编译的话只要按照参考链接的步骤来就没什么问题。虽然在这个过程中遇到了很多错误,但后来发现归根结底都是系统配置不够导致的。下面几点是容易被忽略的, 但却是编译过程所必须的~

需要64位的主机配64位的操作系统来进行编译

增加swap分区,Backtrack 默认不带,增加方法:

mount 一个windows分区过来,最好和代码存放的分区不同,然后增加一个swap文件就可以了比如windows分区mount到了/media/D

##########

dd if=/dev/zero of=/media/D/swapfile bs=1024 count=4096k   #这样就增加了一个4G的swap文件

mkswap /media/D/swapfile #格式化这个文件

swapon /media/D/swapfile #开启swap

swapon -S #用于查看swap是否已经被正确开启

##########

我的电脑是intel i7 8核的,内存4G 但为了保证编译过程中不至于卡死,使用了 make -j4 命令进行编译 (只用4个核免得系统太忙碌),如此这般,system.img就会被编译出来了