1
root思路
2
获取原系统镜像文件
3
获取recovery模式下的root权限
buildscript { repositories { mavenCentral() } ...}
buildscript { repositories { maven { setUrl("http://maven.aliyun.com/nexus/content/groups/public/") } mavenCentral() } ...}
adb reboot bootloaderfastboot flash --disable-verity --disable-verification vbmeta vbmeta.img.signedfastboot flash boot boot.img.signedfastboot reboot recovery
4
在recovery模式下修改system文件的方式
#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <errno.h> #define BLOCK_SIZE 4096#define LISTEN_PORT 4096 typedef enum { READ, SEEK, WRITE, TELL, OPEN, CLOSE} foperate; typedef struct { foperate op; u_int64_t arg;} fcommand; int recv_all(int sock_fd, u_char* buffer, uint64_t size) { uint64_t recved_size = 0, recv_size; while (recved_size < size) { recv_size = recv(sock_fd, buffer + recved_size, size, MSG_WAITALL); if(recv_size <= 0) { break; } else { recved_size += recv_size; } } return recved_size;} int send_all(int sock_fd, u_char* buffer, uint64_t size) { uint64_t sended_size = 0, send_size; while (sended_size < size) { send_size = send(sock_fd, buffer + sended_size, size, MSG_WAITALL); if(send_size <= 0) { break; } else { sended_size += send_size; } } return sended_size;} int main(int argc, const char**argv) { int super_fd, sock_fd, client_addr_size, conn_fd, shutdown; uint64_t transfered_size, transfer_size; struct sockaddr_in listen_addr, client_addr; u_char* buffer; fcommand command; buffer = (u_char*)malloc(BLOCK_SIZE); super_fd = open("/dev/block/by-name/super", O_RDWR | O_SYNC); sock_fd = socket(PF_INET, SOCK_STREAM, 0); memset(&listen_addr, 0, sizeof(listen_addr)); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); listen_addr.sin_port = htons(LISTEN_PORT); bind(sock_fd, (struct sockaddr*)&listen_addr, sizeof(listen_addr)); listen(sock_fd, 2); while (1) { client_addr_size = sizeof(client_addr); conn_fd = accept(sock_fd, (struct sockaddr *)&client_addr, &client_addr_size); shutdown = 0; while (1) { if(recv_all(conn_fd, &command.op, 4) != 4) { close(conn_fd); break; }; if(recv_all(conn_fd, &command.arg, 8) != 8) { close(conn_fd); break; }; switch (command.op) { case READ: transfered_size = 0; while (transfered_size < command.arg) { transfer_size = command.arg - transfered_size > BLOCK_SIZE ? BLOCK_SIZE : command.arg - transfered_size; read(super_fd, buffer, transfer_size); if(send_all(conn_fd, buffer, transfer_size) != transfer_size) { shutdown = 1; break; } transfered_size += transfer_size; } break; case SEEK: lseek64(super_fd, command.arg, SEEK_SET); break; case WRITE: transfered_size = 0; while (transfered_size < command.arg) { transfer_size = command.arg - transfered_size > BLOCK_SIZE ? BLOCK_SIZE : command.arg - transfered_size; if(recv_all(conn_fd, buffer, transfer_size) != transfer_size) { shutdown = 1; break; } write(super_fd, buffer, transfer_size); transfered_size += transfer_size; } break; case TELL: command.arg = lseek64(super_fd, 0, SEEK_CUR); if(send_all(conn_fd, &command.arg, 8) != 8) { shutdown = 1; }; break; case OPEN: if(recv_all(conn_fd, buffer, command.arg) != command.arg) { shutdown = 1; break; }; buffer[command.arg] = 0; close(super_fd); super_fd = open(buffer, O_RDWR | O_SYNC); break; case CLOSE: shutdown = 1; break; } if(shutdown) { close(conn_fd); break; } } }}
from pwn import *import ext4 class RemoteStream: def __init__(self) -> None: self.remote = remote('127.0.0.1', 4096) def read(self, size) -> bytes: self.remote.send(p32(0) + p64(size)) return self.remote.recvn(size) def seek(self, offset, whence): self.remote.send(p32(1) + p64(offset)) def write(self, data): self.remote.send(p32(2) + p64(len(data))) self.remote.send(data) def tell(self) -> int: self.remote.send(p32(3) + p64(0)) return u64(self.remote.recvn(8)) def open(self, path): self.remote.send(p32(4) + p64(len(path))) self.remote.send(path) def flush(self): pass rfs = RemoteStream()system = ext4.Volume(rfs, offset=1024*1024)ext4.Tools.list_dir(system, system.root)
rfs = RemoteStream()system = ext4.Volume(rfs, offset=1024*1024)targetfile = system.root.get_inode("path", "to", "file").open_read()targetdata = open('editedfile', 'rb').read() # 本地读取修改后的数据# 因为是在文件系统上直接覆写文件,修改后的文件大小一定要和原文件相同targetfile.rewrite(targetdata)
5
获取root权限
MOV X0, #1RET
import ext4img = open("apex_payload.img", "rb+")imgfs = ext4.Volume(img, offset=0)target_adbd = imgfs.root.get_inode("bin", "adbd").open_read()target_adbd.rewrite(open("adbd", "rb").read())
import zlibfrom pwn import *apex = bytearray(open("com.android.adbd.apex", "rb").read())org_img = open("apex_payload.img.bak", "rb").read()org_crc = p32(zlib.crc32(org_img))new_img = open("apex_payload.img", "rb").read()new_crc = p32(zlib.crc32(new_img))apex = apex.replace(org_img, new_img)apex = apex.replace(org_crc, new_crc)open("com.android.adbd.apex.new", "wb").write(apex)
rfs = RemoteStream()system = ext4.Volume(rfs, offset=1024*1024)apex = system.root.get_inode("system", "apex", "com.android.adbd.apex").open_read()apex.rewrite(open("com.android.adbd.apex.new", "rb").read())
之后问题是对u:r:su:s0制限解除的策略代码要怎么写,首先要找一些参考资料。aosp中完整的sepolicy策略项目在https://android.googlesource.com/platform/system/sepolicy ,在该项目目录下可以找到prebuilts/api/系统api版本/public/su.te,此文件中将dontaudit改为allow后就是我们需要的制限解除代码。
类别的属性集定义在system/sepolicy/prebuilts/api/系统api版本/private/access_vectors,有了这两个文件就可以进行手动展开。比如:
allow su self:capability_class_set *;
allow su self:capability *;allow su self:capability2 *;allow su self:cap_userns *;allow su self:cap2_userns *;
common cap{ chown dac_override ...}class capabilityinherits cap
; allow su self:capability_class_set *;(allow su self (capability (chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap)))(allow su self (capability2 (mac_override mac_admin syslog wake_alarm block_suspend audit_read)))(allow su self (cap_userns (chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap)))(allow su self (cap2_userns (mac_override mac_admin syslog wake_alarm block_suspend audit_read)))
import ext4from pwn import *class RemoteStream: def __init__(self) -> None: self.remote = remote('127.0.0.1', 4096) def read(self, size) -> bytes: self.remote.send(p32(0) + p64(size)) return self.remote.recvn(size) def seek(self, offset, whence): self.remote.send(p32(1) + p64(offset)) def write(self, data): self.remote.send(p32(2) + p64(len(data))) self.remote.send(data) def tell(self) -> int: self.remote.send(p32(3) + p64(0)) return u64(self.remote.recvn(8)) def open(self, path): self.remote.send(p32(4) + p64(len(path))) self.remote.send(path) def flush(self): pass def zipcil(): orgcil = open('plat_sepolicy.cil').readlines() newcil = [] for line in orgcil: line = line.strip() if line.startswith(';'): pass elif len(line): newcil.append(line.encode('latin-1')) open('plat_sepolicy_ziped.cil', 'wb').write(b'\n'.join(newcil)) def build_newcil(): oldlen = len(open('plat_sepolicy.cil').read()) sepolicy = open('plat_sepolicy_ziped.cil').read() typeattributes = open('typeattribute.txt').readlines() for line in typeattributes: attr_name = line.strip().split(' ')[-1] pre = "typeattributeset " + attr_name + " (" end = ")" start = sepolicy.find(pre) + len(pre) end = sepolicy.find(end, start) if start == len(pre)-1: sepolicy = sepolicy + '\n(typeattributeset ' + attr_name + " (su))" else: groups = sepolicy[start:end].split(' ') if 'su' not in groups: sepolicy = sepolicy[:start] + 'su ' + sepolicy[start:] payload = open('su.cil').read() sepolicy = sepolicy + '\n' + payload + '\n;' sepolicy += ' '*(oldlen - len(sepolicy)) open('plat_sepolicy_patched.cil', 'wb').write(sepolicy.encode('latin-1')) def rwrite(): s = RemoteStream() system = ext4.Volume(s, offset=1024*1024) sepolicy = system.root.get_inode("system", "etc", "selinux", "plat_sepolicy.cil").open_read() sepolicy.rewrite(open('plat_sepolicy_patched.cil', 'rb').read())zipcil()build_newcil()rwrite()
6
将system挂载为可写
from pwn import *#省略 class RemoteStreamrfs = RemoteStream()rfs.seek(1024*1024 + 0x400 + 0x64)s_feature_ro_compat = u32(rfs.read(4))if s_feature_ro_compat & 0x4000: s_feature_ro_compat = s_feature_ro_compat ^ 0x4000rfs.seek(1024*1024 + 0x400 + 0x64)rfs.write(p32(s_feature_ro_compat))
7
安装frida-gadget
见: https://bbs.pediy.com/thread-266785.htm
END
看雪ID:tacesrever
https://bbs.pediy.com/user-home-888604.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!