【问题标题】:Changing program execution flow by signal and return address通过信号和返回地址改变程序执行流程
【发布时间】:2015-09-28 06:20:40
【问题描述】:

我正在尝试通过更改此代码中函数的返回地址来更改程序执行流程:

void s(int signum) {
    int b = 1;
    *(&b+3) = *(&b+3) + 4;
}

void f() {
    while(true);
    printf("f exit\n");
}

int main() {
    signal( SIGCONT, s );

    f();

    printf("end of prog");

    return 0;
}

为此,我调用f 函数。所以它卡在while(true)。然后我使用kill -SIGCONT <PID> 命令向程序发送SIGCONT 信号。现在程序必须中断在f 中执行while(true) 并执行s 函数。在s 函数中,我定义了b 以在运行时堆栈中找到s 函数的返回地址*(&b+3)。我尝试使用*(&b+3) = *(&b+3) + 4 更改此值,以便当它返回f 时,跳过while(true) 的执行并执行printf("f exit\n")。但它一直卡在while,我不知道如何使它工作。

注意:我通过将 *(&b+3) 与之前 __builtin_return_address(0) 返回的值进行比较,验证了它是返回地址。

函数体 mainf 必须保持不变。

谢谢。

【问题讨论】:

  • 您有理由这样做吗?您可以使用更便携的方法,例如 setjmp(3) / longjmp(3) 或在信号处理程序中使用标志。
  • s 的返回地址不在f 内——它在调度信号的任何运行时函数中。
  • 我正在尝试在 SIGCONT 进入时模拟分支故障。程序必须停留在while(true),直到信号到来并执行s。然后s 应该通过更改其返回地址来实现。默认情况下,s 的返回地址是f 中的while(true),我想将其更改为其他位置,例如printf("f exit\n");。感谢您的帮助

标签: c++ g++ signals callstack activation-record


【解决方案1】:

解决方案是以某种方式告诉 while 循环发生了一些变化。 例如

volatile int flag = 0 ;

void s(int signum) {
    int b = 1;
    __sync_fetch_and_add( &flag, 1 ) ;
}

void f() {
    while(__sync_fetch_and_add( &flag, 0 ) == 0);
    printf("f exit\n");
}

添加了原子内在函数(函数 __sync_fetch_and_add)以避免优化循环。我不确定一个简单的 volatile 就足够了。在这方面等待我自己的cmets....

【讨论】:

  • 只需将flag 设为volatile sig_atomic_t 而不是volatile int。然后,您可以在不依赖平台的内置函数的情况下更改其值。
  • 亲爱的马罗姆。感谢您的回答。但我只想通过更改s 返回地址来模拟分支错误来实现这一点。所以我想在不改变fmain 的正文的情况下做到这一点。
猜你喜欢
  • 2013-05-29
  • 2021-11-13
  • 2013-08-23
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2019-10-07
  • 2019-03-16
  • 2015-02-09
相关资源
最近更新 更多