📊
CTF-All-In-One
  • 简介
  • 前言
  • 一、基础知识篇
    • 1.1 CTF 简介
    • 1.2 学习方法
    • 1.3 Linux 基础
    • 1.4 Web 安全基础
      • 1.4.1 HTML 基础
      • 1.4.2 HTTP 协议基础
      • 1.4.3 JavaScript 基础
      • 1.4.4 常见 Web 服务器基础
      • 1.4.5 OWASP Top Ten Project 漏洞基础
      • 1.4.6 PHP 源码审计基础
    • 1.5 逆向工程基础
      • 1.5.1 C/C++ 语言基础
      • 1.5.2 汇编基础
      • 1.5.3 Linux ELF
      • 1.5.4 Windows PE
      • 1.5.5 静态链接
      • 1.5.6 动态链接
      • 1.5.7 内存管理
      • 1.5.8 glibc malloc
      • 1.5.9 Linux 内核
      • 1.5.10 Windows 内核
      • 1.5.11 jemalloc
    • 1.6 密码学基础
      • 1.6.1 密码学导论
      • 1.6.2 流密码
      • 1.6.3 分组密码
      • 1.6.4 公钥密码
      • 1.6.5 消息认证和哈希函数
      • 1.6.6 数字签名
      • 1.6.7 密码协议
      • 1.6.8 密钥分配与管理
      • 1.6.9 数字货币
    • 1.7 Android 安全基础
      • 1.7.1 Android 环境搭建
      • 1.7.2 Dalvik 指令集
      • 1.7.3 ARM 汇编基础
      • 1.7.4 Android 常用工具
  • 二、工具篇
    • 虚拟化分析环境
      • 2.1.1 VirtualBox
      • 2.1.2 QEMU
      • 2.1.3 Docker
      • 2.1.4 Unicorn
    • 静态分析工具
      • 2.2.1 radare2
      • 2.2.2 IDA Pro
      • 2.2.3 JEB
      • 2.2.4 Capstone
      • 2.2.5 Keystone
      • 2.2.6 Ghidra
    • 动态分析工具
      • 2.3.1 GDB
      • 2.3.2 OllyDbg
      • 2.3.3 x64dbg
      • 2.3.4 WinDbg
      • 2.3.5 LLDB
    • 其他工具
      • 2.4.1 pwntools
      • 2.4.2 zio
      • 2.4.3 metasploit
      • 2.4.4 binwalk
      • 2.4.5 Burp Suite
      • 2.4.6 Wireshark
      • 2.4.7 Cuckoo Sandbox
  • 三、分类专题篇
    • Pwn
      • 3.1.1 格式化字符串漏洞
      • 3.1.2 整数溢出
      • 3.1.3 栈溢出
      • 3.1.4 返回导向编程(ROP)(x86)
      • 3.1.5 返回导向编程(ROP)(ARM)
      • 3.1.6 Linux 堆利用(一)
      • 3.1.7 Linux 堆利用(二)
      • 3.1.8 Linux 堆利用(三)
      • 3.1.9 Linux 堆利用(四)
      • 3.1.10 内核 ROP
      • 3.1.11 Linux 内核漏洞利用
      • 3.1.12 Windows 内核漏洞利用
      • 3.1.13 竞争条件
      • 3.1.14 虚拟机逃逸
    • Reverse
      • 3.2.1 patch 二进制文件
      • 3.2.2 脱壳技术(PE)
      • 3.2.3 脱壳技术(ELF)
      • 3.2.4 反调试技术(PE)
      • 3.2.5 反调试技术(ELF)
      • 3.2.6 指令混淆
    • Web
      • 3.3.1 SQL 注入利用
      • 3.3.2 XSS 漏洞利用
    • Crypto
    • Misc
      • 3.5.1 Lsb
    • Mobile
  • 四、技巧篇
    • 4.1 Linux 内核调试
    • 4.2 Linux 命令行技巧
    • 4.3 GCC 编译参数解析
    • 4.4 GCC 堆栈保护技术
    • 4.5 ROP 防御技术
    • 4.6 one-gadget RCE
    • 4.7 通用 gadget
    • 4.8 使用 DynELF 泄露函数地址
    • 4.9 shellcode 开发
    • 4.10 跳转导向编程(JOP)
    • 4.11 利用 mprotect 修改栈权限
    • 4.12 利用 __stack_chk_fail
    • 4.13 利用 _IO_FILE 结构
    • 4.14 glibc tcache 机制
    • 4.15 利用 vsyscall 和 vDSO
  • 五、高级篇
    • 5.0 软件漏洞分析
    • 5.1 模糊测试
      • 5.1.1 AFL fuzzer
      • 5.1.2 libFuzzer
    • 5.2 动态二进制插桩
      • 5.2.1 Pin
      • 5.2.2 DynamoRio
      • 5.2.3 Valgrind
    • 5.3 符号执行
      • 5.3.1 angr
      • 5.3.2 Triton
      • 5.3.3 KLEE
      • 5.3.4 S²E
    • 5.4 数据流分析
      • 5.4.1 Soot
    • 5.5 污点分析
      • 5.5.1 TaintCheck
    • 5.6 LLVM
      • 5.6.1 Clang
    • 5.7 程序切片
    • 5.8 SAT/SMT
      • 5.8.1 Z3
    • 5.9 基于模式的漏洞分析
    • 5.10 基于二进制比对的漏洞分析
    • 5.11 反编译技术
      • 5.11.1 RetDec
  • 六、题解篇
    • Pwn
      • 6.1.1 pwn HCTF2016 brop
      • 6.1.2 pwn NJCTF2017 pingme
      • 6.1.3 pwn XDCTF2015 pwn200
      • 6.1.4 pwn BackdoorCTF2017 Fun-Signals
      • 6.1.5 pwn GreHackCTF2017 beerfighter
      • 6.1.6 pwn DefconCTF2015 fuckup
      • 6.1.7 pwn 0CTF2015 freenote
      • 6.1.8 pwn DCTF2017 Flex
      • 6.1.9 pwn RHme3 Exploitation
      • 6.1.10 pwn 0CTF2017 BabyHeap2017
      • 6.1.11 pwn 9447CTF2015 Search-Engine
      • 6.1.12 pwn N1CTF2018 vote
      • 6.1.13 pwn 34C3CTF2017 readme_revenge
      • 6.1.14 pwn 32C3CTF2015 readme
      • 6.1.15 pwn 34C3CTF2017 SimpleGC
      • 6.1.16 pwn HITBCTF2017 1000levels
      • 6.1.17 pwn SECCONCTF2016 jmper
      • 6.1.18 pwn HITBCTF2017 Sentosa
      • 6.1.19 pwn HITBCTF2018 gundam
      • 6.1.20 pwn 33C3CTF2016 babyfengshui
      • 6.1.21 pwn HITCONCTF2016 Secret_Holder
      • 6.1.22 pwn HITCONCTF2016 Sleepy_Holder
      • 6.1.23 pwn BCTF2016 bcloud
      • 6.1.24 pwn HITCONCTF2016 House_of_Orange
      • 6.1.25 pwn HCTF2017 babyprintf
      • 6.1.26 pwn 34C3CTF2017 300
      • 6.1.27 pwn SECCONCTF2016 tinypad
      • 6.1.28 pwn ASISCTF2016 b00ks
      • 6.1.29 pwn Insomni'hack_teaserCTF2017 The_Great_Escape_part-3
      • 6.1.30 pwn HITCONCTF2017 Ghost_in_the_heap
      • 6.1.31 pwn HITBCTF2018 mutepig
      • 6.1.32 pwn SECCONCTF2017 vm_no_fun
      • 6.1.33 pwn 34C3CTF2017 LFA
      • 6.1.34 pwn N1CTF2018 memsafety
      • 6.1.35 pwn 0CTF2018 heapstorm2
      • 6.1.36 pwn NJCTF2017 messager
      • 6.1.37 pwn sixstarctf2018 babystack
      • 6.1.38 pwn HITCONCMT2017 pwn200
      • 6.1.39 pwn BCTF2018 house_of_Atum
      • 6.1.40 pwn LCTF2016 pwn200
      • 6.1.41 pwn PlaidCTF2015 PlaidDB
      • 6.1.42 pwn hacklu2015 bookstore
      • 6.1.43 pwn 0CTF2018 babyheap
      • 6.1.44 pwn ASIS2017 start_hard
      • 6.1.45 pwn LCTF2016 pwn100
    • Reverse
      • 6.2.1 re XHPCTF2017 dont_panic
      • 6.2.2 re ECTF2016 tayy
      • 6.2.3 re CodegateCTF2017 angrybird
      • 6.2.4 re CSAWCTF2015 wyvern
      • 6.2.5 re PicoCTF2014 Baleful
      • 6.2.6 re SECCONCTF2017 printf_machine
      • 6.2.7 re CodegateCTF2018 RedVelvet
      • 6.2.8 re DefcampCTF2015 entry_language
    • Web
      • 6.3.1 web HCTF2017 babycrack
    • Crypto
    • Misc
    • Mobile
  • 七、实战篇
    • CVE
      • 7.1.1 CVE-2017-11543 tcpdump sliplink_print 栈溢出漏洞
      • 7.1.2 CVE-2015-0235 glibc __nss_hostname_digits_dots 堆溢出漏洞
      • 7.1.3 CVE-2016-4971 wget 任意文件上传漏洞
      • 7.1.4 CVE-2017-13089 wget skip_short_body 栈溢出漏洞
      • 7.1.5 CVE–2018-1000001 glibc realpath 缓冲区下溢漏洞
      • 7.1.6 CVE-2017-9430 DNSTracer 栈溢出漏洞
      • 7.1.7 CVE-2018-6323 GNU binutils elf_object_p 整型溢出漏洞
      • 7.1.8 CVE-2010-2883 Adobe CoolType SING 表栈溢出漏洞
      • 7.1.9 CVE-2010-3333 Microsoft Word RTF pFragments 栈溢出漏洞
    • Malware
  • 八、学术篇
    • 8.1 The Geometry of Innocent Flesh on the Bone: Return-into-libc without Function Calls (on the x86)
    • 8.2 Return-Oriented Programming without Returns
    • 8.3 Return-Oriented Rootkits: Bypassing Kernel Code Integrity Protection Mechanisms
    • 8.4 ROPdefender: A Detection Tool to Defend Against Return-Oriented Programming Attacks
    • 8.5 Data-Oriented Programming: On the Expressiveness of Non-Control Data Attacks
    • 8.7 What Cannot Be Read, Cannot Be Leveraged? Revisiting Assumptions of JIT-ROP Defenses
    • 8.9 Symbolic Execution for Software Testing: Three Decades Later
    • 8.10 AEG: Automatic Exploit Generation
    • 8.11 Address Space Layout Permutation (ASLP): Towards Fine-Grained Randomization of Commodity Softwa
    • 8.13 New Frontiers of Reverse Engineering
    • 8.14 Who Allocated My Memory? Detecting Custom Memory Allocators in C Binaries
    • 8.21 Micro-Virtualization Memory Tracing to Detect and Prevent Spraying Attacks
    • 8.22 Practical Memory Checking With Dr. Memory
    • 8.23 Evaluating the Effectiveness of Current Anti-ROP Defenses
    • 8.24 How to Make ASLR Win the Clone Wars: Runtime Re-Randomization
    • 8.25 (State of) The Art of War: Offensive Techniques in Binary Analysis
    • 8.26 Driller: Augmenting Fuzzing Through Selective Symbolic Execution
    • 8.27 Firmalice - Automatic Detection of Authentication Bypass Vulnerabilities in Binary Firmware
    • 8.28 Cross-Architecture Bug Search in Binary Executables
    • 8.29 Dynamic Hooks: Hiding Control Flow Changes within Non-Control Data
    • 8.30 Preventing brute force attacks against stack canary protection on networking servers
    • 8.33 Under-Constrained Symbolic Execution: Correctness Checking for Real Code
    • 8.34 Enhancing Symbolic Execution with Veritesting
    • 8.38 TaintEraser: Protecting Sensitive Data Leaks Using Application-Level Taint Tracking
    • 8.39 DART: Directed Automated Random Testing
    • 8.40 EXE: Automatically Generating Inputs of Death
    • 8.41 IntPatch: Automatically Fix Integer-Overflow-to-Buffer-Overflow Vulnerability at Compile-Time
    • 8.42 Dynamic Taint Analysis for Automatic Detection, Analysis, and Signature Generation of Exploits
    • 8.43 DTA++: Dynamic Taint Analysis with Targeted Control-Flow Propagation
    • 8.44 Superset Disassembly: Statically Rewriting x86 Binaries Without Heuristics
    • 8.45 Ramblr: Making Reassembly Great Again
    • 8.46 FreeGuard: A Faster Secure Heap Allocator
    • 8.48 Reassembleable Disassembling
  • 九、附录
    • 9.1 更多 Linux 工具
    • 9.2 更多 Windows 工具
    • 9.3 更多资源
    • 9.4 Linux 系统调用表
    • 9.5 python2到3字符串转换
    • 9.6 幻灯片
