简体   繁体   English

从装配中反向设计优化的c代码

[英]Reverse engineer optimized c code from assembly

The point of this problem is to reverse engineer c code that was made after running the compiler with level 2 optimization. 这个问题的关键是对使用2级优化运行编译器后生成的c代码进行逆向工程。 The original c code is as follows (computes the greatest common divisor): 原始c代码如下(计算最大公约数):

int gcd(int a, int b){
    int returnValue = 0;
    if (a != 0 &&  b != 0){
        int r;
        int flag = 0;
        while (flag == 0){
            r = a % b;
            if (r ==0){
                flag = 1;
            } else {
                a = b;
                b = r;
            }
        }
        returnValue = b;
    }
    return(returnValue);
}

when I ran the optimized compile I ran this from the command line: 当我运行优化编译时,我从命令行运行它:

gcc -O2 -S Problem04b.c

to get the assembly file for this optimized code 获取此优化代码的程序集文件

.gcd:
    .LFB12:
        .cfi_startproc
        testl   %esi, %esi
        je  .L2
        testl   %edi, %edi
        je  .L2
    .L7:
        movl    %edi, %edx
        movl    %edi, %eax
        movl    %esi, %edi
        sarl    $31, %edx
        idivl   %esi
        testl   %edx, %edx
        jne .L9
        movl    %esi, %eax
        ret
        .p2align 4,,10
        .p2align 3
    .L2:
        xorl    %esi, %esi
        movl    %esi, %eax
        ret
        .p2align 4,,10
        .p2align 3
    .L9:
        movl    %edx, %esi
        jmp .L7
        .cfi_endproc

I need to convert this assembly code back to c code here is where I am at right now: 我需要将此汇编代码转换回c代码,这是我现在所处的位置:

int gcd(int a int b){
    /*
       testl %esi %esi
       sets zero flag if a is 0 (ZF) but doesn't store anything
       */
    if (a == 0){
        /*
           xorl %esi %esi
           sets the value of a variable to 0. More compact than movl
           */
        int returnValue = 0;
        /*
           movl %esi %eax
           ret

           return the value just assigned
           */
        return(returnValue);
    }
    /*
       testl %edi %edi
       sets zero flag if b is 0 (ZF) but doesn't store anything
       */
    if (b == 0){
        /*
           xorl %esi %esi
           sets the value of a variable to 0. More compact than movl
           */
        int returnValue = 0;
        /*
           movl %esi %eax
           ret

           return the value just assigned
           */
        return(returnValue);
    }

    do{
        int r = b;
        int returnValue = b;

    }while();


}

Can anyone help me write this back in to c code? 任何人都可以帮我写回c代码吗? I'm pretty much lost. 我很丢失。

First of all, you have the values mixed in your code. 首先,您在代码中混合了值。 %esi begins with the value b and %edi begins with the value a . %esi以值b开头, %edi以值a开头。

You can infer from the testl %edx, %edx line that %edx is used as the condition variable for the loop beginning with .L7 (if %edx is different from 0 then control is transferred to the .L9 block and then returned to .L7 ). 您可以从testl %edx, %edx行推断出%edx用作以.L7开头的循环的条件变量(如果%edx与0不同,则控制转移到.L9块然后返回.L7 )。 We'll refer to %edx as remainder in our reverse-engineered code. 我们将%edx称为反向工程代码中的remainder


Let's begin reverse-engineering the main loop: 让我们开始对主循环进行逆向工程:

movl    %edi, %edx

Since %edi stores a , this is equivalent to initializing the value of remainder with a : int remainder = a; 由于%edi存储a ,这等同于初始化的值remainderaint remainder = a; .

movl    %edi, %eax

Store int temp = a; Store int temp = a;

movl    %esi, %edi

Perform int a = b; 执行int a = b; (remember that %edi is a and %esi is b ). (记住%edia%esib )。

sarl $31, %edx

This arithmetic shift instruction shifts our remainder variable 31 bits to the right whilst maintaining the sign of the number. 该算术移位指令将remainder变量31位向右移位,同时保持数字的符号 By shifting 31 bits you're setting remainder to 0 if it's positive (or zero) and to -1 if it's negative. 通过移位31位,如果它为正(或零),则将remainder设置为0,如果为负,则将其设置为-1。 So it's equivalent to remainder = (remainder < 0) ? -1 : 0 所以它相当于remainder = (remainder < 0) ? -1 : 0 remainder = (remainder < 0) ? -1 : 0 . remainder = (remainder < 0) ? -1 : 0

idivl %esi

Divide %edx:%eax by %esi , or in our case, divide remainder * temp by b (the variable). %edx:%eax除以%esi ,或者在我们的例子中,将remainder * temp除以b (变量)。 The remainder will be stored in %edx , or in our code, remainder . 余数将存储在%edx ,或存储在我们的代码中, remainder When combining this with the previous instruction: if remainder < 0 then remainder = -1 * temp % b , and otherwise remainder = temp % b . 将此与前一条指令组合时:如果remainder < 0remainder = -1 * temp % b ,否则remainder = temp % b

testl   %edx, %edx
jne .L9

Check to see if remainder is equal to 0 - if it's not, jump to .L9 . 检查remainder是否等于0 - 如果不是,则跳转到.L9 The code there simply sets b = remainder; 那里的代码只是设置b = remainder; before returning to .L7 . 在返回.L7之前。 In order to implement this in C, we'll keep a count variable that will store the amount of times the loop has iterated. 为了在C中实现这一点,我们将保留一个count变量,该变量将存储循环迭代的次数。 We'll perform b = remainder at the beginning of the loop but only after the first iteration, meaning when count != 0 . 我们将在循环开始时执行b = remainder ,但仅在第一次迭代之后执行,这意味着当count != 0

We're now ready to build our full C loop: 我们现在准备构建完整的C循环:

int count = 0;
do {
    if (count != 0)
        b = remainder;
    remainder = a;
    temp = a;
    a = b;
    if (remainder < 0){
        remainder = -1 * temp % b;
    } else {
        remainder = temp % b;
    }

    count++;
} while (remainder != 0)

And after the loop terminates, 循环结束后,

movl    %esi, %eax
ret

Will return the GCD that the program computed (in our code it'll be stored in the b variable). 将返回程序计算的GCD(在我们的代码中它将存储在b变量中)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM