看雪CTF第八题

时间:2024-11-06 15:36:20

IDA查看Exports有3个TlsCallback

只有TlsCallback_2有用

其中创建6个线程用于代码动态解码smc

只有前三个线程有用 分别对check_part1,check_part2,check_part3代码解码

HANDLE sub_402C70()
{
hMutex = CreateMutexW(, , "Mutex");
CreateThread(, , (LPTHREAD_START_ROUTINE)thread_smc1, , , );
CreateThread(, , (LPTHREAD_START_ROUTINE)thread_smc2, , , );
CreateThread(, , (LPTHREAD_START_ROUTINE)thread_smc3, , , );
CreateThread(, , (LPTHREAD_START_ROUTINE)sub_402BB0, , , );
CreateThread(, , (LPTHREAD_START_ROUTINE)sub_402BF0, , , );
return CreateThread(, , (LPTHREAD_START_ROUTINE)sub_402C30, , , );
}

thread_smc1

void __stdcall __noreturn thread_smc1(LPVOID lpThreadParameter)
{
signed int v1; // eax@2
signed int v2; // ecx@4
signed int v3; // esi@4
char v4; // bl@5
char *v5; // eax@5
char v6; // dl@5
DWORD flOldProtect; // [sp+Ch] [bp-10h]@2
char v8[]; // [sp+10h] [bp-Ch]@1 while ( )
{
v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
WaitForSingleObject(hMutex, 0xFFFFFFFF);
if ( thread_flag == )
{
flOldProtect = ;
VirtualProtect(check_part1, 0x2Eu, 0x40u, &flOldProtect);
v1 = ;
do
{
*((_BYTE *)check_part1 + v1 - ) ^= byte_4064F0[v1 - ];
*((_BYTE *)check_part1 + v1) ^= byte_4064F0[v1];
v1 += ;
}
while ( v1 - < );
VirtualProtect(check_part1, 0x2Eu, flOldProtect, &flOldProtect);
VirtualProtect(smc_code1, 6u, 0x40u, &flOldProtect);
v2 = ;
v3 = (_BYTE *)smc_code1 - v8;
do
{
v4 = v8[v2];
v5 = &v8[v2];
v6 = *(&v8[v2++] + v3);
v5[v3] = v4;
*v5 = v6;
}
while ( v2 < );
VirtualProtect(smc_code1, 6u, flOldProtect, &flOldProtect);
thread_flag = ;
}
ReleaseMutex(hMutex);
Sleep(0x32u);
}
}

thread_smc2

void __stdcall __noreturn thread_smc2(LPVOID lpThreadParameter)
{
signed int v1; // eax@3
signed int v2; // ecx@5
signed int v3; // esi@5
char v4; // bl@6
char *v5; // eax@6
char v6; // dl@6
DWORD flOldProtect; // [sp+10h] [bp-10h]@3
char v8[]; // [sp+14h] [bp-Ch]@1 v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
v8[] = -;
while ( )
{
WaitForSingleObject(hMutex, 0xFFFFFFFF);
if ( thread_flag == )
{
flOldProtect = ;
VirtualProtect(check_part2, 0x2Eu, 0x40u, &flOldProtect);
v1 = ;
do
{
*((_BYTE *)check_part2 + v1 - ) ^= byte_406520[v1 - ];
*((_BYTE *)check_part2 + v1) ^= byte_406520[v1];
v1 += ;
}
while ( v1 - < );
VirtualProtect(check_part2, 0x2Eu, flOldProtect, &flOldProtect);
VirtualProtect(smc_code2, 6u, 0x40u, &flOldProtect);
v2 = ;
v3 = (_BYTE *)smc_code2 - v8;
do
{
v4 = v8[v2];
v5 = &v8[v2];
v6 = *(&v8[v2++] + v3);
v5[v3] = v4;
*v5 = v6;
}
while ( v2 < );
VirtualProtect(smc_code2, 6u, flOldProtect, &flOldProtect);
thread_flag = ;
}
ReleaseMutex(hMutex);
Sleep(0x32u);
}
}

