攻防世界 RE simple-unpack

攻防世界官网:https://adworld.xctf.org.cn/

源程序下载: http://file.eonew.cn/ctf/re/simple2

一道简单的逆向题,虽然不知道什么壳,但是手脱后分析还是很简单的。

观察

拖进IDA分析,并不知道是什么壳,所以直接用gdb,把相对应的内存dump下来。

ex@Ex:~/Downloads$ gdb ./simple2 
pwndbg: loaded 175 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./simple2...(no debugging symbols found)...done.
pwndbg> r
Starting program: /home/ex/Downloads/simple2 
^C
Program received signal SIGINT, Interrupt.
0x000000000043f590 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
 RAX  0xfffffffffffffe00
 RBX  0x6ca540 ◂— 0xfbad2288
 RCX  0x43f590 ◂— cmp    rax, -0xfff
 RDX  0x400
 RDI  0x0
 RSI  0x6cf880 ◂— 0x0
 R8   0x6cc5e0 ◂— 0x0
 R9   0x6ce880 ◂— 0x6ce880
 R10  0x4a12c4 ◂— and    eax, 0x733639 /* '%96s' */
 R11  0x246
 R12  0x0
 R13  0xffffffffffffffd0
 R14  0x6cb9e0 —▸ 0x4a6e20 —▸ 0x4b554d ◂— add    byte ptr [r15 + 0x4d], al /* 'C' */
 R15  0x6ca540 ◂— 0xfbad2288
 RBP  0x6ca320 ◂— 0xfbad2084
 RSP  0x7fffffffc298 —▸ 0x411f98 ◂— cmp    rax, 0
 RIP  0x43f590 ◂— cmp    rax, -0xfff
───────────────────────────────────[ DISASM ]───────────────────────────────────
  0x43f590    cmp    rax, -0xfff
   0x43f596    jae    0x444560
    
   0x444560    neg    rax
   0x444563    mov    dword ptr fs:[0xffffffffffffffd0], eax
   0x44456b    or     rax, 0xffffffffffffffff
   0x44456f    ret    

   0x444570    push   rbp
   0x444571    mov    rbp, rsp
   0x444574    push   r15
   0x444576    push   r14
   0x444578    push   r13
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp  0x7fffffffc298 —▸ 0x411f98 ◂— cmp    rax, 0
01:0008│      0x7fffffffc2a0 ◂— 0x84f4dc
02:0010│      0x7fffffffc2a8 —▸ 0x6ca540 ◂— 0xfbad2288
03:0018│      0x7fffffffc2b0 —▸ 0x7fffffffc990 —▸ 0x7fffffffcaf0 —▸ 0x6ca018 —▸ 0x43b130 ◂— ...
04:0020│      0x7fffffffc2b8 —▸ 0x4152ae ◂— cmp    eax, -1
05:0028│      0x7fffffffc2c0 ◂— 0x0
06:0030│      0x7fffffffc2c8 —▸ 0x4629f0 ◂— cmp    eax, -1
07:0038│      0x7fffffffc2d0 ◂— 0xeb8
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
  f 0           43f590
   f 1           411f98
   f 2           84f4dc
   f 3           6ca540
   f 4     7fffffffc990
   f 5           4152ae
   f 6                0
Program received signal SIGINT
pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
          0x400000           0x4ca000 r-xp    ca000 0      
          0x4ca000           0x6c9000 ---p   1ff000 0      
          0x6c9000           0x6f1000 rwxp    28000 0      [heap]
          0x800000           0x801000 rwxp     1000 0      
    0x7ffff7ffa000     0x7ffff7ffd000 r--p     3000 0      [vvar]
    0x7ffff7ffd000     0x7ffff7fff000 r-xp     2000 0      [vdso]
    0x7ffffffdd000     0x7ffffffff000 rwxp    22000 0      [stack]
0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]
pwndbg> dump memory bin 0x400000 0x6c9000

分析

将dump下来的文件拖进IDA进行分析。

