手动反编译这样的小片段并不太难。让我们试试吧。
您已经发现它cl
包含一个字符,这意味着eax
它的读取位置是一个指向字符数组的指针。让我们称之为p
。现在,让我们对每个汇编语句进行愚蠢的 C 语言翻译:
l1: ; l1:
mov cl, [eax] ; cl = *p;
cmp cl, ' ' ; if ( cl < ' ' )
jb short l2 ; goto l2
cmp cl, ',' ; if ( cl != ',' )
jnz short l3 ; goto l3
l2: ; l2:
mov byte ptr [eax], ' ' ; *p = ' '
l3: ; l3:
mov cl, [eax+1] ; cl = *(p+1)
inc eax ; p = p + 1
test cl, cl ; if ( cl != 0 )
jnz short l1 ; goto l1
并清理:
l1:
cl = *p;
if ( cl < ' ' )
goto l2;
if ( cl != ',' )
goto l3;
l2:
*p = ' ';
l3:
cl = *(p+1);
p = p + 1;
if ( cl != 0 )
goto l1;
现在,让我们看看第二个if
. 它具有以下形式:
if ( condition )
goto end_of_if;
<if body>
end_of_if:
这是我们如何摆脱goto
:
if ( !condition )
{
<if body>
}
将其应用于我们的代码段:
l1:
cl = *p;
if ( cl < ' ' )
goto l2;
if ( cl == ',' ) {
l2:
*p = ' ';
}
cl = *(p+1);
p = p + 1;
if ( cl != 0 )
goto l1;
现在,我们怎样才能摆脱goto l2
?如果您仔细查看它,您会发现l2
如果或 中的任一个 ,则主体 at will 将被执行。因此,我们可以将两个条件与逻辑 OR ( )结合起来:cl < ' '
cl == ','
||
l1:
cl = *p;
if ( cl < ' ' || cl == ',' ) {
*p = ' ';
}
cl = *(p+1);
p = p + 1;
if ( cl != 0 )
goto l1;
现在我们还goto
剩下一个。我们有:1) 语句块开头的标签 2) 在块的末尾检查 3) 如果检查成功,则转到块的开头。这是一个典型的do-while
循环模式,我们可以很容易地转换它:
do {
cl = *p;
if ( cl < ' ' || cl == ',' ) {
*p = ' ';
}
cl = *(p+1);
p = p + 1;
} while ( cl != 0 )
现在代码几乎漂亮了,但我们可以通过替换等效语句来进一步压缩它:
do {
if ( *p < ' ' || *p == ',' )
*p = ' ';
cl = *++p;
} while ( cl != 0 )
最后,最后一个赋值可以移动到条件中:
do {
if ( *p < ' ' || *p == ',' )
*p = ' ';
} while ( *++p != 0 )
现在代码在做什么很明显:它遍历字符串,并用空格替换所有特殊字符(那些代码小于 0x20 又名空格的字符)和逗号。