thread_smc3

void __stdcall __noreturn thread_smc3(LPVOID lpThreadParameter)
{
signed int v1; // eax@3
char *v2; // ecx@5
signed int v3; // eax@5
char v4; // bl@6
DWORD flOldProtect; // [sp+10h] [bp-10h]@3
char v6[]; // [sp+14h] [bp-Ch]@1 v6[] = -;
v6[] = -;
v6[] = -;
v6[] = -;
v6[] = -;
v6[] = -;
while ( )
{
WaitForSingleObject(hMutex, 0xFFFFFFFF);
if ( thread_flag == )
{
flOldProtect = ;
VirtualProtect(check_part3, 0x2Eu, 0x40u, &flOldProtect);
v1 = ;
do
{
*((_BYTE *)check_part3 + v1 - ) ^= byte_406550[v1 - ];
*((_BYTE *)check_part3 + v1) ^= byte_406550[v1];
v1 += ;
}
while ( v1 - < );
VirtualProtect(check_part3, 0x2Eu, flOldProtect, &flOldProtect);
VirtualProtect(smc_code3, 6u, 0x40u, &flOldProtect);
v2 = (char *)smc_code3;
v3 = ;
do
{
v4 = v6[v3];
v6[v3] = *v2;
*v2 = v4;
++v3;
++v2;
}
while ( v3 < );
VirtualProtect(smc_code3, 6u, flOldProtect, &flOldProtect);
thread_flag = ;
}
ReleaseMutex(hMutex);
Sleep(0x32u);
}
}

调用check_part1前,会置thread_flag=1, 这个时候thread_smc1开始解密

调用check_part1后,会置thread_flag=1, 这个时候thread_smc1开始加密

调用check_part2前,会置thread_flag=2, 这个时候thread_smc2开始解密

调用check_part2后,会置thread_flag=2, 这个时候thread_smc2开始加密

调用check_part3前,会置thread_flag=3, 这个时候thread_smc3开始解密

调用check_part3后,会置thread_flag=3, 这个时候thread_smc3开始加密

smc需要还原代码

import idaapi
tmp_point = {0x4068E4:0x4025DC, 0x4068E0:0x40263C, 0x4068EC:0x40269C}
def dec_func(func_addr, key_addr, tmp_addr, tmp):
func = bytearray(idaapi.get_many_bytes(func_addr, 0x2E))
key = bytearray(idaapi.get_many_bytes(key_addr, 0x2E))
for i in xrange(len(func)):
func[i] ^= key[i]
idaapi.patch_many_bytes(func_addr, str(func))
idaapi.patch_many_bytes(tmp_point[tmp_addr], str(bytearray(tmp)))
dec_func(0x401EC0, 0x4064F0, 0x4068E4, [0x8B, 0xC0, 0x8B, 0xFF, 0x8B, 0xDB])
dec_func(0x402090, 0x406520, 0x4068E0, [0x8B, 0xC0, 0x8B, 0xDB, 0x8B, 0xFF])
dec_func(0x4021D0, 0x406550, 0x4068EC, [0x8B, 0xFF, 0x8B, 0xC0, 0x8B, 0xDB])

fn_check

