Let's try Radare2

Published on Friday, 22 August 2014 in Reverse Engineering ; tagged with reverse, radare2, r2, challenge, ctf ; text version

It has been a long time since I didn't write something about re. With the GSoC I mostly wrote python code over the past couple of months.

I want something more low-level now and what is better than some re? Plus, it is a good opportunity to use for the first time this awesome tool jvoisin is always bragging about: radare2!

The binary comes from an old CTF but I feel like I should not name it nor give the actual flag. I will use radare2 to analyze and reverse it so let's begin!

Information gathering

Since I am not familiar at all with radare2, let see the help:

 -- I did it for the pwnz.
[0x08048450]> ?
Usage: [.][times][cmd][~grep][@[@iter]addr!size][|>pipe] ; ...
Append '?' to any char command to get detailed help
Prefix with number to repeat command N times (f.ex: 3x)
|%var =valueAlias for 'env' command
| *off[=[0x]value]     Pointer read/write data/values (see ?v, wx, wv)
| (macro arg0 arg1)    Manage scripting macros
| .[-|(m)|f|!sh|cmd]   Define macro or load r2, cparse or rlang file
| = [cmd]              Run this command via rap://
| /                    Search for bytes, regexps, patterns, ..
| ! [cmd]              Run given command as in system(3)
| # [algo] [len]       Calculate hash checksum of current block
| a                    Perform analysis of code
| b                    Get or change block size
| c [arg]              Compare block with given data
| C                    Code metadata management
| d                    Debugger commands
| e [a[=b]]            List/get/set config evaluable vars
| f [name][sz][at]     Set flag at current address
| g [arg]              Go compile shellcodes with r_egg
| i [file]             Get info about opened file
| k [sdb-query]        Run sdb-query. see k? for help, 'k *', 'k **' ...
| l [-] [num|msg]      Log utility
| m                    Mountpoints commands
| o [file] ([offset])  Open file at optional address
| p [len]              Print current block with format and length
| P                    Project management utilities
| q [ret]              Quit program with a return value
| r [len]              Resize file
| s [addr]             Seek to address (also for '0x', '0x1' == 's 0x1')
| S                    Io section manipulation information
| t                    Cparse types management
| V                    Enter visual mode (vcmds=visualvisual  keystrokes)
| w [str]              Multiple write operations
| x [len]              Alias for 'px' (print hexadecimal)
| y [len] [[@]addr    Yank/paste bytes from/to memory
| z                    Zignatures management
| ?[??][expr]          Help or evaluate math expression
| ?$?                  Show available '$' variables and aliases
| ?@?                  Misc help for '@' (seek), '~' (grep) (see ~??)]

First thing first, I want to check the binary information and from the previous output I can see that I should use the i [file] command.

[0x08048450]> i?
|Usage: i Get info from opened file
| Output mode:  
| '*'           Output in radare commands
| 'j'           Output in json
| 'q'           Simple quiet output
| Actions:      
 ...
| iI            Binary info
 ...
| iz            Strings

I removed the commands that don't interest me.

[0x08048450]> iI
file    [redacted]
type    EXEC (Executable file)
pic false
canary  false
nx  true
crypto  false
has_va  true
root    elf
class   ELF32
lang    c
arch    x86
bits    32
machine Intel 80386
os  linux
subsys  linux
endian  little
strip   true
static  false
linenum false
lsyms   false
relocs  false
rpath   NONE

From lines 10, 12, 13 and 18 I understand that I am dealing with an ELF32 bit binary that has been stripped. No surprise here.

