Saturday, 1 November 2014

reversing example

coursera had a malware course, one of the class was to reverse engineer a binary and crack the key. I have tried to explain it here by taking baby steps using objdump in linux. The approach is trying to comeup with a pseudo code from binary. steps are objdump output, manual analysis, write pseudo code from the analysis and the finally the real code which was compiled to verify. Used gdb only for printing strings and converting hex to decimal. 

====== Example 1 =======

objdump
-------
In 1_objdump file search for main
08048394 <main>:
 8048394:       55                      push   %ebp
 8048395:       89 e5                   mov    %esp,%ebp
 8048397:       b8 7b 00 00 00          mov    $0x7b,%eax
 804839c:       5d                      pop    %ebp
 804839d:       c3                      ret
 804839e:       90                      nop
 804839f:       90                      nop

study
-----
 8048394:       55                      push   %ebp
save previous frame pointer on stack
 8048395:       89 e5                   mov    %esp,%ebp
Intialize the frame pointer to current stack pointer sp->bp.
 8048397:       b8 7b 00 00 00          mov    $0x7b,%eax
moving 0x7b value to eax register. 0x7b in decimal is
gdb ./a.out (using gdb for converting 123 to hex).)
(gdb) p/x 123
$1 = 0x7b
As you can see eax register is used to return values to the caller.

pseudocode
----------
main
    return 123;

code
----
#include <stdio.h>

int main(int argc, char **argv)
{
    return 123;
}

build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 2 =======

080483c4 <main>:
 80483c4:       55                      push   %ebp
 80483c5:       89 e5                   mov    %esp,%ebp
 80483c7:       83 e4 f0                and    $0xfffffff0,%esp
 80483ca:       83 ec 10                sub    $0x10,%esp
 80483cd:       b8 b4 84 04 08          mov    $0x80484b4,%eax
 80483d2:       89 04 24                mov    %eax,(%esp)
 80483d5:       e8 1a ff ff ff          call   80482f4 <printf@plt>
 80483da:       b8 7b 00 00 00          mov    $0x7b,%eax
 80483df:       c9                      leave
 80483e0:       c3                      ret

Our 0x7b is still there, there is a call to function printf. so our string
"Hello World" should pushed on stack, so eax which looks like a pointer value
is pushed onto stack before calling printf. But objdump file doesn't contain
the address contents [0x80484b4].
objdump -D ./a.out > 1_objdump
 80484b4:       48                      dec    %eax
 80484b5:       65                      gs
 80484b6:       6c                      insb   (%dx),%es:(%edi)
 80484b7:       6c                      insb   (%dx),%es:(%edi)
 80484b8:       6f                      outsl  %ds:(%esi),(%dx)
 80484b9:       20 57 6f                and    %dl,0x6f(%edi)
 80484bc:       72 6c                   jb     804852a <__dso_handle+0x7a>
 80484be:       64                      fs

b ./a.out
(gdb) x/s 0x80484b4
0x80484b4 <__dso_handle+4>:     "Hello World"
(gdb) x/16xb 0x80484b4
0x80484b4 <__dso_handle+4>:    0x48    0x65    0x6c    0x6c    0x6f    0x20    0x57    0x6f
0x80484bc <__dso_handle+12>:    0x72    0x6c    0x64    0x00    0x01    0x1b    0x03    0x3b
(gdb) x/16cb 0x80484b4
0x80484b4 <__dso_handle+4>:    72 'H'    101 'e'    108 'l'    108 'l'    111 'o'    32 ' '    87 'W'    111 'o'
0x80484bc <__dso_handle+12>:    114 'r'    108 'l'    100 'd'    0 '\000'    1 '\001'    27 '\033'    3 '\003'    59 ';'

Ok, we have our "Hello world" pointer in stack before calling printf.

 80483c4:       55                      push   %ebp
 80483c5:       89 e5                   mov    %esp,%ebp
usual prologue
 80483c7:       83 e4 f0                and    $0xfffffff0,%esp
Aligning the stack to 16 bytes.
 80483ca:       83 ec 10                sub    $0x10,%esp
Allocating 16 bytes, only 4 bytes are needed to put arg to printf, adhering to
alignment of 16 bytes.
 80483cd:       b8 b4 84 04 08          mov    $0x80484b4,%eax
 80483d2:       89 04 24                mov    %eax,(%esp)
"Hello world" pointer is pushed to eax to contents on allocated stack.
 80483d5:       e8 1a ff ff ff          call   80482f4 <printf@plt>
 80483da:       b8 7b 00 00 00          mov    $0x7b,%eax
 80483df:       c9                      leave
 80483e0:       c3                      ret

pseudocode
----------
main
    printf "Hello World";
    return 123;