int __cdecl fn_check(const char *src)
{
int result; // eax@14
char v2; // [sp+20h] [bp-110h]@3
char Dst; // [sp+21h] [bp-10Fh]@3
char v4; // [sp+34h] [bp-FCh]@4
char v5; // [sp+35h] [bp-FBh]@5
char v6; // [sp+5Dh] [bp-D3h]@6
char v7; // [sp+5Eh] [bp-D2h]@7
int len; // [sp+128h] [bp-8h]@2
int v9; // [sp+12Ch] [bp-4h]@3 lpAddress = &loc_4025DC;
dword_4068E0 = &loc_40263C;
dword_4068EC = &loc_40269C;
if ( (unsigned __int8)crc_check()
&& (len = strlen(src), len <= 0x100)
&& (v2 = , memset(&Dst, , 0xFFu), v9 = base64_decode(&v2), strlen(&v2) == 0x5A)
&& v4 == '-'
&& v5 == '-'
&& v6 == '-'
&& v7 == '-' )
{
if ( !(unsigned __int8)crc_check() )
ExitProcess(1u);
thread_flag = ;
while ( thread_flag )
;
if ( ((int (__cdecl *)(char *))check_part1)(&v2) )
{
thread_flag = ;
while ( thread_flag )
;
if ( !(unsigned __int8)crc_check() )
ExitProcess(1u);
thread_flag = ;
while ( thread_flag )
;
if ( ((int (__cdecl *)(char *))check_part2)(&v2) )
{
thread_flag = ;
while ( thread_flag )
;
if ( !(unsigned __int8)crc_check() )
ExitProcess(1u);
thread_flag = ;
while ( thread_flag )
;
if ( (*(int (__cdecl **)(char *))check_part3)(&v2) )
{
thread_flag = ;
while ( thread_flag )
;
if ( !(unsigned __int8)crc_check() )
ExitProcess(1u);
result = ;
}
else
{
result = ;
}
}
else
{
result = ;
}
}
else
{
result = ;
}
}
else
{
result = ;
}
return result;
}

check_part1

signed int __cdecl fn_check_part1(_BYTE *a1)
{
unsigned __int64 v1; // rax@1
_BYTE *v2; // eax@1
signed int v3; // edx@1
char v4; // bl@3
bool v5; // zf@3
const char *v6; // esi@4
signed int result; // eax@6
unsigned __int64 v8; // [sp+10h] [bp-28h]@4
signed int v9; // [sp+14h] [bp-24h]@1
unsigned __int64 v10; // [sp+30h] [bp-8h]@1 __asm { fcmovnbe st, st() }
v1 = __rdtsc();
v10 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << );
v2 = a1;
v3 = &unk_99B6F1 - (_UNKNOWN *)a1;
v9 = ;
while ( )
{
v4 = *v2 ^ v2["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - a1];
v2 += ;
v2[&unk_99B6F0 - (_UNKNOWN *)a1 - ] = v4;
v2[v3 - ] = *(v2 - ) ^ v2[ - (_DWORD)a1 - ];
v2[&unk_99B6F2 - (_UNKNOWN *)a1 - ] = *(v2 - ) ^ v2[ - (_DWORD)a1 - ];
v2[&unk_99B6F3 - (_UNKNOWN *)a1 - ] = *(v2 - ) ^ v2[ - (_DWORD)a1 - ];
v5 = v9-- == ;
v2[byte_99B6F4 - a1 - ] = *(v2 - ) ^ v2[ - (_DWORD)a1 - ];
if ( v5 )
break;
v3 = &unk_99B6F1 - (_UNKNOWN *)a1;
}
v6 = (const char *)sub_403EA0(&unk_99B6F0, aXztrprtzxzrt_0);
v8 = __rdtsc();
if ( !strcmp(v6, aPwwRWX_Zhejg_0)
&& (unsigned int)v8 + ((unsigned __int64)HIDWORD(v8) << ) - v10 < (unsigned int)&unk_87A238 )
{
operator delete(v6);
result = ;
}
else
{
operator delete(v6);
result = ;
}
return result;
}

check_part2

