汇编代码转C语言(反编译)

逆向工程 部件 反编译
2021-06-16 06:24:43

我有以下汇编代码,我想将其转换为 C 语言。在转型过程中,我遇到了一些我找不到任何答案的问题。

所以,这里是:

                     ...
  +---->6C250EAD     MOV DL, BYTE PTR DS:[ESI]
  |     .....EAF     TEST DL, DL
  |     .....EB1     JE SHORT func.6C250EDF   -----------------+
  |     .....EB3     MOVZX EDX, DL                             |
  |     .....EB6     TEST BYTE PTR DS:[EDX+0x6C25EF39],0x4     |
  |     .....EBD     JE SHORT func.6C250ECE   -----+           |
  |     .....EBF     ADD DWORD PRT DS:[ECX],0x2    |           |
  |     .....EC2     TEST EAX,EAX                  |           |
  |     .....EC4     JE SHORT func.6C250ED9 ----------+        |
  |     .....EC6     MOV DL, BYTE PTR DS:[ESI]     |  |        |
  |     .....EC8     INC ESI                       |  |        |
  |     .....EC9     MOV BYTE PTR DS:[EAX], DL     |  |        |
  |     .....ECB     INC EAX                       |  |        |
  |  +--.....ECC-----JMP SHORT func.6C250ED4       |  |        |
  |  |  6C250ECE     INC DWORD PTR DS:[ECX]<<<<<<--+  |        |
  |  |  .....ED0     TEST EAX, EAX                    |        |
  |  |  .....ED2     JMP SHORT func.6C250ED9  -----------+     |
  |  +->6C250ED4     MOV DL, BYTE PTR DS:[ESI]        |  |     |
  |     .....ED6     MOV BYTE PTR DS:[EAX],DL         |  |     |
  |     .....ED8     INC EAX                          |  |     |
  |     6C250ED9     INC ESI    <<<<<-----------------+--+     |
  |     .....EDA     CMP BYTE PTR DS:[ESI],0x22                |
  +-----.....EDD-----JNZ SHORT func.6C250EAD                   |
        6C250EDF    .....    <<<<------------------------------+

首先,我必须说我们在寄存器 ESI 中存储了一个字符串。特别地,它是我尝试检查的当前进程的路径。所以它以“C:\Users...(等等)”开头

我的观察如下。它是一个代表循环的例程。循环通过在循环末尾增加 esi 指针来遍历存储的字符串。还有一个递增的计数器 ECX。我的问题是关于这条线的:

 TEST BYTE PTR DS:[EDX+0x6C25EF39],0x4

在这里,ollydbg 告诉我 ANSCII 代码 08 在 [EDX+0x6C25EF39] 中。我查了一下,这是退格的代码。此外,0x4 是 EOT 的表示(= 传输结束)。老实说,我真的不明白是什么。(我假设它可能是删除最后一个当前字符,因为它不是“传输结束”,因此是 0x4,但我不确定。)我唯一能说的是结果总是 ZF =1,所以跳转,我们去到箭头的目标,即计数器ECX递增的地方。关于 ECX 和 EAX,我可以说它们是用 0 初始化的。

因此,根据这些观察,我尝试编写一个 C 代码来想象如何实际编写它:

while(esi != NULL){

  char *dl = *(esi);

  if(dl != dl){
     break;
  }

  char *edx = *(dl);

  //at that the line which I do not understand really comes

  ecx++;

  if(eax!=0){
      esi++;
  }

  if(esi-- == esi){
      break;
  }
}

我想补充一点,我也尝试学习 C 语言。所以,我希望你能告诉我我的错误或其他错误的事情,我必须好好学习。

3个回答

请注意,我将代码从 6C250ED4-6C250ED8 移至 ....ECC 以使 if/else 更清晰

6C250EAD    MOV DL, BYTE PTR DS:[ESI]                  |    while (dl = *esi) {
            TEST DL, DL                                |
            JE SHORT 6C250EDF                          | 

            MOVZX EDX, DL                              |
            TEST BYTE PTR DS:[EDX+0x6C25EF39],0x4      |    if (charinfo[dl]&4) {
            JE SHORT 6C250ECE                          |

            ADD DWORD PRT DS:[ECX],0x2                 |       *ecx += 2
            TEST EAX,EAX                               |       if (eax) {
            JE SHORT 6C250ED9                          |

            MOV DL, BYTE PTR DS:[ESI]                  |          *eax++ = *esi++
            INC ESI                                    |
            MOV BYTE PTR DS:[EAX], DL                  |
            INC EAX                                    |

            MOV DL, BYTE PTR DS:[ESI]                  |          *eax++ = *esi
            MOV BYTE PTR DS:[EAX],DL                   |
            INC EAX                                    |      }

            JMP SHORT 6C250ED9                         |   } else {

6C250ECE    INC DWORD PTR DS:[ECX]                     |        *ecx += 1
            TEST EAX, EAX                              |        // ignored
            JMP SHORT 6C250ED9                         |   }

6C250ED9    INC ESI                                    |
            CMP BYTE PTR DS:[ESI],0x22                 |   } while (*++esi!='"')
            JNZ SHORT 6C250EAD                         |