code
----
#include <stdio.h>

int main(int argc, char **argv)
{
        printf("Hello World");
        return 123;
}

build
-----
gcc 1.c
objdump -d ./a.out > 1_objdump
====== Example 3 =======
08048474 <main>:
 8048474:       55                      push   %ebp
 8048475:       89 e5                   mov    %esp,%ebp
 8048477:       83 e4 f0                and    $0xfffffff0,%esp
 804847a:       81 ec 20 02 00 00       sub    $0x220,%esp
 8048480:       b8 c4 85 04 08          mov    $0x80485c4,%eax
 8048485:       89 04 24                mov    %eax,(%esp)
 8048488:       e8 1b ff ff ff          call   80483a8 <printf@plt>
 804848d:       a1 a0 97 04 08          mov    0x80497a0,%eax
 8048492:       89 04 24                mov    %eax,(%esp)
 8048495:       e8 ee fe ff ff          call   8048388 <fflush@plt>
 804849a:       c7 44 24 08 ff 01 00    movl   $0x1ff,0x8(%esp)
 80484a1:       00
 80484a2:       8d 44 24 14             lea    0x14(%esp),%eax
 80484a6:       89 44 24 04             mov    %eax,0x4(%esp)
 80484aa:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 80484b1:       e8 c2 fe ff ff          call   8048378 <read@plt>
 80484b6:       8d 44 24 14             lea    0x14(%esp),%eax
 80484ba:       89 04 24                mov    %eax,(%esp)
 80484bd:       e8 d6 fe ff ff          call   8048398 <strlen@plt>
 80484c2:       89 84 24 14 02 00 00    mov    %eax,0x214(%esp)
 80484c9:       8b 84 24 14 02 00 00    mov    0x214(%esp),%eax
 80484d0:       83 e8 01                sub    $0x1,%eax
 80484d3:       0f b6 44 04 14          movzbl 0x14(%esp,%eax,1),%eax
 80484d8:       3c 0a                   cmp    $0xa,%al
 80484da:       75 0f                   jne    80484eb <main+0x77>
 80484dc:       8b 84 24 14 02 00 00    mov    0x214(%esp),%eax
 80484e3:       83 e8 01                sub    $0x1,%eax
 80484e6:       c6 44 04 14 00          movb   $0x0,0x14(%esp,%eax,1)
 80484eb:       b8 7b 00 00 00          mov    $0x7b,%eax
 80484f0:       c9                      leave
 80484f1:       c3                      ret

study
-----
 8048474:       55                      push   %ebp
 8048475:       89 e5                   mov    %esp,%ebp
 8048477:       83 e4 f0                and    $0xfffffff0,%esp
usual

 804847a:       81 ec 20 02 00 00       sub    $0x220,%espa
(gdb) p 0x220
$1 = 544
Allocating 544 bytes on stack

 8048480:       b8 c4 85 04 08          mov    $0x80485c4,%eax
 8048485:       89 04 24                mov    %eax,(%esp)
 8048488:       e8 1b ff ff ff          call   80483a8 <printf@plt>
objdump -D ./a.out > 1_objdump
shows the contents of 0x80485c4.
(gdb) x/s 0x80485c4
0x80485c4 <__dso_handle+4>:     "Are you feeling lucky today? "
printf with one arg "Are you feeling lucky today? ".


 804848d:       a1 a0 97 04 08          mov    0x80497a0,%eax
 8048492:       89 04 24                mov    %eax,(%esp)
 8048495:       e8 ee fe ff ff          call   8048388 <fflush@plt>

man fflush

(gdb) x/s 0x80497a0
0x80497a0 <stdout@@GLIBC_2.0>:     ""
(gdb) p/x *0x80497a0
$6 = 0x0
so fflush is flusihing all open output streams. I think fflush(NULL).

 804849a:       c7 44 24 08 ff 01 00    movl   $0x1ff,0x8(%esp)
 80484a1:       00
 80484a2:       8d 44 24 14             lea    0x14(%esp),%eax
 80484a6:       89 44 24 04             mov    %eax,0x4(%esp)
 80484aa:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 80484b1:       e8 c2 fe ff ff          call   8048378 <read@plt>

man 2 read
ssize_t read(int fd, void *buf, size_t count);
stack is 0x1ff (511), something in stack which is at 20 (0x14) bytes , 0
so args to read are fd = 0, buf, 511.
main() stack allocated is 544 bytes of which
...
something like buf of size 524 ...(there could be other local variables,
read call is only restricted to overwrite 511)
20
0
pointer to buf
511
...

 80484b6:       8d 44 24 14             lea    0x14(%esp),%eax
 80484ba:       89 04 24                mov    %eax,(%esp)
 80484bd:       e8 d6 fe ff ff          call   8048398 <strlen@plt>
 80484c2:       89 84 24 14 02 00 00    mov    %eax,0x214(%esp)

