简体   繁体   English

此程序集x86代码的反编译(C)代码构造是什么?

[英]What is the decompiled (C) code construct of this assembly x86 code?

This code compares every char of a string (located at ebp+arg_0 ) with different constants (ASCII chars) like 'I', 'o' and 'S'. 此代码将字符串的每个字符(位于ebp+arg_0 )与不同的常量(ASCII字符)(例如“ I”,“ o”和“ S”)进行比较。 I guess, based on other code parts, this code is originally written in C. 我猜,基于其他代码部分,该代码最初是用C编写的。

部件

This compare-code-part looks very inefficient to. 这个比较代码部分看起来效率很低。 My question , how do you think this code will look in C? 我的问题 ,您如何看待这段代码在C语言中的表现? What code construct was used originally? 最初使用什么代码构造? my thoughts so far 到目前为止我的想法

  • It's not a for loop . 这不是for循环 Because i don't see any upward jump and stop-condition. 因为我看不到任何向上跳跃和停止的情况。

  • It's not a while/case/switch code construct 它不是while / case / switch代码构造

  • My best guess is that this are a lot of consecutive if/else statements. 我最好的猜测是,这是许多连续的if / else语句。 Can you help? 你能帮我吗?

Yes it's part of a challenge, i already have the flag/solution, no worries about that. 是的,这是挑战的一部分,我已经有了举报/解决方案,对此无后顾之忧。 Just trying to better understand the code. 只是试图更好地理解代码。

It's not a for loop. 这不是for循环。 Because i don't see any upward jump and stop-condition. 因为我看不到任何向上跳跃和停止的情况。

Correct. 正确。

It's not a while/case/switch code constuct 不是一会儿/案例/切换代码的​​构造

It can't be, it compares different indicies of the array. 不能,它比较数组的不同指标。

My best guess is that this are a lot of consecutive if/elses. 我最好的猜测是,这是很多连续的if / els。 Can you help? 你能帮我吗?

Looks like it could be this code: 看起来可能是这样的代码:

void f(const char* arg_0) {
    if(arg_0[4] == 'I' && arg_0[5] == 'o' && arg_0[6] == 'S') {
        printf("Gratz man :)");
        exit(0); //noreturn, hence your control flow ends here in the assembly
    }
    puts("Wrong password"); // Or `printf("Wrong password\n");` which gets optimized to `puts`
    // leave, retn
}

This is how gcc compiles it without optimizations : 这是gcc无需优化即可编译的方式

.LC0:
        .string "Gratz man :)"
.LC1:
        .string "Wrong password"
f(char const*):
        push    ebp
        mov     ebp, esp
        sub     esp, 8
        mov     eax, DWORD PTR [ebp+8]
        add     eax, 4
        movzx   eax, BYTE PTR [eax]
        cmp     al, 73
        jne     .L2
        mov     eax, DWORD PTR [ebp+8]
        add     eax, 5
        movzx   eax, BYTE PTR [eax]
        cmp     al, 111
        jne     .L2
        mov     eax, DWORD PTR [ebp+8]
        add     eax, 6
        movzx   eax, BYTE PTR [eax]
        cmp     al, 83
        jne     .L2
        sub     esp, 12
        push    OFFSET FLAT:.LC0
        call    printf
        add     esp, 16
        sub     esp, 12
        push    0
        call    exit
.L2:
        sub     esp, 12
        push    OFFSET FLAT:.LC1
        call    puts
        add     esp, 16
        nop
        leave
        ret

Looks very similar to your disassembled code. 看起来非常类似于您的反汇编代码。

This compare-code-part looks very inefficient 这个比较代码部分看起来效率很低

Looks like it was compiled without optimizations. 看起来它是未经优化而编译的。 With optimizations enabled, gcc compiled the code to : 启用优化后, gcc将代码编译为

.LC0:
        .string "Gratz man :)"
.LC1:
        .string "Wrong password"
f(char const*):
        sub     esp, 12
        mov     eax, DWORD PTR [esp+16]
        cmp     BYTE PTR [eax+4], 73
        jne     .L2
        cmp     BYTE PTR [eax+5], 111
        je      .L5
.L2:
        mov     DWORD PTR [esp+16], OFFSET FLAT:.LC1
        add     esp, 12
        jmp     puts
.L5:
        cmp     BYTE PTR [eax+6], 83
        jne     .L2
        sub     esp, 12
        push    OFFSET FLAT:.LC0
        call    printf
        mov     DWORD PTR [esp], 0
        call    exit

Not sure why gcc decided to jump down and back up again instead of a straight line of jne s. 不知道为什么gcc决定跳下来然后再跳回来而不是jne s的直线。 Also, the ret is gone, your printf got tail-call-optimized, ie a jmp printf istead of a call printf followed by a ret . 同样, ret消失了,您的printf了尾调用优化,即使用jmp printf代替了call printf后跟ret

The first argument ( arg_0 ) is a pointer to the given password string, eg, const char *arg_0 . 第一个参数( arg_0 )是指向给定密码字符串的指针,例如const char *arg_0 This pointer (the address of the first character) is loaded into the eax register ( mov eax, [ebp+arg_0] ), and then the index of the current character is added to advance it to that index ( add eax, 4 etc.). 该指针(第一个字符的地址)被加载到eax寄存器( mov eax, [ebp+arg_0] )中,然后添加当前字符的索引以将其前进到该索引( add eax, 4等)。 )。 The single byte at that address is then loaded into eax ( movzx eax, byte ptr [eax] ). 然后将该地址处的单个字节加载到eaxmovzx eax, byte ptr [eax] )。

Then that byte/character is compared against the correct one ( cmp eax, 'I' , etc). 然后将该字节/字符与正确的字节/字符进行比较( cmp eax, 'I'等)。 If the result is not zero (ie, if they are not equal), the program jumps to the "Wrong password" branch ( jnz - jump if not zero), otherwise it continues on to the next comparison (and ultimately success). 如果结果不为零(即,如果它们不相等),则程序将跳转到“错误密码”分支( jnz如果不为零,则跳转),否则它将继续进行下一个比较(最终成功)。

The nearest direct C equivalent would therefore be something like: 因此,最接近的直接C等效项将类似于:

void check(const char *arg_0) {
    // presumably comparisons 0-3 are omitted
    if (arg_0[4] != 'I') goto fail;
    if (arg_0[5] != 'o') goto fail;
    if (arg_0[6] != 'S') goto fail;
    printf("Gratz man :)");
    exit(0);
fail:
    puts("Wrong password");
}

(Of course the actual C code is unlikely to have looked like this, since the goto fail arrangement is not typical.) (当然,实际的C代码不太可能看起来像这样,因为goto fail安排并不常见。)

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

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