Powered by GitBook
On this page
  • 准备工作
  • 获取符号文件
  • 获取源文件
  • printk
  • QEMU + gdb
  • kdb
  • 参考资料

Was this helpful?

  1. 四、技巧篇

4.1 Linux 内核调试

Previous四、技巧篇Next4.2 Linux 命令行技巧

Last updated 3 years ago

Was this helpful?

准备工作

与用户态程序不同,为了进行内核调试,我们需要两台机器,一台调试,另一台被调试。在调试机上需要安装必要的调试器(如GDB),被调试机上运行着被调试的内核。

这里选择用 Ubuntu16.04 来展示,因为该发行版默认已经开启了内核调试支持:

$ cat /boot/config-4.13.0-38-generic | grep GDB
# CONFIG_CFG80211_INTERNAL_REGDB is not set
CONFIG_SERIAL_KGDB_NMI=y
CONFIG_GDB_SCRIPTS=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
# CONFIG_KGDB_TESTS is not set
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_KDB=y

获取符号文件

下面我们来准备调试需要的符号文件。看一下该版本的 code name:

$ lsb_release -c
Codename: xenial

然后在下面的目录下新建文件 ddebs.list,其内容如下(注意看情况修改Codename):

$ cat /etc/apt/sources.list.d/ddebs.list
deb http://ddebs.ubuntu.com/ xenial      main restricted universe multiverse
deb http://ddebs.ubuntu.com/ xenial-security main restricted universe multiverse
deb http://ddebs.ubuntu.com/ xenial-updates  main restricted universe multiverse
deb http://ddebs.ubuntu.com/ xenial-proposed main restricted universe multiverse

