jjzjj

linux - 使用 kprobes 获取函数参数

coder 2023-06-19 原文

我已经在一个函数上放置了一个 kprobe,现在我需要在 kprobe 的预处理器函数中获取它的参数值。

这是我的功能:

void foobar(int arg, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8)
{
    printk("foobar called\n");
}

将kprobe放在上面并调用函数:

...
kp.addr = (kprobe_opcode_t *) foobar;
register_kprobe(&kp);

foobar(0xdead1, 0xdead2, 0xdead3, 0xdead4, 0xdead5, 0xdead6, 0xdead7, 0xdead8);

最后是预处理器函数(取自 here ):

static int inst_generic_make_request(struct kprobe *p, struct pt_regs *regs)
{
  printk(KERN_INFO "eax: %08lx   ebx: %08lx   ecx: %08lx   edx: %08lx\n",
    regs->ax, regs->bx, regs->cx, regs->dx);
    printk(KERN_INFO "esi: %08lx   edi: %08lx   ebp: %08lx   esp: %08lx\n",
      regs->si, regs->di, regs->bp, regs->sp);
    regs++;
    //...
}

预处理器函数的输出如下所示(我将 regs 指针递增了 3 次)

May 10 22:58:07 kernel: [  402.640994] eax: 000dead1   ebx: f7d80086   ecx: 000dead3   edx: 000dead2
May 10 22:58:07 kernel: [  402.640996] esi: 00000000   edi: b77c8040   ebp: 00000000   esp: f7d8006c

May 10 22:58:07 kernel: [  402.641006] eax: f7d8032c   ebx: 000dead5   ecx: 000dead6   edx: 000dead7
May 10 22:58:07 kernel: [  402.641007] esi: 000dead8   edi: f7d800e0   ebp: f7d80330   esp: 08049674

May 10 22:58:07 kernel: [  402.641014] eax: 00000080   ebx: 0992b018   ecx: 0000108e   edx: 0992b008
May 10 22:58:07 kernel: [  402.641015] esi: 08049674   edi: b77c8040   ebp: bfe23fb8   esp: bfe23f50

现在我可以在各种寄存器中看到 foobar 函数的参数(但是 0xdead4 在哪里?),它们不应该在堆栈中吗?如何从预处理器函数访问堆栈?或者我如何在不知道它们的类型和计数的情况下获取任何函数的参数?我知道这可能不是一件容易的事(甚至不可能获得所有值),但只有近似值就足够了。我正在计算两个函数的参数之间的相关性,我真的不需要确切的值。如果我有将参数压入堆栈的调用函数的汇编代码,会有帮助吗?

最佳答案

至少有两种方法。

方法一:Jprobes

可能是最简单的一个:如果 Jprobes 适合您的任务,您可以尝试一下。它们是 kprobes 的近亲(请参阅它们的详细描述和指向 kernel docs 中示例的链接)。

Jprobes 允许在进入后者时使用与被探测函数相同的签名调用您的函数。您可以通过这种方式自动获得所有参数。

方法 2:寄存器和堆栈

另一种方法可能是扩展您已经做的事情并从寄存器和堆栈中检索参数。根据您问题的输出日志,我假设您正在使用 32 位 x86 系统。

x86,32 位

据我所知,在 x86 上的 Linux 内核中有两种最常见的参数传递约定(详细信息可在 manual by Agner Fog 中找到)。请注意,系统调用遵循其他约定(有关详细信息,请参阅 manual),但我假设您对分析“普通”函数而不是系统调用感兴趣。

约定 1

对于标有asmlinkage 的函数以及具有可变参数列表的函数,所有参数都在堆栈上传递。函数的返回地址应该位于函数入口处的堆栈顶部,第一个参数位于它的正下方。第二个参数在第一个参数之下,以此类推。

因为你有 esp 的保存值,你可以找到它指向的内容。如果使用此约定,*(esp+4) 应该是第一个参数,*(esp+8) - 第二个等等。

约定 2

它似乎用于大多数内核函数,包括您在问题中提到的那个。

内核使用 -mregparm=3 编译,因此前 3 个参数在 eaxedxecx 中传递,按照这个顺序,其余的进入堆栈。 *(esp+4) 应该是第 4 个参数,*(esp+8) - 第 5 个,依此类推。

x86, 64 位

在 x86-64 上似乎事情要简单一些。大多数内核函数(包括那些具有可变参数列表的函数)在 rdirsirdxrcx 中获取前 6 个参数, r8, r9,按照这个顺序,剩下的入栈。 *(esp+8) 应该是第 7 个参数,*(esp+16) - 第 8 个等等。

编辑:

请注意,在 x86-32 上,esp 的值不会保存在 pt_regs 中以用于内核模式陷阱(包括 KProbes 所依赖的软件断点)。 <asm/ptrace.h>提供 kernel_stack_pointer() 函数来检索 esp 的正确值,它在 x86-32 和 x86-64 上都有效。有关详细信息,请参阅该头文件中对 kernel_stack_pointer() 的描述。

此外,regs_get_kernel_stack_nth()(也在该 header 中定义)提供了一种在处理程序中获取堆栈内容的便捷方法。

关于linux - 使用 kprobes 获取函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10563635/

有关linux - 使用 kprobes 获取函数参数的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

随机推荐