当程序打开特定文件时 gdb 中断

发布于 2024-11-04 16:12:16 字数 377 浏览 1 评论 0原文

背景故事:在 strace 下运行程序时,我注意到“/dev/urandom”正在被 open 编辑。我想知道这个调用来自哪里(它不是程序本身的一部分,它是系统的一部分)。

因此,使用 gdb,我尝试在发出 open 调用时中断(使用 catch syscall open)程序执行,以便我可以看到回溯。问题是 open 被调用很多,比如几百次,所以我无法缩小打开 /dev/urandom 的特定调用范围。我应该如何缩小特定呼叫的范围?有没有一种方法可以按参数进行过滤,如果是的话,我该如何为系统调用执行此操作?

任何建议都会有帮助——也许我的做法是错误的。

Back story: While running a program under strace I notice that '/dev/urandom' is being open'ed. I would like to know where this call is coming from (it is not part of the program itself, it is part of the system).

So, using gdb, I am trying to break (using catch syscall open) program execution when the open call is issued, so I can see a backtrace. The problem is that open is being called alot, like several hundred times so I can't narrow down the specific call that is opening /dev/urandom. How should I go about narrowing down the specific call? Is there a way to filter by arguments, and if so how do I do it for a syscall?

Any advice would be helpful -- maybe I am going about this all wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

帅冕 2024-11-11 16:12:16

GDB 是一个非常强大的工具,但有一些学习曲线。

基本上,您想要设置一个条件断点。

首先使用 -i 标志来 strace 或 objdump -d 来查找 open 函数的地址,或者更实际地在到达那里的链中查找某些东西,例如在 plt.

