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?如果仔细看,您会发现如果l2cl < ' '都执行了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空格的字符)和逗号。

评论


很好的答案,尤其是因为您正在解释每个步骤。

–雷姆科
13年5月27日在13:02

很棒的答案。

–轨道轻赛
13年5月30日在11:31

我自己做不到

–06needhamt
2013年11月1日14:06

读到答案:“哇,这真的很详细,提供了信息,我想知道是谁...”意识到这是对英特尔IME“啊……

–多项式
15年3月23日在21:03

#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]>