C 带循环的反编译辅助
从2014年开始,我正在从一个旧的CTF中撤销一些x86,并试图理解下面的代码(它已被大幅缩短)。我相信它是通过字符串x执行某种while或for循环,其中x是字符串的长度 一些基本信息:C 带循环的反编译辅助,c,assembly,x86,decompiling,C,Assembly,X86,Decompiling,从2014年开始,我正在从一个旧的CTF中撤销一些x86,并试图理解下面的代码(它已被大幅缩短)。我相信它是通过字符串x执行某种while或for循环,其中x是字符串的长度 一些基本信息: 英特尔语法 给出了功能原型: int main(char*) 我的主要困惑在于.L3和.L2的末尾: 我相信.L3的结尾将寄存器算术存储在[ebp-12]中,然后增加[ebp-8]的值(我相信这是指向char*arg副本的指针) 我对它的松散转换(忽略了大部分.L3)在c中如下所示: int main
- 英特尔语法
- 给出了功能原型:
- int main(char*)李>
int main(char* arg)
{
int loc1 = 0;
char* str = arg;
for(i = 0; str[i] != '\0'; i++) { // <=== Pretty Sure
// .L3 Stuff w/ Assignment to loc1 // This is incorrect
}
return loc1;
}
我相信这三行是去引用指针地址,零扩展位,然后符号扩展al字节。就“c”代码而言,我相信它只是用来索引数组中的每个特定字符,特别是用来使用其十进制值进行算术运算。是的,它似乎在对字符串中的每个字符做“某些事情”。它可以计算一个散列码或CRC,或者无限多个可能的事物中的任何一个。如果不知道“讨厌的数学”是什么,就不可能说出来 更正确的C版本代码是:
int main(char* arg)
{
char* p = arg;
int loc1 = 0;
for (; *p != 0; p++)
{
loc1 = do_something_with(*p);
}
return 0;
}
如您所述,它不会返回loc1
。终止条件如下:
movzx eax, BYTE PTR [eax]
test al, al
jne .L3
第一条指令零扩展EAX。因此,如果AL寄存器为零,那么EAX也为零。如果未执行跳转,则EAX为0,这是函数返回的值
至少在我看来是这样的。但是,这个函数做什么呢。如果我的读数是正确的,那么函数实际上没有做任何有用的事情。除非“恼人的数学”包含对外部作用域中某些变量的引用。也有一个StackExchange站点,用于此类内容,名为.post。不过有点希望这能得到更快的响应。在英特尔语法中,
movzx-eax,字节PTR[eax]
加载并零将eax
指向的字节扩展到寄存器eax
,替换指针的值。@iwillnotexistidoxist:是的,这是正确的。因此,如果在该指令之后,AL寄存器为0,则所有EAX都为0。如果al为0,则下一条指令测试al,al
将设置Z标志。仅当未设置Z标志时才进行跳转。因此,当函数退出时,AL为0,因此EAX为0。@JimMischel在执行movzx-EAX,BYTE PTR[EAX]
命令后,何时不设置Z标志?当它指向一个空字节时,它会将空字节与空字节进行比较,并使用下面的test al,al
指令?@Kaiser17:你的问题是什么?我的观点是,正如我在上面解释的那样,函数总是返回0。如果您不同意,请解释返回值可以是什么。@Kaiser17 Jim是对的。是一种指令,当寄存器分别设置奇数位、符号位或未设置位时,该指令对两个寄存器进行and运算,并根据结果设置P、S和Z寄存器标志。当您将一个值与它自身合并时,它是不变的((x&x)=x
),因此test
指令有效地单独检查x
的奇偶校验、符号和零。只有当al
包含NUL字节时,“Z”才会出现。
int main(char* arg)
{
char* p = arg;
int loc1 = 0;
for (; *p != 0; p++)
{
loc1 = do_something_with(*p);
}
return 0;
}
movzx eax, BYTE PTR [eax]
test al, al
jne .L3