这是一项家庭作业,因此,如果我仅得到提示而不是完整答案,我将不胜感激。我编写了该程序,该程序应打印以下内容:




Executing function_a
Executing function_b
Finished!
main()函数已给出,仅允许在标记的部分中更改function_a()。 。我们必须对堆栈进行操作,以使从function_b()返回时,我们不会返回其实际父级function_b(),而是返回其祖父function_a()。然后将main()的返回地址和保存的帧指针复制到function_a()的帧。我的程序执行以下操作:



#include <stdio.h>
#include <stdint.h>

void function_b(void) {
    char buffer[4];

    // edit between here...
    uint32_t * x = &buffer;
    while (*(x++) != 0xa0b1c2d3);           // Find the beacon
    *(uint32_t*)(&buffer + 6) = *(x + 2);   // Copy return address from caller
    *(uint32_t*)(&buffer + 5) = *(x + 1);   // Copy frame pointer from caller
    // ... and here

    fprintf(stdout, "Executing function_b\n");
}

void function_a(void) {
    int beacon = 0xa0b1c2d3;
    fprintf(stdout, "Executing function_a\n");
    function_b();
    fprintf(stdout, "Executed function_b\n");
}

int main(void) {
    function_a();
    fprintf(stdout, "Finished!\n");
    return 0;
}


所以它执行正确的操作,但segfault除外。从function_a()函数返回时失败。我用gdb来获得此信息:无法理解function_b()崩溃。我可以看到发生这种情况的唯一方法是,我弄错了main()的堆栈框架,但我没有弄错,或者我应该在那里更改一些东西,但是我不知道是什么。

注意:该程序使用GCC和标志function_b()进行编译。我在64位计算机上。

#1 楼


我在64位计算机上。


function_b()中的代码将指针视为32位值而不是64位值。您应该使用uint64_t*而不是uint32_t*

#2 楼

正如Jason所写,我应该使用64位指针。除此之外,事实证明,我必须从堆栈帧中复制四个数字。这是有效的代码:

uint64_t * my_ptr = &buf;
int * x = my_ptr;

while (*(++x)  != 0xa0b1c2d3);  // Find the beacon. We could of course simply have a look
uint64_t * y = x + 1;           // with gdb where it's stored, but this works generically.

*(my_ptr+7) = *(y+3);           // Copy frame information
*(my_ptr+6) = *(y+2);
*(my_ptr+5) = *(y+1);
*(my_ptr+4) = *y;


通常,您需要弄些必须复制的地址。您可以像使用gdb一样大致了解。确切的数字取决于函数及其变量。

评论


“如果我仅获得提示而不是完整的答案,我将不胜感激。”但是,您接受了非提示的完整答案作为接受的答案:

–詹森·格夫纳(Jason Geffner)
15年3月18日在16:43

我以为我们同意我将在注释中编辑我的工作代码。但是您回滚了我的编辑而没有解释。

–user187
15年3月19日在7:44