3

I have the following assembly code and I wanted to transform it into the C language. During the transformation, I had some question for which I could not find any answers.

So, here is it:

                     ...
  +---->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    .....    <<<<------------------------------+

First of all, I must say that we have a string stored in the register ESI. Specially, it is the path of the current process which I try to examine. So it begins with "C:\Users...(and so on)"

My observation was the following. It is a routine which represents a loop. The loop goes through the stored string by increasing the esi pointer at the end of the loop. There is also a counter ECX which is incremented. My question was about the line:

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

Here, ollydbg announces me that I the ANSCII code 08 is in [EDX+0x6C25EF39]. I look that up and that is the code for the backspace. Furthermore, 0x4 is the representation for EOT (= End of transmission). Honestly, I do not understand really what is does. (I assume that it is maybe delete the last current character because it is not the "end of transmission", thus 0x4, but I am not sure.) The only thing which I can say about that is that it the result is always ZF=1, so the jumps is taken, and we go to the target of arrow, namely to the place where the counter ECX is incremented. About ECX and EAX I can say that they are initialized with 0.

So, from that observations I try to write a C code to imagine how it could be written in real:

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;
  }
}

I wanted to add that I also try to learn C language. So, I hope you can tell me my mistakes or other wrong things, which I must learn better.

1
  • Please may we have the assembly listing with addresses? There are several loops in that sample with which they would help.
    – lornix
    May 27, 2014 at 4:47

3 Answers 3

4

note that i move the code from 6C250ED4-6C250ED8 to ....ECC to make the if/else clearer

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                         |

the charinfo table is probably something like isspace() or isalnum(), from ctype.h

4
//   +---->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;
    }
}

I'd almost guess it's copying characters from [ESI] to [EAX], perhaps counting single or double-wide characters as it does this, stopping at either end of the string ([ESI]) or at a double-quote character.

3
  • TEST ..., 0x4 is a bitwise-AND, not an equality check. +1 anyway, since you beat me to posting an answer :)
    – DCoder
    May 27, 2014 at 5:15
  • Duh! You're right! So we're checking a flag.... I'll update...
    – lornix
    May 27, 2014 at 5:16
  • almost like it's using the flag to determine whether to skip that char, or to copy TWO characters. Crazy Windows and their UTF16 weirdness.
    – lornix
    May 27, 2014 at 5:25
3

You can't be sure with stuff like that if you don't see it in action with some sample data, (or at least the 256 bytes at 6C25EF39), but i'd say this routine calculates the length of a utf-8 string and optionally copies it. ESI is a pointer to the original string, EAX is a pointer to the destination, but might be zero as well, and ECX is a pointer to the length of the string.

The table at 0x6C25EF39 would be a 256-byte table, using the ascii code as index, which has some flags per byte that define the character's property. Like this:

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

The "esi++" part of the loop is at 6C250ED9, this is where the "continue" jumps to. In my for loop, the *esi != '"' is a precondition; it isn't in your code, but i'd expect it to be in front of your loop.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.