64位程序,好像是个vm题?
ida64查看主函数
void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
__int64 v3[2]; // [rsp+10h] [rbp-10h] BYREF
v3[1] = __readfsqword(0x28u);
v3[0] = 0LL;
puts("Please input something:");
sub_CD1(v3);
sub_E0B(v3);
sub_F83(v3);
puts("And the flag is GWHT{true flag}");
exit(0);
}
看一下sub_F83函数,这应该是check函数了,qword_2022A8存放的应该是加密后的flag。前两个应该就是加密函数了。
unsigned __int64 sub_F83()
{
int i; // [rsp+Ch] [rbp-14h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
for ( i = 0; dword_2022A4 - 1 > i; ++i )
{
if ( *(qword_2022A8 + i + 32) != aFzAmAmFmtSum[i] )
{
puts("WRONG!");
exit(0);
}
}
puts("Congratulation?");
puts("tips: input is the start");
return __readfsqword(0x28u) ^ v2;
}
先用angr解一下试试水。
import angr
p=angr.Project("./Desktop/attachment",auto_load_libs=False)
sm=p.factory.simulation_manager(p.factory.entry_state())
sm.explore(find=0x401081)
print(sm.found[0].posix.dumps(0))
解出来是个假flag,不足为奇,是vm题不错了。
解vm题第一步需要搞清楚指令的格式,操作码和操作数。
sub_CD1函数是vm初始化的过程,unk_202060里面存储的是操作码,接下来每一个操作码对应一个函数实现(如0xF1对应sub_B5F函数)
unsigned __int64 __fastcall sub_CD1(__int64 a1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u); // 反调试
*a1 = 0;
*(a1 + 4) = 18;
*(a1 + 8) = 0;
*(a1 + 12) = 0;
*(a1 + 16) = &unk_202060; // unk_202060是操作码的内容
*(a1 + 24) = 0xF1; // 0xF1操作码代表sub_B5F函数
*(a1 + 32) = sub_B5F;
*(a1 + 40) = 0xF2; // 0xF2操作码代表sub_A64函数
*(a1 + 48) = sub_A64;
*(a1 + 56) = 0xF5; // 0xF5操作码代表sub_AC5函数
*(a1 + 64) = sub_AC5;
*(a1 + 72) = 0xF4; // 0xF4操作码代表sub_956函数
*(a1 + 80) = sub_956;
*(a1 + 88) = 0xF7; // 0xF7操作码代表sub_A08函数
*(a1 + 96) = sub_A08;
*(a1 + 104) = 0xF8; // 0xF8操作码代表sub_8F0函数
*(a1 + 112) = sub_8F0;
*(a1 + 120) = 0xF6; // 0xF6操作码代表sub_99C函数
*(a1 + 128) = sub_99C;
qword_2022A8 = malloc(0x512uLL);
memset(qword_2022A8, 0, 0x512uLL);
return __readfsqword(0x28u) ^ v2;
}
分析一下各个操作码进行的操作。
0xF1
0xE1,0xE2,0xE3,0xE4对应5个寄存器,实际的具体位置分别是a1,a1+4,a1+8,a1+12,而*(qword_2022A8 + *v2)对应内存单元。
0xF1进行的操作类似于mov操作符,
unsigned __int64 __fastcall sub_B5F(__int64 a1)
{
int *v2; // [rsp+28h] [rbp-18h]
unsigned __int64 v3; // [rsp+38h] [rbp-8h]
v3 = __readfsqword(0x28u);
v2 = (*(a1 + 16) + 2LL);
switch ( *(*(a1 + 16) + 1LL) )
{
case 0xE1:
*a1 = *(qword_2022A8 + *v2);
break;
case 0xE2:
*(a1 + 4) = *(qword_2022A8 + *v2);
break;
case 0xE3:
*(a1 + 8) = *(qword_2022A8 + *v2);
break;
case 0xE4:
*(qword_2022A8 + *v2) = *a1;
break;
case 0xE5:
*(a1 + 12) = *(qword_2022A8 + *v2);
break;
case 0xE7:
*(qword_2022A8 + *v2) = *(a1 + 4);
break;
default:
break;
}
*(a1 + 16) += 6LL;
return __readfsqword(0x28u) ^ v3;
}
0xF2
异或xor,两个操作数间隔4。
unsigned __int64 __fastcall sub_A64(__int64 a1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
*a1 ^= *(a1 + 4);
++*(a1 + 16);
return __readfsqword(0x28u) ^ v2;
}
0xF5
是个读取输入字符并判断长度的操作,存入qword_2022A8。
unsigned __int64 __fastcall sub_AC5(__int64 a1)
{
const char *buf; // [rsp+10h] [rbp-10h]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
buf = qword_2022A8;
read(0, qword_2022A8, 0x20uLL);
dword_2022A4 = strlen(buf);
if ( dword_2022A4 != 21 )
{
puts("WRONG!");
exit(0);
}
++*(a1 + 16);
return __readfsqword(0x28u) ^ v3;
}
0xF4
空指令nop
unsigned __int64 __fastcall sub_956(__int64 a1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
++*(a1 + 16);
return __readfsqword(0x28u) ^ v2;
}
0xF7
相乘操作mul,两个操作数间隔12。
unsigned __int64 __fastcall sub_A08(__int64 a1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
*a1 *= *(a1 + 12);
++*(a1 + 16);
return __readfsqword(0x28u) ^ v2;
}
0xF8
交换swap
unsigned __int64 __fastcall sub_8F0(int *a1)
{
int v2; // [rsp+14h] [rbp-Ch]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
v2 = *a1;
*a1 = a1[1];
a1[1] = v2;
++*(a1 + 2);
return __readfsqword(0x28u) ^ v3;
}
0xF6
线性运算
unsigned __int64 __fastcall sub_99C(__int64 a1)
{
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
*a1 = *(a1 + 8) + 2 * *(a1 + 4) + 3 * *a1;
++*(a1 + 16);
return __readfsqword(0x28u) ^ v2;
}
反汇编
机器码 | 备注 |
---|---|
0xF1 | mov |
0xF2 | xor |
0xF4 | nop |
0xF5 | input |
0xF7 | mul |
0xF8 | swap |
0xF6 | 线性运算 |
0xE1 | 寄存器r1 |
0xE2 | 寄存器r2 |
0xE3 | 寄存器r3 |
0xE4 | 内存单元flag |
0xE5 | 寄存器r4 |
现在开始翻译unk_202060中的字节码
0xF5, #获取输入
0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, #mov r1,flag[0]
0xF2, #xor r1,r2
0xF1, 0xE4, 0x20, 0x00, 0x00, 0x00, #mov flag[32],r1
0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00, #mov r1,flag[1]
0xF2, #xor r1,r2
0xF1, 0xE4, 0x21, 0x00, 0x00, 0x00, #mov flag[33],r1
0xF1, 0xE1, 0x02, 0x00, 0x00, 0x00, #mov r1,flag[2]
0xF2, #xor r1,r2
0xF1, 0xE4, 0x22, 0x00, 0x00, 0x00, #mov flag[34],r1
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,
#主要是下面这部分字节码,stack即flag
0xf5,#read(0,buf,0x20)
0xf1,0xe1,0x0,0x0,0x0,0x0,#r1 = flag[0]
0xf1,0xe2,0x1,0x0,0x0,0x0,#r2 = flag[1]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x0,0x0,0x0,0x0,#stack[0] = r1
0xf1,0xe1,0x1,0x0,0x0,0x0,#r1 = flag[1]
0xf1,0xe2,0x2,0x0,0x0,0x0,#r2 = flag[2]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x1,0x0,0x0,0x0,#stack[1] = r1
0xf1,0xe1,0x2,0x0,0x0,0x0,#r1 = flag[2]
0xf1,0xe2,0x3,0x0,0x0,0x0,#r2 = flag[3]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x2,0x0,0x0,0x0,#stack[2] = r1
0xf1,0xe1,0x3,0x0,0x0,0x0,#r1 = flag[3]
0xf1,0xe2,0x4,0x0,0x0,0x0,#r2 = flag[4]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x3,0x0,0x0,0x0,#stack[3] = r1
0xf1,0xe1,0x4,0x0,0x0,0x0,#r1 = flag[4]
0xf1,0xe2,0x5,0x0,0x0,0x0,#r2 = flag[5]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x4,0x0,0x0,0x0,#stack[4] = r1
0xf1,0xe1,0x5,0x0,0x0,0x0,#r1 = flag[5]
0xf1,0xe2,0x6,0x0,0x0,0x0,#r2 = flag[6]
0xf2,#r1 = r1^r2
0xf1,0xe4,0x5,0x0,0x0,0x0,#stack[5] = r1
0xf1,0xe1,0x6,0x0,0x0,0x0,#r1 = flag[6]
0xf1,0xe2,0x7,0x0,0x0,0x0,#r2 = flag[7]
0xf1,0xe3,0x8,0x0,0x0,0x0,#r3 = flag[8]
0xf1,0xe5,0xC,0x0,0x0,0x0,#r4 = flag[12]
0xf6, #r1 = (3*r1+2*r2+r3)
0xf7, #r1 = r1*r4
0xf1,0xe4,0x6,0x0,0x0,0x0,#stack[6] = r1
0xf1,0xe1,0x7,0x0,0x0,0x0,#r1 = flag[7]
0xf1,0xe2,0x8,0x0,0x0,0x0,#r2 = flag[8]
0xf1,0xe3,0x9,0x0,0x0,0x0,#r3 = flag[9]
0xf1,0xe5,0xC,0x0,0x0,0x0,#r4 = flag[12]
0xf6, #r1 = (3*r1+2*r2+r3)
0xf7, #r1 = r1*r4
0xf1,0xe4,0x7,0x0,0x0,0x0,#stack[7] = r1
0xf1,0xe1,0x8,0x0,0x0,0x0,#r1 = flag[8]
0xf1,0xe2,0x9,0x0,0x0,0x0,#r2 = flag[9]
0xf1,0xe3,0xA,0x0,0x0,0x0,#r3 = flag[10]
0xf1,0xe5,0xC,0x0,0x0,0x0,#r4 = flag[12]
0xf6, #r1 = (3*r1+2*r2+r3)
0xf7, #r1 = r1*r4
0xf1,0xe4,0x8,0x0,0x0,0x0,#stack[8] = r1
0xf1,0xe1,0xD,0x0,0x0,0x0,#r1 = flag[13]
0xf1,0xe2,0x13,0x0,0x0,0x0,#r2 = flag[19]
0xf8,#r1 = r2,r2 = r1
0xf1,0xe4,0xD,0x0,0x0,0x0,#stack[13] = r1
0xf1,0xe7,0x13,0x0,0x0,0x0,#stack[19] = r2
0xf1,0xe1,0xE,0x0,0x0,0x0,#r1 = flag[14]
0xf1,0xe2,0x12,0x0,0x0,0x0,#r2 = flag[18]
0xf8,#r1 = r2,r2 = r1
0xf1,0xe4,0xE,0x0,0x0,0x0,#stack[14] = r1
0xf1,0xe7,0x12,0x0,0x0,0x0,#stack[18] = r2
0xf1,0xe1,0xF,0x0,0x0,0x0,#r1 = flag[15]
0xf1,0xe2,0x11,0x0,0x0,0x0,#r2 = flag[17]
0xf8,#r1 = r2,r2 = r1
0xf1,0xe4,0xF,0x0,0x0,0x0,#stack[15] = r1
0xf1,0xe7,0x11,0x0,0x0,0x0,#stack[17] = r2
0xf4#ret
再找一下check函数,直接看qword_2022A8的交叉引用,找到真正的check函数
unsigned __int64 sub_F00()
{
int i; // [rsp+Ch] [rbp-14h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]
v2 = __readfsqword(0x28u);
for ( i = 0; dword_2022A4 - 1 > i; ++i )
{
if ( *(qword_2022A8 + i) != byte_202020[i] )
exit(0);
}
return __readfsqword(0x28u) ^ v2;
}
byte_202020[]={0x69, 0x45, 0x2A, 0x37, 0x09, 0x17,
0xC5, 0x0B, 0x5C, 0x72, 0x33, 0x76,
0x33, 0x21, 0x74, 0x31, 0x5F, 0x33,
0x73, 0x72, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00}
EXP
from z3 import *
a=Real('a')
b=Real('b')
c=Real('c')
byte=[0x69, 0x45, 0x2A, 0x37, 0x09, 0x17, 0xC5, 0x0B, 0x5C, 0x72, 0x33, 0x76, 0x33, 0x21, 0x74, 0x31, 0x5F, 0x33, 0x73, 0x72,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0]
temp=byte[15]
byte[15]=byte[17]
byte[17]=temp
temp=byte[14]
byte[14]=byte[18]
byte[18]=temp
temp=byte[13]
byte[13]=byte[19]
byte[19]=temp
solve((3*a+2*b+c)*0x33==0x6dc5,(3*b+2*c+0x72)*0x33==0x5b0b,(3*c+2*0x72+0x33)*0x33==0x705c)
#a = 118,b = 51,c = 95
byte[6] = 118
byte[7] = 51
byte[8] = 95
byte[5]^=(byte[6])
byte[4]^=(byte[5])
byte[3]^=(byte[4])
byte[2]^=(byte[3])
byte[1]^=(byte[2])
byte[0]^=(byte[1])
flag=''
for i in range(32):
flag+=chr(byte[i])
print(flag)
flag{Y0u_hav3_r3v3rs3_1t!}