此汇编 x86 代码的反编译 (C) 代码构造是什么?
What is the decompiled (C) code construct of this assembly x86 code?
此代码将字符串(位于 ebp+arg_0
处)的每个字符与 'I'、'o' 和 'S' 等不同常量(ASCII 字符)进行比较。我猜,根据其他代码部分,这段代码最初是用C编写的。
这个compare-code-part看起来效率很低。 我的问题,你认为这段代码在 C 中看起来如何?最初使用什么代码结构?到目前为止我的想法
这不是 for 循环。因为我没有看到任何向上跳跃和 stop-condition.
这不是 while/case/switch 代码构造
我最好的猜测是这是很多连续的 if/else 语句。
你能帮忙吗?
是的,这是挑战的一部分,我已经有了 flag/solution,不用担心。只是想更好地理解代码。
It's not a for loop. Because i don't see any upward jump and stop-condition.
正确。
It's not a while/case/switch code constuct
不可能,它比较的是数组的不同指标
My best guess is that this are a lot of consecutive if/elses. Can you help?
看起来可能是这个代码:
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:
.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
看起来与您的反汇编代码非常相似。
This compare-code-part looks very inefficient
看起来它是在没有优化的情况下编译的。启用优化后,gcc compiled the code to:
.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
不知道为什么 gcc 决定跳下来再跳起来,而不是 jne
s 的直线。此外,ret
消失了,您的 printf
得到了尾调用优化,即 jmp printf
而不是 call printf
后跟 ret
.
第一个参数 (arg_0
) 是指向给定密码字符串的指针,例如 const char *arg_0
。这个指针(第一个字符的地址)被加载到eax
寄存器(mov eax, [ebp+arg_0]
),然后将当前字符的索引添加到那个索引(add eax, 4
ETC。)。然后将该地址处的单个字节加载到 eax
(movzx eax, byte ptr [eax]
).
然后将 byte/character 与正确的(cmp eax, 'I'
,等等)进行比较。如果结果不为零(即,如果它们不相等),程序跳转到 "Wrong password" 分支(jnz
- 如果不为零则跳转),否则它继续下一个比较(和最终成功)。
因此,最接近的直接 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");
}
(当然,实际的 C 代码不太可能看起来像这样,因为 goto fail
排列并不典型。)
此代码将字符串(位于 ebp+arg_0
处)的每个字符与 'I'、'o' 和 'S' 等不同常量(ASCII 字符)进行比较。我猜,根据其他代码部分,这段代码最初是用C编写的。
这个compare-code-part看起来效率很低。 我的问题,你认为这段代码在 C 中看起来如何?最初使用什么代码结构?到目前为止我的想法
这不是 for 循环。因为我没有看到任何向上跳跃和 stop-condition.
这不是 while/case/switch 代码构造
我最好的猜测是这是很多连续的 if/else 语句。 你能帮忙吗?
是的,这是挑战的一部分,我已经有了 flag/solution,不用担心。只是想更好地理解代码。
It's not a for loop. Because i don't see any upward jump and stop-condition.
正确。
It's not a while/case/switch code constuct
不可能,它比较的是数组的不同指标
My best guess is that this are a lot of consecutive if/elses. Can you help?
看起来可能是这个代码:
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:
.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
看起来与您的反汇编代码非常相似。
This compare-code-part looks very inefficient
看起来它是在没有优化的情况下编译的。启用优化后,gcc compiled the code to:
.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
不知道为什么 gcc 决定跳下来再跳起来,而不是 jne
s 的直线。此外,ret
消失了,您的 printf
得到了尾调用优化,即 jmp printf
而不是 call printf
后跟 ret
.
第一个参数 (arg_0
) 是指向给定密码字符串的指针,例如 const char *arg_0
。这个指针(第一个字符的地址)被加载到eax
寄存器(mov eax, [ebp+arg_0]
),然后将当前字符的索引添加到那个索引(add eax, 4
ETC。)。然后将该地址处的单个字节加载到 eax
(movzx eax, byte ptr [eax]
).
然后将 byte/character 与正确的(cmp eax, 'I'
,等等)进行比较。如果结果不为零(即,如果它们不相等),程序跳转到 "Wrong password" 分支(jnz
- 如果不为零则跳转),否则它继续下一个比较(和最终成功)。
因此,最接近的直接 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");
}
(当然,实际的 C 代码不太可能看起来像这样,因为 goto fail
排列并不典型。)