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.