(kernel) virt\_to\_phys
virt_to_phys
직접 호출하고 싶다면 kernel mode에서 실행해야 하기 때문에 LKM 등을 사용해야 하며, 어느 아키텍쳐든 최종 인터페이스로 다음 함수를 제공하기 때문에 이를 사용하는 편이 좋다.
1
static inline phys\_addr\_t virt\_to\_phys(volatile void \*address)
x86 ( not x86_64 )
http://elixir.free-electrons.com/linux/v4.13/source/arch/x86/mm/physaddr.c#L70
1
2
3
4
5
6
7
8
unsigned long \_\_phys\_addr(unsigned long x)
{
unsigned long phys\_addr = x - PAGE\_OFFSET;
....
return phys\_addr;
}
arm
기본적으로 다음과 같은 방식으로 동작한다. http://elixir.free-electrons.com/linux/v4.13/source/arch/arm/include/asm/memory.h#L255
1
2
3
4
static inline phys\_addr\_t \_\_virt\_to\_phys\_nodebug(unsigned long x)
{
return (phys\_addr\_t)x - PAGE\_OFFSET + PHYS\_OFFSET;
}
CONFIG\_ARM\_PATCH\_PHYS_VIRT
flag 있는 경우 define이 좀 달라진다. http://elixir.free-electrons.com/linux/v4.13/source/arch/arm/include/asm/memory.h#L223
PAGE_OFFSET
출력되는 주소는 virtual address다.
x86
1
2
/ # cat /boot/config-4.9.0-kali3-686-pae | grep PAGE\_OFFSET
CONFIG\_PAGE\_OFFSET=0xC0000000
arm (armv7)
1
2
/ $ zcat /proc/config.gz | grep PAGE
CONFIG\_PAGE\_OFFSET=0x80000000
get virtual symbol
2017/10/14 - [System/Exploit] - [kernel] get & hook sys_call_table / page protection
/proc/iomem : PHYS_OFFSET
virtual address로 변환하는 것은 아키텍쳐마다 다른데, virt\_to_phys()
를 반대로 수행하면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@kali32:/boot# cat /proc/iomem
00000000-00000fff : reserved
00001000-0009ebff : System RAM
0009ec00-0009ffff : reserved
000a0000-000bffff : PCI Bus 0000:00
000a0000-000bffff : Video RAM area
000c0000-000c7fff : Video ROM
000ca000-000cafff : Adapter ROM
000cc000-000cffff : PCI Bus 0000:00
......
000dc000-000fffff : reserved
000f0000-000fffff : System ROM
00100000-3fedffff : System RAM // 이 range 내에서 좌측 1byte만 kASLR
04000000-04595ef1 : Kernel code(text) // left 2hex are PHYS\_OFFSET
04595ef2-047df57f : Kernel data
048a1000-04912fff : Kernel bss
3fee0000-3fefefff : ACPI Tables
3feff000-3fefffff : ACPI Non-volatile Storage
3ff00000-3fffffff : System RAM
40000000-febfffff : PCI Bus 0000:00
40000000-febfffff : PCI Bus 0000:00
40008000-4000bfff : 0000:00:10.0
e5b00000-e5bfffff : PCI Bus 0000:22
......
fffe0000-ffffffff : reserved
e.g.,
x86
1
2
3
4
5
6
7
8
root@kali32:~# cat /proc/kallsyms | grep setresuid
d1079030 T sys\_setresuid
root@kali32:~# cat /proc/iomem
11000000-11595ef1 : Kernel code == PHYS\_OFFSET
phy\_addr = 11079030
arm
1
2
3
4
5
6
/ $ cat /proc/kallsyms | grep sys\_call\_ta
8000e348 T sys\_call\_table
/ $ cat /proc/iomem
60008000-60485f3f : Kernel code
phys\_addr = 6000e348
/dev/mem : access using physical address
1
2
3
4
5
root@kali32:~# cat /boot/config-4.13.0-kali1-686-pae | grep DEVMEM
CONFIG\_DEVMEM=y
CONFIG\_ARCH\_HAS\_DEVMEM\_IS\_ALLOWED=y
CONFIG\_STRICT\_DEVMEM=y
CONFIG\_IO\_STRICT\_DEVMEM=y
CONFIG\_STRICT_DEVMEM
이 설정되어 있다면 /dev/mem
으로 접근 시 다음 체크를 수행한다.
1
int devmem\_is\_allowed(unsigned long phys\_page\_number)
devmem\_is\_allowed(phys\_page_number)
checks to see if /dev/mem access to a certain address is valid.- x86에서는 first megabyte of RAM(
0x00100000
)과 non-kernel-ram area에만 접근할 수 있음.
실제로 0x000fffff
까지는 잘 읽히는데 여기를 넘어가자마자 읽히지 않는다.
- first megabyte of RAM에는 BIOS code와 X, dosemu 등 apps에서 사용하는 data region이 위치.
- non-kernel-ram area는 PCI mmio resource, potential bios/acpi data region을 포함하는 영역.
- disallowed 되어야 하는 영역의 경우 reject되는 대신 0으로 채워져 있을 수 있음.
Note ) 정의와 체크 위치는 아키텍쳐마다 다르지만 웬만한 아키텍쳐에서는 다 체크한다. Note ) 이를 해제하려면 kernel을 recompile해야 한다.
/proc//pagemap
https://github.com/torvalds/linux/blob/v4.9/Documentation/vm/pagemap.txt