从 LKM 读取 ARM CPU 寄存器
Posted
技术标签:
【中文标题】从 LKM 读取 ARM CPU 寄存器【英文标题】:Reading ARM CPU registers from LKM 【发布时间】:2016-06-02 20:45:37 【问题描述】:我想从 linux 内核模块读取存储在链接寄存器或帧指针中的值,但我不确定要使用的语法。对于上下文,我已经编译了 android goldfish 3.4 内核并使用 insmod 将我的模块加载到内核中。
【问题讨论】:
为什么你想要这个?链接寄存器和帧指针都不能保证用于其声明的目的。 编写一些内联汇编来提取特定寄存器非常简单,但也毫无意义,因为充其量您只会发现直接调用那段代码的位置从(你几乎肯定知道)以及它自己的本地堆栈帧在哪里(哇哦)。首先解释您希望通过此实现的目标会更有用... @EOF 不,但这是从 ring-0 调试器展开堆栈的好地方! @ZephyrPellerin 环 0?错误的架构。我希望你意识到 ARM 有多达 7 个分组链接寄存器和至少两个不同的帧指针约定(如果有的话),用于当前可能正在运行的任何内容,而且这甚至没有考虑问题实际上可能是关于检查保存的pt_regs
调用模块的用户空间任务;简而言之,如果没有更多详细信息,这个问题是无法回答的,而且目前还远远不能成为网站的“有用的编程问题”......
我不知道。我普遍使用术语 ring0 来表示“内核模式”。
【参考方案1】:
我对这方面的了解完全是业余爱好者,其他人可能知道一些非常时尚的东西,可以避免这种危险和骇人的方法。
作为一个哲学问题,内核不会篡改用户模式操作作为其正常职责的一部分。这意味着您将不得不篡改内核的直接操作,并可能导致崩溃、损坏和其他有问题的 c 字。
有两种方法可以做到这一点。您可以通过系统调用进入/退出机制:将单个正在运行的线程从运行用户模式代码切换到在该线程的上下文中运行内核代码,同时在它再次返回之前巧妙地替换它存储的寄存器。第二个是上下文切换机制本身,它在内核模式下从一个线程的上下文中切换到另一个线程的上下文中,再次替换相关的存储寄存器材料。
所有这一切背后的操作理论是每个用户线程都有一个用户模式堆栈和一个内核模式堆栈。当一个线程进入内核时,用户态栈的当前值和指令指针被保存到线程的kernel-mode栈中,CPU切换到内核态栈。剩余的寄存器值和标志随后也被保存到内核堆栈中。
在此阶段,您可以在进程退出运行队列之前直接读取和修改这些值。之后,当您的线程从内核返回到用户模式时,寄存器值和标志从内核模式堆栈中弹出,然后用户模式堆栈和指令指针值从内核模式上的修改值恢复堆栈。
调度有一个内部机制来选择接下来要运行的进程,调用switch_to()
。顾名思义,这个函数本质上只是切换内核堆栈——它将堆栈指针的当前值保存到当前线程的 TCB(在 Linux 中称为 struct task_struct
),并从 TCB 加载先前保存的堆栈指针为下一个线程。您可以使用它来计算有问题的用户模式进程(可能需要交叉引用现有内核模式进程结构)
【讨论】:
【参考方案2】:从内核端查看当前用户空间进程状态的方法是current_pt_regs()
(具体任务参见task_pt_regs()
)。这将为您提供指向struct pt_regs
的指针,这与您在信号处理程序中的mcontext_t
中找到的相同(至少在ARM 上)。内核甚至提供了很好的访问宏来使整个 caboodle 变得相当文明 - 阅读源代码中的现有用法应该可以很好地了解如何做到这一点,但为了完整起见,这里有一个简单的例子*:
#include <asm/ptrace.h>
void func()
struct pt_regs *regs = current_pt_regs();
pr_info("User LR was %p\n", (void *)regs->ARM_lr);
您必须知道用户空间二进制文件的 ABI 详细信息才能知道哪个寄存器(如果有)被用作帧指针,但如果有的话,它通常在 r11 或 r7 中。
*代码在深夜直接输入浏览器,通常的免责声明适用,等等。
【讨论】:
谢谢...但是没有内核宏可以从 android goldfish 访问寄存器:android.googlesource.com/kernel/goldfish/+/android-goldfish-3.4/…以上是关于从 LKM 读取 ARM CPU 寄存器的主要内容,如果未能解决你的问题,请参考以下文章