感觉出题人是做病毒分析的…做的两题全是shellcode。规则定的很严,不乏py被禁赛的,不多做评论。赛时做了两题,做这类病毒分析题还是比较生疏的。正好当作学习了…
Hideit
拿到的文件打开报后门…
ida跑起来会发现,调用VirtualAlloc
加载了shellcode
跑起来会有一个
等到程序正常运行后,此时Ctrl+S能看到一个奇怪的区段TestEv1l.dll
,dump下来的程序是没有IAT的,所以干脆直接动调了。
进TestEv1l.dll
区段,手动去创建函数,能看到主逻辑如下
int __fastcall sub_2A44F9A1BB0(unsigned __int8 *a1) { __int64 v2; // rbx unsigned int v3; // er9 int v4; // esi unsigned int v5; // er10 unsigned int v6; // edi unsigned int v7; // er11 __int64 v8; // r8 __int64 v10; // [rsp+40h] [rbp-C0h] BYREF char v11; // [rsp+48h] [rbp-B8h] __int64 v12; // [rsp+50h] [rbp-B0h] BYREF int v13[4]; // [rsp+60h] [rbp-A0h] __int128 v14[2]; // [rsp+70h] [rbp-90h] BYREF char v15; // [rsp+90h] [rbp-70h] int v16[12]; // [rsp+A0h] [rbp-60h] BYREF __int64 v17; // [rsp+D0h] [rbp-30h] int v18; // [rsp+D8h] [rbp-28h] int v19; // [rsp+DCh] [rbp-24h] char v20[512]; // [rsp+E0h] [rbp-20h] BYREF char v21[560]; // [rsp+2E0h] [rbp+1E0h] BYREF int v22; // [rsp+528h] [rbp+428h] BYREF int v23; // [rsp+530h] [rbp+430h] BYREF __int64 v24; // [rsp+538h] [rbp+438h] BYREF v2 = 0i64; v15 = 0; memset(v14, 0, sizeof(v14)); v24 = 0i64; if ( !off_2A44F9A3000(-2147483646i64, aSoftwareClasse, &v24) ) { v23 = 0; memset(); v22 = 66; if ( !off_2A44F9A3008(v24, aKeysSecret, 0i64, &v23, v21, &v22) ) off_2A44F9A3020(0i64, 0i64, v21, 0xFFFFFFFFi64, v14, 260, 0i64, 0i64); } printf("First secret here:"); v10 = 0i64; v11 = 0; scanf("%s", &v10); v12 = 0i64; strcpy(&v12, &v10); v13[0] = 114; v13[1] = 514; v13[2] = 19; v13[3] = 19; memset(); v3 = HIDWORD(v12); v4 = 32; v5 = v12; v6 = HIDWORD(v12); v7 = 0; do { v7 -= 1640531527; v8 = (v7 >> 2) & 3; v5 += ((v7 ^ v3) + (v6 ^ v13[v8])) ^ (((16 * v6) ^ (v3 >> 3)) + ((v6 >> 5) ^ (4 * v3))); v3 += ((v7 ^ v5) + (v5 ^ v13[v8 ^ 1])) ^ (((16 * v5) ^ (v5 >> 3)) + ((v5 >> 5) ^ (4 * v5))); v6 = v3; --v4; } while ( v4 ); if ( v5 == 288407067 && v3 == 1668576323 ) { v17 = 0i64; v18 = v10 | ((BYTE1(v10) | (WORD1(v10) << 8)) << 8); v19 = BYTE4(v10) | ((BYTE5(v10) | (HIWORD(v10) << 8)) << 8); sub_2A44F9A1000(v16, a1); sub_2A44F9A1150(v16, v14, v20); while ( byte_2A44F9A31D0[v2] == v20[v2] ) { if ( ++v2 >= 32 ) return printf("You find last secret!"); } } return 0; }
逻辑很简单,首先是tea加密的check
#include <stdio.h> #include <stdint.h> #include <windows.h> void dec() { int key[4]; __int64 v2; // rbx unsigned int v3; // er9 int i; // esi unsigned int v5; // er10 unsigned int v6; // edi unsigned int v7; // er11 __int64 v8; // r8 key[0] = 0x72; key[1] = 0x202; key[2] = 0x13; key[3] = 0x13; v3 = 0x63747443; //v5 == 0x1130BE1B && v3 == 0x63747443 i = 32; v5 = 0x1130BE1B; v6 = v3; v7 = 0; for (int j = 0; j < 32; ++j) { v7 -= 0x61C88647; } do { v8 = (v7 >> 2) & 3; v3 -= ((v7 ^ v5) + (v5 ^ key[v8 ^ 1])) ^ (((16 * v5) ^ (v5 >> 3)) + ((v5 >> 5) ^ (4 * v5))); v6 = v3; v5 -= ((v7 ^ v3) + (v6 ^ key[v8])) ^ (((16 * v6) ^ (v3 >> 3)) + ((v6 >> 5) ^ (4 * v3))); v7 += 0x61C88647; --i; } while ( i ); printf("0x%x, 0x%x", v5, v3); printf("\n"); } int main() { dec(); return 0; } // 0x69746f64, 0x74697374
拿到明文dotitsit
下面的sub_2A44F9A1000
和sub_2A44F9A1150
就是一个ChaCha20加密
拿到key:0N3@aYI_M3l0dy_KurOm1_W_Suk1dqy0
很容易想到之前得到的dotitsit
就是nonce
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: test23.py @Time: 2021-11-14 16:06 @Desc: It's all about getting better. """ from Crypto.Cipher import ChaCha20 import struct key = b"0N3@aYI_M3l0dy_KurOm1_W_Suk1dqy0" enc = bytes.fromhex("EB8E5CA562B41C845C59FC0D433CAB20D8933313A19E39007614B504589D06B8") # print(struct.pack("2L", 0x69746f64, 0x74697374)) flag = ChaCha20.new(key=key, nonce=b"dotitsit").decrypt(enc) print(flag)
shell
进去一样是加载了shellcode,这里注意到Hook回调
int __fastcall sub_7FF712681560(_DWORD *a1) { __int64 v1; // rax DWORD64 v2; // rax __int64 v3; // rax __m128i si128; // xmm1 __int64 i; // rax __int64 j; // rax char Buffer[8]; // [rsp+30h] [rbp-58h] BYREF SIZE_T NumberOfBytesRead; // [rsp+38h] [rbp-50h] BYREF char v10[48]; // [rsp+40h] [rbp-48h] BYREF LODWORD(v1) = *a1; if ( *a1 == 0x80000003 ) { v3 = qword_7FF712685630; if ( qword_7FF712685630 ) { Context.ContextFlags = 0x10000B; if ( !GetThreadContext(hThread, &Context) ) { GetLastError(); sub_7FF712681010("GetThreadContext failed: %llx\n"); } ReadProcessMemory(hProcess, (LPCVOID)(qword_7FF712685638 + 0x40A0), v10, 0x2Aui64, &NumberOfBytesRead); si128 = _mm_load_si128((const __m128i *)"xxxxxxxxxxxxxxxx"); for ( i = 0i64; i < 32; i += 16i64 ) *(__m128i *)&v10[i] = _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v10[i]), si128); for ( j = 32i64; j < 42; ++j ) v10[j] ^= 0x78u; WriteProcessMemory(hProcess, (LPVOID)(qword_7FF712685638 + 0x40A0), v10, 0x2Aui64, &NumberOfBytesRead); v3 = qword_7FF712685630; } v1 = v3 + 1; qword_7FF712685630 = v1; goto LABEL_21; } if ( (_DWORD)v1 == 0xC000001D ) { Context.ContextFlags = 0x10000B; if ( !GetThreadContext(hThread, &Context) ) { GetLastError(); sub_7FF712681010("GetThreadContext failed: %llx\n"); } ReadProcessMemory(hProcess, (LPCVOID)(Context.Rip + 1), Buffer, 1ui64, &NumberOfBytesRead); if ( Buffer[0] == 0x12 ) { v2 = qword_7FF712685638 + 0x1035; } else { if ( Buffer[0] != 0x48 ) goto LABEL_10; v2 = qword_7FF712685638 + 0x1242; } Context.Rip = v2; LABEL_10: LODWORD(v1) = SetThreadContext(hThread, &Context); if ( !(_DWORD)v1 ) { GetLastError(); LODWORD(v1) = sub_7FF712681010("SetThreadContext failed: %llx\n"); } LABEL_21: *(_QWORD *)&dwContinueStatus = 0x10001i64; } return v1; }
上火绒剑,dump下来
没法正常解析
换种思路,CE直接附加,hook点下个断,停下来之后直接暴力搜输入的字符串
汇编搜int 3
定位到
简单分析下汇编,结合Hook的跳转,动调一下,就一个简单的位操作
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: test22.py @Time: 2021-11-14 13:21 @Desc: It's all about getting better. """ from z3 import * flag = [BitVec(f"flag[{i}]", 8) for i in range(42)] enc = list(bytes.fromhex("1E151B1C074D1F1B12174B44475812475858475F5454584259575001495153573D6B3E6F3D6D6C3E692C")) print(enc) res = [0] * 42 for i in range(42): res[i] = flag[i] ^ 0x78 for i in range(42): tmp = (res[i] & i) ^ 0xff tmp2 = (tmp & res[i]) ^ 0xff tmp3 = (tmp & i) ^ 0xff tmp4 = (tmp2 & tmp3) ^ 0xff res[i] = tmp4 sol = Solver() for i in range(42): sol.add(enc[i] == res[i]) assert sol.check() == sat mol = sol.model() print("".join([chr(mol.eval(i).as_long()) for i in flag]))
后记
shell这题,静态分析也是可以的,只不过需要自己手动修复一下偏移,patch一下花指令。相对而言此题算法相对简单,汇编量较小,侥幸而解;如若遇到大量汇编执行的情况,修复文件结构也许更具优势了吧。
发表回复