charinfo 表可能类似于 ctype.h 中的 isspace() 或 isalnum()

//   +---->6C250EAD     MOV DL, BYTE PTR DS:[ESI]
//   |     .....EAF     TEST DL, DL
//   |     .....EB1     JE SHORT func.6C250EDF   -----------------+
//   |     .....EB3     MOVZX EDX, DL                             |
//   |     .....EB6     TEST BYTE PTR DS:[EDX+0x6C25EF39],0x4     |
//   |     .....EBD     JE SHORT func.6C250ECE   -----+           |
//   |     .....EBF     ADD DWORD PRT DS:[ECX],0x2    |           |
//   |     .....EC2     TEST EAX,EAX                  |           |
//   |     .....EC4     JE SHORT func.6C250ED9 ----------+        |
//   |     .....EC6     MOV DL, BYTE PTR DS:[ESI]     |  |        |
//   |     .....EC8     INC ESI                       |  |        |
//   |     .....EC9     MOV BYTE PTR DS:[EAX], DL     |  |        |
//   |     .....ECB     INC EAX                       |  |        |
//   |  +--.....ECC-----JMP SHORT func.6C250ED4       |  |        |
//   |  |  6C250ECE     INC DWORD PTR DS:[ECX]<<<<<<--+  |        |
//   |  |  .....ED0     TEST EAX, EAX                    |        |
//   |  |  .....ED2     JMP SHORT func.6C250ED9  -----------+     |
//   |  +->6C250ED4     MOV DL, BYTE PTR DS:[ESI]        |  |     |
//   |     .....ED6     MOV BYTE PTR DS:[EAX],DL         |  |     |
//   |     .....ED8     INC EAX                          |  |     |
//   |     6C250ED9     INC ESI    <<<<<-----------------+--+     |
//   |     .....EDA     CMP BYTE PTR DS:[ESI],0x22                |
//   +-----.....EDD-----JNZ SHORT func.6C250EAD                   |
//         6C250EDF    .....    <<<<------------------------------+

while (*ESI!=0) {
    DL=(char)*ESI;
    if ((some_table_of_chars[DL]&4)!=0) { /* lengthy, but explicit */
        *ECX=*ECX+1; /* 4 byte integer */
    } else {
        *ECX=*ECX+2; /* 4 byte integer */
        if (EAX!=0) { /* don't write to NULL address */
            DL=(char)*ESI;
            (char)*EAX=DL;
            ESI++;
            EAX++;
            DL=(char)*ESI;
            (char)*EAX=DL;
            EAX++;
        }
    }
    ESI++;
    if (*ESI=='"') {
        break;
    }
}

我几乎猜到它是从[ESI]to复制字符[EAX],可能会在这样做时计算单宽或双宽字符,在字符串 ( [ESI]) 的任一端或双引号字符处停止

如果您没有看到它与某些示例数据(或至少 6C25EF39 处的 256 个字节)一起运行,则您无法确定此类内容,但我想说这个例程计算 utf-8 的长度字符串并可选择复制它。 ESI是指向原始字符串EAX的指针是指向目标的指针,但也可能为零,并且ECX是指向字符串长度的指针。

0x6C25EF39 处的表将是一个 256 字节的表,使用 ascii 代码作为索引,每个字节都有一些标志来定义字符的属性。像这样:

#define UTF8_2BYTE   0x04
unsigned char flags[256]={ .... }

#define IS_UTF8_2BYTEMARK(x)    (flags[(x)] & UTF8_2BYTE)


.... // char *esi=source, char *eax=dest, int *ecx=length

for ( ; *esi != '"'; esi++) {
    dl=*esi;                                // ...EAD
    if (dl=='\0')
            break;
    if (IS_UTF8_2BYTEMARK(dl)) {            // ...EB6
            *ecx+=2;
            if (!eax)                       // ...EC2
                    continue;
            *eax++=*esi++;                  // ...EC6..ECB
    } else {
            *ecx++;                         // ...ECE
    }
    if (eax)
            *eax++=*esi;                    // ...ED4
}

循环的“esi++”部分位于 6C250ED9,这是“continue”跳转到的地方。在我的 for 循环中, the*esi != '"'是一个前提条件;它不在您的代码中,但我希望它在您的循环前面。