trash houz
Linux Kernel Debugging with QEMU 본문
빌드를 위한 필수 패키지 설치
Documentation/Changes
문서에 커널 빌드시 사용되는 패키지의 최소 버전이 명시되어 있습니다.
sudo apt install build-essential kernel-package libncurses5-dev libssl-dev ccache flex bison libelf-dev bin86 qemu qemu-kvm
커널 소스코드 다운로드
아래 두 링크에서 다운로드 할 수 있습니다.
이외에도 토발즈 깃허브에서 받아온뒤 버전을 변경할수 있습니다.
git clone https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
git checkout v3.16
커널 config 파일 설정하기
make defconfig
를 통해 기본 설정을 할 수 있습니다.
make defconfig
추가 설정을 위해 make menuconfig
를 이용하면 됩니다. 직접 .config
파일을 수정해도 됩니다.
make menuconfig
다음과 같이 아키텍처의 직접적인 명시도 가능합니다.
make ARCH=x86_64 x86_64_defconfig
make ARCH=x86_64 menuconfig
- 디버깅 심볼 추가:
CONFIG_DEBUG_INFO=y
kallsyms
활성화:CONFIG_KALLSYMS=y
,kallsyms
에 추가 정보 출력:CONFIG_KALLSYMS_ALL=y
- 드라이버 디버깅시 메시지 추가:
CONFIG_DEBUG_DRIVER=y
KASLR
활성화:CONFIG_RANDOMIZE_BASE=y
KASAN
활성화:CONFIG_KASAN=y
,CONFIG_KASAN_INLINE=y
UBSAN
활성화:CONFIG_UBSAN=y
,CONFIG_UBSAN_SANITIZE_ALL=y
KCSAN
활성화:CONFIG_KCSAN=y
KFENCE
활성화:CONFIG_KFENCE=y
Kmemleak
활성화:CONFIG_DEBUG_KMEMLEAK=y
커널 빌드
make
를 이용해 빌드하면 됩니다. -j
옵션을 통해 사용할 코어를 선택할 수 있습니다.
make -j4
만약 cc1: error: code model kernel does not support PIC mode
오류가 발생한다면 pie.patch
로 다음 코드를 저장합니다.
해당 오류는 특정 gcc
버전 이상에서 pie
적용이 기본으로 설정되어 발생하는것 입니다.
diff --git a/Makefile b/Makefile
index dda982c..f96b174 100644
--- a/Makefile
+++ b/Makefile
@@ -608,6 +608,12 @@ endif # $(dot-config)
# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux
+# force no-pie for distro compilers that enable pie by default
+KBUILD_CFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CFLAGS += $(call cc-option, -no-pie)
+KBUILD_AFLAGS += $(call cc-option, -fno-pie)
+KBUILD_CPPFLAGS += $(call cc-option, -fno-pie)
+
# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default
# values of the respective KBUILD_* variables
ARCH_CPPFLAGS :=
이후 .config
파일 설정이 끝난 상태에서 아래 명령어로 패치를 진행한뒤 다시 빌드를 시작하면 됩니다.
patch -p1 < pie.patch
결과물 확인
정상적으로 컴파일이 완료되면 arch/x86/boot/bzImage
가 생성됩니다.
bzImage 는 vmlinux 에서 순수하게 명령어 셋만 뽑아낸 파일입니다.
vmlinux 는 디버깅에 유용한 심볼들이 포함된 파일입니다.
debug-kit 다운로드
다음 명령어를 통해 미리 작성해놓은 스크립트를 다운로드하여 사용하면 됩니다. .gdbinit
파일은 수정이 필요합니다.
git clone https://github.com/applemasterz17/linux-kernel-debug-kit.git
보호기법 설정
KPTI
를 설정하려면 -cpu kvm64
옵션을 사용하면 됩니다. 해제시 -cpu qemu64
옵션을 사용하면 됩니다. 혹은 -append "kpti=1"
을 사용해 활성화 하거나 -append "nopti"
를 사용해 해제할 수 있습니다.
SMEP
, SMAP
을 설정하려면 -cpu +smep, +smap
옵션을 사용하면 됩니다. 해제시 -append "nosmep nosmap"
옵션을 사용하면 됩니다. 혹은 -cpu
에서 제거해도 됩니다.
KASLR
을 설정하려면 기본적으로 커널 빌드시 CONFIG_RANDOMIZE_BASE=y
인 상태로 빌드 된 이미지여야 합니다. 추가 설정이 필요없습니다. 해제시 -append "nokaslr"
옵션을 사용하면 됩니다.
KADR
보호기법은 파일 시스템 내부의 init
스크립트를 수정해야 합니다. 보호 기법을 해제하는것이 아닌 사용자 권한을 root
권한으로 변경해야 합니다. setuidgid
를 0
으로 변경합니다.
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
setsid cttyhack setuidgid 0 sh
umount /proc
umount /sys
poweroff -d 0 -f
GDB 로 디버깅하기
먼저 ~/.gdbinit
에 다음 스크립트를 추가해 gdb-script 를 자동으로 로드하도록 합니다.
set auto-load safe-path /home/applemasterz17/kernel/linux-5.15.6/scripts/gdb
만약 모듈을 로딩해야한다면 insmod
명령어를 통해 모듈을 먼저 로딩합니다.
이후 .text
베이스 주소를 찾습니다.
sudo insmod test_module.ko
sudo cat /sys/module/test_module/sections/.text
QEMU 의 -s
옵션을 이용해 GDB 에서 Attach 할 수 있습니다.
모듈을 디버깅 하려면 모듈 심볼 로딩도 추가로 해줘야합니다.
gdb -q ./vmlinux
target remote:1234
add-symbol-file ./test_module.ko [.text 주소]
BP
를 설정할 함수의 주소를 찾아줍니다. KADR
을 해제한뒤 확인해야 합니다.
cat /proc/kallsyms | grep printk
커널 모듈의 베이스 주소를 확인하려면 /proc/modules
를 확인하면 됩니다.
sudo cat /proc/modules
루트 파일 시스템 생성하기 (BusyBox)
BusyBox
는 리눅스 커널 2.4.x
버전부터 모든 기능을 지원합니다. 다운로드 링크 에서 원하는 버전을 다운로드 합니다.
wget <https://busybox.net/downloads/busybox-1.32.0.tar.bz2>
tar xvf busybox-1.32.0.tar.bz2
make menuconfig
를 이용해 빌드 옵션을 설정해야 합니다.
make menuconfig
- Settings -> --Build Options -> Build static binary [체크]
- Networking Utilities -> inetd [체크 해제]
빌드 결과물이 저장될 디렉토리를 생성하고 소스코드를 빌드하면 됩니다.
mkdir ../target
make CONFIG_PREFIX=../target install
빌드 결과물이 담긴 디렉토리에서 필요한 디렉토리들을 생성해줍니다.
cd ../target
mkdir dev etc lib proc tmp sys
해당 디렉토리에 init
스크립트를 작성해주고 755
권한을 부여합니다. init
스크립트는 부팅 후 가장 먼저 실행되는 PID:1
프로세스 입니다.
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
setsid cttyhack setuidgid 1000 sh
umount /proc
umount /sys
poweroff -d 0 -f
vim init
chmod 755 init
지금까지 생성한 파일들을 cpio
명령어로 전부 압축하면 rootfs.cpio
파일이 생성됩니다.
find . | cpio -o --format=newc > rootfs.cpio
파일 시스템에 파일을 추가하려면 아래의 명령어를 사용하면 됩니다.
cpio -idm < ../rootfs.cpio
cpio -id -v < rootfs.cpio
보통 편리를 위해 아래와 같이 스크립트를 작성해 repack_fs.sh
로 저장해서 사용합니다.
-masm=intel 옵션은 인텔 어셈블리 문법 옵션입니다.
#!/bin/bash
gcc -masm=intel -static -o exploit exploit.c -no-pie
mkdir fs
cd fs
cpio -idm < ../rootfs.cpio
mv ../exploit ./
find . | cpio -o --format=newc > ../rootfs.cpio
cd ..
rm -rf fs
QEMU 스크립트 작성하기
아래 스크립트는 BusyBox
파일 시스템을 사용한 QEMU 스크립트 예제입니다.
#!/bin/bash
qemu-system-x86_64 \\
-m 512M \\
-kernel ./bzImage \\
-initrd ./rootfs.cpio \\
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet nokaslr" \\
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \\
-nographic \\
-cpu qemu64,smep,smap \\
-s \\
-pidfile vm.pid \\
- -m 512M : 주 메모리 512mb 할당
- -smp 2 : CPU 코어를 두개 사용
- -kernel ./bzImage : bzImage 를 커널 이미지로 사용
- -initrd ./rootfs.cpio : rootfs.cpio 를 파일 시스템으로 사용
- -append "nokaslr" : KASLR 보호기법 해제
- -append "quiet" : 부팅시 시끄러운것들 끄기
- -cpu smep, smap, qemu64 : SMEP, SMAP 보호기법 해제, 프로세서 아키텍처
- -s : GDB Attach 를 위해 1234번 포트를 오픈
- -S : 부팅하자마자 멈춤
- -nographic : 그래픽 옵션 사용 안함
- -pidfile vm.pid : 부팅한 커널 pid 를 vm.pid 에 저장
실행된 가상머신을 종료하려면 아래 명령어를 이용해 종료합니다.
kill $(cat vm.pid)
'Linux' 카테고리의 다른 글
task_struct 에서 권한상승 (0) | 2019.08.05 |
---|