signed int __cdecl check_part2(int a1)
{
unsigned __int64 v1; // rax@1
unsigned __int64 v2; // kr00_8@1
signed int v3; // eax@1
char v4; // dl@2
const char *v5; // esi@3
unsigned __int64 v7; // ST20_8@6 __asm { fcmovnbe st, st() }
v1 = __rdtsc();
v2 = ((unsigned __int64)HIDWORD(v1) << ) + (unsigned int)v1;
v3 = ;
do
{
v4 = aAbcdefghijklmn[v3] ^ *(_BYTE *)(a1 + v3 + );
v3 += ;
*(_BYTE *)(v3 + ) = v4;
*(_BYTE *)(v3 + ) = *(_BYTE *)(v3 + ) ^ *(_BYTE *)(a1 + v3 + );
*(_BYTE *)(v3 + ) = *(_BYTE *)(v3 + ) ^ *(_BYTE *)(a1 + v3 + );
}
while ( v3 < );
v5 = (const char *)sub_403EA0(, );
sub_403DC0(v5, aXuvwttsQzrXB_0);
if ( strcmp(v5, a13095069099216) )
{
operator delete(v5);
return ;
}
operator delete(v5);
v7 = __rdtsc();
if ( (unsigned int)v7 + ((unsigned __int64)HIDWORD(v7) << ) - v2 >= 0x14B230CE38i64 )
return ;
return ;
}

check_part3

int __cdecl check_part3(int a1)
{
unsigned __int64 v1; // rax@1
char *v2; // edi@1
char *v3; // ecx@1
signed int v4; // ebx@1
signed int v5; // esi@2
signed int v6; // ecx@3
char v7; // al@4
char v8; // al@6
char v9; // al@8
char v10; // al@10
char v11; // al@12
char v12; // al@14
char v13; // al@16
char v14; // al@18
char v15; // al@20
char v16; // al@22
char v17; // al@24
char v18; // al@26
int result; // eax@29
unsigned __int64 v20; // rax@32
unsigned __int64 v21; // [sp+18h] [bp-2E8h]@1
char v22; // [sp+20h] [bp-2E0h]@29
int v23; // [sp+24h] [bp-2DCh]@29
int v24[]; // [sp+28h] [bp-2D8h]@30
char v25; // [sp+170h] [bp-190h]@29
char v26; // [sp+2C4h] [bp-3Ch]@1
char Dst; // [sp+2C5h] [bp-3Bh]@1
char v28; // [sp+2C6h] [bp-3Ah]@12
char v29; // [sp+2C7h] [bp-39h]@16
char v30; // [sp+2C8h] [bp-38h]@20
char v31[]; // [sp+2C9h] [bp-37h]@24 v1 = __rdtsc();
v21 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << );
sub_4010C0();
v26 = ;
memset(&Dst, , 0x37u);
v2 = (char *)(a1 + );
v3 = &Dst;
v4 = ;
do
{
v5 = *v2;
*(v3 - ) = *v2 / ;
*v3 = v5 % ;
++v2;
v3 += ;
--v4;
}
while ( v4 );
v6 = ;
do
{
v7 = *(&v26 + v6);
if ( v7 < || v7 > )
v8 = v7 + ;
else
v8 = v7 + ;
*(&v26 + v6) = v8;
v9 = *(&Dst + v6);
if ( v9 < || v9 > )
v10 = v9 + ;
else
v10 = v9 + ;
*(&Dst + v6) = v10;
v11 = *(&v28 + v6);
if ( v11 < || v11 > )
v12 = v11 + ;
else
v12 = v11 + ;
*(&v28 + v6) = v12;
v13 = *(&v29 + v6);
if ( v13 < || v13 > )
v14 = v13 + ;
else
v14 = v13 + ;
*(&v29 + v6) = v14;
v15 = *(&v30 + v6);
if ( v15 < || v15 > )
v16 = v15 + ;
else
v16 = v15 + ;
*(&v30 + v6) = v16;
v17 = v31[v6];
if ( v17 < || v17 > )
v18 = v17 + ;
else
v18 = v17 + ;
v31[v6] = v18;
v6 += ;
}
while ( v6 < );
sub_401C50(&v26, );
sub_4010C0();
sub_401C50(&unk_99B6F0, );
sub_4010C0();
sub_401C50(, );
sub_401A90(&v22, &v25);
result = ;
if ( v23 == )
{
while ( v24[result] == dword_4064E0[result] )
{
++result;
if ( result >= )
{
v20 = __rdtsc();
if ( (unsigned int)v20 + ((unsigned __int64)HIDWORD(v20) << ) - v21 < 0x54C5638 )
return ;
break;
}
}
result = ;
}
return result * ;
}

