当程序打开特定文件时 gdb 中断
背景故事:在 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
GDB 是一个非常强大的工具,但有一些学习曲线。
基本上,您想要设置一个条件断点。
首先使用 -i 标志来 strace 或 objdump -d 来查找 open 函数的地址,或者更实际地在到达那里的链中查找某些东西,例如在 plt.
在该地址设置一个断点(如果你有调试符号,你可以使用它们,省略 *,但我假设你没有 - 尽管你很可能将它们用于库函数,如果没有其他的话。
接下来你需要使它成为有条件的
(理想情况下,您可以将字符串参数与所需的字符串进行比较。我在尝试的前几分钟内没有让这个工作)
让我们希望我们可以假设该字符串是程序中某处的常量或其中之一你可以查看它加载的库。 /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 指针的指针。所以我们需要取消引用它来进行比较。
然后你可以输入 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.
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.
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.
就像 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.
(改编自问题编辑)
按照Chris的回答,以下是最终让我得到什么的过程我一直在寻找:(
我试图找到哪些函数在“/dev/urandom”上调用
open
系统调用)grep
查找“urandom”rdi<中传递/code> -- 你的里程可能会有所不同
break open if $rdi == _addr_
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")grep
through each lib (shell command) looking for 'urandom'rdi
-- your mileage may varybreak open if $rdi == _addr_
bt
to see backtraceAfter 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.
请注意,从寄存器读取会给出存储在寄存器中的数字,即本例中的地址。
因此,对于通过检查 $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")