【问题标题】:Reverse engineering C codes with GCC -march=i686使用 GCC -march=i686 逆向工程 C 代码
【发布时间】:2013-07-03 01:41:58
【问题描述】:

这是我的 C 代码:

int test(int x, int y){
    int val=4*x;
    if (y>0){
        if (x<y) val=x-y;
        else val=x^y;
    }
    else if (y<-2) val=x+y;
    return val;
}

这是我在 GCC 命令行中输入的内容:

gcc -O1 -S -march=i686 test.c

这是我得到的S文件(只有计算部分):

pushl   %ebx
movl    8(%esp), %ecx
movl    12(%esp), %edx
testl   %edx, %edx
jle     L2
movl    %ecx, %eax
subl    %edx, %eax
movl    %edx, %ebx
xorl    %ecx, %ebx
cmpl    %edx, %ecx
cmovge  %ebx, %eax
jmp     L4

L2:
leal    0(,%ecx,4), %eax
addl    %edx, %ecx
cmpl    $-2, %edx
cmovl   %ecx, %eax

L4:
popl    %ebx
ret

我的问题是:我可以使用上面的 S 文件返回完全相同的 C 代码吗?我的意思是完全一样的。例如,我可以确定val 的默认值为4*x(C 代码的第2 行)吗?我可以确定每个if 语句的测试表达式吗?

我真的需要你的帮助。谢谢!!!

【问题讨论】:

  • 没有。例如,无法确定变量名称。

标签: c gcc assembly reverse-engineering


【解决方案1】:

在这种情况下,你可以发现每个寄存器对应一个变量:

  • %eax - var
  • %ebx - 上下文临时变量
  • %ecx - x
  • %edx - y

如果你的意思是“完全”的标识符,只有当一个名为“符号表”的特殊结构时才有可能。 (在 GCC 中使用 -g 标志编译)

无论如何,您应该知道编译器始终可以优化代码。这意味着,在这种情况下,您的代码将更改为另一个具有相同数学含义的代码。如果你的代码是反向翻译的,应该是这样的。

int test(int x, int y) {
    int val;
    if (y > 0) {
        if (x < y)
            val = x - y;
        else
            val = x ^ y;
    } else {
        if (y < -2)
            val = x + y;
        else
            val = 4 * x;
    }
    return val;
}

如果您不想优化,请使用标志-O0 而不是-O1

【讨论】:

  • :谢谢。实际上,这是我正在阅读的一本书的练习题。书中的解决方案建议你真的可以使用上面的汇编代码来获取原始的 C 代码,因为 GCC 总是遵循一些特定的规则。例如,对于 C 中的“if-else”语句,编译器会首先考虑“else”。这就解释了 S 文件第 5 行的“jle L2”。
  • 但即使这是真的,我仍然无法向后翻译第 6-12 行和第 14-17 行,因为这里编译器使用 i686 并且似乎同时考虑了这两种情况......任何人对这些部分的翻译有什么想法吗?
  • 这是一个使用条件指令的优化技巧。通过这样做,分支会减少。您可能知道分支会导致性能损失。
  • 所以你的意思是没有办法翻译这些部分?
  • 我认为你可以,但是。是的。尝试编译您的代码和我的代码,然后将最后一个 if 语句替换为 if (y &gt;= -2) val = 4 * x; else val = x + y;。 GCC 的足迹很小但很重要。如果你完全熟练,也许这是可能的。
猜你喜欢
  • 2010-09-11
  • 2015-04-13
  • 2011-05-28
  • 2011-12-28
  • 1970-01-01
  • 1970-01-01
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多