【问题标题】:Can someone convert this assembly to C有人可以将此程序集转换为 C
【发布时间】:2014-12-24 18:29:53
【问题描述】:

我有这个我似乎无法弄清楚的课堂作业。 关键是将这个程序集转换为 C(使用 GNU 汇编器 AT&T 语法汇编的代码):

 .section .rdata,"dr"
LC0:
.ascii "%d\12\0"
.text
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp)
call _atoi
movl %eax, 24(%esp)
cmpl $4, 24(%esp)
je L2
cmpl $6, 24(%esp)
jle L3
cmpl $9, 24(%esp)
jg L3
L2:
movl 24(%esp), %eax
addl $20, %eax
movl %eax, 28(%esp)
jmp L4
L3:
cmpl $0, 24(%esp)
jne L5
movl $44, 28(%esp)
jmp L4
L5:
cmpl $-1, 24(%esp)
jne L6
movl $-44, 28(%esp)
jmp L4
L6:
movl $99, 28(%esp)
L4:
movl 28(%esp), %eax
movl %eax, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret

但是我总是迷失在 L2 上。似乎无论我们是否进入第一个 if 语句,我们都将始终执行标签 L2,这没有任何意义。我试图理解这一切,我得到的最接近的是这段 C 代码:

#include <stdio.h>

int main(int argc, char *argv[]){
    int y = 0;
    int x = atoi(*++argv);
    if (x != 4){
        if (x > 6 && x <= 9){
            y = 20 + x;
        }
        else if (x == 0){
            y = 44;
        }
        else if (x == -1){
            y = -44;
        }
        else {
            y = 99;
        }

    }
    else{
        y = 20 + x;
    }
    printf("%d %d", y, x);
}

有人可以帮忙解决我遇到的这个令人困惑的问题吗? 谢谢

【问题讨论】:

  • 我想知道为什么会有这么多反对票?这是一个非常明智的问题。 OP 提供了问题、他的部分解决方案、他迷路的描述和一个明确定义的问题。请停止仅仅因为这是家庭作业而投反对票。
  • 我同意。不应该允许人们在没有给出充分理由的情况下投反对票……有些人更倾向于搁置问题,从而阻碍了正常的讨论渠道。

标签: c if-statement assembly x86 reverse-engineering


【解决方案1】:

在解码编译器输出时,仅使用基本的低级转换通常有助于以更密集但仍然非常低级的形式(伪代码)重写汇编代码。关键是以一种难以出错但更好地暴露代码片段的内部逻辑的方式对少量指令进行分组/组合。下一步是消除冗余存储和临时存储(例如用于存储 x + 20 到 y 的 EAX)。我在这里跳过了第一步,但在更复杂的代码中这样做可能很危险。

然后条件序列变为:

x equ [esp + 24]
y equ [esp + 28]

     if (x == 4) goto L2;
     if (x <= 6) goto L3;
     if (x >  9) goto L3;

L2:  y = x + 20; goto L4;

L3:  if (x != 0) goto L5;

     y = 44; goto L4;

L5:  if (x != -1) goto L6;

     y = -44; goto L4;

L6:  y = 99;

L4:  printf("%d\f", y);

前三个条件构成了编译器用来评估复杂条件的显着模式。编译器反转了该条件的第二项和第三项以使用其“跳转”解决方案片段;再次反转允许您对原始条件进行编码(跳转到 L2/'then' 是 OR,跳转到 L3/'else' 是 AND NOT):

if (x == 4 || !(x <= 6) && !(x > 9))

->

if (x == 4 || (x > 6) && (x <= 9))

鲍勃是你的叔叔。其他条件可能是链式 if 或 switch 语句的结果,很难说。但这并不重要。因此,您的反编译已经几乎完美,您只是错过了一点点。在中间步骤中,C 化条件句如下所示:

if (x == 4 || x > 6 && x <= 9)
{
   y = x + 20;
}
else // L3
{
   if (x == 0)
   {
      y = 44;
   }
   else // L5
   {
      if (x == -1)
      {
         y = -44;
      }
      else // L6
      {
         y = 99;
      }
   }
}

然后可以将其收紧为:

if (x == 4 || x > 6 && x <= 9)
{
   y = x + 20;
}
else if (x == 0)
{
   y = 44;
}
else if (x == -1)
{
   y = -44;
}
else
{
   y = 99;
}

P.S.:(argv + 1) 的值不会存储回argv,只是取消引用。因此它是atoi(*(argv + 1))atoi(argv[1])

【讨论】:

  • 我怀疑原始代码可能包含一个switch-statement,就像这样:gist.github.com/fuzxxl/9c818d186f5ceff00f31
  • 好收获。当案例数量变大时,“switch”的诊断变得更容易,即使编译器决定使用大量比较而不是表分派。让我想到这里的是开关变量没有保存在寄存器中的事实,这使我倾向于人造代码。 ;-)
  • 我怀疑代码是在没有优化的情况下编译的,据说是为了让 OP 类的翻译更容易。
猜你喜欢
  • 2011-05-20
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多