http://ddebs.ubuntu.com 是 Ubuntu 的符号服务器。执行下面的命令添加密钥:

$ wget -O - http://ddebs.ubuntu.com/dbgsym-release-key.asc | sudo apt-key add -

然后就可以更新并下载符号文件了:

$ sudo apt-get update
$ uname -r
4.13.0-38-generic
$ sudo apt-get install linux-image-4.13.0-38-generic-dbgsym

完成后,符号文件将会放在下面的目录下:

$ file /usr/lib/debug/boot/vmlinux-4.13.0-38-generic
/usr/lib/debug/boot/vmlinux-4.13.0-38-generic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=f00f4b7ef0ab8fa738b6a9caee91b2cbe23fef97, not stripped

可以看到这是一个静态链接的可执行文件,使用 gdb 即可进行调试,例如这样:

$ gdb -q /usr/lib/debug/boot/vmlinux-4.13.0-38-generic
Reading symbols from /usr/lib/debug/boot/vmlinux-4.13.0-38-generic...done.
gdb-peda$ p init_uts_ns
$1 = {
  kref = {
    refcount = {
      refs = {
        counter = 0x2
      }
    }
  },
  name = {
    sysname = "Linux", '\000' <repeats 59 times>,
    nodename = "(none)", '\000' <repeats 58 times>,
    release = "4.13.0-38-generic", '\000' <repeats 47 times>,
    version = "#43~16.04.1-Ubuntu SMP Wed Mar 14 17:48:43 UTC 2018", '\000' <repeats 13 times>,
    machine = "x86_64", '\000' <repeats 58 times>,
    domainname = "(none)", '\000' <repeats 58 times>
  },
  user_ns = 0xffffffff822517a0 <init_user_ns>,
  ucounts = 0x0 <irq_stack_union>,
  ns = {
    stashed = {
      counter = 0x0
    },
    ops = 0xffffffff81e2cc80 <utsns_operations>,
    inum = 0xeffffffe
  }
}