size_t strlen(const char *s);
so strlen(buf);
(gdb) p 0x214
$8 = 532

local variables of main are
(544 = 8,4 (var1),512 (buf),20(alignment, padding (4)))
main
    char buf[512]
    int var1
    char unknown[8]
   
    printf("Are you feeling lucky today? ");
    fflush(NULL);
   
    read(0, buf, 511);
    var1 = strlen(buf);
 80484d0:       83 e8 01                sub    $0x1,%eax
512 - 1 = 511
 80484d3:       0f b6 44 04 14          movzbl 0x14(%esp,%eax,1),%eax
displacement(%base, %index, scale) = displacement+%base+%index*scale.
since scale is 1 it is a char array.
buf[511]
 80484d8:       3c 0a                   cmp    $0xa,%al
(gdb) p/c 0xa
$10 = 10 '\n'
if (buf[511 == '\n')
 80484da:       75 0f                   jne    80484eb <main+0x77>
 80484dc:       8b 84 24 14 02 00 00    mov    0x214(%esp),%eax
 80484e3:       83 e8 01                sub    $0x1,%eax
 80484e6:       c6 44 04 14 00          movb   $0x0,0x14(%esp,%eax,1)
    buf[511] = 0;
 80484eb:       b8 7b 00 00 00          mov    $0x7b,%eax
 80484f0:       c9                      leave
 80484f1:       c3                      ret

pseudo code
main
    char buf[512]
    int var1
    char unknown[8]
   
    printf("Are you feeling lucky today? ");
    fflush(NULL);
   
    read(0, buf, 511);
    var1 = strlen(buf);

    if (buf[511 == '\n')
        buf[511] = 0;

    return 123

code
----
#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
        char buf[512];
        int n,ret;
        int (*f)(char *);

        printf("Are you feeling lucky today? ");
        fflush(stdout);

        (void)read(0, buf, sizeof(buf)-1);
        n = strlen(buf);
        if (buf[n-1] == '\n')
                buf[n-1] = 0;

        return 123;
}

====== Example 4 =======
080484ee <main>:
 80484ee:       55                      push   %ebp
 80484ef:       89 e5                   mov    %esp,%ebp
 80484f1:       83 e4 f0                and    $0xfffffff0,%esp
 80484f4:       81 ec 20 02 00 00       sub    $0x220,%esp
 80484fa:       b8 7c 86 04 08          mov    $0x804867c,%eax
 80484ff:       89 04 24                mov    %eax,(%esp)
 8048502:       e8 c1 fe ff ff          call   80483c8 <printf@plt>
 8048507:       a1 60 98 04 08          mov    0x8049860,%eax
 804850c:       89 04 24                mov    %eax,(%esp)
 804850f:       e8 94 fe ff ff          call   80483a8 <fflush@plt>
 8048514:       c7 44 24 08 ff 01 00    movl   $0x1ff,0x8(%esp)
 804851b:       00
 804851c:       8d 44 24 14             lea    0x14(%esp),%eax
 8048520:       89 44 24 04             mov    %eax,0x4(%esp)
 8048524:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 804852b:       e8 68 fe ff ff          call   8048398 <read@plt>
 8048530:       8d 44 24 14             lea    0x14(%esp),%eax
 8048534:       89 04 24                mov    %eax,(%esp)
 8048537:       e8 7c fe ff ff          call   80483b8 <strlen@plt>
 804853c:       89 84 24 14 02 00 00    mov    %eax,0x214(%esp)
 8048543:       8b 84 24 14 02 00 00    mov    0x214(%esp),%eax
 804854a:       83 e8 01                sub    $0x1,%eax
 804854d:       0f b6 44 04 14          movzbl 0x14(%esp,%eax,1),%eax
 8048552:       3c 0a                   cmp    $0xa,%al
 8048554:       75 0f                   jne    8048565 <main+0x77>
 8048556:       8b 84 24 14 02 00 00    mov    0x214(%esp),%eax
 804855d:       83 e8 01                sub    $0x1,%eax
 8048560:       c6 44 04 14 00          movb   $0x0,0x14(%esp,%eax,1)
 8048565:       0f b6 44 24 14          movzbl 0x14(%esp),%eax
 804856a:       0f be c0                movsbl %al,%eax
 804856d:       83 f8 42                cmp    $0x42,%eax
 8048570:       74 17                   je     8048589 <main+0x9b>
 8048572:       83 f8 43                cmp    $0x43,%eax
 8048575:       74 21                   je     8048598 <main+0xaa>
 8048577:       83 f8 41                cmp    $0x41,%eax
 804857a:       75 29                   jne    80485a5 <main+0xb7>
 804857c:       c7 84 24 1c 02 00 00    movl   $0x80484a4,0x21c(%esp)
 8048583:       a4 84 04 08
 8048587:       eb 1e                   jmp    80485a7 <main+0xb9>
 8048589:       b8 9a 86 04 08          mov    $0x804869a,%eax
 804858e:       89 04 24                mov    %eax,(%esp)
 8048591:       e8 32 fe ff ff          call   80483c8 <printf@plt>
 8048596:       eb 0f                   jmp    80485a7 <main+0xb9>
 8048598:       c7 84 24 1c 02 00 00    movl   $0x80484d6,0x21c(%esp)
 804859f:       d6 84 04 08
 80485a3:       eb 02                   jmp    80485a7 <main+0xb9>
 80485a5:       eb fe                   jmp    80485a5 <main+0xb7>
 80485a7:       b8 7b 00 00 00          mov    $0x7b,%eax
 80485ac:       c9                      leave
 80485ad:       c3                      ret


rom 80484ee to 8048565 is
main
    char buf[512]
    int var1
    char unknown[8]
   
    printf("Are you feeling lucky today? ");
    fflush(NULL);
   
    read(0, buf, 511);
    var1 = strlen(buf);

    if (buf[511 == '\n')
        buf[511] = 0;

 8048565:       0f b6 44 24 14          movzbl 0x14(%esp),%eax
 804856a:       0f be c0                movsbl %al,%eax
 804856d:       83 f8 42                cmp    $0x42,%eax
 8048570:       74 17                   je     8048589 <main+0x9b>
if (buf[0] == 0x42)
(gdb) x/s 0x804869a
0x804869a <__dso_handle+42>:     "Hello"

    printf("Hello")

 8048572:       83 f8 43                cmp    $0x43,%eax
 8048575:       74 21                   je     8048598 <main+0xaa>
if (buf[0] == 0x43)
(gdb) x 0x80484d6
0x80484d6 <foobar>:    0x83e58955
    moving address of foobar to a local variable (function pointer).
 8048577:       83 f8 41                cmp    $0x41,%eax
 804857a:       75 29                   jne    80485a5 <main+0xb7>
 804857c:       c7 84 24 1c 02 00 00    movl   $0x80484a4,0x21c(%esp)
 8048583:       a4 84 04 08
 8048587:       eb 1e                   jmp    80485a7 <main+0xb9>
if (buf[0] == 0x41)
(gdb) x 0x80484a4
0x80484a4 <foo>:    0x83e58955
    moving address of foo to a local variable (function pointer).

 8048589:       b8 9a 86 04 08          mov    $0x804869a,%eax
 804858e:       89 04 24                mov    %eax,(%esp)
 8048591:       e8 32 fe ff ff          call   80483c8 <printf@plt>
// done with printf("Hello");
 8048596:       eb 0f                   jmp    80485a7 <main+0xb9>
 8048598:       c7 84 24 1c 02 00 00    movl   $0x80484d6,0x21c(%esp)
 804859f:       d6 84 04 08
 80485a3:       eb 02                   jmp    80485a7 <main+0xb9>
 80485a5:       eb fe                   jmp    80485a5 <main+0xb7>
Loo.....oop

switch (buf[0]) {
    case 0x41:
        var2 = &foo;
        break;
    case 0x42:
        printf("Hello");
        break;
    case 0x43:
        var2 = &foobar;
        break;
    default:
        loop here.
}
 80485a7:       b8 7b 00 00 00          mov    $0x7b,%eax
 80485ac:       c9                      leave
 80485ad:       c3                      ret

return 123;
====== Example 5 =======
08048577 <main>:
 8048577:       55                      push   %ebp
 8048578:       89 e5                   mov    %esp,%ebp
 804857a:       57                      push   %edi
 804857b:       83 e4 f0                and    $0xfffffff0,%esp
 804857e:       81 ec 30 02 00 00       sub    $0x230,%esp
 8048584:       b8 91 87 04 08          mov    $0x8048791,%eax
 8048589:       89 04 24                mov    %eax,(%esp)
 804858c:       e8 1f fe ff ff          call   80483b0 <printf@plt>
 8048591:       a1 40 a0 04 08          mov    0x804a040,%eax
 8048596:       89 04 24                mov    %eax,(%esp)
 8048599:       e8 22 fe ff ff          call   80483c0 <fflush@plt>
 804859e:       c7 44 24 08 ff 01 00    movl   $0x1ff,0x8(%esp)
 80485a5:       00
 80485a6:       8d 44 24 24             lea    0x24(%esp),%eax
 80485aa:       89 44 24 04             mov    %eax,0x4(%esp)
 80485ae:       c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 80485b5:       e8 e6 fd ff ff          call   80483a0 <read@plt>
 80485ba:       8d 44 24 24             lea    0x24(%esp),%eax
 80485be:       c7 44 24 1c ff ff ff    movl   $0xffffffff,0x1c(%esp)
 80485c5:       ff
 80485c6:       89 c2                   mov    %eax,%edx
 80485c8:       b8 00 00 00 00          mov    $0x0,%eax
 80485cd:       8b 4c 24 1c             mov    0x1c(%esp),%ecx
 80485d1:       89 d7                   mov    %edx,%edi
 80485d3:       f2 ae                   repnz scas %es:(%edi),%al
 80485d5:       89 c8                   mov    %ecx,%eax
 80485d7:       f7 d0                   not    %eax
 80485d9:       83 e8 01                sub    $0x1,%eax
 80485dc:       89 84 24 28 02 00 00    mov    %eax,0x228(%esp)
 80485e3:       8b 84 24 28 02 00 00    mov    0x228(%esp),%eax
 80485ea:       83 e8 01                sub    $0x1,%eax
 80485ed:       0f b6 44 04 24          movzbl 0x24(%esp,%eax,1),%eax
 80485f2:       3c 0a                   cmp    $0xa,%al
 80485f4:       75 0f                   jne    8048605 <main+0x8e>
 80485f6:       8b 84 24 28 02 00 00    mov    0x228(%esp),%eax
 80485fd:       83 e8 01                sub    $0x1,%eax
 8048600:       c6 44 04 24 00          movb   $0x0,0x24(%esp,%eax,1)
 8048605:       0f b6 44 24 24          movzbl 0x24(%esp),%eax
 804860a:       0f be c0                movsbl %al,%eax
 804860d:       83 f8 42                cmp    $0x42,%eax
 8048610:       74 17                   je     8048629 <main+0xb2>
 8048612:       83 f8 43                cmp    $0x43,%eax
 8048615:       74 1f                   je     8048636 <main+0xbf>
 8048617:       83 f8 41                cmp    $0x41,%eax
 804861a:       75 27                   jne    8048643 <main+0xcc>
 804861c:       c7 84 24 2c 02 00 00    movl   $0x804852d,0x22c(%esp)
 8048623:       2d 85 04 08
 8048627:       eb 1c                   jmp    8048645 <main+0xce>
 8048629:       c7 84 24 2c 02 00 00    movl   $0x80484c4,0x22c(%esp)
 8048630:       c4 84 04 08
 8048634:       eb 0f                   jmp    8048645 <main+0xce>
 8048636:       c7 84 24 2c 02 00 00    movl   $0x804855f,0x22c(%esp)
 804863d:       5f 85 04 08
 8048641:       eb 02                   jmp    8048645 <main+0xce>
 8048643:       eb fe                   jmp    8048643 <main+0xcc>
 8048645:       8d 44 24 24             lea    0x24(%esp),%eax
 8048649:       83 c0 01                add    $0x1,%eax
 804864c:       89 04 24                mov    %eax,(%esp)
 804864f:       8b 84 24 2c 02 00 00    mov    0x22c(%esp),%eax
 8048656:       ff d0                   call   *%eax
 8048658:       89 84 24 24 02 00 00    mov    %eax,0x224(%esp)
 804865f:       83 bc 24 24 02 00 00    cmpl   $0x0,0x224(%esp)
 8048666:       00
 8048667:       74 1a                   je     8048683 <main+0x10c>
 8048669:       b8 af 87 04 08          mov    $0x80487af,%eax
 804866e:       8d 54 24 24             lea    0x24(%esp),%edx
 8048672:       83 c2 01                add    $0x1,%edx
 8048675:       89 54 24 04             mov    %edx,0x4(%esp)
 8048679:       89 04 24                mov    %eax,(%esp)
 804867c:       e8 2f fd ff ff          call   80483b0 <printf@plt>
 8048681:       eb 0c                   jmp    804868f <main+0x118>
 8048683:       c7 04 24 be 87 04 08    movl   $0x80487be,(%esp)
 804868a:       e8 41 fd ff ff          call   80483d0 <puts@plt>
 804868f:       8b 84 24 24 02 00 00    mov    0x224(%esp),%eax
 8048696:       89 04 24                mov    %eax,(%esp)
 8048699:       e8 52 fd ff ff          call   80483f0 <exit@plt>
 804869e:       90                      nop
 804869f:       90                      nop

from 8048577 to 8048645 is similar with minor changes in switch and local
variables.
allocated stack = 0x230 (560 = 36 padding, buffer 512, var1 4,var2 4,function pointer 4)
36 (var1, var2 and function pointer are 4 bytes they are aligned to 16 bytes
so 12*3 = 36 bytes).
buf[512] 0x24(%esp)
var1   
var2    0x224(%esp) NOTE: stack is gowing in reverse so this value is ret.
function pointer(fp)

(gdb) x 0x80484c4
0x80484c4 <checkkey>:     "U\211\345WV\203\354\020\213E\b\211E\364\353\024\213E\364\017\266"

switch(buf[0])
    case 0x41
        fp = &foo;
        break;
    case 0x42
        fp = &checkkey;
        break;
    case 0x43
        fp = &foobar;
        break;
    default:
        loop here

 8048649:       83 c0 01                add    $0x1,%eax
 804864c:       89 04 24                mov    %eax,(%esp)
    var2 = fp(buf+1);
    exit(ret);
puts at 804868a
(gdb) x/s 0x80487be
0x80487be:     "[-] Nope."

[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? c
^C
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? A
foo
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? B
[-] Nope.
[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? C
foo
[-] Nope.

So input with B calls checkkey(); 
080484c4 <checkkey>:
 80484c4:       55                      push   %ebp
 80484c5:       89 e5                   mov    %esp,%ebp
 80484c7:       57                      push   %edi
 80484c8:       56                      push   %esi
 80484c9:       83 ec 10                sub    $0x10,%esp
 80484cc:       8b 45 08                mov    0x8(%ebp),%eax
 80484cf:       89 45 f4                mov    %eax,-0xc(%ebp)
 80484d2:       eb 14                   jmp    80484e8 <checkkey+0x24>
char *p = buf[1];
 80484d4:       8b 45 f4                mov    -0xc(%ebp),%eax
 80484d7:       0f b6 00                movzbl (%eax),%eax
 80484da:       89 c2                   mov    %eax,%edx
 80484dc:       83 f2 2a                xor    $0x2a,%edx
 80484df:       8b 45 f4                mov    -0xc(%ebp),%eax
 80484e2:       88 10                   mov    %dl,(%eax)
*p = *p^42
 80484e4:       83 45 f4 01             addl   $0x1,-0xc(%ebp)
p++;
 80484e8:       8b 45 f4                mov    -0xc(%ebp),%eax
 80484eb:       0f b6 00                movzbl (%eax),%eax
 80484ee:       84 c0                   test   %al,%al
*p check in for loop
 80484f0:       75 e2                   jne    80484d4 <checkkey+0x10>

for (;*p ; p++)
    *p = *p ^ 0x2a; (0x2a = 42)

 80484f2:       8b 45 08                mov    0x8(%ebp),%eax
 80484f5:       89 c2                   mov    %eax,%edx
 80484f7:       b8 70 87 04 08          mov    $0x8048770,%eax
(gdb) x/s 0x8048770
0x8048770:     "KFFSE_XHKYOKXOHOFEDM^E_Y"

 80484fc:       b9 19 00 00 00          mov    $0x19,%ecx
 8048501:       89 d6                   mov    %edx,%esi
 8048503:       89 c7                   mov    %eax,%edi
 8048505:       f3 a6                   repz cmpsb %es:(%edi),%ds:(%esi)
 8048507:       0f 97 c2                seta   %dl
 804850a:       0f 92 c0                setb   %al
 804850d:       89 d1                   mov    %edx,%ecx
 804850f:       28 c1                   sub    %al,%cl
 8048511:       89 c8                   mov    %ecx,%eax
 8048513:       0f be c0                movsbl %al,%eax
 8048516:       85 c0                   test   %eax,%eax
strcmp()
 8048518:       75 07                   jne    8048521 <checkkey+0x5d>
 804851a:       b8 01 00 00 00          mov    $0x1,%eax
return 1 if match
 804851f:       eb 05                   jmp    8048526 <checkkey+0x62>
 8048521:       b8 00 00 00 00          mov    $0x0,%eax
 8048526:       83 c4 10                add    $0x10,%esp
 8048529:       5e                      pop    %esi
 804852a:       5f                      pop    %edi
 804852b:       5d                      pop    %ebp
 804852c:       c3                      ret

(Given input) ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") is the check in code
(Given input) ^ 42 ^ 42 = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42
(Given input) = ("KFFSE_XHKYOKXOHOFEDM^E_Y") ^ 42

So to get the Given input
#include<stdio.h>
#include<string.h>

#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"

main()
{
   char *p = KEY;   
   for (; *p; p++) {
      printf("%c",(*p) ^ 42);   
   }
   printf("\n");   
}
gcc above code
./a.out
allyourbasearebelongtous

[chetan@chetan reverse]$ ./reverse-ex
Are you feeling lucky today? Ballyourbasearebelongtous
[-] Nope.

Bug in the code
gcc -g reverse-ex.c
gdb ./a.out
(gdb) b checkkey
Breakpoint 1 at 0x804850a: file reverse-ex.c, line 13.
(gdb) r
Breakpoint 1, checkkey (
    key=0xbffff0b5 "allyourbasearebelongtous\n\377\277\265\306>")
    at reverse-ex.c:13
13       char *p = key;

There are junk characters read by read() call.
Fixing the read code (man read tells this)
from
   (void) read(0, buf, sizeof(buf)-1);
   n = strlen(buf);
to
   n = read(0, buf, sizeof(buf)-1);
   //n = strlen(buf);

checking through gdb
Breakpoint 1, checkkey (key=0xbffff0b5 "allyourbasearebelongtous")
    at ./reverse-ex.c:13
13       char *p = key;

[chetan@chetan reverse]$ ./a.out
Are you feeling lucky today? Ballyourbasearebelongtous
[+] WooT!: KFFSE_XHKYOKXOHOFEDM^E_Y

So the INPUT is Ballyourbasearebelongtous

code
---
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

#define KEY "KFFSE_XHKYOKXOHOFEDM^E_Y"

int
checkkey(char *key)
{

   char *p = key;

   for (; *p; p++)
      *p ^= 42;

   if (!strcmp(key,KEY))
      return 1;
   return 0;
}

int
foo(char *data)
{
   printf("foo\n");
   return 0;
}

int
bar(char *data)
{
   printf("bar\n");
   return 0;
}
int
foobar(char *data)
{

   foo(data);
   return 0;
}

int
main(void)
{

   char buf[512];
   int n, ret;
   int (*f)(char *);

   //memset(buf, 0, sizeof(buf));

   printf("Are you feeling lucky today? ");
   fflush(stdout);

   n = read(0, buf, sizeof(buf)-1);
   //n = strlen(buf);
   if (buf[n-1] == '\n')
      buf[n-1] = 0;

   switch (buf[0]) {

      case 0x41:
         f = &foo;
         break;
      case 0x42:
         f = &checkkey;
         break;
      case 0x43:
         f = &foobar;
         break;
      default:
      loop:
         goto *&&loop;
   }

   ret = f(buf+1);
   if (ret)
      printf("[+] WooT!: %s\n", buf+1);
   else
      printf("[-] Nope.\n");

   exit(ret);
}

Tuesday, 1 November 2011

FreeBSD kernel module debugging

I wanted to do kernel mode programming on FreeBSD and needed a setup to load a  kernel module and do kgdb remote debugging. I wanted the whole setup on my windows laptop. The following
details the steps needed to setup VMs connect them serially (virtual) for kgdb debugging and compile/debug a FreeBSD hello world kernel module.

Goal: To write a FreeBSD kernel module and be able to do remote source level debugging.
Setup needs two instances of Virtual Box running FreeBSD (hosted on windows),
one VM (Target VM) runs a test kernel module which needs to be debugged and the second VM (Dev VM) is used to run kgdb to remote debug the test kernel module loaded on target VM.
                       
    1) Download FreeBSD i386 iso
    2) Download Virtual Box
    3) Install standard FreeBSD with sources in a Virtual Box VM.
    4) Build a Debug FreeBSD kernel
            # cd /usr/src/sys/i386/ 
            # cp conf/GENERIC conf/MYDEBUGKERNEL
            Edit MYDEBUGKERNEL with more debug optins DEBUG -g (already set), OPTION KDB
           (already set),  OPTION DDB, OPTION GDB
            Compile the kernel
            # cd /usr/src/ 
            # make buildkernel KERNCONF=MYDEBUGKERNEL 
            # make installkernel KERNCONF=MYDEBUGKERNEL
    5) Clone the Virtual Box, So that we have two VMs Dev/Target debugging setup having the same  
        sources binaries and symbols.        
    6) setup serial communication  between VMs.
        Serial communication: through windows named pipe \\.\Pipe\<pipe name> and on
        Target VM, edit /boot/device.hints , "hint.uart.0.flags" to the value "0xC0" and reboot.
        Check VMs can communicate serially.
        Target VM: cat /dev/cuau0 (or some other file).
        Dev VM: echo "test string" >> /dev/cuau0 (or some other file) - you should see "test string"
        on Target VM. This is done so that kgdb can send commands from Dev VM to Target VM.
       
        one VM will create the named pipe and the other VM uses it, make sure when you start the
        VMs always start the VM which creates the  named pipe first
        
    7) setup Network communication between VMs.
        setup Internal Network, allow all with different mac address between VM. provide
        static ips to both the VMs.
        ifconfig em0 10.1.1.1 up on Dev machine
        ifconfig em0 10.1.1.2 up on Target machine.
        test it using ping 10.1.1.1 from 10.1.1.2 and arp -a.
       
    8) setup ftp or rsync server on Target machine and test it
        http://www.freebsd.org/doc/handbook/network-ftp.html
        I ftp my test FreeBSD .ko from Dev VM to target VM.
           
    9) Test remote debugging.
        Dev VM>
        cd /usr/obj/usr/src/sys/MYDEBUGKERNEL
        kgdb -r /dev/cuau0 ./kernel.debug
       
        Target VM>
        # sysctl debug.kdb.enter=1
        db> gdb 
        Step to enter the remote GDB backend. 
        db> c (continue)
           
        Try breaking (sysctl debug.kdb.enter=1) Target VM multiple times and continuing as above
        in target VM, till the Dev VM is able to grab the Target VM in kgdb.
       
        Dev VM: stack trace on DEV VM should confirm the remote debugging capability.
        kgdb> bt
        kgdb> c (continue)
               
        Now the whole setup is ready with Dev VM and Target VM with serial cable connected and
        also a network connected, also load the gdb macros in kgdb
        DEV VM:
        # cd /usr/obj/usr/src/sys/MYDEBUGKERNEL  (or name of kernel config)
        # make gdbinit (generates .gdbinit which is loaded when kgdb is started from the above
                                  directory).
       
        Reconnect Dev and Target with the gdb macros loaded in dev VM.
        DEV VM:
        kgdb> kldstat (gdb macro list all the modules loaded in Target VM, should be same as kldstat
                                 command when run in Target VM.)
       
        gdb macros is a nice way to figure out how the FreeBSD datastructures are laid out 
        in memory (checkout gdbinit.kernel, gdbinit.i386 in MYDEBUGKERNEL) along with
        cscope  and ctags for code browsing.
       
        Building and debugging "Hello world" kernel module: need two files Makefile and hello.c
        http://www.freesoftwaremagazine.com/articles/writing_a_kernel_module_for_freebsd
   
    Makefile:
        KMOD = hello
        SRCS = hello.c
   
        .include <bsd.kmod.mk>
   
    hello.c
   
    #include <sys/param.h>
    #include <sys/module.h>
    #include <sys/kernel.h>
    #include <sys/systm.h>
   
    void hello_debug_unload(void)  /* needed for testing remote debugging */
    {
        uprintf("Bye Bye hello_debug_unload\n");
    }
   
    /* The function called at load/unload. */
    static
    int event_handler(struct module *module, int event, void *arg) {
        int e = 0; /* Error, 0 for normal return status */
        switch (event) {
        case MOD_LOAD:
                uprintf("Hello Free Software Magazine Readers! \n");
                break;
        case MOD_UNLOAD:
                uprintf("Bye Bye FSM reader, be sure to check http://freesoftwaremagazine.com !\n");
                break;
        default:
                e = EOPNOTSUPP; /* Error, Operation Not Supported */
                break;
        }
      
        return(e);
   }
