• Linux内核之vmlinuz反汇编


    本文介绍在Fedora上对Linux内核的vmlinuz进行反汇编。如果内核是debug版本,可以用来查看某个函数的源代码。

    1. 安装kernel-devel软件包

    dnf -y install kernel-devel

    2. 提取vmlinux

    • vmlinux是一个包括Linux kernel的静态链接的可运行文件。
    • vmlinuz是vmlinux经过gzip和objcopy制作出来的压缩文件。
    /usr/src/kernels/$(uname -r)/scripts/extract-vmlinux /boot/vmlinuz-$(uname -r) > vmlinux

    3. 反汇编vmlinux

    objdump -D vmlinux > vmlinux.out

    4.  查看vmlinux里的函数

    这里以函数tcp4_proc_init为例。/proc/kallsyms存储了所有的内核符号表,/boot/System.map则存储了静态的内核符号表。有关System.map,请阅读这里

    e.g.

    root# grep tcp4_proc_init /proc/kallsyms
    ffffffffa37dd330 t tcp4_proc_init_net
    ffffffffa479d258 T tcp4_proc_init
    
    root# grep tcp4_proc_init /boot/System.map-$(uname -r)
    ffffffff817dd330 t tcp4_proc_init_net
    ffffffff8279d258 T tcp4_proc_init
    
    root# egrep -in ffffffff8279d258 vmlinux.out
    8960512:ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
    8960912:ffffffff8279d96d:       e8 e6 f8 ff ff          callq  0xffffffff8279d258
    
    root# N=8960512
    root# sed -n "$((N-5)),$((N+5))"p vmlinux.out
    ffffffff8279d24e:       e8 7d 14 91 fe          callq  0xffffffff810ae6d0
    ffffffff8279d253:       eb bd                   jmp    0xffffffff8279d212
    ffffffff8279d255:       5b                      pop    %rbx
    ffffffff8279d256:       5d                      pop    %rbp
    ffffffff8279d257:       c3                      retq   
    ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
    ffffffff8279d25d:       48 c7 c7 40 ca 31 82    mov    $0xffffffff8231ca40,%rdi
    ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
    ffffffff8279d269:       e8 82 47 26 ff          callq  0xffffffff81a019f0
    ffffffff8279d26e:       48 c7 c7 60 c8 31 82    mov    $0xffffffff8231c860,%rdi
    ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590

    函数tcp4_proc_init()的源代码如下:

    /* https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/ipv4/tcp_ipv4.c?h=v4.16.9#n2392 */ 
    2377  static int __net_init tcp4_proc_init_net(struct net *net)
    2378  {
    2379          return tcp_proc_register(net, &tcp4_seq_afinfo);
    2380  }
    2381  
    2382  static void __net_exit tcp4_proc_exit_net(struct net *net)
    2383  {
    2384          tcp_proc_unregister(net, &tcp4_seq_afinfo);
    2385  }
    2386  
    2387  static struct pernet_operations tcp4_net_ops = {
    2388          .init = tcp4_proc_init_net,
    2389          .exit = tcp4_proc_exit_net,
    2390  };
    2391  
    2392  int __init tcp4_proc_init(void)
    2393  {
    2394          return register_pernet_subsys(&tcp4_net_ops);
    2395  }
    2396  
    2397  void tcp4_proc_exit(void)
    2398  {
    2399          unregister_pernet_subsys(&tcp4_net_ops);
    2400  }

    从L2394,我们可以看出tcp4_proc_init()调用了函数register_pernet_subsys(), 重新查看vmlinux.out验证一下。

    root# egrep 'T register_pernet_subsys' /boot/System.map-$(uname -r)
    ffffffff8175a590 T register_pernet_subsys
    
    root# sed -n "$N, $((N+20))"p vmlinux.out > /tmp/1
    root# egrep -in retq /tmp/1
    11:ffffffff8279d28a:    c3                      retq   
    
    root# sed -n '1,11'p /tmp/1 | cat -n
         1  ffffffff8279d258:       e8 93 47 26 ff          callq  0xffffffff81a019f0
         2  ffffffff8279d25d:       48 c7 c7 40 ca 31 82    mov    $0xffffffff8231ca40,%rdi
         3  ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
         4  ffffffff8279d269:       e8 82 47 26 ff          callq  0xffffffff81a019f0
         5  ffffffff8279d26e:       48 c7 c7 60 c8 31 82    mov    $0xffffffff8231c860,%rdi
         6  ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590
         7  ffffffff8279d27a:       85 c0                   test   %eax,%eax
         8  ffffffff8279d27c:       74 0c                   je     0xffffffff8279d28a
         9  ffffffff8279d27e:       48 c7 c7 c0 d0 14 82    mov    $0xffffffff8214d0c0,%rdi
        10  ffffffff8279d285:       e8 b4 c1 90 fe          callq  0xffffffff810a943e
        11  ffffffff8279d28a:       c3                      retq   
    root# sed -n '1,11'p /tmp/1 | cat -n | egrep ffffffff8175a590
         3  ffffffff8279d264:       e9 27 d3 fb fe          jmpq   0xffffffff8175a590
         6  ffffffff8279d275:       e8 16 d3 fb fe          callq  0xffffffff8175a590

    参考资料:

  • 相关阅读:
    Maven_自动化构建和构建环节
    Maven_运行时环境
    构建的概念
    Maven_真的需要吗?
    28)拷贝构造函数
    27)构造和析构函数
    26)多文件形式编写类步骤
    25)类的封装
    24)类
    23)函数重载和函数指针
  • 原文地址:https://www.cnblogs.com/idorax/p/11171394.html
Copyright © 2020-2023  润新知