获取源文件

将 /etc/apt/sources.list 里的 deb-src 行都取消掉注释:

$ sed -i '/^#\sdeb-src /s/^#//' "/etc/apt/sources.list"

然后就可以更新并获取 Linux 内核源文件了:

$ sudo apt-get update
$ mkdir -p ~/kernel/source
$ cd ~/kernel/source
$ apt-get source $(dpkg-query '--showformat=${source:Package}=${source:Version}' --show linux-image-$(uname -r))
$ ls linux-hwe-4.13.0/
arch     CREDITS     debian.master  firmware  ipc      lib          net      security        tools   zfs
block    crypto      Documentation  fs        Kbuild   MAINTAINERS  README   snapcraft.yaml  ubuntu
certs    debian      drivers        include   Kconfig  Makefile     samples  sound           usr
COPYING  debian.hwe  dropped.txt    init      kernel   mm           scripts  spl

printk

在用户态程序中,我们常常使用 printf() 来打印信息,方便调试,在内核中也可以这样做。内核(v4.16.3)使用函数 printk() 来输出信息,在 include/linux/kern_levels.h 中定义了 8 个级别:

#define KERN_EMERG  KERN_SOH "0"  /* system is unusable */
#define KERN_ALERT  KERN_SOH "1"  /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2"  /* critical conditions */
#define KERN_ERR  KERN_SOH "3"  /* error conditions */
#define KERN_WARNING  KERN_SOH "4"  /* warning conditions */
#define KERN_NOTICE KERN_SOH "5"  /* normal but significant condition */
#define KERN_INFO KERN_SOH "6"  /* informational */
#define KERN_DEBUG  KERN_SOH "7"  /* debug-level messages */