LOAD:00000000004009AE ; int __cdecl main(int argc, const char **argv, const char **envp)
LOAD:00000000004009AE main            proc near               ; DATA XREF: start+1D↑o
LOAD:00000000004009AE
LOAD:00000000004009AE var_70          = byte ptr -70h
LOAD:00000000004009AE var_8           = qword ptr -8
LOAD:00000000004009AE
LOAD:00000000004009AE                 push    rbp
LOAD:00000000004009AF                 mov     rbp, rsp
LOAD:00000000004009B2                 sub     rsp, 112
LOAD:00000000004009B6                 mov     rax, fs:28h
LOAD:00000000004009BF                 mov     [rbp+var_8], rax
LOAD:00000000004009C3                 xor     eax, eax
LOAD:00000000004009C5                 lea     rax, [rbp+var_70]
LOAD:00000000004009C9                 mov     rsi, rax
LOAD:00000000004009CC                 mov     edi, offset a96s ; "%96s"
LOAD:00000000004009D1                 mov     eax, 0
LOAD:00000000004009D6                 call    scanf
LOAD:00000000004009DB                 lea     rax, [rbp+var_70]
LOAD:00000000004009DF                 mov     esi, offset unk_6CA0A0
LOAD:00000000004009E4                 mov     rdi, rax
LOAD:00000000004009E7                 call    strcpy
LOAD:00000000004009EC                 test    eax, eax
LOAD:00000000004009EE                 jnz     short loc_4009FC
LOAD:00000000004009F0                 mov     edi, offset aCongratulation ; "Congratulations!"
LOAD:00000000004009F5                 call    printf
LOAD:00000000004009FA                 jmp     short loc_400A06
LOAD:00000000004009FC ; ---------------------------------------------------------------------------
LOAD:00000000004009FC
LOAD:00000000004009FC loc_4009FC:                             ; CODE XREF: main+40↑j
LOAD:00000000004009FC                 mov     edi, offset aTryAgain ; "Try again!"
LOAD:0000000000400A01                 call    printf
LOAD:0000000000400A06
LOAD:0000000000400A06 loc_400A06:                             ; CODE XREF: main+4C↑j
LOAD:0000000000400A06                 mov     eax, 0
LOAD:0000000000400A0B                 mov     rdx, [rbp+var_8]
LOAD:0000000000400A0F                 xor     rdx, fs:28h
LOAD:0000000000400A18                 jz      short locret_400A1F
LOAD:0000000000400A1A                 call    sub_442EC0
LOAD:0000000000400A1F ; ---------------------------------------------------------------------------
LOAD:0000000000400A1F
LOAD:0000000000400A1F locret_400A1F:                          ; CODE XREF: main+6A↑j
LOAD:0000000000400A1F                 leave
LOAD:0000000000400A20                 retn
LOAD:0000000000400A20 main            endp

调试

发现main函数就是字符串比较,所以在0x4009E7下断点。

ex@Ex:~/Downloads$ gdb ./simple2 
pwndbg: loaded 175 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Reading symbols from ./simple2...(no debugging symbols found)...done.
pwndbg> r
Starting program: /home/ex/Downloads/simple2 
^C
Program received signal SIGINT, Interrupt.
0x000000000043f590 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
 RAX  0xfffffffffffffe00
 RBX  0x6ca540 ◂— 0xfbad2288
 RCX  0x43f590 ◂— cmp    rax, -0xfff
 RDX  0x400
 RDI  0x0
 RSI  0x6cf880 ◂— 0x0
 R8   0x6cc5e0 ◂— 0x0
 R9   0x6ce880 ◂— 0x6ce880
 R10  0x4a12c4 ◂— and    eax, 0x733639 /* '%96s' */
 R11  0x246
 R12  0x0
 R13  0xffffffffffffffd0
 R14  0x6cb9e0 —▸ 0x4a6e20 —▸ 0x4b554d ◂— add    byte ptr [r15 + 0x4d], al /* 'C' */
 R15  0x6ca540 ◂— 0xfbad2288
 RBP  0x6ca320 ◂— 0xfbad2084
 RSP  0x7fffffffc298 —▸ 0x411f98 ◂— cmp    rax, 0
 RIP  0x43f590 ◂— cmp    rax, -0xfff