[0x08048450]> iz
vaddr=0x080488f0 paddr=0x000008f0 ordinal=000 sz=12 len=11 section=.rodata type=a string=Next time!\n
vaddr=0x080488fc paddr=0x000008fc ordinal=001 sz=11 len=10 section=.rodata type=a string=Congrats!\n
vaddr=0x08049b9f paddr=0x00000b9f ordinal=000 sz=5 len=4 section=.data type=a string=\eE[7

The two first strings that appear are likely the Good boy and the Bad boy. The last could be the encrypted flag or a key. Time to analyse the code now.

Code analysis

From ? I saw some interesting commands.

[0x08048450]> a?
|Usage: a
 ...
| aa                analyze all (fcns + bbs)
 ...
Examples:
 f ts @ `S*~text:0[3]`; f t @ section..text
 f ds @ `S*~data:0[3]`; f d @ section..data
 .ad t t+ts @ d:ds
[0x08048450]> p?
|Usage: p[=68abcdDfiImrstuxz] [arg|len]
 ...
| p[dD][lf] [l]     disassemble N opcodes/bytes (see pd?)
 ...
[0x08048450]> pd?
|Usage: pd[f|i|l] [len] [arch] [bits] @ [addr] # Print Disassembly
| NOTE:len  parameter can be negative
 ...
| pdf       disassemble function
 ...

So let's use aa and pdf.

[0x08048450]> aa
[0x08048450]> pdf
   ;      [12] va=0x08048450 pa=0x00000450 sz=1156 vsz=1156 rwx=-r-x .text
/ (fcn) entry0 34
|          ;-- section..text:
|          0x08048450    31ed         xor ebp, ebp
|          0x08048452    5e           pop esi
|          0x08048453    89e1         mov ecx, esp
|          0x08048455    83e4f0       and esp, 0xfffffff0
|          0x08048458    50           push eax
|          0x08048459    54           push esp
|          0x0804845a    52           push edx
|          0x0804845b    68d0880408   push loc.080488d0 ; loc.080488d0
|          0x08048460    6860880408   push fcn.08048860 ;  0x08048860 
|          0x08048465    51           push ecx
|          0x08048466    56           push esi
|          0x08048467    68c1860408   push main ; main
|          0x0804846c    e88fffffff   call sym.imp.__libc_start_main
|             sym.imp.__libc_start_main(unk, unk, unk, unk, unk, unk, unk, unk)
\          0x08048471    f4           hlt

Though the binary has been stripped, radare2 recognizes the GCC convention (lines 17 and 18) and named the main function (line 17).

[0x08048450]> pdf@main
|           ; UNKNOWN XREF from 0x080486c1 (unk)
|           ; DATA XREF from 0x08048467 (entry0)
/ (fcn) main 412
|           0x080486c1    55           push ebp
|           0x080486c2    89e5         mov ebp, esp
|           0x080486c4    83e4f0       and esp, 0xfffffff0
|           0x080486c7    83ec40       sub esp, 0x40
|           0x080486ca    c744242c508. mov dword [esp+0x2c], 0x8048550 ;  0x08048550 
|           0x080486d2    c7442430000. mov dword [esp+0x30], 0x0
|           0x080486da    c7442410557. mov dword [esp+0x10], 0x67617355 ;  0x67617355 
|           0x080486e2    c7442414652. mov dword [esp+0x14], 0x203a2065 ;  0x203a2065 
|           0x080486ea    c74424182e2. mov dword [esp+0x18], 0x72632f2e ;  0x72632f2e 
|           0x080486f2    c744241c616. mov dword [esp+0x1c], 0x6d6b6361 ;  0x6d6b6361 
|           0x080486fa    c7442420652. mov dword [esp+0x20], 0x61702065 ;  0x61702065 
|           0x08048702    c7442424737. mov dword [esp+0x24], 0x6f777373 ;  0x6f777373 
|           0x0804870a    c7442428726. mov dword [esp+0x28], 0xa6472 ;  0x000a6472 
|           0x08048712    837d0802     cmp dword [ebp+0x8], 0x2
|       ,=< 0x08048716    742e         je loc.08048746
|       |   0x08048718    8d442410     lea eax, [esp+0x10]
|       |   0x0804871c    890424       mov [esp], eax
|       |   0x0804871f    e8ccfcffff   call fcn.080483f0
|       |      fcn.080483f0(unk)
|       |   0x08048724    89442408     mov [esp+0x8], eax
|       |   0x08048728    8d442410     lea eax, [esp+0x10]
|       |   0x0804872c    89442404     mov [esp+0x4], eax
|       |   0x08048730    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
|       |   0x08048737    e8d4fcffff   call sym.imp.write
|       |      sym.imp.write()
|       |   0x0804873c    b800000000   mov eax, 0x0
|      ,==< 0x08048741    e915010000   jmp loc.0804885b
|      ||   ; JMP XREF from 0x08048716 (unk)
|- loc.08048746 279
|      |`-> 0x08048746    8b450c       mov eax, [ebp+0xc]
|      |    0x08048749    83c004       add eax, 0x4
|      |    0x0804874c    8b00         mov eax, [eax]
|      |    0x0804874e    890424       mov [esp], eax
|      |    0x08048751    e89afcffff   call fcn.080483f0
|      |       fcn.080483f0()
|      |    0x08048756    8944243c     mov [esp+0x3c], eax
|      |    0x0804875a    837c243c15   cmp dword [esp+0x3c], 0x15
|     ,===< 0x0804875f    7426         je fcn.08048787
|     ||    0x08048761    c74424080b0. mov dword [esp+0x8], 0xb ;  0x0000000b 
|     ||    0x08048769    c7442404f08. mov dword [esp+0x4], str.Next_time__n ; str.Next_time__n
|     ||    0x08048771    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
|     ||    0x08048778    e893fcffff   call sym.imp.write
|     ||       sym.imp.write()
|     ||    0x0804877d    b800000000   mov eax, 0x0
|    ,====< 0x08048782    e9d4000000   jmp loc.0804885b
|    ||     ; JMP XREF from 0x0804875f (unk)
|- fcn.08048787 214
|    |`---> 0x08048787    c7442438000. mov dword [esp+0x38], 0x0
|    | |    0x0804878f    c7442434000. mov dword [esp+0x34], 0x0
|   ,=====< 0x08048797    eb6d         jmp 0x8048806 ; (main)
|           ; JMP XREF from 0x0804880e (unk)
|- fcn.08048799 196
| --------> 0x08048799    8b542438     mov edx, [esp+0x38]
|   || |    0x0804879d    8b44242c     mov eax, [esp+0x2c]
|   || |    0x080487a1    01d0         add eax, edx
|   || |    0x080487a3    0fb600       movzx eax, byte [eax]
|   || |    0x080487a6    84c0         test al, al
|  ,======< 0x080487a8    7411         je loc.080487bb
|- fcn.080487aa 179
|  ||| |    0x080487aa    8b542438     mov edx, [esp+0x38]
|  ||| |    0x080487ae    8b44242c     mov eax, [esp+0x2c]
|  ||| |    0x080487b2    01d0         add eax, edx
|  ||| |    0x080487b4    0fb600       movzx eax, byte [eax]
|  ||| |    0x080487b7    3cff         cmp al, 0xff
| ,=======< 0x080487b9    7507         jne 0x80487c2
| ||        ; JMP XREF from 0x080487a8 (unk)
|- loc.080487bb 179
| |`------> 0x080487bb    8344243c01   add dword [esp+0x3c], 0x1
| ========< 0x080487c0    eb3f         jmp 0x8048801 ; (main)
| |         ; JMP XREF from 0x080487b9 (unk)
| `-------> 0x080487c2    8b542438     mov edx, [esp+0x38]
|   || |    0x080487c6    8b44242c     mov eax, [esp+0x2c]
|   || |    0x080487ca    01d0         add eax, edx
|   || |    0x080487cc    0fb610       movzx edx, byte [eax]
|   || |    0x080487cf    8b450c       mov eax, [ebp+0xc]
|   || |    0x080487d2    83c004       add eax, 0x4
|   || |    0x080487d5    8b08         mov ecx, [eax]
|   || |    0x080487d7    8b442434     mov eax, [esp+0x34]
|   || |    0x080487db    01c8         add eax, ecx
|   || |    0x080487dd    0fb608       movzx ecx, byte [eax]
|   || |    0x080487e0    8b442434     mov eax, [esp+0x34]
|   || |    0x080487e4    05909b0408   add eax, 0x8049b90
|   || |    0x080487e9    0fb600       movzx eax, byte [eax]
|   || |    0x080487ec    31c8         xor eax, ecx
|   || |    0x080487ee    38c2         cmp dl, al
| ========< 0x080487f0    740a         je 0x80487fc
|   || |    0x080487f2    c7442430010. mov dword [esp+0x30], 0x1 ;  0x00000001 
| ========< 0x080487fa    eb14         jmp loc.08048810
|           ; JMP XREF from 0x080487f0 (unk)
| --------> 0x080487fc    8344243401   add dword [esp+0x34], 0x1
|           ; JMP XREF from 0x080487c0 (unk)
| --------> 0x08048801    8344243801   add dword [esp+0x38], 0x1
|   |       ; JMP XREF from 0x08048797 (unk)
|   `-----> 0x08048806    8b442438     mov eax, [esp+0x38]
|    | |    0x0804880a    3b44243c     cmp eax, [esp+0x3c]
| ========< 0x0804880e    7c89         jl fcn.08048799
|           ; JMP XREF from 0x080487fa (unk)
|- loc.08048810 77
| --------> 0x08048810    837c243000   cmp dword [esp+0x30], 0x0
| ========< 0x08048815    7523         jne loc.0804883a
|    | |    0x08048817    c74424080a0. mov dword [esp+0x8], 0xa ;  0x0000000a 
|    | |    0x0804881f    c7442404fc8. mov dword [esp+0x4], str.Congrats__n ; str.Congrats__n
|    | |    0x08048827    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
|    | |    0x0804882e    e8ddfbffff   call sym.imp.write
|    | |       sym.imp.write()
|    | |    0x08048833    b801000000   mov eax, 0x1 ;  0x00000001 
| ========< 0x08048838    eb21         jmp loc.0804885b
|           ; JMP XREF from 0x08048815 (unk)
|- loc.0804883a 35
| --------> 0x0804883a    c74424080b0. mov dword [esp+0x8], 0xb ;  0x0000000b 
|    | |    0x08048842    c7442404f08. mov dword [esp+0x4], str.Next_time__n ; str.Next_time__n
|    | |    0x0804884a    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
|    | |    0x08048851    e8bafbffff   call sym.imp.write
|    | |       sym.imp.write()
|    | |    0x08048856    b800000000   mov eax, 0x0
|    | |    ; JMP XREF from 0x08048838 (unk)
|    | |    ; JMP XREF from 0x08048782 (unk)
|    | |    ; JMP XREF from 0x08048741 (unk)
|- loc.0804885b 2
| ---`-`--> 0x0804885b    c9           leave
\           0x0804885c    c3           ret

From the lines 106 and 115, I can read respectively the Good boy and the Bad boy strings I found earlier when looking for strings.

Step by step

It will be more readable for you if I go slow and detail the steps.

I read the beginning of the main function.

[0x08048450]> pd 25@main
           ;-- main:
           0x080486c1    55           push ebp
           0x080486c2    89e5         mov ebp, esp
           0x080486c4    83e4f0       and esp, 0xfffffff0
           0x080486c7    83ec40       sub esp, 0x40
           0x080486ca    c744242c508. mov dword [esp+0x2c], 0x8048550 ;  0x08048550 
           0x080486d2    c7442430000. mov dword [esp+0x30], 0x0
           0x080486da    c7442410557. mov dword [esp+0x10], 0x67617355 ;  0x67617355 
           0x080486e2    c7442414652. mov dword [esp+0x14], 0x203a2065 ;  0x203a2065 
           0x080486ea    c74424182e2. mov dword [esp+0x18], 0x72632f2e ;  0x72632f2e 
           0x080486f2    c744241c616. mov dword [esp+0x1c], 0x6d6b6361 ;  0x6d6b6361 
           0x080486fa    c7442420652. mov dword [esp+0x20], 0x61702065 ;  0x61702065 
           0x08048702    c7442424737. mov dword [esp+0x24], 0x6f777373 ;  0x6f777373 
           0x0804870a    c7442428726. mov dword [esp+0x28], 0xa6472 ;  0x000a6472 
           0x08048712    837d0802     cmp dword [ebp+0x8], 0x2
       ,=< 0x08048716    742e         je 0x8048746
       |   0x08048718    8d442410     lea eax, [esp+0x10]
       |   0x0804871c    890424       mov [esp], eax
       |   0x0804871f    e8ccfcffff   call 0x80483f0
       |      0x080483f0(unk) ; sym.imp.kill
       |   0x08048724    89442408     mov [esp+0x8], eax
       |   0x08048728    8d442410     lea eax, [esp+0x10]
       |   0x0804872c    89442404     mov [esp+0x4], eax
       |   0x08048730    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
       |   0x08048737    e8d4fcffff   call sym.imp.write
       |      0x08048410() ; sym.imp.write
       |   0x0804873c    b800000000   mov eax, 0x0
       |   0x08048741    e915010000   jmp 0x804885b

Two things are pushed onto the stack. The first one seems to be a function address (line 7) and the second one a string (lines 7 to 15).

[0x0804a450]> pdf@0x8048550
/ (fcn) fcn.08048520 113
|            ...
|           ; CALL XREF from 0x080485c2 (fcn.08048591)
|           ; DATA XREF from 0x080486ca (unk)
|           0x08048550    55           push ebp
|           0x08048551    89e5         mov ebp, esp
|           0x08048553    83ec28       sub esp, 0x28
|           0x08048556    c745f000000. mov dword [ebp-0x10], 0x0
|           0x0804855d    c745f400000. mov dword [ebp-0xc], 0x0
|   ,=====< 0x08048564    eb20         jmp 0x8048586 ; (fcn.08048520)
|   |       ; JMP XREF from 0x0804858a (fcn.08048520)
|   |       0x08048566    c7442404010. mov dword [esp+0x4], 0x1 ;  0x00000001 
|   |       0x0804856e    8b45f4       mov eax, [ebp-0xc]
|   |       0x08048571    890424       mov [esp], eax
|   |       0x08048574    e8a7feffff   call sym.imp.fcntl
|   |          sym.imp.fcntl(unk)
|   |       0x08048579    83f8ff       cmp eax, 0xffffffff
|  ,======< 0x0804857c    7404         je 0x8048582
| |||       0x0804857e    8345f001     add dword [ebp-0x10], 0x1
| ||        ; JMP XREF from 0x0804857c (fcn.08048520)
| |`------> 0x08048582    8345f401     add dword [ebp-0xc], 0x1
| | |       ; JMP XREF from 0x08048564 (fcn.08048520)
| | `-----> 0x08048586    837df40a     cmp dword [ebp-0xc], 0xa
|           0x0804858a    7eda         jle 0x8048566
|           0x0804858c    8b45f0       mov eax, [ebp-0x10]
|           0x0804858f    c9           leave
\           0x08048590    c3           ret

The 0x8048550 function uses fcntl but I don't really get what it does. Meh, I will come back on that later if needed. I am more interested in that handmade string.

[0x08048450]> pxw 64 @0x080486da
0x080486da  0x102444c7 0x67617355 0x142444c7 0x203a2065  .D$.Usag.D$.e : 
0x080486ea  0x182444c7 0x72632f2e 0x1c2444c7 0x6d6b6361  .D$../cr.D$.ackm
0x080486fa  0x202444c7 0x61702065 0x242444c7 0x6f777373  .D$ e pa.D$$sswo
0x0804870a  0x282444c7 0x000a6472 0x02087d83 0x448d2e74  .D$(rd...}..t..D

All together, that gives Usage : ./crackme password which is the usage string. Moving on.

|      |`-> 0x08048746    8b450c       mov eax, [ebp+0xc] ;  from the stack
|      |    0x08048749    83c004       add eax, 0x4 ;        retrieve the param
|      |    0x0804874c    8b00         mov eax, [eax] ;      and dereference it
|      |    0x0804874e    890424       mov [esp], eax ;      for strlen
|      |    0x08048751    e89afcffff   call fcn.080483f0
|      |       fcn.080483f0()
|      |    0x08048756    8944243c     mov [esp+0x3c], eax ;  and save the result in esp+0x3c
|      |    0x0804875a    837c243c15   cmp dword [esp+0x3c], 0x15
|     ,===< 0x0804875f    7426         je fcn.08048787
|     ||    0x08048761    c74424080b0. mov dword [esp+0x8], 0xb ;  0x0000000b 
|     ||    0x08048769    c7442404f08. mov dword [esp+0x4], str.Next_time__n ; str.Next_time__n
|     ||    0x08048771    c7042401000. mov dword [esp], 0x1 ;  0x00000001 
|     ||    0x08048778    e893fcffff   call sym.imp.write
|     ||       sym.imp.write()
|     ||    0x0804877d    b800000000   mov eax, 0x0

Then the binary retrieves my input, calls a function and compares its result with 0x15 (21). fcn.080483f0 is also called elsewhere in the code and if I check the got entries, it is in fact strlen. Let's rename it:

[0x08048450]> afn?
Usage: afn newname [off]   # set new name to given function
[0x08048450]> afn strlen 0x080483f0
fr fcn.080483f0 strlen@ 0x80483f0

It is much more readable now:

|      |    0x0804874e    890424       mov [esp], eax
|      |    0x08048751    e89afcffff   call strlen
|      |       strlen()
|      |    0x08048756    8944243c     mov [esp+0x3c], eax
|      |    0x0804875a    837c243c15   cmp dword [esp+0x3c], 0x15
|     ,===< 0x0804875f    7426         je fcn.08048787

Therefore the key has to be 21 characters long otherwise I would not take the jump but reach the bad boy instead.

|      |    0x0804875a    837c243c15   cmp dword [esp+0x3c], 0x15 ;  21 chars long.
|     ,===< 0x0804875f    7426         je fcn.08048787
|           ; . . .
|    |`---> 0x08048787    c7442438000. mov dword [esp+0x38], 0x0 ;  init counter i.
|    | |    0x0804878f    c7442434000. mov dword [esp+0x34], 0x0 ;  init counter j.
|   ,=====< 0x08048797    eb6d         jmp 0x8048806 ; (main)
|           ; . . .
|   `-----> 0x08048806    8b442438     mov eax, [esp+0x38] ;  retrieve counter i.
|    | |    0x0804880a    3b44243c     cmp eax, [esp+0x3c] ;  compare it to 21.
| ========< 0x0804880e    7c89         jl fcn.08048799

Then it enters into a loop which stops when 21 is reached. It it most likely going to check my key, character by character.

Crypto 101

I should analyze what this loop does.

| `-------> 0x080487c2    8b542438     mov edx, [esp+0x38] ;  counter i.
|   || |    0x080487c6    8b44242c     mov eax, [esp+0x2c] ;  the mysterious function address, remember?
|   || |    0x080487ca    01d0         add eax, edx
|   || |    0x080487cc    0fb610       movzx edx, byte [eax] ;  edx=function[i] - process next char (wut?)
|   || |    0x080487cf    8b450c       mov eax, [ebp+0xc]
|   || |    0x080487d2    83c004       add eax, 0x4
|   || |    0x080487d5    8b08         mov ecx, [eax]
|   || |    0x080487d7    8b442434     mov eax, [esp+0x34] ;  counter j.
|   || |    0x080487db    01c8         add eax, ecx
|   || |    0x080487dd    0fb608       movzx ecx, byte [eax] ;  ecx=input[j] - same with the user input.
|   || |    0x080487e0    8b442434     mov eax, [esp+0x34] ; counter j again.
|   || |    0x080487e4    05909b0408   add eax, 0x8049b90 ;  the encrypted flag.
|   || |    0x080487e9    0fb600       movzx eax, byte [eax] ; eax=flag[j] - next char of encrypted flag.
|   || |    0x080487ec    31c8         xor eax, ecx ;  xor user input and encrypted flag.
|   || |    0x080487ee    38c2         cmp dl, al ;  check if equals to byte of function.
| ========< 0x080487f0    740a         je 0x80487fc

The first thing that is weird is the line 4. Why? Because the $edx register contains the dereferenced value of $eax which is somewhere in the 0x8048550 code (line 2).

So this loop iterates over each character of my input the and encrypted flag, xor them and checks if the result gives the byte from the mysterious function (line 12).

Since A xor B = C <=> A xor C = B I can retrieve the valid key. Let's ask radare2 to print A (the mysterious function byte codes) and C (the encrypted flag).

First the encrypted flag.

[0x0804a450]> p8 0x15@0x8049b90
34d6a8e28877aa049e983382da548f1b455b37bb1d
[0x0804a450]> pcp 0x15@0x8049b90
import struct
buf = struct.pack ("21B", 
0x34,0xd6,0xa8,0xe2,0x88,0x77,0xaa,0x04,0x9e,0x98,0x33,
0x82,0xda,0x54,0x8f,0x1b,0x45,0x5b,0x37,0xbb,0x1d)

Then the function. I should be careful because of the line 6 not all bytes are used. Therefore I only keep the non-0x00 ones.

[0x0804a450]> pcp 0x20@0x8048550
import struct
buf = struct.pack ("32B", 
0x55,0x89,0xe5,0x83,0xzz,0xzz,0xzz,0xzz,0xf0,0x00,0x00,
0x00,0x00,0xc7,0x45,0xf4,0x00,0x00,0x00,0x00,0xeb,0x20,
0xc7,0x44,0x24,0x04,0x01,0x00,0x00,0x00,0xzz,0xzz)

(I redacted some bytes in order to avoid a complete spoil).

With radare2, I can even operate some xor operations from the prompt!

First I need to configure radare2 so it can have a write access to the binary.

[0x08048450]> e?
|Usage: e[?] [var[=value]]Evaluable vars
 ...
| e??             list config vars with description
 ...
[0x08048450]> e??
        ...
        io.cache: Enable cache for io changes
        ...
[0x08048450]> e io.cache = 1

The io.cache will not permanently save the modification.

[0x08048450]> wo?
|Usage: wo[asmdxoArl24] [hexpairs] @ addr[:bsize]
|Example:
|  wox 0x90   ; xor cur block with 0x90
|  wox 90     ; xor cur block with 0x90
|  wox 0x0203 ; xor cur block with 0203
|  woa 02 03  ; add [0203][0203][...] to curblk
|  woe 02 03  
|Supported operations:
 ...
|  wox  ^=  xor
 ...
[0x08048450]> wox 0x34d6a8e2 @ 0x8048550
[0x08048450]> pxw 4 @0x8048550
0x08048550  0x614d5f61                                a_Ma

That really looks like the beginning of a flag. Let's put that in a script.

import struct


encrypted = struct.pack ("21B",
    0x34,0xd6,0xa8,0xe2,0x88,0x77,0xaa,0x04,0x9e,0x98,0x33,
    0x82,0xda,0x54,0x8f,0x1b,0x45,0x5b,0x37,0xbb,0x1d)
key = struct.pack ("21B",
    0x55,0x89,0xe5,0x83,0xzz,0xzz,0xzz,0xzz,0xf0,0xc7,0x45,
    0xf4,0xeb,0x20,0xc7,0x44,0x24,0x04,0x01,0xzz,0xzz)


print(''.join([chr(a ^ c) for a, c in zip(encrypted, key)]))

Hence the flag: a_Ma????n_vv1tH_a_6??

Conclusion

That was the first time I used radare2 to do some reverse. My first impression? It is really awesome.

Usually I take my gdb to do re stuff but radare2 is way (way) more user friendly (when run without using any custom configuration file because gdb with peda is handy as hell too).

I was also able to quickly find out how to rename a function and it gave me less headache than with gdb.

But radare2 offers even more with functions like pcp which are really awesome! Finding the pcp function in a couple of second after running radare2 was a really nice surprise and I can't wait to see what it can offer more!

Plus, you can operate basic operations from within radare2 using wo! It is really helpful if you want to be sure before coding your script :)

Long story short? I can't wait to use radare2 again!


contactdepier.re License WTFPL2