用法是:

printk(KERN_EMERG "hello world!\n");  // 中间没有逗号

而当前控制台的日志级别如下所示:

$ cat /proc/sys/kernel/printk
4       4       1       4

这 4 个数值在文件定义及默认值在如下所示:

// kernel/printk/printk.c

int console_printk[4] = {
  CONSOLE_LOGLEVEL_DEFAULT,	/* console_loglevel */
  MESSAGE_LOGLEVEL_DEFAULT,	/* default_message_loglevel */
  CONSOLE_LOGLEVEL_MIN,		/* minimum_console_loglevel */
  CONSOLE_LOGLEVEL_DEFAULT,	/* default_console_loglevel */
};


// include/linux/printk.h

/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT

/* We show everything that is MORE important than this.. */
#define CONSOLE_LOGLEVEL_MIN	 1 /* Minimum loglevel we let people use */

/*
 * Default used to be hard-coded at 7, we're now allowing it to be set from
 * kernel config.
 */
#define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT

#define console_loglevel (console_printk[0])
#define default_message_loglevel (console_printk[1])
#define minimum_console_loglevel (console_printk[2])
#define default_console_loglevel (console_printk[3])

虽然这些数值控制了当前控制台的日志级别,但使用虚拟文件 /proc/kmsg 或者命令 dmesg 总是可以查看所有的信息。

QEMU + gdb

QEMU 是一款开源的虚拟机软件,可以使用它模拟出一个完整的操作系统(参考章节2.1.1)。这里我们介绍怎样使用 QEMU 和 gdb 进行内核调试,关于 Linux 内核的编译可以参考章节 1.5.9。

接下来我们需要借助 BusyBox 来创建用户空间:

$ wget -c http://busybox.net/downloads/busybox-1.28.3.tar.bz2
$ tar -xvjf busybox-1.28.3.tar.bz2
$ cd busybox-1.28.3/

生成默认配置文件并修改 CONFIG_STATIC=y 让它生成的是一个静态链接的 BusyBox,这是因为 qemu 中没有动态链接库:

$ make defconfig
$ cat .config | grep "CONFIG_STATIC"
CONFIG_STATIC=y

编译安装后会出现在 _install 目录下:

$ make
$ sudo make install
$ ls _install
bin  linuxrc  sbin  usr

接下来创建 initramfs 的目录结构:

