如何在Linux用户和内核空间中进行动态跟踪

如何在Linux用户和内核空间中进行动态跟踪,第1张

你不记得如何在代码中插入探针点了吗? 没问题!了解如何使用uprobe和kprobe来动态插入它们吧。 基本上,程序员需要在源代码汇编指令的不同位置插入动态探针点。

探针点

探针点是一个调试语句,有助于探索软件的执行特性(即,执行流程以及当探针语句执行时软件数据结构的状态)。printk是探针语句的最简单形式,也是黑客用于内核攻击的基础工具之一。

因为它需要重新编译源代码,所以printk插入是静态的探测方法。内核代码中重要位置上还有许多其他静态跟踪点可以动态启用或禁用。 Linux内核有一些框架可以帮助程序员探测内核或用户空间应用程序,而无需重新编译源代码。Kprobe是在内核代码中插入探针点的动态方法之一,并且uprobe在用户应用程序中执行此 *** 作。

使用uprobe跟踪用户空间

可以通过使用thesysfs接口或perf工具将uprobe跟踪点插入用户空间代码。

使用sysfs接口插入uprobe

考虑以下简单测试代码,没有打印语句,我们想在某个指令中插入探针:

[source,c\ntestc

#include <stdioh>\n#include <stdlibh>\n#include <unistdh>

编译代码并找到要探测的指令地址:

# gcc -o test test\n# objdump -d test

假设我们在ARM64平台上有以下目标代码:

0000000000400620 <func_1>: 400620\t90000080\tadr\tx0, 410000 <__FRAME_END__+0xf6f8>

并且我们想在偏移量0x620和0x644之间插入探针。执行以下命令:

# echo 'p:func_2_entry test:0x620' > /sys/kernel/debug/tracing/uprobe_event\n# echo 'p:func_1_entry test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable# /test&

在上面的第一个和第二个echo语句中,p告诉我们这是一个简单的测试。(探测器可以是简单的或返回的。)func_n_entry是我们在跟踪输出中看到的名称,名称是可选字段,如果没有提供,我们应该期待像p_test_0x644这样的名字。test 是我们要插入探针的可执行二进制文件。如果test 不在当前目录中,则需要指定path_to_test / test。

0x620或0x640是从程序启动开始的指令偏移量。请注意>>在第二个echo语句中,因为我们要再添加一个探针。所以,当我们在前两个命令中插入探针点之后,我们启用uprobe跟踪,当我们写入events/ uprobes / enable时,它将启用所有的uprobe事件。程序员还可以通过写入在该事件目录中创建的特定事件文件来启用单个事件。一旦探针点被插入和启用,每当执行探测指令时,我们可以看到一个跟踪条目。

读取跟踪文件以查看输出:

# cat /sys/kernel/debug/tracing/trac\n# tracer: no\n\n# entries-in-buffer/entries-written: 8/8\n#P:\n\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softir\n# || / _--=> preempt-dept\n# ||| / dela\n# TASK-PID CP\n# |||| TIMESTAMP FUNCTION# | | | |||| | |

我们可以看到哪个CPU完成了什么任务,什么时候执行了探测指令。

返回探针也可以插入指令。当返回该指令的函数时,将记录一个条目:

# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'r:func_2_exit test:0x620' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 'r:func_1_exit test:0x644' >> /sys/kernel/debug/tracing/uprobe_event\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable

这里我们使用r而不是p,所有其他参数是相同的。请注意,如果要插入新的探测点,需要禁用uprobe事件:

test-3009 [002] 4813852674: func_1_entry: (0x400644)

上面的日志表明,func_1返回到地址0x4006b0,时间戳为4813852691。

# echo 0 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo 'p:func_2_entry test:0x630' > /sys/kernel/debug/tracing/uprobe_events count=%x\n# echo 1 > /sys/kernel/debug/tracing/events/uprobes/enabl\n# echo > /sys/kernel/debug/tracing/trace# /test&

当执行偏移量0x630的指令时,将打印ARM64 x1寄存器的值作为count =。

输出如下所示:

test-3095 [003] 7918629728: func_2_entry: (0x400630) count=0x1

使用perf插入uprobe

找到需要插入探针的指令或功能的偏移量很麻烦,而且需要知道分配给局部变量的CPU寄存器的名称更为复杂。 perf是一个有用的工具,用于帮助引导探针插入源代码中。

除了perf,还有一些其他工具,如SystemTap,DTrace和LTTng,可用于内核和用户空间跟踪;然而,perf与内核配合完美,所以它受到内核程序员的青睐。

# gcc -g -o test testc# perf probe -x /test func_2_entry=func_\n# perf probe -x /test func_2_exit=func_2%retur\n# perf probe -x /test test_15=testc:1\n# perf probe -x /test test_25=testc:25 numbe\n# perf record -e probe_test:func_2_entry -e\nprobe_test:func_2_exit -e probe_test:test_15\n-e probe_test:test_25 /test

如上所示,程序员可以将探针点直接插入函数start和return,源文件的特定行号等。可以获取打印的局部变量,并拥有许多其他选项,例如调用函数的所有实例。 perf探针用于创建探针点事件,那么在执行/testexecutable时,可以使用perf记录来探测这些事件。当创建一个perf探测点时,可以使用其他录音选项,例如perf stat,可以拥有许多后期分析选项,如perf脚本或perf报告。

使用perf脚本,上面的例子输出如下:

# perf script

使用kprobe跟踪内核空间

与uprobe一样,可以使用sysfs接口或perf工具将kprobe跟踪点插入到内核代码中。

使用sysfs接口插入kprobe

程序员可以在/proc/kallsyms中的大多数符号中插入kprobe;其他符号已被列入内核的黑名单。还有一些与kprobe插入不兼容的符号,比如kprobe_events文件中的kprobe插入将导致写入错误。 也可以在符号基础的某个偏移处插入探针,像uprobe一样,可以使用kretprobe跟踪函数的返回,局部变量的值也可以打印在跟踪输出中。

以下是如何做:

; disable all events, just to insure that we see only kprobe output in trace\n# echo 0 > /sys/kernel/debug/tracing/events/enable; disable kprobe events until probe points are inseted\n# echo 0 > /sys/kernel/debug/tracing/events/kprobes/enable; clear out all the events from kprobe_events\n to insure that we see output for; only those for which we have enabled

[root@pratyush ~\n# more /sys/kernel/debug/tracing/trace# tracer: no\n\n# entries-in-buffer/entries-written: 9037/9037\n#P:8\n# _-----=> irqs-of\n# / _----=> need-resche\n# | / _---=> hardirq/softirq#\n|| / _--=> preempt-depth#\n ||| / delay# TASK-PID CPU#\n |||| TIMESTAMP FUNCTION#\n | | | |||| | |

使用perf插入kprobe

与uprobe一样,程序员可以使用perf在内核代码中插入一个kprobe,可以直接将探针点插入到函数start和return中,源文件的特定行号等。程序员可以向-k选项提供vmlinux,也可以为-s选项提供内核源代码路径:

# perf probe -k vmlinux kfree_entry=kfre\n# perf probe -k vmlinux kfree_exit=kfree%retur\n# perf probe -s / kfree_mid=mm/slubc:3408 \n# perf record -e probe:kfree_entry -e probe:kfree_exit -e probe:kfree_mid sleep 10

使用perf脚本,以上示例的输出:

关于Linux命令的介绍,看看《linux就该这么学》,具体关于这一章地址3w(dot)linuxprobe/chapter-02(dot)html

Linux是一种免费、开放源代码的 *** 作系统,被广泛应用于服务器、移动设备、嵌入式系统等领域。以下是Linux *** 作系统的基础教程:

下载和安装Linux *** 作系统

Linux有很多不同的发行版,如Ubuntu、Debian、Fedora等,用户可以根据自己的需求选择不同的发行版。可以从官方网站上下载对应的ISO文件,然后通过软件将ISO文件写入U盘或者刻录成DVD,然后插入计算机,选择从U盘或DVD启动,进入安装过程。

基本的Linux命令

在Linux中,用户可以通过终端来 *** 作系统,输入命令来完成不同的任务。以下是一些基本的Linux命令:

ls:列出当前目录下的文件和文件夹。

cd:切换当前目录。

mkdir:创建一个新的文件夹。

touch:创建一个新的文件。

rm:删除一个文件或者文件夹。

mv:移动或者重命名文件或文件夹。

cp:复制文件或者文件夹。

chmod:改变文件或者文件夹的权限。

sudo:以管理员身份运行命令。

学习Linux的编辑器

Linux *** 作系统中有很多不同的文本编辑器,比如nano、vim、emacs等。其中,vim是最常用的编辑器之一。学习如何使用一个编辑器是非常重要的,因为在Linux中,编辑器常常用来编辑配置文件和编写脚本等任务。

学习Linux的软件包管理器

Linux *** 作系统中有很多不同的软件包管理器,如apt、yum、pacman等。这些软件包管理器可以帮助用户安装、升级、删除软件包。用户可以通过命令行来使用软件包管理器,也可以使用图形界面来完成这些任务。

学习Shell脚本编程

Shell脚本是一种在Linux中编写自动化任务的简单方法。脚本可以用来完成许多任务,如备份文件、自动化部署应用程序、批量处理文件等。学习Shell脚本编程可以让用户更加高效地管理Linux系统。

以上是Linux *** 作系统的基础教程,希望能对您有所帮助。

1、打开kali linux的终端。创建一个文件并命名为testc。在终端输入:touch testc。

2、可以看到已经生成了一个后缀为testc的源文件。然后用vim工具打开这个文件并编写代码。在终端中输入:vim testc或者gvim testc打开这个文件并编写代码。

3、编写完了这个代码。现在开始编译源文件。在终端中输入:gcc testcgcc是linux自带的c语言编译器。如果是windows则要用ide工具来编译。linux系统一般写C语言用gcc +vim+gdb三个自带的工具就可以了。

4、打完gcc testc编译完C源文件。然后就可以看见aout的文件。一般linux系统就默认为aout为编译完的文件。现在运行aout文件。在aout文件的目录下打开终端并输入/aout就是运行文件了。

5、如果想要编译完的文件名不要用aout文件。就可以在编译时打入gcc testc -o testout然后就可以看见有一个testout文件 了。-o后面跟着的编译生成的文件名。

6、再运行testout在终端中输入/testout结果如图。这样在linux系统下编译并运行C语言就完成了。

Java可以通过使用Process类来实现Linux的持续输入。Process类可以帮助Java程序调用外部程序,从而实现linux持续输入。

可以通过使用ProcessBuilder,Runtime或Executor类来实现外部程序的调用。

此外,可以使用JSch库的Session类来连接到Linux服务器,并使用ChannelExec类来执行Linux命令。

还可以使用Apache Commons Exec库来实现Linux持续输入,该库提供了一个用于执行外部命令的API,可以使用它来执行Linux命令。

以上就是关于如何在Linux用户和内核空间中进行动态跟踪全部的内容,包括:如何在Linux用户和内核空间中进行动态跟踪、linux *** 作系统教程、在Linux系统中,如何运行一个C语言程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10083139.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存