Skip to content

cherepanov74/r2con-2019

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 

Repository files navigation

vermu 1

We got two binary files: vermu and level1

Vermu is 64 bit macho executable, level is binary file.

The macho binary expects level file as argument. Task name suggest that it might be Virtual Machine (VM) crackme.

It looks like the level file contains virtual machine bytecode and the vermu is execting it.

After quick analysis we got confirmation - the 100002870 function looks like a typical VM loop.

[0x100002870]> pd 55
            ;-- func.100002870:
/ (fcn) vm_loop 260
|   vm_loop (int32_t arg1);
|           ; var int32_t op_byte @ rbp-0x19
|           ; var int32_t handler_pointer @ rbp-0x18
|           ; var int32_t vm_bytecode @ rbp-0x10
|           ; var int32_t var_4h @ rbp-0x4
|           ; arg int32_t arg1 @ rdi
|           ; CALL XREF from entry0 @ 0x100002ec2
|           0x100002870      55             push rbp
|           0x100002871      4889e5         mov rbp, rsp
|           0x100002874      4883ec20       sub rsp, 0x20
|           0x100002878      48897df0       mov qword [vm_bytecode], rdi ; arg1
|           0x10000287c      48c745e80000.  mov qword [handler_pointer], 0
|           0x100002884      c645e700       mov byte [op_byte], 0
|           0x100002888      48837df000     cmp qword [vm_bytecode], 0
|       ,=< 0x10000288d      0f850c000000   jne 0x10000289f
|       |   0x100002893      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
|      ,==< 0x10000289a      e9cc000000     jmp 0x10000296b
|      ||   ; CODE XREF from vm_loop @ 0x10000288d
|     ,=`-> 0x10000289f      e900000000     jmp 0x1000028a4
|     ||    ; CODE XREFS from vm_loop @ 0x10000289f, 0x10000295f
|     `-.-> 0x1000028a4      488b45f0       mov rax, qword [vm_bytecode]
|      |:   0x1000028a8      8a8808000800   mov cl, byte [rax + 0x80008]
|      |:   0x1000028ae      80f1ff         xor cl, 0xff               ; 255
|      |:   0x1000028b1      f6c101         test cl, 1                 ; 1
|     ,===< 0x1000028b4      0f8505000000   jne 0x1000028bf
|    ,====< 0x1000028ba      e9a5000000     jmp 0x100002964
|    |||:   ; CODE XREF from vm_loop @ 0x1000028b4
|    |`---> 0x1000028bf      488b45f0       mov rax, qword [vm_bytecode]
|    | |:   0x1000028c3      81b800000800.  cmp dword [rax + 0x80000], 0x80000
|    |,===< 0x1000028cd      0f820c000000   jb 0x1000028df
|    |||:   0x1000028d3      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
|   ,=====< 0x1000028da      e98c000000     jmp 0x10000296b
|   ||||:   ; CODE XREF from vm_loop @ 0x1000028cd
|   ||`---> 0x1000028df      488b45f0       mov rax, qword [vm_bytecode]
|   || |:   0x1000028e3      488b4df0       mov rcx, qword [vm_bytecode]
|   || |:   0x1000028e7      8b9100000800   mov edx, dword [rcx + 0x80000]
|   || |:   0x1000028ed      89d1           mov ecx, edx
|   || |:   0x1000028ef      408a3408       mov sil, byte [rax + rcx]
|   || |:   0x1000028f3      408875e7       mov byte [op_byte], sil
|   || |:   0x1000028f7      0fb655e7       movzx edx, byte [op_byte]
|   || |:   0x1000028fb      81faff000000   cmp edx, 0xff              ; 255
|   ||,===< 0x100002901      0f8c0c000000   jl 0x100002913
|   ||||:   0x100002907      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
|  ,======< 0x10000290e      e958000000     jmp 0x10000296b
|  |||||:   ; CODE XREF from vm_loop @ 0x100002901
|  |||`---> 0x100002913      488b45f0       mov rax, qword [vm_bytecode]
|  ||| |:   0x100002917      0fb64de7       movzx ecx, byte [op_byte]
|  ||| |:   0x10000291b      89ca           mov edx, ecx
|  ||| |:   0x10000291d      488b84d01000.  mov rax, qword [rax + rdx*8 + 0x80010]
|  ||| |:   0x100002925      488945e8       mov qword [handler_pointer], rax
|  ||| |:   0x100002929      48837de800     cmp qword [handler_pointer], 0
|  |||,===< 0x10000292e      0f850c000000   jne 0x100002940
|  |||||:   0x100002934      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
| ,=======< 0x10000293b      e92b000000     jmp 0x10000296b
| ||||||:   ; CODE XREF from vm_loop @ 0x10000292e
| ||||`---> 0x100002940      488b45e8       mov rax, qword [handler_pointer]
| |||| |:   0x100002944      488b7df0       mov rdi, qword [vm_bytecode]
| |||| |:   0x100002948      ffd0           call rax
| |||| |:   0x10000294a      83f800         cmp eax, 0
| ||||,===< 0x10000294d      0f840c000000   je 0x10000295f
| ||||||:   0x100002953      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
| ========< 0x10000295a      e90c000000     jmp 0x10000296b
| |||||||   ; CODE XREF from vm_loop @ 0x10000294d
| ||||`-`=< 0x10000295f      e940ffffff     jmp 0x1000028a4
| |||| |    ; CODE XREF from vm_loop @ 0x1000028ba
| |||`----> 0x100002964      c745fc000000.  mov dword [var_4h], 0
| |||  |    ; CODE XREFS from vm_loop @ 0x10000289a, 0x1000028da, 0x10000290e, 0x10000293b, 0x10000295a
| ```--`--> 0x10000296b      8b45fc         mov eax, dword [var_4h]
|           0x10000296e      4883c420       add rsp, 0x20
|           0x100002972      5d             pop rbp
\           0x100002973      c3             ret

This function fetches bytecode instructions and then calls specific handler for fetched VM opcode in a loop.

Let's check where 0x80010 is also used.

> pdf @@ func ~ 0x80010
|  ||| |:   0x10000291d      488b84d01000.  mov rax, qword [rax + rdx*8 + 0x80010]
|      |    0x100002b3a      488988100008.  mov qword [rax + 0x80010], rcx
|     ||    0x100002d53      4881c7100008.  add rdi, 0x80010
> pd 50 @ 0x100002b3a
|           0x100002b3a      488988100008.  mov qword [rax + 0x80010], rcx
|           0x100002b41      488b45f0       mov rax, qword [var_10h]
|           0x100002b45      488d0d74eeff.  lea rcx, [sym.func.1000019c0] ; 0x1000019c0
|           0x100002b4c      488988900008.  mov qword [rax + 0x80090], rcx
|           0x100002b53      488b45f0       mov rax, qword [var_10h]
|           0x100002b57      488d0d02efff.  lea rcx, [sym.func.100001a60] ; 0x100001a60
|           0x100002b5e      488988980008.  mov qword [rax + 0x80098], rcx
|           0x100002b65      488b45f0       mov rax, qword [var_10h]
|           0x100002b69      488d0d60efff.  lea rcx, [sym.func.100001ad0] ; 0x100001ad0
|           0x100002b70      488988100108.  mov qword [rax + 0x80110], rcx
|           0x100002b77      488b45f0       mov rax, qword [var_10h]
|           0x100002b7b      488d0d0ef0ff.  lea rcx, [sym.func.100001b90] ; 0x100001b90
|           0x100002b82      488988180108.  mov qword [rax + 0x80118], rcx
|           0x100002b89      488b45f0       mov rax, qword [var_10h]
|           0x100002b8d      488d0dbcf0ff.  lea rcx, [sym.func.100001c50] ; 0x100001c50
|           0x100002b94      488988900108.  mov qword [rax + 0x80190], rcx
|           0x100002b9b      488b45f0       mov rax, qword [var_10h]
|           0x100002b9f      488d0d6af1ff.  lea rcx, [sym.func.100001d10] ; 0x100001d10
|           0x100002ba6      488988980108.  mov qword [rax + 0x80198], rcx
|           0x100002bad      488b45f0       mov rax, qword [var_10h]
|           0x100002bb1      488d0d18f2ff.  lea rcx, [sym.func.100001dd0] ; 0x100001dd0
|           0x100002bb8      488988a00108.  mov qword [rax + 0x801a0], rcx
|           0x100002bbf      488b45f0       mov rax, qword [var_10h]
|           0x100002bc3      488d0d06f3ff.  lea rcx, [sym.func.100001ed0] ; 0x100001ed0
|           0x100002bca      488988a80108.  mov qword [rax + 0x801a8], rcx
|           0x100002bd1      488b45f0       mov rax, qword [var_10h]
|           0x100002bd5      488d0db4f3ff.  lea rcx, [sym.func.100001f90] ; 0x100001f90
|           0x100002bdc      488988b00108.  mov qword [rax + 0x801b0], rcx
|           0x100002be3      488b45f0       mov rax, qword [var_10h]
|           0x100002be7      488d0d62f4ff.  lea rcx, [sym.func.100002050] ; 0x100002050
|           0x100002bee      488988b80108.  mov qword [rax + 0x801b8], rcx
|           0x100002bf5      488b45f0       mov rax, qword [var_10h]
|           0x100002bf9      488d0d10f5ff.  lea rcx, [sym.func.100002110] ; 0x100002110
|           0x100002c00      488988c00108.  mov qword [rax + 0x801c0], rcx
|           0x100002c07      488b45f0       mov rax, qword [var_10h]
|           0x100002c0b      488d0dbef5ff.  lea rcx, [sym.func.1000021d0] ; 0x1000021d0
|           0x100002c12      488988c80108.  mov qword [rax + 0x801c8], rcx
|           0x100002c19      488b45f0       mov rax, qword [var_10h]
|           0x100002c1d      488d0d6cf6ff.  lea rcx, [sym.func.100002290] ; 0x100002290
|           0x100002c24      488988d00108.  mov qword [rax + 0x801d0], rcx
|           0x100002c2b      488b45f0       mov rax, qword [var_10h]
|           0x100002c2f      488d0dfaf6ff.  lea rcx, [sym.func.100002330] ; 0x100002330
|           0x100002c36      488988100208.  mov qword [rax + 0x80210], rcx
|           0x100002c3d      488b45f0       mov rax, qword [var_10h]
|           0x100002c41      488d0d88f7ff.  lea rcx, [sym.func.1000023d0] ; 0x1000023d0
|           0x100002c48      488988180208.  mov qword [rax + 0x80218], rcx
|           0x100002c4f      488b45f0       mov rax, qword [var_10h]
|           0x100002c53      488d0de6f7ff.  lea rcx, [sym.func.100002440] ; 0x100002440
|           0x100002c5a      488988200208.  mov qword [rax + 0x80220], rcx
|           0x100002c61      488b45f0       mov rax, qword [var_10h]

> s 0x100002b3a; sf.
[0x100002b10]> 

The function 0x100002b10 initializes pointers of the bytecode handlers. From the VM loop we know that the first byte of bytecode is used as index of handlers array.

Thus, we can make a following table:

Opcode Handler address
0x00 0x100001980
0x10 0x1000019C0
0x11 0x100001A60
0x20 0x100001AD0
0x21 0x100001B90
0x30 0x100001C50
0x31 0x100001D10
0x32 0x100001DD0
0x33 0x100001ED0
0x34 0x100001F90
0x35 0x100002050
0x36 0x100002110
0x37 0x1000021D0
0x38 0x100002290
0x40 0x100002330
0x41 0x1000023D0
0x42 0x100002440
0x43 0x1000025C0
0x44 0x100002680
0x45 0x100002500
0x50 0x100002740
0x60 0x100002820

There are only 22 handlers, we can analyze them manually.

Let's check handler for the 0x00 instruction.

> pd 15 @ 0x100001980
/ (fcn) sym.func.100001980 62
|   sym.func.100001980 (uint32_t arg1);
|           ; var uint32_t var_10h @ rbp-0x10
|           ; var int32_t var_4h @ rbp-0x4
|           ; arg uint32_t arg1 @ rdi
|           ; DATA XREF from sym.func.100002b10 @ 0x100002b33
|           0x100001980      55             push rbp
|           0x100001981      4889e5         mov rbp, rsp
|           0x100001984      48897df0       mov qword [var_10h], rdi   ; arg1
|           0x100001988      48837df000     cmp qword [var_10h], 0
|       ,=< 0x10000198d      0f850c000000   jne 0x10000199f
|       |   0x100001993      c745fcffffff.  mov dword [var_4h], 0xffffffff ; -1
|      ,==< 0x10000199a      e91a000000     jmp 0x1000019b9
|      ||   ; CODE XREF from sym.func.100001980 @ 0x10000198d
|      |`-> 0x10000199f      488b45f0       mov rax, qword [var_10h]
|      |    0x1000019a3      8b8800000800   mov ecx, dword [rax + 0x80000]
|      |    0x1000019a9      83c101         add ecx, 1
|      |    0x1000019ac      898800000800   mov dword [rax + 0x80000], ecx
|      |    0x1000019b2      c745fc000000.  mov dword [var_4h], 0
|      |    ; CODE XREF from sym.func.100001980 @ 0x10000199a
|      `--> 0x1000019b9      8b45fc         mov eax, dword [var_4h]
|           0x1000019bc      5d             pop rbp
\           0x1000019bd      c3             ret

As we can see this instruction does not do anything just increases the VM_IP (which stored at ptr + 0x80000). So 0x00 is NOP instruction.

After analyzing some of handlers I come up with this disassemler code in python:

import sys
import struct

def print_opcodes(addr, data, size, mnemonics = None):

    string1 = ''
    
    for i in range(size):
        string1 = string1 + '{0:02X} '.format(data[addr + i])
    
    line = '{0:08X}:  {1:s}'.format(addr, string1)
    
    if mnemonics is None:
        print(line.ljust(50 , ' '))
    else:
        print(line.ljust(50 , ' ') + mnemonics)

    return    
    
def main():
    
    if len(sys.argv) < 2:
        print("Usage: {0:s} file".format(sys.argv[0]))
        return

    f = open(sys.argv[1], "rb")
    data = f.read()
    f.close()
    
    current_ptr = 0
    STACK = 0x0
    while True:
        
        opcode = struct.unpack_from('<B', data, current_ptr)[0]
       
        if opcode == 0x00:
          
            decoded = 'NOP'
            print_opcodes(current_ptr, data, 0x1)
            current_ptr += 0x1
            
        elif opcode == 0x10:
            param1 = struct.unpack_from('>L', data, current_ptr + 1)[0]
            
            STACK = param1
            decoded = 'PUSH STACK 0x{0:04X}'.format(param1)
            print_opcodes(current_ptr, data, 0x5, decoded)
            current_ptr += 0x5

        elif opcode == 0x11:
           
            decoded = 'POP STACK'
            print_opcodes(current_ptr, data, 0x1)
            current_ptr += 0x1

            
        elif opcode == 0x20:
          
            decoded = 'MOV [STACK1], STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1
        elif opcode == 0x21:
          
            decoded = 'PUSH VALUE AT [STACK1]'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1 
            
        elif opcode == 0x30:
          
            decoded = 'STACK1 = STACK1 + STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1
        elif opcode == 0x31:
          
            decoded = 'STACK1 = STACK1 ^ STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1 
            
        elif opcode == 0x32:
          
            decoded = 'STACK1 = STACK1 vs STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1             
        elif opcode == 0x33:
          
            decoded = 'STACK1 = STACK1 * STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1  
        elif opcode == 0x34:
          
            decoded = 'STACK1 = STACK1 & STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1 
        elif opcode == 0x35:
          
            decoded = 'STACK1 = STACK1 | STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1
        elif opcode == 0x36:
          
            decoded = 'STACK1 = STACK1 SHL STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1     
        elif opcode == 0x37:
          
            decoded = 'STACK1 = STACK1 SHR STACK2'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1  
        elif opcode == 0x38:
          
            decoded = 'STACK1 = STACK1 ^ 0xFFFFFFFF'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1

        elif opcode == 0x40:
          
            decoded = 'CALL 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            
            current_ptr += 0x1
                
        elif opcode == 0x41:
          
            decoded = 'JMP 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            
            current_ptr = STACK
            
        elif opcode == 0x42:
          
            decoded = 'CONDITIONAL JMP 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            
            
            if current_ptr == 0x4EC:
                current_ptr = STACK
            else:
                current_ptr += 0x1
            
        elif opcode == 0x43:
          
            decoded = 'UNK1 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1   
        elif opcode == 0x44:
          
            decoded = 'UNK2 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1
        elif opcode == 0x45:
          
            decoded = 'CONDITIONAL JMP 0x{0:04X}'.format(STACK)
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1

        elif opcode == 0x50:
            
            if STACK == 0x01:
               decoded = 'CALL PRINT'
            else:
               decoded = 'CALL INPUT'
               
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1
            
        elif opcode == 0x60:
          
            decoded = 'EXIT'
            print_opcodes(current_ptr, data, 0x1, decoded)
            current_ptr += 0x1            
            
        else:
            print_opcodes(current_ptr, data, 0x1)
            break
        
    
if __name__=='__main__':
    main()

Not all handlers are analyzed properly, but it's good enough to produce readable result.

Here is how disassemled version of level1 VM looks like:

00000000:  10 00 00 10 08                         PUSH STACK 0x1008
00000005:  10 00 00 00 20                         PUSH STACK 0x0020
0000000A:  10 00 00 00 00                         PUSH STACK 0x0000
0000000F:  50                                     CALL INPUT
00000010:  10 00 00 00 56                         PUSH STACK 0x0056
00000015:  41                                     JMP 0x0056
00000056:  10 00 00 00 01                         PUSH STACK 0x0001
0000005B:  10 00 00 10 04                         PUSH STACK 0x1004
00000060:  20                                     MOV [STACK1], STACK2
00000061:  10 00 00 10 08                         PUSH STACK 0x1008
00000066:  10 00 00 10 00                         PUSH STACK 0x1000
0000006B:  21                                     PUSH VALUE AT [STACK1]
0000006C:  10 00 00 00 04                         PUSH STACK 0x0004
00000071:  33                                     STACK1 = STACK1 * STACK2
00000072:  30                                     STACK1 = STACK1 + STACK2
00000073:  21                                     PUSH VALUE AT [STACK1]
00000074:  10 00 00 00 16                         PUSH STACK 0x0016
00000079:  10 00 00 10 00                         PUSH STACK 0x1000
0000007E:  21                                     PUSH VALUE AT [STACK1]
0000007F:  10 00 00 00 04                         PUSH STACK 0x0004
00000084:  33                                     STACK1 = STACK1 * STACK2
00000085:  30                                     STACK1 = STACK1 + STACK2
00000086:  21                                     PUSH VALUE AT [STACK1]
00000087:  38                                     STACK1 = STACK1 ^ 0xFFFFFFFF
00000088:  31                                     STACK1 = STACK1 ^ STACK2
00000089:  10 00 00 00 36                         PUSH STACK 0x0036
0000008E:  10 00 00 10 00                         PUSH STACK 0x1000
00000093:  21                                     PUSH VALUE AT [STACK1]
00000094:  10 00 00 00 04                         PUSH STACK 0x0004
00000099:  33                                     STACK1 = STACK1 * STACK2
0000009A:  30                                     STACK1 = STACK1 + STACK2
0000009B:  21                                     PUSH VALUE AT [STACK1]
0000009C:  32                                     STACK1 = STACK1 vs STACK2
0000009D:  10 00 00 00 B4                         PUSH STACK 0x00B4
000000A2:  42                                     CONDITIONAL JMP 0x00B4
000000A3:  10 00 00 00 00                         PUSH STACK 0x0000
000000A8:  10 00 00 10 04                         PUSH STACK 0x1004
000000AD:  20                                     MOV [STACK1], STACK2
000000AE:  10 00 00 00 C6                         PUSH STACK 0x00C6
000000B3:  41                                     JMP 0x00C6
000000C6:  10 00 00 10 00                         PUSH STACK 0x1000
000000CB:  21                                     PUSH VALUE AT [STACK1]
000000CC:  10 00 00 00 01                         PUSH STACK 0x0001
000000D1:  30                                     STACK1 = STACK1 + STACK2
000000D2:  10 00 00 10 00                         PUSH STACK 0x1000
000000D7:  20                                     MOV [STACK1], STACK2
000000D8:  10 00 00 00 08                         PUSH STACK 0x0008
000000DD:  10 00 00 10 00                         PUSH STACK 0x1000
000000E2:  21                                     PUSH VALUE AT [STACK1]
000000E3:  32                                     STACK1 = STACK1 vs STACK2
000000E4:  10 00 00 00 61                         PUSH STACK 0x0061
000000E9:  45                                     CONDITIONAL JMP 0x0061
000000EA:  10 00 00 10 04                         PUSH STACK 0x1004
000000EF:  21                                     PUSH VALUE AT [STACK1]
000000F0:  10 00 00 00 01                         PUSH STACK 0x0001
000000F5:  32                                     STACK1 = STACK1 vs STACK2
000000F6:  10 00 00 01 0D                         PUSH STACK 0x010D
000000FB:  42                                     CONDITIONAL JMP 0x010D
000000FC:  10 00 00 01 24                         PUSH STACK 0x0124
00000101:  10 00 00 00 08                         PUSH STACK 0x0008
00000106:  10 00 00 00 01                         PUSH STACK 0x0001
0000010B:  50                                     CALL PRINT
0000010C:  60                                     EXIT
0000010D:  10 00 00 01 1E                         PUSH STACK 0x011E
00000112:  10 00 00 00 06                         PUSH STACK 0x0006
00000117:  10 00 00 00 01                         PUSH STACK 0x0001
0000011C:  50                                     CALL PRINT
0000011D:  60                                     EXIT

The most important instructions are:

00000074:  10 00 00 00 16                         PUSH STACK 0x0016
...
00000087:  38                                     STACK1 = STACK1 ^ 0xFFFFFFFF
00000088:  31                                     STACK1 = STACK1 ^ STACK2
...
00000089:  10 00 00 00 36                         PUSH STACK 0x0036
...

0x0016 and 0x0036 are not constants, but offsets.

So VM takes user's input, and compares it with value, which is decrypted using XOR. To decrypt the value we just need to XOR bytes at 0x0016 and 0x0036 to each other, then XOR with 0xFF.

I printed offsets:

[0x00000000]> px32 @ 0x16
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00000016  bce6 b80a baad 1bab c5dd 1214 b2c1 1b74  ...............t
0x00000026  7fc5 2197 6555 1298 9315 df80 1529 7c7d  ..!.eU.......)|}
[0x00000000]> px32 @ 0x36
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x00000036  312b 249a 2b29 d567 0d7d 80d8 124e 91be  1+$.+).g.}...N..
0x00000046  e865 a758 efd8 b252 18de 4314 cbed aaff  .e.X...R..C.....

Then used the CyberChief

The flag is: r2con{137_m3_pu5h_y0ur_5t4ck!;)}

vermu 2

This is exactly similar task. The binary is not modified at all, which means we can use our python VM disassemler.

00000000:  10 00 00 01 05                         PUSH STACK 0x0105
00000005:  41                                     JMP 0x0105
00000105:  10 00 00 08 AF                         PUSH STACK 0x08AF
0000010A:  10 00 00 00 14                         PUSH STACK 0x0014
0000010F:  10 00 00 00 01                         PUSH STACK 0x0001
00000114:  50                                     CALL PRINT
00000115:  10 00 00 02 1A                         PUSH STACK 0x021A
0000011A:  41                                     JMP 0x021A
0000021A:  10 00 00 10 0C                         PUSH STACK 0x100C
0000021F:  10 00 00 00 20                         PUSH STACK 0x0020
00000224:  10 00 00 00 00                         PUSH STACK 0x0000
00000229:  50                                     CALL INPUT
0000022A:  10 00 00 03 2F                         PUSH STACK 0x032F
0000022F:  41                                     JMP 0x032F
0000032F:  10 00 00 00 01                         PUSH STACK 0x0001
00000334:  10 00 00 10 08                         PUSH STACK 0x1008
00000339:  20                                     MOV [STACK1], STACK2
0000033A:  10 00 00 04 44                         PUSH STACK 0x0444
0000033F:  41                                     JMP 0x0444
00000444:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000449:  10 00 00 10 00                         PUSH STACK 0x1000
0000044E:  21                                     PUSH VALUE AT [STACK1]
0000044F:  10 00 00 00 04                         PUSH STACK 0x0004
00000454:  33                                     STACK1 = STACK1 * STACK2
00000455:  30                                     STACK1 = STACK1 + STACK2
00000456:  21                                     PUSH VALUE AT [STACK1]
00000457:  10 00 00 08 D1                         PUSH STACK 0x08D1
0000045C:  21                                     PUSH VALUE AT [STACK1]
0000045D:  31                                     STACK1 = STACK1 ^ STACK2
0000045E:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000463:  10 00 00 10 00                         PUSH STACK 0x1000
00000468:  21                                     PUSH VALUE AT [STACK1]
00000469:  10 00 00 00 04                         PUSH STACK 0x0004
0000046E:  33                                     STACK1 = STACK1 * STACK2
0000046F:  30                                     STACK1 = STACK1 + STACK2
00000470:  20                                     MOV [STACK1], STACK2
00000471:  10 00 00 10 00                         PUSH STACK 0x1000
00000476:  21                                     PUSH VALUE AT [STACK1]
00000477:  10 00 00 00 01                         PUSH STACK 0x0001
0000047C:  30                                     STACK1 = STACK1 + STACK2
0000047D:  10 00 00 10 00                         PUSH STACK 0x1000
00000482:  20                                     MOV [STACK1], STACK2
00000483:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000488:  10 00 00 10 00                         PUSH STACK 0x1000
0000048D:  21                                     PUSH VALUE AT [STACK1]
0000048E:  10 00 00 00 04                         PUSH STACK 0x0004
00000493:  33                                     STACK1 = STACK1 * STACK2
00000494:  30                                     STACK1 = STACK1 + STACK2
00000495:  10 00 00 05 3E                         PUSH STACK 0x053E
0000049A:  32                                     STACK1 = STACK1 vs STACK2
0000049B:  10 00 00 04 44                         PUSH STACK 0x0444
000004A0:  44                                     UNK2 0x0444
000004A1:  10 00 00 04 AC                         PUSH STACK 0x04AC
000004A6:  41                                     JMP 0x04AC

In this VM XOR loop is used between bytes at two offset: 0x08D1 and 0x04AC However this time the VM decrypts code, not the flag.

I performed this XOR operation manually, after that I got the following code of full VM:

00000000:  10 00 00 01 05                         PUSH STACK 0x0105
00000005:  41                                     JMP 0x0105
00000105:  10 00 00 08 AF                         PUSH STACK 0x08AF
0000010A:  10 00 00 00 14                         PUSH STACK 0x0014
0000010F:  10 00 00 00 01                         PUSH STACK 0x0001
00000114:  50                                     CALL PRINT
00000115:  10 00 00 02 1A                         PUSH STACK 0x021A
0000011A:  41                                     JMP 0x021A
0000021A:  10 00 00 10 0C                         PUSH STACK 0x100C
0000021F:  10 00 00 00 20                         PUSH STACK 0x0020
00000224:  10 00 00 00 00                         PUSH STACK 0x0000
00000229:  50                                     CALL INPUT
0000022A:  10 00 00 03 2F                         PUSH STACK 0x032F
0000022F:  41                                     JMP 0x032F
0000032F:  10 00 00 00 01                         PUSH STACK 0x0001
00000334:  10 00 00 10 08                         PUSH STACK 0x1008
00000339:  20                                     MOV [STACK1], STACK2
0000033A:  10 00 00 04 44                         PUSH STACK 0x0444
0000033F:  41                                     JMP 0x0444
00000444:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000449:  10 00 00 10 00                         PUSH STACK 0x1000
0000044E:  21                                     PUSH VALUE AT [STACK1]
0000044F:  10 00 00 00 04                         PUSH STACK 0x0004
00000454:  33                                     STACK1 = STACK1 * STACK2
00000455:  30                                     STACK1 = STACK1 + STACK2
00000456:  21                                     PUSH VALUE AT [STACK1]
00000457:  10 00 00 08 D1                         PUSH STACK 0x08D1
0000045C:  21                                     PUSH VALUE AT [STACK1]
0000045D:  31                                     STACK1 = STACK1 ^ STACK2
0000045E:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000463:  10 00 00 10 00                         PUSH STACK 0x1000
00000468:  21                                     PUSH VALUE AT [STACK1]
00000469:  10 00 00 00 04                         PUSH STACK 0x0004
0000046E:  33                                     STACK1 = STACK1 * STACK2
0000046F:  30                                     STACK1 = STACK1 + STACK2
00000470:  20                                     MOV [STACK1], STACK2
00000471:  10 00 00 10 00                         PUSH STACK 0x1000
00000476:  21                                     PUSH VALUE AT [STACK1]
00000477:  10 00 00 00 01                         PUSH STACK 0x0001
0000047C:  30                                     STACK1 = STACK1 + STACK2
0000047D:  10 00 00 10 00                         PUSH STACK 0x1000
00000482:  20                                     MOV [STACK1], STACK2
00000483:  10 00 00 04 AC                         PUSH STACK 0x04AC
00000488:  10 00 00 10 00                         PUSH STACK 0x1000
0000048D:  21                                     PUSH VALUE AT [STACK1]
0000048E:  10 00 00 00 04                         PUSH STACK 0x0004
00000493:  33                                     STACK1 = STACK1 * STACK2
00000494:  30                                     STACK1 = STACK1 + STACK2
00000495:  10 00 00 05 3E                         PUSH STACK 0x053E
0000049A:  32                                     STACK1 = STACK1 vs STACK2
0000049B:  10 00 00 04 44                         PUSH STACK 0x0444
000004A0:  44                                     UNK2 0x0444
000004A1:  10 00 00 04 AC                         PUSH STACK 0x04AC
000004A6:  41                                     JMP 0x04AC
000004AC:  10 00 00 10 0C                         PUSH STACK 0x100C
000004B1:  10 00 00 10 04                         PUSH STACK 0x1004
000004B6:  21                                     PUSH VALUE AT [STACK1]
000004B7:  10 00 00 00 04                         PUSH STACK 0x0004
000004BC:  33                                     STACK1 = STACK1 * STACK2
000004BD:  30                                     STACK1 = STACK1 + STACK2
000004BE:  21                                     PUSH VALUE AT [STACK1]
000004BF:  10 00 00 04 FE                         PUSH STACK 0x04FE
000004C4:  10 00 00 10 04                         PUSH STACK 0x1004
000004C9:  21                                     PUSH VALUE AT [STACK1]
000004CA:  10 00 00 00 04                         PUSH STACK 0x0004
000004CF:  33                                     STACK1 = STACK1 * STACK2
000004D0:  30                                     STACK1 = STACK1 + STACK2
000004D1:  21                                     PUSH VALUE AT [STACK1]
000004D2:  31                                     STACK1 = STACK1 ^ STACK2
000004D3:  10 00 00 05 1E                         PUSH STACK 0x051E
000004D8:  10 00 00 10 04                         PUSH STACK 0x1004
000004DD:  21                                     PUSH VALUE AT [STACK1]
000004DE:  10 00 00 00 04                         PUSH STACK 0x0004
000004E3:  33                                     STACK1 = STACK1 * STACK2
000004E4:  30                                     STACK1 = STACK1 + STACK2
000004E5:  21                                     PUSH VALUE AT [STACK1]
000004E6:  32                                     STACK1 = STACK1 vs STACK2
000004E7:  10 00 00 06 41                         PUSH STACK 0x0641
000004EC:  42                                     CONDITIONAL JMP 0x0641
00000641:  10 00 00 00 01                         PUSH STACK 0x0001
00000646:  10 00 00 10 08                         PUSH STACK 0x1008
0000064B:  21                                     PUSH VALUE AT [STACK1]
0000064C:  34                                     STACK1 = STACK1 & STACK2
0000064D:  10 00 00 10 08                         PUSH STACK 0x1008
00000652:  20                                     MOV [STACK1], STACK2
00000653:  10 00 00 07 58                         PUSH STACK 0x0758
00000658:  41                                     JMP 0x0758
00000758:  10 00 00 10 04                         PUSH STACK 0x1004
0000075D:  21                                     PUSH VALUE AT [STACK1]
0000075E:  10 00 00 00 01                         PUSH STACK 0x0001
00000763:  30                                     STACK1 = STACK1 + STACK2
00000764:  10 00 00 10 04                         PUSH STACK 0x1004
00000769:  20                                     MOV [STACK1], STACK2
0000076A:  10 00 00 00 08                         PUSH STACK 0x0008
0000076F:  10 00 00 10 04                         PUSH STACK 0x1004
00000774:  21                                     PUSH VALUE AT [STACK1]
00000775:  32                                     STACK1 = STACK1 vs STACK2
00000776:  10 00 00 04 AC                         PUSH STACK 0x04AC
0000077B:  45                                     CONDITIONAL JMP 0x04AC
0000077C:  10 00 00 10 08                         PUSH STACK 0x1008
00000781:  21                                     PUSH VALUE AT [STACK1]
00000782:  10 00 00 00 01                         PUSH STACK 0x0001
00000787:  32                                     STACK1 = STACK1 vs STACK2
00000788:  10 00 00 08 9E                         PUSH STACK 0x089E
0000078D:  42                                     CONDITIONAL JMP 0x089E
0000078E:  10 00 00 08 C9                         PUSH STACK 0x08C9
00000793:  10 00 00 00 08                         PUSH STACK 0x0008
00000798:  10 00 00 00 01                         PUSH STACK 0x0001
0000079D:  50                                     CALL PRINT
0000079E:  60                                     EXIT
0000079F:  D1                                     

Again we can spot the XOR operation inside decrypted code between 0x04FE and 0x051E

Let's dump these values again (from the manually patched version):

[0x00000000]> px32 @ 0x04FE
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x000004fe  cce1 a20a bada b1ba 7cdd 120a b21c 1b57  ........|......W
0x0000050e  7fc5 2197 6555 0248 9315 df80 1529 7c7d  ..!.eU.H.....)|}
[0x00000000]> px32 @ 0x051E
- offset -   0 1  2 3  4 5  6 7  8 9  A B  C D  E F  0123456789ABCDEF
0x0000051e  bed3 c165 d4a1 d2d6 48bc 7c55 d67d 4424  ...e....H.|U.}D$
0x0000052e  0bf1 42fc 3a37 312e fc67 badf 7f44 0c00  ..B.:71..g...D..

Then let's use the CyberChief

The flag is: r2con{cl4an_da_st4ck_b3fore_jmp}

About

A write-up for r2con 2019 CTF

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published