3 minutes
Practical Reverse Engineering - Exercise 1, Page 11
Table of Contents
Question
This function uses a combination SCAS
and STOS
to do its work. First, explain what is the type of the [EBP+8]
and [EBP+C]
in line 1 and 8, respectively. Next, explain what this snippet does.
01: mov edi, [ebp + 8]
02: mov edx, edi
03: xor eax, eax
04: or ecx, 0FFFFFFFFh
05: repne scasb
06: add ecx, 2
07: neg ecx
08: mov al, [ebp + 0Ch]
09: mov edi, edx
10: rep stosb
11: mov eax, edx
Answer
[EBP + 8h]
appears to be a char buffer pointer/PCHAR
(size = 4 bytes) since it is loaded into EDI
register which is then implicitly used by scasb
instruction with repne
prefix as the memory operand address to compare for a particular byte value specified by AL
register.
[EBP + 0Ch]
appears to be a CHAR
(size = 1 byte) since it is loaded into AL
register which is then implicitly used by stosb
instruction with rep
prefix as the byte value to store into the destination operand given by EDI
register.
Line 1 sets EDI
to the value at address (EBP+8h)
which is probably the first argument(PCHAR
) passed to this function following the __cdecl/__stdcall
calling convention.
Line 2 sets EDX
with EDI
, essentially saving a copy of the first parameter in EDX
register. This is necessary because in Line 5 when scasb
is used, it automatically increments/decrements EDI
based on EFLAGS.DF
, therefore, trashing the original value.
Line 3 performs Bitwise Exclusive OR
operation on EAX
with itself, thereby clearing it to 0.
Line 4 performs Bitwise Inclusive OR
operation on ECX
with 0xFFFFFFFF
, thereby setting it to 0xFFFFFFFF
.
Line 5 uses the scasb
instruction to scan the string(pointed to by EDI
) for the NULL
byte terminator(given by AL
) one byte at a time. repne
prefix(which uses ECX
as an unsigned counter) is used to indicate to keep scanning until it finds the NULL
byte. This will also decrement ECX
for each byte scanned until the NULL
byte is encountered.
Line 6 adds 2 to ECX
to compensate for counting from -1 instead of 0 and including the NULL
byte.
Line 7 replaces ECX
with its 2’s complement, thereby turning it into a positive value. Now, ECX
contains the length of the string excluding the NULL
byte.
Line 8 sets AL
to the value at address (EBP+0xC)
which is probably the second argument(CHAR
) passed to this function following the __cdecl/__stdcall
calling convention.
Line 9 sets EDI
with EDX
to prime it with the destination operand address for the next instruction.
Line 10 uses the stosb
instruction to store the byte(given by AL
) into the string(pointed to by EDI
) one byte at a time. rep
prefix is used to indicate to keep setting until ECX
decrements to 0(i.e. the entire length of the string).
Line 11 sets EAX
with EDX
now pointing to the overwritten string. EAX
register holds the return value when returning from a procedure.
Based on all of the above, we can construct a decompilation of the assembly snippet as follows:
extern "C" __declspec(noinline) PCHAR __cdecl asm_func(
_In_ PCHAR pchBuffer,
_In_ CHAR chValue
) {
return (PCHAR)memset(pchBuffer, chValue, strlen(pchBuffer));
}
527 Words
2022-07-13 02:00