vm_context

00000000 vm_context      struc ; (sizeof=0x70, mappedto_32)
00000000 r0 dd ?
00000004 r1 dd ?
00000008 r2 dd ?
0000000C r3 dd ?
00000010 r4 dd ?
00000014 opcode dd ?
00000018 cmdA0 dd ?
0000001C fn_set_imm dd ?
00000020 cmdA1 dd ?
00000024 fn_xor_r0_r1 dd ?
00000028 cmdA2 dd ?
0000002C fn_cmp dd ?
00000030 cmdA4 dd ?
00000034 fn_prompt dd ?
00000038 cmdA5 dd ?
0000003C fn_exit dd ?
00000040 cmdA3 dd ?
00000044 fn_null dd ?
00000048 cmdA6 dd ?
0000004C fn_jnz dd ?
00000050 cmdA7 dd ?
00000054 fn_input dd ?
00000058 cmdA8 dd ?
0000005C fn_output dd ?
00000060 cmdA9 dd ?
00000064 fn_check dd ?
00000068 cmdAA dd ?
0000006C fn_decrypt_string dd ?
00000070 vm_context ends

vm_init()

void *__usercall vm_init@<eax>(vm_context *vm_ctx@<eax>, void *data_start)
{
char *v2; // ecx@1
signed int v3; // edx@1 vm_ctx->r0 = 0;
vm_ctx->r1 = 0;
vm_ctx->r2 = 0;
vm_ctx->r3 = 0;
vm_ctx->r4 = 0;
v2 = (char *)&vm_ctx->cmdA0;
v3 = 32;
do
{
*v2 = 0;
v2 += 8;
--v3;
}
while ( v3 ); LOBYTE(vm_ctx->cmdA0) = 0xA0u;
vm_ctx->fn_set_imm = (int)fn_set_imm;
LOBYTE(vm_ctx->cmdA1) = 0xA1u;
vm_ctx->fn_xor_r0_r1 = (int)fn_xor_r0_r1;
LOBYTE(vm_ctx->cmdA2) = 0xA2u;
vm_ctx->fn_cmp = (int)fn_cmp;
LOBYTE(vm_ctx->cmdA4) = 0xA4u;
vm_ctx->fn_prompt = (int)fn_prompt;
LOBYTE(vm_ctx->cmdA5) = 0xA5u;
vm_ctx->fn_exit = (int)fn_exit;
LOBYTE(vm_ctx->cmdA3) = 0xA3u;
vm_ctx->fn_null = (int)fn_null;
LOBYTE(vm_ctx->cmdA6) = 0xA6u;
vm_ctx->fn_jnz = (int)fn_jnz;
LOBYTE(vm_ctx->cmdA7) = 0xA7u;
vm_ctx->fn_input = (int)fn_input;
LOBYTE(vm_ctx->cmdA8) = 0xA8u;
vm_ctx->fn_output = (int)fn_output;
LOBYTE(vm_ctx->cmdA9) = 0xA9u;
vm_ctx->fn_check = (int)fn_check;
LOBYTE(vm_ctx->cmdAa) = 0xAAu;
vm_ctx->fn_decrypt_string = (int)fn_decrypt_string;
return memset(data_start, 0, 0x1000u);
}

vm_dispatcher()

int __usercall vm_dispatcher@<eax>(int opcode_start@<eax>, vm_context *vm_ctx@<esi>, int data_start)
{
char *vm_handler_type; // ecx@2 vm_ctx->opcode = opcode_start;
while ( *(_BYTE *)vm_ctx->opcode != 0xA3u )
{
opcode_start = 0;
vm_handler_type = (char *)&vm_ctx->cmdA0;
while ( opcode_start < 0x20 )
{
if ( *(_BYTE *)vm_ctx->opcode == *vm_handler_type )
{
opcode_start = (*((int (__cdecl **)(_DWORD, _DWORD))&vm_ctx->fn_set_imm + 2 * opcode_start))(vm_ctx, data_start);
break;
}
++opcode_start;
vm_handler_type += 8;
}
}
return opcode_start;
}

