gwctf2019 babyvm

yuhury發表於2024-05-04

gwctf2019 babyvm

大概溜一圈,是vm,sub_CD1是vm_init

建立結構體修復一下

排程器

寫指令碼翻譯一下

#include<stdio.h>
#include<stdlib.h>
int main(){
    unsigned char opcode[] =
    {
        0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 
        0x20, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00, 
        0xF2, 0xF1, 0xE4, 0x21, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02, 
        0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x22, 0x00, 0x00, 0x00, 
        0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x23, 
        0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00, 0xF2, 
        0xF1, 0xE4, 0x24, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00, 
        0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x25, 0x00, 0x00, 0x00, 0xF1, 
        0xE1, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x26, 0x00, 
        0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00, 0x00, 0xF2, 0xF1, 
        0xE4, 0x27, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08, 0x00, 0x00, 
        0x00, 0xF2, 0xF1, 0xE4, 0x28, 0x00, 0x00, 0x00, 0xF1, 0xE1, 
        0x09, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x29, 0x00, 0x00, 
        0x00, 0xF1, 0xE1, 0x0A, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 
        0x2A, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0B, 0x00, 0x00, 0x00, 
        0xF2, 0xF1, 0xE4, 0x2B, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0C, 
        0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2C, 0x00, 0x00, 0x00, 
        0xF1, 0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2D, 
        0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00, 0xF2, 
        0xF1, 0xE4, 0x2E, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0F, 0x00, 
        0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x2F, 0x00, 0x00, 0x00, 0xF1, 
        0xE1, 0x10, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x30, 0x00, 
        0x00, 0x00, 0xF1, 0xE1, 0x11, 0x00, 0x00, 0x00, 0xF2, 0xF1, 
        0xE4, 0x31, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x12, 0x00, 0x00, 
        0x00, 0xF2, 0xF1, 0xE4, 0x32, 0x00, 0x00, 0x00, 0xF1, 0xE1, 
        0x13, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x33, 0x00, 0x00, 
        0x00, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xF1, 
        0xE1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x01, 0x00, 0x00, 
        0x00, 0xF2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1, 
        0x01, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00, 
        0xF2, 0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02, 
        0x00, 0x00, 0x00, 0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00, 0xF2, 
        0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00, 
        0x00, 0x00, 0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xF1, 
        0xE4, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 
        0x00, 0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 
        0x04, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00, 0x00, 0x00, 
        0xF1, 0xE2, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x05, 
        0x00, 0x00, 0x00, 0xF1, 0xE1, 0x06, 0x00, 0x00, 0x00, 0xF1, 
        0xE2, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x08, 0x00, 0x00, 
        0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1, 
        0xE4, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00, 
        0x00, 0xF1, 0xE2, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x09, 
        0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 
        0xF7, 0xF1, 0xE4, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08, 
        0x00, 0x00, 0x00, 0xF1, 0xE2, 0x09, 0x00, 0x00, 0x00, 0xF1, 
        0xE3, 0x0A, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 
        0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x08, 0x00, 0x00, 0x00, 0xF1, 
        0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x13, 0x00, 0x00, 
        0x00, 0xF8, 0xF1, 0xE4, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE7, 
        0x13, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00, 
        0xF1, 0xE2, 0x12, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0E, 
        0x00, 0x00, 0x00, 0xF1, 0xE7, 0x12, 0x00, 0x00, 0x00, 0xF1, 
        0xE1, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x11, 0x00, 0x00, 
        0x00, 0xF8, 0xF1, 0xE4, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE7, 
        0x11, 0x00, 0x00, 0x00, 0xF4
    };//ida shift+e 提取資料
    unsigned char input[60] = "Fz{aM{aM|}fMt~suM !!";
    unsigned int r0 = 0;
    unsigned int r1 = 18;
    unsigned int r2 = 0;
    unsigned int r3 = 0;
    unsigned int rip = 288;//第一段是0,第二段是288
    unsigned int v2,temp;
    while(opcode[rip]!=0xf4){
        switch (opcode[rip])
        {
        case 0xf1:
            v2=opcode[rip+2];
            switch (opcode[rip+1])
            {
            case 0xe1:
                r0=input[v2];
                printf("r0=input[%d] :%d\n",v2,input[v2]);
                break;
            case 0xe2:
                r1=input[v2];
                printf("r1=input[%d] :%d\n",v2,input[v2]);
                break;
            case 0xe3:
                r2=input[v2];
                printf("r2=input[%d] :%d\n",v2,input[v2]);
                break;
            case 0xe4:
                input[v2]=r0;
                printf("input[%d]=r0 :%c\n",v2,r0);
                break;
            case 0xe5:
                r3=input[v2];
                printf("r3=input[%d] :%d\n",v2,input[v2]);
                break;
            case 0xe7:
                input[v2]=r1;
                printf("input[%d]=r1 :%d\n",v2,r1);
                break;

            default:
                break;
            }
            rip+=6;
            break;
        case 0xf2:
            r0^=r1;
            printf("r0^=r1 :%d\n",r0);
            rip+=1;
            break;
        case 0xf5:
            //read
            rip+=1;
            break;
        case 0xf4:
            rip+=1;
            printf("nop\n");
            break;
        case 0xf7:
            r0*=r3;
            printf("r0*=r3 :%d\n",r0);
            rip+=1; 
            break;
        case 0xf8:
            temp=r0;
            r0=r1;
            r1=temp;
            printf("temp=r0,r0=r1,r1=temp  now:%d %d \n",r0,r1);
            rip+=1;
            break;
        case 0xf6:
            r0=r2+2*r1+3*r0;
            printf("r0=r2+2*r1+3*r0 :%d \n",r0);
            rip+=1;
            break;
        default:
            break;
        }
    }
    return 0;
}