在该地址设置一个断点(如果你有调试符号,你可以使用它们,省略 *,但我假设你没有 - 尽管你很可能将它们用于库函数,如果没有其他的话。

break * 0x080482c8 

接下来你需要使它成为有条件的

(理想情况下,您可以将字符串参数与所需的字符串进行比较。我在尝试的前几分钟内没有让这个工作)

让我们希望我们可以假设该字符串是程序中某处的常量或其中之一你可以查看它加载的库。 /proc/pid/maps 了解加载的内容和位置,然后使用 grep 验证该字符串实际上在文件中,使用 objdump -s 查找它的地址,然后使用 gdb 验证您是否确实在其中找到了它通过将映射中地址的高位部分与文件中的低位部分相结合来获取内存(编辑:在可执行文件上使用 ldd 可能比查看 /proc/pid/maps 更容易)

接下来,您需要了解有关平台的abi您正在研究,特别是如何传递参数。我最近一直在研究arm,这非常好,因为前几个参数只是进入寄存器r0,r1,r2...等。x86有点不太方便 - 似乎它们在堆栈上,即* ($esp+4),*($esp+8),*($esp+12)。

因此,假设我们在 x86 上,并且我们想要检查 esp+4 中的第一个参数是否等于我们为试图捕获它传递的常量找到的地址。只是,esp+4 是一个指向 char 指针的指针。所以我们需要取消引用它来进行比较。

cond 1 *(char **)($esp+4)==0x8048514

然后你可以输入 run 并希望得到最好的结果

如果你捕获了断点条件,并且使用信息寄存器和 x 命令来检查内存似乎是正确的,那么你可以使用 return 命令来渗透回来向上调用堆栈,直到找到您认识的内容。

GDB is a pretty powerful tool, but has a bit of a learning curve.

Basically, you want to set up a conditional breakpoint.

First use the -i flag to strace or objdump -d to find the address of the open function or more realistically something in the chain of getting there, such as in the plt.

set a breakpoint at that address (if you have debug symbols, you can use those instead, omitting the *, but I'm assuming you don't - though you may well have them for library functions if nothing else.

break * 0x080482c8 

Next you need to make it conditional

(Ideally you could compare a string argument to a desired string. I wasn't getting this to work within the first few minutes of trying)

Let's hope we can assume the string is a constant somewhere in the program or one of the libraries it loads. You could look in /proc/pid/maps to get an idea of what is loaded and where, then use grep to verify the string is actually in a file, objdump -s to find it's address, and gdb to verify that you've actually found it in memory by combining the high part of the address from maps with the low part from the file. (EDIT: it's probably easier to use ldd on the executable than look in /proc/pid/maps)

Next you will need to know something about the abi of the platform you are working on, specifically how arguments are passed. I've been working on arm's lately, and that's very nice as the first few arguments just go in registers r0, r1, r2... etc. x86 is a bit less convenient - it seems they go on the stack, ie, *($esp+4), *($esp+8), *($esp+12).

So let's assume we are on an x86, and we want to check that the first argument in esp+4 equals the address we found for the constant we are trying to catch it passing. Only, esp+4 is a pointer to a char pointer. So we need to dereference it for comparison.

cond 1 *(char **)($esp+4)==0x8048514

Then you can type run and hope for the best

If you catch your breakpoint condition, and looking around with info registers and the x command to examine memory seems right, then you can use the return command to percolate back up the call stack until you find something you recognize.

静若繁花 2024-11-11 16:12:16

就像 Andre Puel 所说:

break open if strcmp($rdi,"/dev/urandom") == 0

可能会完成这项工作。

Like Andre Puel said:

break open if strcmp($rdi,"/dev/urandom") == 0

Might do the job.

好多鱼好多余 2024-11-11 16:12:16

(改编自问题编辑)

按照Chris的回答,以下是最终让我得到什么的过程我一直在寻找:(

我试图找到哪些函数在“/dev/urandom”上调用 open 系统调用)

  1. 查找加载的库
  2. 在可执行文件上使用 ldd通过 grep 查找“urandom”
  3. 每个lib(shell命令)在十六进制编辑器中
  4. 打开库文件并查找字符串的地址找出如何在系统调用中传递参数(对于打开,文件是第一个参数。在x86_64上它在rdi<中传递/code> -- 你的里程可能会有所不同
  5. ,现在我们可以设置条件断点:break open if $rdi == _addr_
  6. run program and wait for break to hit
  7. run bt to看到 backtrace

毕竟我发现 glib 的 g_random_int() 和 g_rand_new() 使用 urandom 和 ORBit 调用这些函数——如果有人好奇的话。

(Adapted from a question edit)

Following Chris's answer, here is the process that eventually got me what I was looking for:

(I am trying to find what functions are calling the open syscall on "/dev/urandom")

  1. use ldd on executable to find loaded libraries
  2. grep through each lib (shell command) looking for 'urandom'
  3. open library file in hex editor and find address of string
  4. find out how parameters are passed in syscalls (for open, file is first parameter. on x86_64 it is passed in rdi -- your mileage may vary
  5. now we can set the conditional breakpoint: break open if $rdi == _addr_
  6. run program and wait for break to hit
  7. run bt to see backtrace

After all this I find that glib's g_random_int() and g_rand_new() use urandom. Gtk+ and ORBit were calling these functions -- if anybody was curious.

一萌ing 2024-11-11 16:12:16

请注意,从寄存器读取会给出存储在寄存器中的数字,即本例中的地址。

因此,对于通过检查 $rdi 的解决方案,您需要在进行字符串比较之前将 $rdi 转换为字符串,即 b open if (int)strcmp((const char*)$rdi, "target") = = 0

此外,如果您无法确定完整的文件名到底是什么,比如说,它可能是相对路径,您可以使用 b open if strstr((const char*)$rdi, "您可以确保文件名的一部分”)

Note that reading from a register gives you the number, i.e., address in this case, stored in the register.

So for the solution by checking $rdi, you'll want to convert $rdi to string before doing string compare, i.e., b open if (int)strcmp((const char*)$rdi, "target") == 0

Moreover, if you somehow cannot determine what the full filename really is, say, it might be a relative path, you may instead use b open if strstr((const char*)$rdi, "part of the filename you can ensure")

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文