2017-07-25 82 views
0
返回值

有这个程序的功能,目前返回我更希望它返回一个0如何更改的功能

从此我推断:我们可以添加偏移量,程序计数器,uregs[R_PC]+arg0,找到返回值的地址。我已经分配了一个32位的“0”,并且我尝试将2个字节写入返回值所在的地址(我们的函数期望返回一个BOOL16,所以我们只需要2个字节的0) :

sudo dtrace -p "$(getpid)" -w -n ' 
int *zero; 
BEGIN { zero=alloca(4); *zero=0; } 
pid$target::TextOutA:return { 
    copyout(zero, uregs[R_PC]+arg0, 2); 
}' 

当然,我得到:

的DTrace:无效的地址(0x41f21c)中:上启用探头ID 2(:pid60498:gdi32.dll.so:TextOutA:返回ID 320426)错误在DIF偏移60的动作#1

uregs[R_PC]可能是一个用户空间地址。可能copyout()想要一个内核地址。

如何将用户空间地址uregs[R_PC]转换为内核空间?我知道用copyin()我们可以将存储在用户空间地址的数据读入内核空间。但是这并没有给我们该内存的内核地址。

或者:是否有其他方法可以使用DTrace更改返回值?

+0

我看不到'arg0 + u_regs [R_PC];'得到你返回值的地址。那是两个地址。添加它们似乎没有意义。你怎么知道返回值的地址?它很可能通过寄存器传递。实际的返回值*在'arg1'中。请参阅http://docs.oracle.com/cd/E19253-01/817-6223/chp-pid/index.html –

+0

我从文档中了解到'u_regs [R_PC]'是程序计数器,而' arg0'是程序counter_的一个_offset。所以,'u_regs [R_PC]'将是一个_absolute_地址,'arg0'是一个_relative_offset_,你可以添加到该绝对地址,以获得不同的绝对地址。对于'arg1', – Birchlabs

+0

:当然这是_value_,但我的意图是在函数返回it_之前修改该值。我们在DTrace中修改数据的唯一工具('copyout()')要求我们知道数据的地址。 – Birchlabs

回答

1

DTrace不是这方面的正确工具。您应该改用像dbx,mdb或gdb这样的调试器。

与此同时,我会尝试澄清一些您提到的概念。

首先,您可能会在源代码中看到一个简单的函数,即有一个返回值。编译结果(即函数的机器特定实现)也很可能只包含一个单一的退出点。然而,通常情况下,实现可能包含多个退出点,并且开发人员可能会知道返回的函数来自哪个特定的退出点。正是这种信息被描述为从函数开始的偏移量,它由返回探测器的arg0给出。然后,你的D脚本正试图更新程序或库本身的一部分;尽管arg0的添加使得目标地址有些随机,但结果很可能仍然在只读的文本部分内。其次,在一般情况下,函数的实现通过将其存储在特定的寄存器中来返回值;例如在amd64上的%rax。因此,覆盖返回值将会覆盖寄存器值。这是不可能的,因为DTrace对用户地址寄存器的访问是只读的。

函数有可能以这样的方式实现,当它返回时,它会在将特定的内存位置写入适当的寄存器之前从特定的内存位置恢复返回值。如果是这种情况,那么确实可以在访问存储器之前修改其值(given its location)。但是,这只适用于一部分情况:返回值可能同样包含在另一个寄存器中,或者在程序文本本身中简单表示为常量。在任何情况下,如果存在更合适的调试工具,这将比其值得多得多。

+0

辉煌!感谢您的详细解释。链接的答案也很有用。好吧,所以'arg0'指向一个_instruction_(即“这个函数中的一个返回指令”),而不是数据 - 所以即使我有它的内核空间地址,它不是我所寻找的。是的,这可能是一个不同工具的工作。 – Birchlabs