选择kernel的版本
搜索含有dbgsym的内核版本apt-cache search linux-image | grep dbgsym | grep 4.11
搜索特定source code的内核版本apt-cache search linux-source
然后选择一个
安装内核
搜索要下载的linux内核版本apt-cache search linux-image | grep linux-image | grep generic
安装内核sudo apt-get install linux-image-4.10.0-19-generic
查看安装的内核版本sudo dpkg --list | grep linux-image
重启,在grub之前,按住shift,选择我们的内核
验证新内核启用uname -sr
安装符号文件
在终端输入下面的代码
1 | codename=$(lsb_release -c | awk '{print $2}') |
添加访问符号服务器的密钥文件:wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add -
执行sudo apt-get update
更新
执行如下命令开始下载符号包:
1 | sudo apt-get install linux-image-`uname -r`-dbgsym |
安装kernel对应的源代码
打开/etc/apt/sources.list,启用deb-src,sudo apt-get update更新
1 | vim /etc/apt/sources.list |
- 搜索所有版本的source code:
apt-cache search linux-source
- 安装指定版本的source code:
sudo apt-get install linux-source-4.10.0
下载好的源码会被放在/usr/src目录下。
解压缩得到源码sudo tar -xvf linux-source-4.10.0.tar.bz2
一切都安装好了之后,就可以拷贝一份我们的虚拟机,一个作为host,一个作为target
移除打印机,添加串口
打印机会占用我们的串口
target
host
配置target
需要让target在开机时候进入kgdb的调试状态,首先需要修改grub文件,增加grub引导时候的菜单项。
sudo vim /etc/grub.d/40_custom
修改的内容从/boot/grub/grub.cfg里复制,复制一个菜单项(menuentry)过来,再把菜单名中增加调试信息,然后在内核命令行中增加KGDB选项,即下面这样:
新增部分:kgdbwait kgdb8250=io,03f8,ttyS0,115200,4 kgdboc=ttyS0,115200 kgdbcon nokaslr
1 | #!/bin/sh |
修改grub的配置后,需要执行sudo update-grub来更新。更新后目标机器就准备好了。
重启按住shift,进入刚才添加的menu即可进入到被调试状态。
配置host
设置串口通信的波特率sudo stty -F /dev/ttyS0 115200
要查看是否设置成功sudo stty -F /dev/ttyS0
注意这个每次host重启都要再输入一遍,嗯,写个shell吧。
调试
编写config,用source加载(直接在gdb里输入也可)
1 | set architecture i386:x86-64:intel |
使用gdb来调试带符号的vmlinux
1 | gdb -s /usr/lib/debug/boot/vmlinux-4.10.0-19-generic |
符号加载完成,bt查看当前栈帧,c运行内核。
查看源码遇到的问题
可以看到,list本来应该显示具体的源码,但是这里只是打印出了它所在的文件,这是因为在这个路径下没有源码。
所以说我们就建立这个路径,然后把源码放进去
然后dir设置好目录dir /build/linux-hwe-edge-gyUj63/linux-hwe-edge-4.10.0
现在就可以查看源码了。
单步调试
我从头开始说:
- host
target remote /dev/ttyS0
按c继续运行target - target
一开始停在下图这个地方,host按c之后,target继续运行进入系统
然后输入sudo su && echo g > "/proc/sysrq-trigger"
这时候target应该进入假死状态,其实就是完全动不了。
这一步就是打开target的kgdb调试。 - host
这时候host那里不再是
而是停下来了,可以下断了
在你想要调试的函数下断点,然后按c,恢复target执行。 - target
这样就可以运行我们的poc了 - host
回到host,此时应该已经停在断点了,然后按n可以单步调试。
至此,内核调试的整个配置和调试方法都写完了。
参考链接
其他
内核调试的坑实在太深,一开始参考了muhe师傅的文章用gdb+qemu调,然后编译了kernel 4.x之后,编译不报错,但是调试过程简直了,gdb花式挂不上去,看网上说某些版本要改gdb源码重新编译gdb……放弃了放弃了。
感谢教我搭建双机调试的师傅……
内核还是很容易调飞的,有时候花式加载不出来。
另外如果下载符号文件太慢,可以参考我的这篇文章,在虚拟机里用ss代理。
http://eternalsakura13.com/2018/02/02/proxy/