輸出

log 
第一段程式
r0=input[0] :70
r0^=r1 :84
input[32]=r0 :T
r0=input[1] :122
r0^=r1 :104
input[33]=r0 :h
r0=input[2] :123
r0^=r1 :105
input[34]=r0 :i
r0=input[3] :97
r0^=r1 :115
input[35]=r0 :s
r0=input[4] :77
r0^=r1 :95
input[36]=r0 :_
r0=input[5] :123
r0^=r1 :105
input[37]=r0 :i
r0=input[6] :97
r0^=r1 :115
input[38]=r0 :s
r0=input[7] :77
r0^=r1 :95
input[39]=r0 :_
r0=input[8] :124
r0^=r1 :110
input[40]=r0 :n
r0=input[9] :125
r0^=r1 :111
input[41]=r0 :o
r0=input[10] :102
r0^=r1 :116
input[42]=r0 :t
r0=input[11] :77
r0^=r1 :95
input[43]=r0 :_
r0=input[12] :116
r0^=r1 :102
input[44]=r0 :f
r0=input[13] :126
r0^=r1 :108
input[45]=r0 :l
r0=input[14] :115
r0^=r1 :97
input[46]=r0 :a
r0=input[15] :117
r0^=r1 :103
input[47]=r0 :g
r0=input[16] :77
r0^=r1 :95
input[48]=r0 :_
r0=input[17] :32
r0^=r1 :50
input[49]=r0 :2
r0=input[18] :33
r0^=r1 :51
input[50]=r0 :3
r0=input[19] :33
r0^=r1 :51
input[51]=r0 :3
//This_is_not_flag_233 

第二段程式
r0=input[0] :105
r1=input[1] :69
r0^=r1 :44
input[0]=r0 :44

r0=input[1] :69
r1=input[2] :42
r0^=r1 :111
input[1]=r0 :111

r0=input[2] :42
r1=input[3] :55
r0^=r1 :29
input[2]=r0 :29

r0=input[3] :55
r1=input[4] :9
r0^=r1 :62
input[3]=r0 :62

r0=input[4] :9
r1=input[5] :23
r0^=r1 :30
input[4]=r0 :30

r0=input[5] :23
r1=input[6] :197
r0^=r1 :210
input[5]=r0 :210

r0=input[6] :197
r1=input[7] :11
r2=input[8] :92
r3=input[12] :51
r0=r2+2*r1+3*r0 :705
r0*=r3 :35955
input[6]=r0 :35955

r0=input[7] :11
r1=input[8] :92
r2=input[9] :114
r3=input[12] :51
r0=r2+2*r1+3*r0 :331
r0*=r3 :16881
input[7]=r0 :16881

r0=input[8] :92
r1=input[9] :114
r2=input[10] :51
r3=input[12] :51
r0=r2+2*r1+3*r0 :555
r0*=r3 :28305
input[8]=r0 :28305

r0=input[13] :33
r1=input[19] :114
temp=r0,r0=r1,r1=temp  now:r !
input[13]=r0 :114
input[19]=r1 :33

r0=input[14] :116
r1=input[18] :115
temp=r0,r0=r1,r1=temp  now:s t
input[14]=r0 :115
input[18]=r1 :116

r0=input[15] :49
r1=input[17] :51
temp=r0,r0=r1,r1=temp  now:3 1
input[15]=r0 :51
input[17]=r1 :49

第一段程式為簡單異或,解出來結果發現是fake flag,所以結果要看第二段程式。另外第二段程式呼叫的密文資料也不同,可以從input陣列的交叉呼叫中找到另一個比較函式,或者在第一段程式的密文附近發現第二段密文。

根據第二段程式和對應的密文可以得出flag,指令碼如下:

from z3 import *
import re
flag=[  
        0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72, 
        0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72
     ]

flag[15], flag[17] = flag[17], flag[15]
flag[14], flag[18] = flag[18], flag[14]
flag[19], flag[13] = flag[13], flag[19]

# z3
a6, a7, a8 = BitVecs('a6 a7 a8', 8)
s = Solver()
s.add(flag[6] == (a8 + 2 * a7 + 3 * a6) * flag[12])
s.add(flag[7] == (flag[9]  + 2 * a8 + 3 * a7) * flag[12])
s.add(flag[8] == (flag[10] + 2 * flag[9] + 3 * a8) * flag[12])
if s.check() == sat:
    m = s.model()
    for i in m:
        index = int(re.search(r'\d+', str(i)).group())
        flag[index] = m[i].as_long()
# 異或
for i in range(5, -1, -1):
    flag[i] ^= flag[i + 1]

print('[+] flag: ', ''.join([chr(_) for _ in flag]))

參考:

babyvm-vm逆向 | Tyaoo's Blog

[GWCTF 2019]babyvm_[gwctf 2019]babyvm_em0s_er1t的部落格-csdn部落格-CSDN部落格

https://mp.weixin.qq.com/s/aVPlvHkb6ohZ5K_zXVhs0w