Jun 29, 2011

Shell code 3(print message)

After the exit_shell.out program is finished, it's time to move on.
This time I will use a new system call which will print a message to the screen.

Background Knowlege:
the way I use the system call is still the same, using the int $0x80.
The parameters of print system call:
eax = 4  => this is the system call number.
ebx = 1  => we want to print the message to the stdout.
ecx =  msg => the address of the message.
edx = len   => the length of the message.

OK, coding time.
1.wrote the program into inline assembly.
print.c
char msg[]="Run Han";
int main(){
        __asm__("
                 movl $4,%eax;\
                 movl $1,%ebx;\
                 movl $0x7,%edx;\
                 movl $msg,%ecx;\
                 int  $0x80;\
                 movl $1,%eax;\
                 movl $0,%ebx;\
                 int  $0x80;\
                 ");
        return 0;
}
2.compile the source code with the following command:
gcc -g -o print.out print.c
3. execute the program

As u can see, the output message is in the global data, that's not good. I want the message is inside the shell code. Let's modified the source code a bit.
print_1.c
int main(){
        __asm__("
                 movl $4,%eax;\
                 movl $1,%ebx;\
                 movl $0x7,%edx;\
                 movl $msg,%ecx;\
                 int  $0x80;\
                 movl $1,%eax;\
                 movl $0,%ebx;\
                 int  $0x80;\
                 .string "Run Han"\
                 ");
        return 0;
}

However, in this way, how do I know the address of the message.
Thanks to this web site: http://insecure.org/stf/smashstack.html
I found the solution. The following is the modified version of the code.
print_2.c
int main(){
        __asm__("jmp 2f;\n\                   #2bytes
                 1:;\n\
                 popl %esi;\n\                #1bytes
                 movl $4,%eax;\n\             #5bytes
                 movl $1,%ebx;\n\             #5bytes
                 movl $0x7,%edx;\n\           #5bytes
                 movl %esi,%ecx;\n\           #2bytes
                 int  $0x80;\n\               #2bytes
                 movl $1,%eax;\n\             #5bytes
                 movl $0,%ebx;\n\             #5bytes
                 int  $0x80;\n\               #2bytes
                 2:;\n\
                 call 1b;\n\                  #5bytes
                 .string "Run Han";\n\
                 ");
        return 0;
}
Explanation:
Use the relative jmp/call to accomplish this job.
1. we first use the relative jump to jump to the call instruction.
2. next we use the relative call instruction to transfer the execution flow to the label 1.

So how does these steps has anything to do with the address of the message.
This is a very tricky way. When u call a function, the cpu will automatically push the eip into the stack. And look what is behind the call function, it is the message. So the cpu will help us to push the address of the message to the stack.

And now let's compile the file, and test the output.
It works.

The next step is much easier than above, all I have to do is use the objdump to dump the file, and change the inline assembly into shell code.

print_shell.c
char shellcode[]=
"\xeb\x20"
"\x5e"
"\xb8\x04\x00\x00\x00"
"\xbb\x01\x00\x00\x00"
"\xba\x07\x00\x00\x00"
"\x89\xf1"
"\xcd\x80"
"\xb8\x01\x00\x00\x00"
"\xbb\x00\x00\x00\x00"
"\xcd\x80"
"\xe8\xdb\xff\xff\xff"
"Run Han";
int main(){
        int *ptr;
        int i;
        /*
         *overflow the return address.
         *transfer the execution flow to shellcode.
         */
        for(i=0;i<10;i++){
                ptr = (int*)&ptr+i;
                *(ptr) = (int)shellcode;
        }
        return 0;
}
compile the program and don't forget to use the execstack command to enable the executable stack.
demo video:
http://www.youtube.com/watch?v=WpfShXa1iEk



No comments:

Post a Comment

Labels