loc_536FB0:
mov cl, [eax]
cmp cl, ' '
jb short loc_536FBC
cmp cl, ','
jnz short loc_536FBF
loc_536FBC:
mov byte ptr [eax], ' '
loc_536FBF
mov cl, [eax+1]
inc eax
test cl, cl
jnz short loc_536FB0
我已经知道它是一个for循环,在退出之前循环了23次。 />
#1 楼
如此小的片段很难手动反编译。试试吧。您已经发现
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
并清理: />现在,让我们来看第二个
if
。它具有以下形式: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;
这就是我们摆脱
goto
的方法:if ( condition )
goto end_of_if;
<if body>
end_of_if:
将其应用于我们的代码段:
if ( !condition )
{
<if body>
}
现在,我们如何摆脱
goto l2
?如果仔细看,您会发现如果l2
或cl < ' '
都执行了cl == ','
的主体。因此,我们可以将两个条件与一个逻辑或(||
)组合在一起:l1:
cl = *p;
if ( cl < ' ' )
goto l2;
if ( cl == ',' ) {
l2:
*p = ' ';
}
cl = *(p+1);
p = p + 1;
if ( cl != 0 )
goto l1;
现在剩下一个
goto
。我们有:1)在语句块的开始处标记2)在块的末尾进行检查,以及3)如果检查成功,则转到块的开始。这是do-while
循环的典型模式,我们可以轻松地对其进行转换:l1:
cl = *p;
if ( cl < ' ' || cl == ',' ) {
*p = ' ';
}
cl = *(p+1);
p = p + 1;
if ( cl != 0 )
goto l1;
现在代码几乎不错,但是我们可以对其进行压缩通过替换等效语句,可以得到更多信息:
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 )
现在很明显代码在做什么:它遍历字符串,并用空格替换所有特殊字符(那些代码小于0x20 aka空格的字符)和逗号。
#2 楼
好吧,特别是为此,发明了Hex-Rays Decompiler。它将ASM代码反编译为伪C,然后您可以编写基于C的汇编代码逻辑。评论
现在解决了这个
–user1365830
13年5月25日在19:58
并非所有人都可以通过十六进制射线访问……Igor的答案要彻底得多。
–0xea
13年5月26日在11:12
好吧,并非每个人都有一小段汇编,因此答案应该比一个具体案例要宽。伊戈尔确实花了宝贵的时间来编写这段特定的代码。
–丹尼斯·拉斯科夫(Denis Laskov)
13年5月26日在11:40
不,你没有回答这个问题。如果要链接到使问题过时的工具,请在对该问题的评论中进行链接。
–轨道轻赛
13年5月30日在11:28
哦,对不起,玛莎:)
–丹尼斯·拉斯科夫(Denis Laskov)
13年5月30日在15:40
#3 楼
这就是源代码中的样子。 Fastcall替代了编译器在优化时使用的自定义叶子约定。void __fastcall __forceinline RemoveControlChars(char* szInput) {
int i;
for (i = 0; i < 23 && *szInput; ++i, ++szInput) {
if (*szInput < ' ' || *szInput == ',')
*szInput = ' ';
}
}
评论
我在原始代码中看不到任何与您的i <24延续条件相对应的内容。从i = 0开始并在i <24时循环还会执行24次循环,而不是OP所述的23次。
–用户
13年5月26日在13:31
fastcall和forceinline在一起毫无意义。如果是内联的,则没有正式的调用约定。
–乔纳森·莱因哈特(Jonathon Reinhart)
13年6月15日在8:52
__fastcall只是意味着args将在寄存器中而不是在堆栈中传递(如果是内联的话,则假定是该参数),但是,如果没有足够的寄存器,则编译器仍可能将args推入堆栈中,这使其有点过时的反优化。根据msdn的说法:即使使用__forceinline,编译器也无法在所有情况下都内联代码。
– Tox1k
2013年6月29日9:17
#4 楼
您可以在雷达2上使用r2dec插件,并使用命令pdda
[0x08048060]> pdda
; assembly | /* r2dec pseudo code output */
| /* ret @ 0x8048060 */
| #include <stdint.h>
|
; (fcn) entry0 () | int32_t entry0 (void) {
| do {
| /* [01] -r-x section size 23 named .text */
0x08048060 mov cl, byte [eax] | cl = *(eax);
0x08048062 cmp cl, 0x20 |
| if (cl >= 0x20) {
0x08048065 jb 0x804806c |
0x08048067 cmp cl, 0x2c |
| if (cl != 0x2c) {
0x0804806a jne 0x804806f | goto label_0;
| }
| }
0x0804806c mov byte [eax], 0x20 | *(eax) = 0x20;
| label_0:
0x0804806f mov cl, byte [eax + 1] | cl = *((eax + 1));
0x08048072 inc eax | eax++;
0x08048073 test cl, cl |
0x08048075 jne 0x8048060 |
| } while (cl != 0);
| }
[0x08048060]>
评论
很好的答案,尤其是因为您正在解释每个步骤。
–雷姆科
13年5月27日在13:02
很棒的答案。
–轨道轻赛
13年5月30日在11:31
我自己做不到
–06needhamt
2013年11月1日14:06
读到答案:“哇,这真的很详细,提供了信息,我想知道是谁...”意识到这是对英特尔IME“啊……
–多项式
15年3月23日在21:03