$ mkdir initramfs
$ cd initramfs
$ cp ../_install/* -rf ./
$ mkdir dev proc sys
$ sudo cp -a /dev/null /dev/console /dev/tty /dev/tty2 /dev/tty3 /dev/tty4 dev/
$ rm linuxrc
$ vim init      # 创建启动脚本
$ cat init
#!/bin/busybox sh
mount -t proc none /proc
mount -t sysfs none /sys

exec /sbin/init

最后把它们打包:

$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

这样 initramfs 根文件系统就做好了,其中包含了必要的设备驱动和工具,boot loader 会加载 initramfs 到内存,然后内核将其挂载到根目录 /,并运行 init 脚本,挂载真正的磁盘根文件系统。

QEMU 启动!

$ qemu-system-x86_64 -s -S -kernel ~/kernelbuild/linux-4.16.3/arch/x86_64/boot/bzImage -initrd ~/kernelbuild/busybox-1.28.3/initramfs.cpio.gz -nographic -append "console=ttyS0"
  • -s:-gdb tcp::1234 的缩写,QEMU 监听在 TCP 端口 1234,等待 gdb 的连接。

  • -S:在启动时冻结 CPU,等待 gdb 输入 c 时继续执行。

  • -kernel:指定内核。

  • -initrd:指定 initramfs。

  • nographic:禁用图形输出并将串行 I/O 重定向到控制台。

  • -append "console=ttyS0:所有内核输出到 ttyS0 串行控制台,并打印到终端。

在另一个终端里使用打开 gdb,然后尝试在函数 cmdline_proc_show() 处下断点:

$ gdb -ex "target remote localhost:1234" ~/kernelbuild/linux-4.16.3/vmlinux
(gdb) b cmdline_proc_show
Breakpoint 1 at 0xffffffff8121ad70: file fs/proc/cmdline.c, line 9.
(gdb) c
Continuing.

Breakpoint 1, cmdline_proc_show (m=0xffff880006701b00, v=0x1 <irq_stack_union+1>) at fs/proc/cmdline.c:9
9               seq_printf(m, "%s\n", saved_command_line);

可以看到,当我们在内核里执行 cat /proc/cmdline 时就被断下来了。

# id
uid=0 gid=0
# echo hello kernel!
hello kernel!
# cat /proc/cmdline
console=ttyS0

现在我们已经可以对内核代码进行单步调试了。对于内核模块,我们同样可以进行调试,但模块是动态加载的,gdb 不会知道这些模块被加载到哪里,所以需要使用 add-symbol-file 命令来告诉它。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static int hello_init(void)
{
        printk(KERN_ALERT "Hello module!\n");
        return 0;
}

static void hello_exit(void)
{
        printk(KERN_ALERT "Goodbye module!\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple module.");

Makefile 如下:

BUILDPATH := ~/kernelbuild/linux-4.16.3/
obj-m += hello.o

all:
        make -C $(BUILDPATH) M=$(PWD) modules

clean:
        make -C $(BUILDPATH) M=$(PWD) clean

编译模块并将 .ko 文件复制到 initramfs,然后重新打包:

$ make && cp hello.ko ~/kernelbuild/busybox-1.28.3/initramfs
$ cd ~/kernelbuild/busybox-1.28.3/initramfs
$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz

最后重新启动 QEMU 即可:

# insmod hello.ko
[    7.887392] hello: loading out-of-tree module taints kernel.
[    7.892630] Hello module!
# lsmod
hello 16384 0 - Live 0xffffffffa0000000 (O)
# rmmod hello.ko
[   24.523830] Goodbye module!

三个命令分别用于载入、列出和卸载模块。

再回到 gdb 中,add-symbol-file 添加模块的 .text、.data 和 .bss 段的地址,这些地址在类似 /sys/kernel/<module>/sections 位置:

# cat /sys/module/hello/sections/.text
0x00000000fa16acc0

在这个例子中,只有 .text 段:

(gdb) add-symbol-file ~/kernelbuild/busybox-1.28.3/initramfs/hello.ko 0x00000000fa16acc0

然后就可以对该模块进行调试了。

kdb

参考资料

来看一个 helloworld 的例子,:

源码
KernelDebuggingTricks
准备工作
printk
QEMU + gdb
kdb
参考资料