───────────────────────────────────[ DISASM ]───────────────────────────────────
  0x43f590    cmp    rax, -0xfff
   0x43f596    jae    0x444560
    
   0x444560    neg    rax
   0x444563    mov    dword ptr fs:[0xffffffffffffffd0], eax
   0x44456b    or     rax, 0xffffffffffffffff
   0x44456f    ret    

   0x444570    push   rbp
   0x444571    mov    rbp, rsp
   0x444574    push   r15
   0x444576    push   r14
   0x444578    push   r13
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rsp  0x7fffffffc298 —▸ 0x411f98 ◂— cmp    rax, 0
01:0008│      0x7fffffffc2a0 ◂— 0x84f4dc
02:0010│      0x7fffffffc2a8 —▸ 0x6ca540 ◂— 0xfbad2288
03:0018│      0x7fffffffc2b0 —▸ 0x7fffffffc990 —▸ 0x7fffffffcaf0 —▸ 0x6ca018 —▸ 0x43b130 ◂— ...
04:0020│      0x7fffffffc2b8 —▸ 0x4152ae ◂— cmp    eax, -1
05:0028│      0x7fffffffc2c0 ◂— 0x0
06:0030│      0x7fffffffc2c8 —▸ 0x4629f0 ◂— cmp    eax, -1
07:0038│      0x7fffffffc2d0 ◂— 0xeb8
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
  f 0           43f590
   f 1           411f98
   f 2           84f4dc
   f 3           6ca540
   f 4     7fffffffc990
   f 5           4152ae
   f 6                0
Program received signal SIGINT
pwndbg> b *0x04009E7
Breakpoint 1 at 0x4009e7
pwndbg> c
Continuing.
12

Breakpoint 1, 0x00000000004009e7 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
 RAX  0x7fffffffca80 ◂— 0x3231 /* '12' */
 RBX  0x4002c8 ◂— sub    rsp, 8
 RCX  0xa
 RDX  0x6cc5f0 ◂— 0x0
 RDI  0x7fffffffca80 ◂— 0x3231 /* '12' */
 RSI  0x6ca0a0 ◂— 'flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}'
 R8   0x0
 R9   0x6ce880 ◂— 0x6ce880
 R10  0x4a12c4 ◂— and    eax, 0x733639 /* '%96s' */
 R11  0x246
 R12  0x401590 ◂— push   r14
 R13  0x401620 ◂— push   rbx
 R14  0x0
 R15  0x7fffffffcfb8 —▸ 0x40000c ◂— syscall 
 RBP  0x7fffffffcaf0 —▸ 0x6ca018 —▸ 0x43b130 ◂— mov    rcx, rsi
 RSP  0x7fffffffca80 ◂— 0x3231 /* '12' */
 RIP  0x4009e7 ◂— call   0x400360
───────────────────────────────────[ DISASM ]───────────────────────────────────
  0x4009e7    call   0x400360

   0x4009ec    test   eax, eax
   0x4009ee    jne    0x4009fc

   0x4009f0    mov    edi, 0x4a12c9
   0x4009f5    call   0x40fcc0

   0x4009fa    jmp    0x400a06

   0x4009fc    mov    edi, 0x4a12da
   0x400a01    call   0x40fcc0

   0x400a06    mov    eax, 0
   0x400a0b    mov    rdx, qword ptr [rbp - 8]
   0x400a0f    xor    rdx, qword ptr fs:[0x28]
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ rax rdi rsp  0x7fffffffca80 ◂— 0x3231 /* '12' */
01:0008│              0x7fffffffca88 ◂— 0x8000
02:0010│              0x7fffffffca90 —▸ 0x7fffffffcc48 —▸ 0x7fffffffcfc0 ◂— '   =/home/ex/Downloads/simple2'
03:0018│              0x7fffffffca98 ◂— 0x2
04:0020│              0x7fffffffcaa0 —▸ 0x7fffffffcfb8 —▸ 0x40000c ◂— syscall 
05:0028│              0x7fffffffcaa8 —▸ 0x400630 ◂— test   rax, rax
06:0030│              0x7fffffffcab0 ◂— 0x1
... 
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
  f 0           4009e7
   f 1             3231
   f 2             8000
   f 3     7fffffffcc48
   f 4                2
   f 5     7fffffffcfb8
   f 6           400630
   f 7                1
   f 8                1
   f 9     7fffffffcc38
   f 10           401607
Breakpoint *0x04009E7

由上面的调试代码看出,flag就在rsi指向的内存中,也就是flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}

总结

虽然Linux上的脱壳题目做的少,但是原理和Windows的差不多。