Challenge RE #9
Hi there, here we are again. This time with the 9th RE Challenge from Dennis Yurichev. Let’s see what we have this time, the 8th one I found it extremely instructive, specially because I saw in first hand how a structure it’s declare or manage at the end.
By the way, if you found any error in my explanations feel free to reach out. Typos will be a lot, normally I don’t pay attention to them, mainly because as long as you understand the idea an ’s’ at the end of a verb is not such big thing. Enough of silly talk, let’s try to understand what this assembly code does.
Analysis
The assembly code to understand is the following:
.LC0:
.string "error!"
f:
sub rsp, 8
movzx eax, BYTE PTR [rdi]
cmp al, 89
je .L3
jle .L21
cmp al, 110
je .L6
cmp al, 121
jne .L2
.L3:
mov eax, 1
add rsp, 8
ret
.L21:
cmp al, 78
je .L6
.L2:
mov edi, OFFSET FLAT:.LC0
call puts
xor edi, edi
call exit
.L6:
xor eax, eax
add rsp, 8
ret
First thing that we encountered is a null terminated string, with the word “error!”…no mystery here. As always let’s try to figure out the signature of f
, I find this step extremely useful, and from our previous challenge another thing that’s useful is to identify a struct in the code. If there’s any of course. Let’s do that, and as always let’s analyze by chunks of code:
f:
sub rsp, 8
movzx eax, BYTE PTR [rdi]
cmp al, 89
je .L3
jle .L21
;; ... more down in the code
.L3:
mov eax, 1
add rsp, 8
ret
.L21:
cmp al, 78
je .L6
Here something to notice, is the comparison to numbers like 89. This number it’s expressed in decimal. Also previous to that comparison we got the read of one byte from rdi
which it’s compared to 89. Mmm…no so hard to assume that in rdi
we have our first parameter which it’s a string. The code 89 represents letter Y in ASCII code, so you are comparing the first letter in the string to Y.
Depending on the result of the comparison, we jump to .L3 or .L21, the first case when we have a equal case and the second one when our letter it’s less than Y. For checking the ASCII table you can use this link.
Now, what we have in .L3? This is interesting, we basically return the function with eax
equal 1, and add 8 to the rsp
register. Why this is needed? Easy, take into account that rsp
is the Stack pointer register, at the start of the program we have the following instruction sub rsp,8
and at the end we have add rsp,8
. With these two instruction, first we allocate space on the stack and later de allocate it(how to write deallocate? Is it correct?).
Why we need 8 bits on the stack? This can be a pointer to char in C. Let’s continue, the rest of the program can give us more clues.
In .L21 we compare the character with N in ASCII code, in case it’s equal to it we return 0 and deallocate the byte on stack that we allocated at the start of the program.
Let’s put this into C code, this program seems fairly simple, just a couple of comparison to characters but still we need to see it by our own eyes. Given our previous discussion, we can infer that we receive a string on rdi
and return an int. Fairly simple signature of f:
int f(char *str)
{
char *result;
if (*str == 'Y') {
// mov eax, 1
// add rsp, 8
// ret
return 1;
}
if (*str < 'Y') {
if (*str == 'N') {
return 0;
}
}
}
As always I’ll clean this code later. The rest of the code, it’s also comparisons to characters. For example:
cmp al, 110
je .L6
cmp al, 121
jne .L2
;; later down in the code...
;; ...
.L2:
mov edi, OFFSET FLAT:.LC0
call puts
xor edi, edi
call exit
.L6:
xor eax, eax
add rsp, 8
ret
Here we compare this first byte with letter n, in case it’s equal we jump to .L6, returning 0. Later a comparison to y, in this case if it’s not equal we print the string defined at the beginning, error!, and exit the program cleaning edi
register where we stored our string.
I think we have everything to construct our code, let’s do that.
int f(char *str)
{
char *result;
if (*str == 'Y')
{
return 1;
}
if ((*str < 'Y') && (*str == 'N'))
{
return 0;
}
if (*str == 'n')
{
return 0;
}
if (*str != 'y')
{
puts("error!");
exit(0);
}
return 1;
}
Kind of silly program to be honest 😂. One thing here to notice, is that the result variable that we saved in the stack was never used, at all. This one doesn’t deserve a formal description, too silly.
Conclusion
I think this is the less interesting of all, to be fair the author warn you that the problems are not enumerated according to difficulty.