IDA查看Exports有3个TlsCallback
只有TlsCallback_2有用
其中创建6个线程用于代码动态解码smc
只有前三个线程有用 分别对check_part1,check_part2,check_part3代码解码
HANDLE sub_402C70() { hMutex = CreateMutexW(0, 0, "Mutex"); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_smc1, 0, 0, 0); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_smc2, 0, 0, 0); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)thread_smc3, 0, 0, 0); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_402BB0, 0, 0, 0); CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_402BF0, 0, 0, 0); return CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sub_402C30, 0, 0, 0); }
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[6]; // [sp+10h] [bp-Ch]@1 while ( 1 ) { v8[0] = -117; v8[1] = -64; v8[2] = -117; v8[3] = -1; v8[4] = -117; v8[5] = -37; WaitForSingleObject(hMutex, 0xFFFFFFFF); if ( thread_flag == 1 ) { flOldProtect = 0; VirtualProtect(check_part1, 0x2Eu, 0x40u, &flOldProtect); v1 = 1; do { *((_BYTE *)check_part1 + v1 - 1) ^= byte_4064F0[v1 - 1]; *((_BYTE *)check_part1 + v1) ^= byte_4064F0[v1]; v1 += 2; } while ( v1 - 1 < 46 ); VirtualProtect(check_part1, 0x2Eu, flOldProtect, &flOldProtect); VirtualProtect(smc_code1, 6u, 0x40u, &flOldProtect); v2 = 0; v3 = (_BYTE *)smc_code1 - v8; do { v4 = v8[v2]; v5 = &v8[v2]; v6 = *(&v8[v2++] + v3); v5[v3] = v4; *v5 = v6; } while ( v2 < 6 ); VirtualProtect(smc_code1, 6u, flOldProtect, &flOldProtect); thread_flag = 0; } 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[6]; // [sp+14h] [bp-Ch]@1 v8[0] = -117; v8[1] = -64; v8[2] = -117; v8[3] = -37; v8[4] = -117; v8[5] = -1; while ( 1 ) { WaitForSingleObject(hMutex, 0xFFFFFFFF); if ( thread_flag == 2 ) { flOldProtect = 0; VirtualProtect(check_part2, 0x2Eu, 0x40u, &flOldProtect); v1 = 1; do { *((_BYTE *)check_part2 + v1 - 1) ^= byte_406520[v1 - 1]; *((_BYTE *)check_part2 + v1) ^= byte_406520[v1]; v1 += 2; } while ( v1 - 1 < 46 ); VirtualProtect(check_part2, 0x2Eu, flOldProtect, &flOldProtect); VirtualProtect(smc_code2, 6u, 0x40u, &flOldProtect); v2 = 0; v3 = (_BYTE *)smc_code2 - v8; do { v4 = v8[v2]; v5 = &v8[v2]; v6 = *(&v8[v2++] + v3); v5[v3] = v4; *v5 = v6; } while ( v2 < 6 ); VirtualProtect(smc_code2, 6u, flOldProtect, &flOldProtect); thread_flag = 0; } 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[6]; // [sp+14h] [bp-Ch]@1 v6[0] = -117; v6[1] = -1; v6[2] = -117; v6[3] = -64; v6[4] = -117; v6[5] = -37; while ( 1 ) { WaitForSingleObject(hMutex, 0xFFFFFFFF); if ( thread_flag == 3 ) { flOldProtect = 0; VirtualProtect(check_part3, 0x2Eu, 0x40u, &flOldProtect); v1 = 1; do { *((_BYTE *)check_part3 + v1 - 1) ^= byte_406550[v1 - 1]; *((_BYTE *)check_part3 + v1) ^= byte_406550[v1]; v1 += 2; } while ( v1 - 1 < 46 ); VirtualProtect(check_part3, 0x2Eu, flOldProtect, &flOldProtect); VirtualProtect(smc_code3, 6u, 0x40u, &flOldProtect); v2 = (char *)smc_code3; v3 = 0; do { v4 = v6[v3]; v6[v3] = *v2; *v2 = v4; ++v3; ++v2; } while ( v3 < 6 ); VirtualProtect(smc_code3, 6u, flOldProtect, &flOldProtect); thread_flag = 0; } 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 = 0, memset(&Dst, 0, 0xFFu), v9 = base64_decode(&v2), strlen(&v2) == 0x5A) && v4 == '-' && v5 == '-' && v6 == '-' && v7 == '-' ) { if ( !(unsigned __int8)crc_check() ) ExitProcess(1u); thread_flag = 1; while ( thread_flag ) ; if ( ((int (__cdecl *)(char *))check_part1)(&v2) ) { thread_flag = 1; while ( thread_flag ) ; if ( !(unsigned __int8)crc_check() ) ExitProcess(1u); thread_flag = 2; while ( thread_flag ) ; if ( ((int (__cdecl *)(char *))check_part2)(&v2) ) { thread_flag = 2; while ( thread_flag ) ; if ( !(unsigned __int8)crc_check() ) ExitProcess(1u); thread_flag = 3; while ( thread_flag ) ; if ( (*(int (__cdecl **)(char *))check_part3)(&v2) ) { thread_flag = 3; while ( thread_flag ) ; if ( !(unsigned __int8)crc_check() ) ExitProcess(1u); result = 1; } else { result = 0; } } else { result = 0; } } else { result = 0; } } else { result = 0; } 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(2) } v1 = __rdtsc(); v10 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << 32); v2 = a1; v3 = &unk_99B6F1 - (_UNKNOWN *)a1; v9 = 4; while ( 1 ) { v4 = *v2 ^ v2["abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" - a1]; v2 += 5; v2[&unk_99B6F0 - (_UNKNOWN *)a1 - 5] = v4; v2[v3 - 5] = *(v2 - 4) ^ v2[4215109 - (_DWORD)a1 - 5]; v2[&unk_99B6F2 - (_UNKNOWN *)a1 - 5] = *(v2 - 3) ^ v2[4215110 - (_DWORD)a1 - 5]; v2[&unk_99B6F3 - (_UNKNOWN *)a1 - 5] = *(v2 - 2) ^ v2[4215111 - (_DWORD)a1 - 5]; v5 = v9-- == 1; v2[byte_99B6F4 - a1 - 5] = *(v2 - 1) ^ v2[4215112 - (_DWORD)a1 - 5]; 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) << 32) - v10 < (unsigned int)&unk_87A238 ) { operator delete(v6); result = 1; } else { operator delete(v6); result = 0; } 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(2) } v1 = __rdtsc(); v2 = ((unsigned __int64)HIDWORD(v1) << 32) + (unsigned int)v1; v3 = 0; do { v4 = aAbcdefghijklmn[v3] ^ *(_BYTE *)(a1 + v3 + 22); v3 += 3; *(_BYTE *)(v3 + 10073861) = v4; *(_BYTE *)(v3 + 10073862) = *(_BYTE *)(v3 + 4215106) ^ *(_BYTE *)(a1 + v3 + 20); *(_BYTE *)(v3 + 10073863) = *(_BYTE *)(v3 + 4215107) ^ *(_BYTE *)(a1 + v3 + 21); } while ( v3 < 39 ); v5 = (const char *)sub_403EA0(10073864, 10073864); sub_403DC0(v5, aXuvwttsQzrXB_0); if ( strcmp(v5, a13095069099216) ) { operator delete(v5); return 0; } operator delete(v5); v7 = __rdtsc(); if ( (unsigned int)v7 + ((unsigned __int64)HIDWORD(v7) << 32) - v2 >= 0x14B230CE38i64 ) return 0; return 1; }
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[40]; // [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[51]; // [sp+2C9h] [bp-37h]@24 v1 = __rdtsc(); v21 = (unsigned int)v1 + ((unsigned __int64)HIDWORD(v1) << 32); sub_4010C0(); v26 = 0; memset(&Dst, 0, 0x37u); v2 = (char *)(a1 + 63); v3 = &Dst; v4 = 27; do { v5 = *v2; *(v3 - 1) = *v2 / 16; *v3 = v5 % 16; ++v2; v3 += 2; --v4; } while ( v4 ); v6 = 0; do { v7 = *(&v26 + v6); if ( v7 < 0 || v7 > 9 ) v8 = v7 + 55; else v8 = v7 + 48; *(&v26 + v6) = v8; v9 = *(&Dst + v6); if ( v9 < 0 || v9 > 9 ) v10 = v9 + 55; else v10 = v9 + 48; *(&Dst + v6) = v10; v11 = *(&v28 + v6); if ( v11 < 0 || v11 > 9 ) v12 = v11 + 55; else v12 = v11 + 48; *(&v28 + v6) = v12; v13 = *(&v29 + v6); if ( v13 < 0 || v13 > 9 ) v14 = v13 + 55; else v14 = v13 + 48; *(&v29 + v6) = v14; v15 = *(&v30 + v6); if ( v15 < 0 || v15 > 9 ) v16 = v15 + 55; else v16 = v15 + 48; *(&v30 + v6) = v16; v17 = v31[v6]; if ( v17 < 0 || v17 > 9 ) v18 = v17 + 55; else v18 = v17 + 48; v31[v6] = v18; v6 += 6; } while ( v6 < 54 ); sub_401C50(&v26, 16); sub_4010C0(); sub_401C50(&unk_99B6F0, 10); sub_4010C0(); sub_401C50(10073864, 10); sub_401A90(&v22, &v25); result = 0; if ( v23 == 4 ) { while ( v24[result] == dword_4064E0[result] ) { ++result; if ( result >= 4 ) { v20 = __rdtsc(); if ( (unsigned int)v20 + ((unsigned __int64)HIDWORD(v20) << 32) - v21 < 0x54C5638 ) return 1; break; } } result = 0; } return result * 4; }
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虚拟机
python指令解析器
#!/usr/bin/python # -*- coding: UTF-8 -*- # 代码段 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[0] | (arr[1]<<8 | arr[2]<<16 | arr[3]<<24) class Context: def __init__(self): self.ip = 0 def cmdA0(self): c = text[self.ip + 1] p = toUint(text[self.ip+2:self.ip+6]) self.ip += 6 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 += 1 print "xor r0, r1" def cmdA2(self): p = text[self.ip+1] self.ip += 2 print "equb r0, [{0}]".format(hex(p)) def cmdA3(self): assert False def cmdA4(self): self.ip += 1 print "msg [r0], [r1]" def cmdA5(self): self.ip += 1 print "exit" def cmdA6(self): p = text[self.ip + 1] self.ip += 2 print "jne +{0}".format(hex(p)) def cmdA7(self): self.ip += 1 print "in [r0]" def cmdA8(self): self.ip += 1 print "out [r0]" def cmdA9(self): self.ip += 1 print "check [r0]" def cmdAA(self): c = text[self.ip + 1] p = toUint(text[self.ip+2:self.ip+6]) self.ip += 6 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], [32] xorstr [0x140], [32] mov r0, 0x0 out [r0] mov r0, 0xf0 out [r0] mov r0, 0x160 in [r0] xorstr key1, [0x80], [32] xorstr key0, [0x60], [32] xorstr key2, [0xb0], [32] 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