/* The second argument of DECLARE_MODULE. */
static moduledata_t hello_conf = {
    "hello",    /* module name */
     event_handler,  /* event handler */
     NULL            /* extra data */
};
DECLARE_MODULE(hello, hello_conf, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);

Compiling kernel module:
    make DEBUG_FLAGS=-g3
    make install DEBUG_FLAGS=-g3  (copies hello.ko and  hello.ko.symbols to /boot/kernel)
   
loading kernel module   
    ftp hello.ko from Dev VM to Target VM, connect remote gdb.
    target VM > kldload ./hello.ko
    target VM> kldstat
   
    Figure out where the text section of hello_fsm kernel module starts in memory (module load
    address + module text section start).
    http://www.cz.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/kerneldebug-kld.html
    objdump --section-headers hello.ko | grep text (text section start offset)
    kldstat would give the hello module load address.
    so kgdb on dev VM needs to be provided with the text section start of the loaded module(sum up
    both the addresses).
   
    On Dev VM break into Target VM and setup the new loaded kmod details.   
    Dev VM kgdb> add-symbol-file hello.ko 0xc0ae22d0
    Dev VM kgdb> b hello_debug_unload
    /* this gets hit when we do kunload on hello_fsm in target, check whether sources can be listed */
   
    target VM > kunload hello_fsm
    /* gets stuck in breakpoint */

    dev VM>  /* got control of  my code, happy digging */

 
Thanks to all the internet authors on FreeBSD kernel debugging.