Linux Kernel 调试环境配置

由于本人用的 Windows 虚拟机为 Hyper-v,希望能在 wsl 中调试 hyper-v 中的虚拟机,网上关于这个的内容比较少,做一下记录

设置串口

hyper-v 有点弱智,不能在 GUI 界面设置串口,只能从 powershell 设置串口路径,下述命令会将虚拟机内的 /dev/ttyS0 映射到 windows 的 \\.\pipe\ubuntu-rootkit 管道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Get-VMComPort Ubuntu-20.04-rootkit

VMName Name Path
------ ---- ----
Ubuntu-20.04-rootkit COM 1
Ubuntu-20.04-rootkit COM 2

Set-VMComPort Ubuntu-20.04-rootkit -Path "\\.\pipe\ubuntu-rootkit" -Number 1
Get-VMComPort Ubuntu-20.04-rootkit

VMName Name Path
------ ---- ----
Ubuntu-20.04-rootkit COM 1 \\.\pipe\ubuntu-rootkit
Ubuntu-20.04-rootkit COM 2

Start-VM -Name Ubuntu-20.04-rootkit
❯ (get-childitem \\.\pipe\).FullName|findstr ubuntu
\\.\pipe\ubuntu-rootkit

参考自:hyper-v-generation-2-virtual-machines-part-5

为了方便调试,还需要在 wsl 中使用命令来把 windows 的串口映射到 linux 下的 pty

npiperelay: https://github.com/jstarks/npiperelay

1
socat pty,link=./ubuntu-rootkit.pty,raw,echo=0 EXEC:"/mnt/d/tools/wsl/npiperelay.exe -ep -s //./pipe/ubuntu-rootkit",nofork

配置 grub

修改 grub 配置文件是为了关闭 kaslr 以及设置 kgdb 调试用的串口信息。设置 kgdb 调试用的串口信息可以在系统启动后再进行设置,但是关闭 kaslr 只能修改 grub 的 kernel 启动参数。

若是不关闭 kaslr,在调试时栈帧符号可能会出现问题

关闭 kaslr:

close-aslr

未关闭 kaslr:

close-aslr

修改配置文件推荐在 /etc/grub.d/40_custom 直接添加 grub 启动项,旧启动项来自 /boot/grub/grub.cfg, 添加了 kgdboc=ttyS0,115200 kgdbcon nokaslr

  • kgdboc: kgdb over console
    • kgdboc=ttyS0,115200 使用 ttyS0 连接,串口频率 115200
    • 也可以通过 echo “ttyS0,115200” > /sys/module/kgdboc/parameters/kgdboc 进行配置
  • kgdbwait: 启动阶段时进入调试模式
  • nokaslr: 关闭 kaslr
  • kgdbcon: 当 gdb 连接到内核时,kgdbcon 特性允许查看 gdb 内部的 printk() 消息。有两个方式激活该特性
    • kgdbcon 内核参数
    • echo 1 > /sys/module/kgdb/parameters/kgdb_use_con
    • 不要在系统控制台使用这个参数

ubuntu 20.04 配置文件 /etc/grub.d/40_custom

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
menuentry 'Ubuntu,KGDB with nokaslr' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-1d1a1fdb-e548-44f2-9e1f-5d230b6179e9' {
recordfail
load_video
gfxmode $linux_gfx_mode
insmod gzio
if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
insmod part_gpt
insmod ext2
set root='hd0,gpt2'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 5c4a24c6-ed02-4d59-930b-2ce672e8b643
else
search --no-floppy --fs-uuid --set=root 5c4a24c6-ed02-4d59-930b-2ce672e8b643
fi
linux /vmlinuz-5.4.0-52-generic root=/dev/mapper/ubuntu--vg-ubuntu--lv ro kgdboc=ttyS0,115200 kgdbcon nokaslr
initrd /initrd.img-5.4.0-52-generic
}

配置资料来自: https://www.kernel.org/doc/htmldocs/kgdb/kgdbreboot.html

为了方便进入自己的 grub 启动项,可以修改 grub 配置文件 /etc/default/grub 中的 GRUB_TIMEOUT

进行完上述操作后需要执行命令让 grub 根据当前配置文件生成对应的启动文件

1
update-grub

中断 kernel

使用命令触发中断让 kernel 进入调试模式

1
echo g > /proc/sysrq-trigger

gdb 附加调试

内核调试信息可以在下面的网址找到,当前内核为 5.4.0-52

1
http://ddebs.ubuntu.com/pool/main/l/linux/linux-image-unsigned-5.4.0-52-generic-dbgsym_5.4.0-52.57_amd64.ddeb

解压出 vmlinux-5.4.0-52-generic

pwndbg,peda 对内核的支持好像有问题,建议使用 peda

1
2
3
4
gdb ./vmlinux-5.4.0-52-generic
# 设置串口波特率 我也不知道干啥的 好像不用设也行
gef➤ set serial baud 115200
gef➤ target remote ./ubuntu-rootkit.pty

在内核已经被中断的情况下可以看到当前寄存器信息:

close-aslr

加载源码

内核调试往往需要结合源码进行

1
gef➤ set substitute-path /sources/were/compiled/here /put/sources/here

或者把 kernel 源码解包到 /usr/src/kernel 或者 kernel build 的目录

GEF 配置 layout

1
legend regs stack code args source memory threads trace extra

根据个人习惯修改为

1
gef config context.layout "regs code args source stack"