【问题标题】:Modifying the return address of a function for jumping a line code修改跳转行代码的函数返回地址
【发布时间】:2019-06-05 07:56:01
【问题描述】:

我想修改以下函数,以便可以跳过主函数中的行:x='b'。

#include <stdio.h>

void function (int a, int b, int c) {
  int i, j;
  char buf[5];
  char buffer1[12];  
  int *ret; 
}

int main() {
  char x;
  x = 'a';
  printf ("Hello\n");
  printf ("I am going to skip a statement\n");  
  function(1,2,3);
  x = 'b';
  printf ("By");
  printf("The following value must be the a letter: %c\n",x);
}

我尝试获取返回地址并使用 `ret' 变量添加必要的字节,但似乎不正确。

ret=buffer1+12+4+1;
(*ret)+=4;


无论如何 x='b' 仍然被执行。

【问题讨论】:

  • 这些都没有任何意义。我什至不明白您要做什么...您是否以某种方式假设 C 指令等同于汇编程序指令?
  • 你的目的是什么?编译器将始终正确处理它,因为始终生成代码以正确从函数返回是它的作用。
  • 顺便说一句,用C手动设置PC是不可能的,所以你不能通过计算相对地址来跳过指令。您必须为此使用汇编程序。
  • 这是相当不正当的,因为语言并不真正支持它。您可以尝试setjmplongjmp、内联汇编等。 &C。但那是“狡猾的”C。
  • 给大家的信息:当一个 C 函数被调用时,返回地址被压入堆栈(除了可能不是的六个原因)。 OP 的代码尝试修改堆栈上的返回地址,以便返回地址指向printf("By"); 而不是x = 'b';。这行不通的原因至少有十几个,但如果一个人了解它可能行不通的所有原因,就可以做到。

标签: c gcc gdb


【解决方案1】:

ret=buffer1+12+4+1;

这是Undefined Behaviour™,因为您的指针算法已离开分配。编译器现在可以随心所欲地做任何事情,包括让守护进程飞出你的鼻子。

(*ret)+=4;

而且 gcc 非常擅长发现未定义的行为,并且在选择它喜欢的东西时非常吝啬。

如果启用了优化,它可能会完全忽略该语句,如果没有,您可能无论如何都错了偏移量,因为绝对不能保证变量的布局。对齐会有一些填充,甚至顺序也可能不同。而且我不确定你从哪里得到+1,但没有合理的布局让它有意义。

您似乎还假设目标是 32 位,但现在大多数 Linux 都是完整的 64 位。

【讨论】:

    【解决方案2】:

    此时,当使用我的个人电脑并且晚上有新月时,下面的代码完美运行(note)。它跳过第二条puts指令,直接跳转到第三条puts

    #include <stdio.h>
    #include <setjmp.h>
    #include <stdint.h>
    
    #define can_you_see_what_I_mean() setjmp(jb)
    #define might_as_well(task) ((uint32_t*)&jb)[20] = 0x401544; task(jb, 0)
    
    static jmp_buf jb;
    
    int main (void)
    {
      puts("I get up");
      if(!can_you_see_what_I_mean())
      {
        might_as_well(longjmp);
      }
      puts("Go ahead and jump");
      puts("Hey you, who said that?");
    }
    

    输出:

    I get up
    Hey you, who said that?
    

    (注) 我不建议任何人出于任何目的使用此代码,因为它依赖于非常糟糕的做法并且包含无数形式的未定义行为。它非常不便携。

    【讨论】:

      【解决方案3】:

      这篇文章可以帮助您解决您的问题,但需要注意的是:问题在于编辑 jmp_buf 或编写内联汇编都不可移植。我建议您使用众多控制流构造中的一种(例如 if 或 goto),话虽如此,请将此作为起点。 Implementing setjmp and longjmp in C without built in functions or assembly (getting incorrect return values)

      【讨论】:

      • 是的,我们不应该使用 goto、setjmp 和 longjmp 等非常脏的词。我觉得他们很冒犯!
      • 先生,您已经收到了,剩下的呢?据我说,这条线真的可以帮助他做他想做的事
      【解决方案4】:

      以下建议的代码:

      1. 干净编译
      2. 依赖function()中的语句跳过语句:x = 'b';

      现在,建议的代码:

      #include <stdio.h>
      
      int function ( void ) 
      {
          return 1;
      }
      
      int main( void ) 
      {
        char x = 'a';
        printf ("Hello\n");
        printf ("I am going to skip a statement\n");  
        if( !function() )
        {
            x = 'b';
        }
        printf ("By");
        printf("The following value must be the a letter: %c\n",x);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-09-19
        • 2017-04-04
        • 2011-07-29
        • 2019-07-17
        • 2014-01-22
        • 2019-10-04
        • 1970-01-01
        • 2019-06-17
        相关资源
        最近更新 更多