自定义vm虚拟机

看雪CTF第八题

python指令解析器

#!/usr/bin/python
# -*- coding: UTF- -*- # 代码段
text = [0xAA, 0x15, 0x20, 0x01, 0x00, 0x00, 0xAA, 0x15, 0x40, 0x01, 0x00, 0x00, 0xA0, 0x10, 0x00, 0x00,
0x00, 0x00, 0xA8, 0xA0, 0x10, 0xF0, 0x00, 0x00, 0x00, 0xA8, 0xA0, 0x10, 0x60, 0x01, 0x00, 0x00,
0xA7, 0xAA, 0x11, 0x80, 0x00, 0x00, 0x00, 0xAA, 0x10, 0x60, 0x00, 0x00, 0x00, 0xAA, 0x12, 0xB0,
0x00, 0x00, 0x00, 0xA9, 0xA2, 0xEA, 0xA6, 0x0E, 0xA0, 0x10, 0x20, 0x01, 0x00, 0x00, 0xA0, 0x11,
0x10, 0x01, 0x00, 0x00, 0xA4, 0xA5, 0xA0, 0x10, 0x40, 0x01, 0x00, 0x00, 0xA0, 0x11, 0x10, 0x01,
0x00, 0x00, 0xA4, 0xA5] def toUint(arr):
return arr[] | (arr[]<< | arr[]<< | arr[]<<) class Context:
def __init__(self):
self.ip =
def cmdA0(self):
c = text[self.ip + ]
p = toUint(text[self.ip+:self.ip+])
self.ip +=
if 0x10 <= c <= 0x13:
print "mov r{0}, {1}".format(c-0x10, hex(p))
elif c == 0x14:
print "movb r0, [{0}]".format(hex(p))
elif c == 0x15:
print "movb [{0}], r0".format(hex(p))
else:
assert False
def cmdA1(self):
self.ip +=
print "xor r0, r1"
def cmdA2(self):
p = text[self.ip+]
self.ip +=
print "equb r0, [{0}]".format(hex(p))
def cmdA3(self):
assert False
def cmdA4(self):
self.ip +=
print "msg [r0], [r1]"
def cmdA5(self):
self.ip +=
print "exit"
def cmdA6(self):
p = text[self.ip + ]
self.ip +=
print "jne +{0}".format(hex(p))
def cmdA7(self):
self.ip +=
print "in [r0]"
def cmdA8(self):
self.ip +=
print "out [r0]"
def cmdA9(self):
self.ip +=
print "check [r0]"
def cmdAA(self):
c = text[self.ip + ]
p = toUint(text[self.ip+:self.ip+])
self.ip +=
if 0x10 <= c <= 0x12:
print "xorstr key{0}, [{1}], [32]".format(c - 0x10, hex(p))
else:
print "xorstr [{0}], [32]".format(hex(p))
def run(self):
ops = [self.cmdA0, self.cmdA1, self.cmdA2, self.cmdA3, self.cmdA4, self.cmdA5,
self.cmdA6, self.cmdA7, self.cmdA8, self.cmdA9, self.cmdAA]
while self.ip < len(text):
c = text[self.ip]
ops[c - 0xA0]() ctx = Context()
ctx.run()

运行结果

xorstr [0x120], []
xorstr [0x140], []
mov r0, 0x0
out [r0]
mov r0, 0xf0
out [r0]
mov r0, 0x160
in [r0]
xorstr key1, [0x80], []
xorstr key0, [0x60], []
xorstr key2, [0xb0], []
check [r0]
equb r0, [0xea]
jne +0xe
mov r0, 0x120
mov r1, 0x110
msg [r0], [r1]
exit
mov r0, 0x140
mov r1, 0x110
msg [r0], [r1]
exit