Follow @void0xcc
Reverse
Engineering ELF
by
Void0xCC
Hi everyone,
A while ago I
came across root-me challenges , and I started reversing a 'crackme'
that looks interesting.
You can download
the 'crackme' from root-me , or you can find it in the attachment.
So lets get
started,
First I run the
binary to get a first look of his functionality :
The program print
“Welcome to Root-me Challenges” and ask for password, I type
“system” it print “Try again!” as Bad boy Message
While reading the
title “ELF
- No software breakpoints” I assume who
ever code this binary has put an anti-breakpoint technique .
I find some informations about the binary by using command “file
ch20.bin”
The file is
“Stripped” , so after loading it into GDB we get “no debugging
symbols found” in other words there is no informations about
functions , variables...etc
In order to get
around this I used “info file” to get the Entry point
as you can see we manage to get the entry point “0x8048080”. Next we put a
breakpoint on the Entry point and launch the binary:
after this we
examine the functionality in deep:
Basically this is
the way we pass arguments to sys_write system call
mov eax, 0x4 ----> 0x4 is the system call number
(sys_write)
mov ecx,
0x80491a1 ----> 0x80491a1
address of the string that gets printed
int 0x80 ----> call kernel
Taking a look at
0x80491a1, we find the first string that gets printed while running
the program
Next
mov
eax, 0x3 ----> 0x3 system call
number (sys_read)
mov
ecx, 0x8049188 ----> 0x8049188
address where the string gets stocked
as you may
already understand this is where our password gets stocked
Next there is
this sequence of instructions
xor
ecx, ecx ----> make ECX =
0x00000000
mov
eax, 0x8048080 ----> if you
remember this is the entry point (beginning of .text section)
mov
ebx, 0x8048123 ----> this is the
end of .text section
call
0x8048115 ----> execution goes
toward 0x8048115 lets see what is there
sub
ebx, eax ----> make EBX=0xa3 = 163
decimal ,the length of .text section.
loop:
add
cl, BYTE PTR [eax] ----> remember
EAX point to the beginning of .text section so it take the first byte and put it on ECX register.
rol
ecx, 0x3 ----> rotate ECX
register to left by 0x3.
inc
eax ----> its
clear increment EAX
dec
ebx ----> decrement EBX
jne
0x8048119 (loop) ----> if EBX !=
0x00000000 go to loop (loop )
lets
explain the big picture here, this code is used to check for
breakpoints. if we put a breakpoint on any instruction between
0x8048080 and 0x8048123 (.text
section) the opcode of that instruction will be changed to 0xCC
, and when we finish this loop we wont get the
right ECX.
Remember this ECX
4 bytes is crucial in password validation routine.
Next we get to
the password validation routine:
as you see the
ECX we spoke about get moved into EDX.
mov
ecx, 0x19 ----> its self
explanatory but we see also “dec ecx”
at the end so I assume this is the length of the
password, so length(password) = 25.
mov
eax, 0x8049155 ----> copy
address into EAX, lets see whats there.
by printing the
first 25 bytes in hexadecimal format we get:
keep this 25
bytes in mind we will use it later
mov
ebx, 0x8049188 ----> this is sere
the password is stocked.
ror
edx, 1 ----> it just a rotation to
right by 1 , remember EDX contain the 4 bytes gotten
from breakpoint check routine.
This instructions
are very important so lets see what they do :
mov
al, BYTE PTR [eax+ecx*1-0x1] ----->
in this instruction we have:
EAX= 0x8049155
ECX=0x19
= 25 decimal
so “BYTE
PTR [eax+ecx*1-0x1]” will point to
the 25th byte from EAX witch is 0xe0
(remember the 25 bytes we just saw).
the 25th byte from EAX witch is 0xe0
(remember the 25 bytes we just saw).
mov
bl, BYTE PTR [ebx+ecx*1-0x1] ----->
the same thing only takes the 25 byte of password (last character) put it in EBX.
xor
al, bl ------> xor
the 25th byte “0xe0” with the 25th byte of password store
result in AL.
xor
al,dl ------> xor AL with the the
first byte of EDX.
jne
0x80480f6 ------> if (al != dl)
jump to “0x80480f6” lets go there
its a sys_write
call with the message stored in “0x804914a” lets see what is the
message
its the Bad Boy
Message.
And if
(AL == DL) we get the 24th elements and repeat the routine
until we finish all 25 bytes and we will get to
witch print
lets summarize,
in order to validate this challenge we need to get the right 4 bytes
stored in ECX in other words we will not put any breakpoint and get
this value, How to do that ????
I'm sure there is
a lot of answers but This is mine:
First I extract
the opcode of .text section:
using the
following command :
“for i in
$(objdump -d ch20.bin -M intel |grep "^ " |cut -f2); do
echo -n '0x'$i','; done;echo”
and i rotate
every byte of this opcode by 0x3 and store result in ECX.
In the other hand
, the password get verified by this equation:
(password[25] XOR
sting[25]) == ROL EDX, 0x1
than:
password[25] = string[25] XOR (ROL EDX, 0x1)
now we have all
the ingredient I wrote a C code to do all that in the attachment
#include <stdio.h>
int main(int argc, char const *argv[])
{
/* code */
int i,j;
unsigned int out = 0x00000000;
unsigned int tmp;
char password[25] = "";
unsigned int bytes[25] = {
0x1e,0xcd,0x2a,0xd5,0x34,0x87,0xfc,0x78,
0x64,0x35,0x9d,0xec,0xde,0x15,0xac,0x97,
0x99,0xaf,0x96,0xda,0x79,0x26,0x4f,0x32,
0xe0
};
unsigned char opcode[163] = {
0xb8,0x04,0x00,0x00,0x00,0xbb,0x01,0x00,0x00,0x00,
0xb9,0xa1,0x91,0x04,0x08,0xba,0x26,0x00,0x00,0x00,
0xcd,0x80,0xb8,0x03,0x00,0x00,0x00,0x31,0xdb,0xb9,
0x88,0x91,0x04,0x08,0xba,0x33,0x00,0x00,0x00,0xcd,
0x80,0x31,0xc9,0xb8,0x80,0x80,0x04,0x08,0xbb,0x23,
0x81,0x04,0x08,0xe8,0x5b,0x00,0x00,0x00,0x89,0xca,
0xb9,0x19,0x00,0x00,0x00,0xb8,0x55,0x91,0x04,0x08,
0xbb,0x88,0x91,0x04,0x08,0xd1,0xca,0x8a,0x44,0x08,
0xff,0x8a,0x5c,0x0b,0xff,0x30,0xd8,0x30,0xd0,0x75,
0x1b,0x49,0x75,0xe3,0xb8,0x04,0x00,0x00,0x00,0xbb,
0x01,0x00,0x00,0x00,0xb9,0x24,0x91,0x04,0x08,0xba,
0x26,0x00,0x00,0x00,0xcd,0x80,0xeb,0x16,0xb8,0x04,
0x00,0x00,0x00,0xbb,0x01,0x00,0x00,0x00,0xb9,0x4a,
0x91,0x04,0x08,0xba,0x0b,0x00,0x00,0x00,0xcd,0x80,
0xb8,0x01,0x00,0x00,0x00,0x31,0xdb,0xcd,0x80,0x29,
0xc3,0x31,0xc9,0x02,0x08,0xc1,0xc1,0x03,0x40,0x4b,
0x75,0xf7,0xc3
};
printf("#########################################\n");
printf("--------KeyGen Coded By Void0xCC---------\n");
printf("------------Root-Me Challenge------------\n");
printf("#########################################\n");
for (j = 0; j < 163; j++)
{
__asm__(
"mov ecx, %2;"
"add cl, %1;" // function to get the right ECX
"rol ecx, 0x3;"
"mov %0, ecx;"
:"=r" (tmp)
:"r" (opcode[j]), "r" (out)
);
out = tmp;
}
printf("XOR hexadecimal ---> 0x%x\n", tmp);
printf("Key Generating ... 99.8%% \n");
sleep(2);
for(i=0; i < 25 ; i++)
{
__asm__(
"mov ebx, %1;"
"ror ebx, 0x1;" //get the password by solving the equation :
"mov %1, ebx;" //password[25] = string[25] XOR (ROL EDX, 0x1)
"mov %0, ebx;"
: "=r" (out)
: "r" (tmp)
);
tmp = out;
printf("%x XOR %x -----> %c\n", out, out ^ bytes[24 - i], out ^ bytes[24 - i]);
password[24 - i] = out ^ bytes[24 - i];
}
printf("Owned \n");
printf("Serial -----> %s\n", password);
printf("\n");
return 0;
}
after the
executing C program :













