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