-
-
[原创]KCTF2020秋季赛 第八题 惊天阴谋 WP
-
2020-12-7 10:49 6012
-
使用工具
X64DBG, Notepad++
反调试处理
程序使用了多种调试器检测方法, 包括PEB,父进程等, 可编写脚本Patch程序检测逻辑, 如下(exe基地址为B80000):
检测流程
下面可以分析程序检测流程了(可先行恢复部分花指令混淆).
HASH用户名
RVA_50F1: HASH(UserName) ==> hash: 7A 1A B1 C6 A2 99 9F 97 97 F5 AB D5 B4 9F D9 A0
RVA_5146: HASH(hash[0-7]) ==> hash1: 51 0B 3D 82 CB 55 77 B5 DC 1A 90 82 33 C1 2A 36
RVA_519B: HASH(hash[8-F]) ==> hash2: F5 0B AB E1 20 7E 50 75 31 2B 89 60 C1 9E F1 44
SERI[0-1F]验证
1. RVA_5208: 编码算法A
2. RVA_529A: AES加密
3. RVA_52D0 - RVA_52F3: 压缩_算法A
4: RVA_53A3: 加密_算法A
5: RVA_53B3 - RVA_53D0: 与hash1做比较, 结果作为验证结果.
SERI[20-DF]验证
1. RVA_53E3: 压缩_算法B
2. RVA_53FE: 编码_算法B
3: RVA_541E: 校验算法(hash2), 结果作为验证结果
SERI[0-1F]及SERI[20-DF]皆验证通过, 则提示'注册成功', 否则提示'注册失败'.
因此, HASH算法无需分析,分别根据hash1和hash2逆算SERI[0-1F]及SERI[20-DF]即可.
算法分析
RVA_5208: 编码算法A
该算法有VM处理, 需特殊分析, 分析方法如下:
下日志断点如下(基地址为1070000):
执行算法, 算法输入为D9D2EB50, 输出为AB01CD31, 记录的日志内容如下(已处理VM及混淆日志):
可分析出正算及逆算实现如下:
//VM编码 static unsigned vm_encode_dword(unsigned d) { d = ((d << 0x12) & 0xac7d9cc9) ^ d; d = ((d << 0x06) & 0x570293D5) ^ d; d = ((d << 0x11) & 0xDFCE7FE6) ^ d; d = ((d >> 0x01) & 0x73F2EF73) ^ d; d = ((d >> 0x08) & 0x3DB7A3B4) ^ d; d = ((d >> 0x0E) & 0x5256D19E) ^ d; d = ((d >> 0x17) & 0x7C058E5D) ^ d; d = ((d >> 0x16) & 0xE8706CCD) ^ d; d = ((d << 0x06) & 0xB80040BD) ^ d; d = ((d << 0x01) & 0xCABBF58C) ^ d; d = ((d << 0x1A) & 0xA6E6880E) ^ d; d = ((d << 0x0F) & 0x2082FAEF) ^ d; d = ((d << 0x03) & 0xA58B9CA0) ^ d; d = ((d << 0x0D) & 0x1797D5D5) ^ d; d = ((d >> 0x0F) & 0xF496B3AF) ^ d; return d; } static unsigned vm_decode_dword(unsigned d) { /*暴力枚举, 约1-2分钟可算出结果(8个双字)*/ for (size_t i = 0; i < MAXUINT32; i++) { if (vm_encode_dword(i) == d) { cout << hex << setw(8) << i << " ==> " << hex << setw(8) << d << endl; return (unsigned)i; } } } static void vm_decode(unsigned char buf[0x20]) { unsigned* p = (unsigned*)buf; for (size_t i = 0; i < 8; i++) { p[i] = vm_decode_dword(p[i]); } }
RVA_529A: AES加密算法
正算及逆算实现如下:
//AES static void aes_enc(unsigned char buf[0x20]) { HCRYPTPROV provider = NULL; HCRYPTHASH hash = NULL; HCRYPTKEY key = NULL; BOOL success = false; __try { success = CryptAcquireContextA(&provider, NULL, NULL, PROV_RSA_AES, 0); if (!success) __leave; success = CryptCreateHash(provider, CALG_SHA_256, NULL, 0, &hash); if (!success) __leave; success = CryptHashData(hash, (const unsigned char*)"1_L0V3_BXS_F0REVER!", strlen("1_L0V3_BXS_F0REVER!"), 0); if (!success) __leave; success = CryptDeriveKey(provider, CALG_AES_256, hash, 0, &key); if (!success) __leave; DWORD len = 0x20; success = CryptEncrypt(key, 0, FALSE, 0, buf, &len, len); if (!success) __leave; } __finally { if (!success) cout << "aes enc failed. err = " << GetLastError() << endl; if (key) CryptDestroyKey(key); if (hash) CryptDestroyHash(hash); if (provider) CryptReleaseContext(provider, 0); } } static void aes_dec(unsigned char buf[0x20]) { HCRYPTPROV provider = NULL; HCRYPTHASH hash = NULL; HCRYPTKEY key = NULL; BOOL success = false; __try { success = CryptAcquireContextA(&provider, NULL, NULL, PROV_RSA_AES, 0); if (!success) __leave; success = CryptCreateHash(provider, CALG_SHA_256, NULL, 0, &hash); if (!success) __leave; success = CryptHashData(hash, (const unsigned char*)"1_L0V3_BXS_F0REVER!", strlen("1_L0V3_BXS_F0REVER!"), 0); if (!success) __leave; success = CryptDeriveKey(provider, CALG_AES_256, hash, 0, &key); if (!success) __leave; DWORD len = 0x20; success = CryptDecrypt(key, 0, FALSE, 0, buf, &len); if (!success) __leave; } __finally { if (!success) cout << "aes dec failed. err = " << GetLastError() << endl; if (key) CryptDestroyKey(key); if (hash) CryptDestroyHash(hash); if (provider) CryptReleaseContext(provider, 0); } }
RVA_52D0 - RVA_52F3: 压缩_算法A
算法教简单, 只实现逆算算法如下:
//膨胀 static void dilate_simple(const unsigned char bufin[0x10], unsigned char bufout[0x20]) { for (size_t i = 0; i < 0x10; i++) { bufout[i * 2 + 0] = bufin[i]; bufout[i * 2 + 1] = ((bufin[i] + 0x7f) & 0xff); } }
RVA_53A3: 加密_算法A
正算及逆算实现如下:
#define __xor_transform(c) ((c) >= 0 ? (c) * 2 : ((c) * 2) ^ 0x1b) #define __xor_untransform(c) (((c) & 1) ? (((c) ^ 0x1b) / 2 | 0x80) : (((c) / 2) & 0x7f)) //rol_xor加解密-双字 static void rol_xor_enc_dword(unsigned char buf[4]) { unsigned char b[8] = { 0 }; for (size_t i = 0; i < 4; i++) { b[i] = __xor_transform((char)buf[i]); auto m = __xor_untransform(b[i]); assert(m == buf[i]); b[4 + i] = buf[i]; } buf[0] = b[0] ^ b[1] ^ b[5] ^ b[6] ^ b[7]; buf[1] = b[1] ^ b[2] ^ b[6] ^ b[7] ^ b[4]; buf[2] = b[2] ^ b[3] ^ b[7] ^ b[4] ^ b[5] ; buf[3] = b[3] ^ b[0] ^ b[4] ^ b[5] ^ b[6]; } static void rol_xor_dec_dword(unsigned char buf[4]) { auto x_4567 = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; auto x_014 = buf[0] ^ x_4567; auto x_125 = buf[1] ^ x_4567; auto x_236 = buf[2] ^ x_4567; auto x_307 = buf[3] ^ x_4567; //暴力枚举 /*方法教笨,若哪位老师了解简便解法,请不吝赐教,感谢。*/ bool found = false; for (size_t i = 0; i < 0x100; i++) { char c0 = (i & 0xff); char c4 = __xor_untransform(c0); char c1 = x_014 ^ c0 ^ c4; char c5 = __xor_untransform(c1); char c2 = x_125 ^ c1 ^ c5; char c6 = __xor_untransform(c2); char c3 = x_236 ^ c2 ^ c6; char c7 = __xor_untransform(c3); char c0_ = x_307 ^ c3 ^ c7; if (c0 == c0_) { found = true; buf[0] = c4; buf[1] = c5; buf[2] = c6; buf[3] = c7; break; } } assert(found == true); } //rol_xor加解密 static void rol_xor_enc(unsigned char buf[0x10]) { for (size_t i = 0; i < 4; i++) { unsigned char tmp[4] = { 0 }; tmp[0] = buf[i + 0]; tmp[1] = buf[i + 4]; tmp[2] = buf[i + 8]; tmp[3] = buf[i + 12]; rol_xor_enc_dword(tmp); buf[i + 0] = tmp[0]; buf[i + 4] = tmp[1]; buf[i + 8] = tmp[2]; buf[i + 12] = tmp[3]; } } static void rol_xor_dec(unsigned char buf[0x10]) { for (size_t i = 0; i < 4; i++) { unsigned char tmp[4] = { 0 }; tmp[0] = buf[i + 0]; tmp[1] = buf[i + 4]; tmp[2] = buf[i + 8]; tmp[3] = buf[i + 12]; rol_xor_dec_dword(tmp); buf[i + 0] = tmp[0]; buf[i + 4] = tmp[1]; buf[i + 8] = tmp[2]; buf[i + 12] = tmp[3]; } } //ror加解密 static void ror_enc(unsigned char buf[0x10]) { for (unsigned char i = 0; i < 4; i++) { unsigned u = *(unsigned*)(buf + i * 4); unsigned char bits = i * 8; __asm { mov eax, u mov cl, bits ror eax, cl mov u, eax } *(unsigned*)(buf + i * 4) = u; } } static void ror_dec(unsigned char buf[0x10]) { for (unsigned char i = 0; i < 4; i++) { unsigned u = *(unsigned*)(buf + i * 4); unsigned char bits = i * 8; __asm { mov eax, u mov cl, bits rol eax, cl mov u, eax } *(unsigned*)(buf + i * 4) = u; } } //转换 static void transform(unsigned char buf[0x10]) { static const unsigned char g_transform_box[256] = { 0x63, 0x7C, 0x7E, 0x8A, 0x7F, 0x27, 0x97, 0x73, 0xFF, 0x8F, 0xD3, 0x36, 0x8B, 0x91, 0x6B, 0xA0, 0x2D, 0xDD, 0x87, 0xC1, 0x3B, 0xB2, 0x5B, 0x2E, 0x17, 0x55, 0x1A, 0xDB, 0x67, 0x50, 0x10, 0xE5, 0xD6, 0x02, 0xAE, 0x30, 0x83, 0xD7, 0x32, 0x8D, 0x4F, 0x16, 0x19, 0x71, 0xED, 0xF4, 0x57, 0xEA, 0x59, 0x06, 0x78, 0x09, 0x4D, 0xE1, 0x3F, 0xD4, 0xF3, 0x58, 0x68, 0x93, 0x48, 0x25, 0x20, 0x2C, 0x2B, 0x45, 0x41, 0xD8, 0x85, 0x5E, 0xCA, 0xBD, 0x13, 0x49, 0xAB, 0x69, 0xCB, 0x33, 0x86, 0x1C, 0x75, 0x08, 0xD9, 0xBF, 0xCC, 0xBA, 0x6A, 0x4A, 0x24, 0xF1, 0xA8, 0x77, 0x79, 0x40, 0x35, 0xE2, 0xEC, 0x96, 0xD1, 0x5F, 0xEE, 0xAD, 0xC4, 0x54, 0x74, 0xC6, 0xB0, 0x3D, 0xDF, 0xA7, 0x2A, 0xF0, 0xB9, 0x07, 0x6C, 0x21, 0xE6, 0xA2, 0x1B, 0xF2, 0x64, 0xF6, 0xD2, 0x53, 0xC2, 0x92, 0x56, 0x5C, 0x47, 0x89, 0x70, 0x4C, 0xE0, 0x84, 0xBE, 0x2F, 0x82, 0x15, 0xFD, 0xEF, 0xB7, 0x8C, 0x0C, 0x43, 0xC9, 0x9F, 0xE4, 0xA3, 0x95, 0x5D, 0x66, 0xCE, 0x37, 0x0F, 0x4B, 0x05, 0x03, 0x1E, 0xDC, 0xC0, 0xFA, 0x28, 0x44, 0xCF, 0x3E, 0x88, 0x0D, 0xFE, 0x26, 0x6D, 0x1D, 0x80, 0xE7, 0x8E, 0x65, 0xC5, 0x52, 0x12, 0xB8, 0xC3, 0x14, 0x0A, 0xFB, 0x3C, 0x6E, 0x46, 0x60, 0x00, 0xDA, 0xB5, 0x31, 0xD0, 0xA4, 0x5A, 0x0B, 0x9D, 0x3A, 0xF5, 0x7D, 0xB4, 0xA5, 0x29, 0x04, 0xEB, 0x22, 0x81, 0xF8, 0x94, 0x7A, 0xAA, 0x23, 0xBC, 0x18, 0xB6, 0xDE, 0xAC, 0xAF, 0x9E, 0x01, 0x99, 0xC7, 0x9A, 0x38, 0x1F, 0x9C, 0xE3, 0x51, 0x7B, 0x76, 0x62, 0x42, 0x61, 0xA1, 0xB1, 0x11, 0x0E, 0xCD, 0x6F, 0x39, 0xE8, 0x72, 0xF7, 0xA9, 0xA6, 0xBB, 0x34, 0xE9, 0x4E, 0xB3, 0x98, 0x9B, 0x90, 0xF9, 0xD5, 0xFC, 0xC8, }; for (size_t i = 0; i < 0x10; i++) { buf[i] = g_transform_box[buf[i]]; } } static void untransform(unsigned char buf[0x10]) { static const unsigned char g_transform_box[256] = { 0x63, 0x7C, 0x7E, 0x8A, 0x7F, 0x27, 0x97, 0x73, 0xFF, 0x8F, 0xD3, 0x36, 0x8B, 0x91, 0x6B, 0xA0, 0x2D, 0xDD, 0x87, 0xC1, 0x3B, 0xB2, 0x5B, 0x2E, 0x17, 0x55, 0x1A, 0xDB, 0x67, 0x50, 0x10, 0xE5, 0xD6, 0x02, 0xAE, 0x30, 0x83, 0xD7, 0x32, 0x8D, 0x4F, 0x16, 0x19, 0x71, 0xED, 0xF4, 0x57, 0xEA, 0x59, 0x06, 0x78, 0x09, 0x4D, 0xE1, 0x3F, 0xD4, 0xF3, 0x58, 0x68, 0x93, 0x48, 0x25, 0x20, 0x2C, 0x2B, 0x45, 0x41, 0xD8, 0x85, 0x5E, 0xCA, 0xBD, 0x13, 0x49, 0xAB, 0x69, 0xCB, 0x33, 0x86, 0x1C, 0x75, 0x08, 0xD9, 0xBF, 0xCC, 0xBA, 0x6A, 0x4A, 0x24, 0xF1, 0xA8, 0x77, 0x79, 0x40, 0x35, 0xE2, 0xEC, 0x96, 0xD1, 0x5F, 0xEE, 0xAD, 0xC4, 0x54, 0x74, 0xC6, 0xB0, 0x3D, 0xDF, 0xA7, 0x2A, 0xF0, 0xB9, 0x07, 0x6C, 0x21, 0xE6, 0xA2, 0x1B, 0xF2, 0x64, 0xF6, 0xD2, 0x53, 0xC2, 0x92, 0x56, 0x5C, 0x47, 0x89, 0x70, 0x4C, 0xE0, 0x84, 0xBE, 0x2F, 0x82, 0x15, 0xFD, 0xEF, 0xB7, 0x8C, 0x0C, 0x43, 0xC9, 0x9F, 0xE4, 0xA3, 0x95, 0x5D, 0x66, 0xCE, 0x37, 0x0F, 0x4B, 0x05, 0x03, 0x1E, 0xDC, 0xC0, 0xFA, 0x28, 0x44, 0xCF, 0x3E, 0x88, 0x0D, 0xFE, 0x26, 0x6D, 0x1D, 0x80, 0xE7, 0x8E, 0x65, 0xC5, 0x52, 0x12, 0xB8, 0xC3, 0x14, 0x0A, 0xFB, 0x3C, 0x6E, 0x46, 0x60, 0x00, 0xDA, 0xB5, 0x31, 0xD0, 0xA4, 0x5A, 0x0B, 0x9D, 0x3A, 0xF5, 0x7D, 0xB4, 0xA5, 0x29, 0x04, 0xEB, 0x22, 0x81, 0xF8, 0x94, 0x7A, 0xAA, 0x23, 0xBC, 0x18, 0xB6, 0xDE, 0xAC, 0xAF, 0x9E, 0x01, 0x99, 0xC7, 0x9A, 0x38, 0x1F, 0x9C, 0xE3, 0x51, 0x7B, 0x76, 0x62, 0x42, 0x61, 0xA1, 0xB1, 0x11, 0x0E, 0xCD, 0x6F, 0x39, 0xE8, 0x72, 0xF7, 0xA9, 0xA6, 0xBB, 0x34, 0xE9, 0x4E, 0xB3, 0x98, 0x9B, 0x90, 0xF9, 0xD5, 0xFC, 0xC8, }; for (size_t i = 0; i < 0x10; i++) { bool found = false; for (unsigned char c = 0; c <= 0xff; c++) { if (g_transform_box[c] == buf[i]) { buf[i] = c; found = true; break; } } assert(found); } } //xor加解密 static void xor_enc_dec(unsigned char buf[0x10], int iv) { const unsigned char KEY[240] = { 0x57, 0x6F, 0x20, 0x59, 0x6F, 0x6E, 0x67, 0x59, 0x75, 0x61, 0x6E, 0x20, 0x58, 0x69, 0x48, 0x75, 0x61, 0x6E, 0x20, 0x4B, 0x61, 0x6E, 0x58, 0x75, 0x6E, 0x20, 0x4C, 0x75, 0x6E, 0x54, 0x61, 0x6E, 0x9A, 0xF9, 0x0A, 0x73, 0xF5, 0x97, 0x6D, 0x2A, 0x80, 0xF6, 0x03, 0x0A, 0xD8, 0x9F, 0x4B, 0x7F, 0xCE, 0xAE, 0x49, 0x17, 0xAF, 0xC0, 0x11, 0x62, 0xC1, 0xE0, 0x5D, 0x17, 0xAF, 0xB4, 0x3C, 0x79, 0x8C, 0xB1, 0xFC, 0xB6, 0x79, 0x26, 0x91, 0x9C, 0xF9, 0xD0, 0x92, 0x96, 0x21, 0x4F, 0xD9, 0xE9, 0xCC, 0xB2, 0xD7, 0xA6, 0x63, 0x72, 0xC6, 0xC4, 0xA2, 0x92, 0x9B, 0xD3, 0x0D, 0x26, 0xA7, 0xAA, 0xBA, 0x4F, 0xE1, 0x27, 0xC3, 0x69, 0x70, 0xBB, 0x3A, 0xB9, 0xE2, 0x2D, 0x1B, 0xF6, 0x3B, 0xC4, 0x17, 0x5B, 0x44, 0x9C, 0x74, 0x29, 0x82, 0x58, 0xD6, 0xBB, 0x19, 0x8B, 0xDB, 0x9D, 0xBE, 0x21, 0xAC, 0x7E, 0xE3, 0xBE, 0x6F, 0x17, 0x93, 0x05, 0x55, 0xAE, 0x71, 0x28, 0x4E, 0x58, 0x4A, 0xEC, 0x91, 0x7F, 0xEF, 0x51, 0xE5, 0x56, 0x6D, 0x09, 0x33, 0xED, 0x74, 0x82, 0xE8, 0x70, 0xCA, 0xA3, 0x05, 0x7A, 0x2C, 0x1F, 0x6A, 0x6D, 0xBF, 0x1A, 0x3F, 0xC3, 0xCE, 0x32, 0x71, 0x9B, 0x84, 0xDE, 0x96, 0x7A, 0x0F, 0x69, 0x73, 0x2C, 0x62, 0x60, 0x40, 0xC1, 0x16, 0xE2, 0xA8, 0xB1, 0xDC, 0x41, 0x37, 0xBD, 0x69, 0x39, 0x5D, 0xD0, 0xD6, 0x23, 0x62, 0x13, 0x18, 0x11, 0x13, 0x88, 0x9C, 0xCF, 0x57, 0xF8, 0x0C, 0xFD, 0x24, 0xD4, 0x6E, 0x9D, 0x64, 0x15, 0x78, 0x7F, 0xCC, 0xA4, 0xA4, 0x3E, 0x49, 0x83, 0x49, 0x1B, 0x14, 0x53, 0x9F, 0x38, 0x76, 0x40, 0x87, 0x29, 0x65, 0xC8, 0x1B, 0xE6, }; const unsigned char* K = KEY + 0x10 * iv; for (size_t i = 0; i < 4; i++) { buf[0 + i * 4] ^= K[0 + i]; buf[1 + i * 4] ^= K[4 + i]; buf[2 + i * 4] ^= K[8 + i]; buf[3 + i * 4] ^= K[12 + i]; } } //加解密 static void encrypt(unsigned char buf[0x10]) { unsigned char buf_[0x10] = { 0 }; for (size_t i = 0; i < 4; i++) { buf_[4 * i + 0] = buf[0 + i]; buf_[4 * i + 1] = buf[4 + i]; buf_[4 * i + 2] = buf[8 + i]; buf_[4 * i + 3] = buf[12 + i]; } xor_enc_dec(buf_, 0x0); for (size_t i = 1; i < 0xe; i++) { transform(buf_); ror_enc(buf_); rol_xor_enc(buf_); xor_enc_dec(buf_, i); } transform(buf_); ror_enc(buf_); xor_enc_dec(buf_, 0xe); for (size_t i = 0; i < 4; i++) { buf[0 + i] = buf_[4 * i + 0]; buf[4 + i] = buf_[4 * i + 1]; buf[8 + i] = buf_[4 * i + 2]; buf[12 + i] = buf_[4 * i + 3]; } } static static void decrypt(unsigned char buf[0x10]) { unsigned char buf_[0x10] = { 0 }; for (size_t i = 0; i < 4; i++) { buf_[4 * i + 0] = buf[0 + i]; buf_[4 * i + 1] = buf[4 + i]; buf_[4 * i + 2] = buf[8 + i]; buf_[4 * i + 3] = buf[12 + i]; } xor_enc_dec(buf_, 0xe); ror_dec(buf_); untransform(buf_); for (int i = 0xd; i > 0; i--) { xor_enc_dec(buf_, i); rol_xor_dec(buf_); ror_dec(buf_); untransform(buf_); } xor_enc_dec(buf_, 0x0); for (size_t i = 0; i < 4; i++) { buf[0 + i] = buf_[4 * i + 0]; buf[4 + i] = buf_[4 * i + 1]; buf[8 + i] = buf_[4 * i + 2]; buf[12 + i] = buf_[4 * i + 3]; } }
RVA_53E3: 压缩_算法B
正算及逆算实现如下:
//压缩 static void compress(const unsigned char bufin[0xc0], unsigned char bufout[0x20]) { const char trans[8] = { -4, -2, 0, 2, 4, 8, 10, 20 }; char mask[0x200] = { 0 }; unsigned ib = 0; unsigned im = 0; unsigned cur = 0; unsigned bits = 0; do { while (bits < 3) { cur <<= 8; cur |= bufin[ib++]; bits += 8; } while (bits >= 3) { //取高3位 auto c = (cur >> (bits - 3)) & 7; mask[im++] = trans[c]; bits -= 3; } //最多还有3位有效位 cur &= 7; } while (im < 0x200); assert(im == 0x200 && bits == 0 && ib == 0xc0); //转换 const int KEY[4][8] = { {-1,-1,-1,1,1,-1,1,1}, {-1,-1,1,-1,1,1,1,-1}, {-1,1,-1,1,1,1,-1,-1}, {-1,1,-1,-1,-1,-1,1,-1}, }; //压缩 im = 0; for (size_t k = 0; k < 8; k++) { unsigned char bytes[4] = { 0 }; for (size_t i = 0; i < 8; i++) { int as[4] = { 0 }; for (size_t j = 0; j < 8; j++) { as[0] += KEY[0][j] * mask[im]; as[1] += KEY[1][j] * mask[im]; as[2] += KEY[2][j] * mask[im]; as[3] += KEY[3][j] * mask[im]; im++; } unsigned char b = 1 << (8 - i - 1); for (size_t m = 0; m < 4; m++) { assert(as[m] == 8 || as[m] == -8); if (as[m] == 8) { bytes[m] |= b; } } } bufout[k + 0] = bytes[0]; bufout[k + 0x8] = bytes[1]; bufout[k + 0x10] = bytes[2]; bufout[k + 0x18] = bytes[3]; } } //膨胀 static void dilate(const unsigned char bufin[0x20], unsigned char bufout[0xc0]) { const char trans[8] = { -4, -2, 0, 2, 4, 6, 8, 10 }; char mask[0x200] = { 0 }; unsigned im = 0; //转换 const int KEY[4][8] = { {-1,-1,-1,1,1,-1,1,1}, {-1,-1,1,-1,1,1,1,-1}, {-1,1,-1,1,1,1,-1,-1}, {-1,1,-1,-1,-1,-1,1,-1}, }; //压缩 im = 0; for (size_t k = 0; k < 8; k++) { unsigned char bytes[4] = { 0 }; bytes[0] = bufin[k + 0]; bytes[1] = bufin[k + 0x8]; bytes[2] = bufin[k + 0x10]; bytes[3] = bufin[k + 0x18]; for (size_t i = 0; i < 8; i++) { int as[4] = { 0 }; unsigned char b = 1 << (8 - i - 1); for (size_t m = 0; m < 4; m++) { if (bytes[m] & b) { as[m] = 8; } else { as[m] = -8; } } /* 组织数据使得【compress】执行下面的运算后as[4]数据正确即可 for (size_t j = 0; j < 8; j++) { as[0] += KEY[0][j] * mask[im]; as[1] += KEY[1][j] * mask[im]; as[2] += KEY[2][j] * mask[im]; as[3] += KEY[3][j] * mask[im]; im++; } */ //枚举遍历出符合条件的数据 size_t limit = 5; //可选8 for (size_t i1 = 0; i1 < limit; i1++) { for (size_t i2 = 0; i2 < limit; i2++) { for (size_t i3 = 0; i3 < limit; i3++) { for (size_t i4 = 0; i4 < limit; i4++) { for (size_t i5 = 0; i5 < limit; i5++) { for (size_t i6 = 0; i6 < limit; i6++) { for (size_t i7 = 0; i7 < limit; i7++) { for (size_t i8 = 0; i8 < limit; i8++) { int as_s[4] = { 0 }; char m_s[8] = { trans[i1], trans[i2] ,trans[i3] ,trans[i4] ,trans[i5] ,trans[i6] ,trans[i7] ,trans[i8] }; for (size_t j = 0; j < 8; j++) { as_s[0] += KEY[0][j] * m_s[j]; as_s[1] += KEY[1][j] * m_s[j]; as_s[2] += KEY[2][j] * m_s[j]; as_s[3] += KEY[3][j] * m_s[j]; } if (as_s[0] == as[0] && as_s[1] == as[1] && as_s[2] == as[2] && as_s[3] == as[3]) { //存在多解, 找出一组即可 memcpy(mask + im, m_s, 8); im += 8; goto leave; } } } } } } } } } leave: continue; } } assert(im == 0x200); //转储为字节数组 im = 0; unsigned ib = 0; unsigned cur = 0; unsigned bits = 0; do { while (bits < 8) { cur <<= 3; bits += 3; auto c = mask[im++]; c /= 2; c += 2; cur |= c; } while (bits >= 8) { //取高3位 auto c = (cur >> (bits - 8)) & 0xff; bufout[ib++] = c; bits -= 8; } } while (im < 0x200); assert(im == 0x200 && bits == 0 && ib == 0xc0); //测试 unsigned char compressed[0x20] = { 0 }; compress(bufout, compressed); for (size_t i = 0; i < 0x20; i++) { if (compressed[i] != bufin[i]) { DebugBreak(); } } }
RVA_53FE: 编码_算法B
算法较复杂, 内存DUMP中间值存储, 只做逆算实现, 如下:
//解同余方程 x + a ≡ val(mod 0xff8f) static long long congruence_add(unsigned short a, unsigned short val) { long long v = val; v -= a; if (v < 0) v += 0xff8f; assert(v <= MAXUINT16); return v; } //解同余方程 x - a ≡ val(mod 0xff8f) static long long congruence_sub(long long a, long long val) { long long v = val; v += a; v %= 0xff8f; /*if (v >= 0xff8f) v -= 0xff8f;*/ assert(v <= MAXUINT16); return v; } //解同余方程 x * a ≡ val(mod 0xff8f) static long long congruence_mul(long long a, long long val) { //x * 0x26c0 ≡ val(mod 0xff8f) long long v = val; while (v % a != 0) { v += 0xff8f; } assert(v <= MAXULONG32); return (unsigned short)((unsigned long)v / a); } //加密盒转换 static long long __transform_box(const unsigned char boxin[0x3700], unsigned char boxout[0x3700], int level) { //原始算法模拟 /*for (int m = 0; m < 16; m++) { long long* p = (long long*)(box + 0x370 * m); for (int n = m + 1; n < 16; n++) { long long* q = (long long*)(box + 0x370 * n); long long c = q[m]; for (int i = m; i < 17; i++) { long long s = q[i] * p[m] - p[i] * c; s %= 0xff8f; if (s < 0) s += 0xff8f; q[i] = s; } } }*/ long long c = 0; memcpy(boxout, boxin, 0x3700); for (int m = 0; m < level; m++) { long long* p = (long long*)(boxout + 0x370 * m); for (int n = m + 1; n < 16; n++) { long long* q = (long long*)(boxout + 0x370 * n); c = q[m]; for (int i = m; i < 17; i++) { long long s = q[i] * p[m] - p[i] * c; s %= 0xff8f; if (s < 0) s += 0xff8f; q[i] = s; } } } return c; } //解码 static void decode(const unsigned char bufin[16], unsigned short bufout[16]) { // unsigned char *box = new unsigned char[0x3700]; unsigned char *box2 = new unsigned char[0x3700]; if (!box || !box2) { cout << "error: alloc memory failed." << endl; return; } //读取缓存的计算数据 ifstream f("1.bin", ifstream::binary | ifstream::in); if (!f || !f.read((char*)box, 0x3700)) { cout << "error: read file data failed." << endl; delete[]box; delete[]box2; return; } f.close(); //计算中间值 unsigned short key[16] = { 0xd6dc, 0xd613, 0x66cd, 0x332e, 0x9932, 0x5db8, 0x1731, 0xacde, 0x3c5a, 0x4d87, 0xbeb1, 0xb5bb, 0x125f, 0x2526, 0xdc64, 0x26c0 }; unsigned short mid[16] = { 0 }; for (int i = 15; i >= 0; i--) { mid[i] = (unsigned short)congruence_mul(key[i], bufin[i]); } for (int m = 0; m < 16; m++) { long long* p = (long long*)(box + 0x370 * m); long long s = mid[m]; for (int i = 15; i >= m + 1; i--) { assert(p[i] <= MAXUINT16); long long ll = p[i] * bufin[i]; s = congruence_sub(ll, s); //cout << hex << s << endl; } mid[m] = (unsigned short)s; //cout << hex << s << " " << p[16] << endl; } //计算原始值 f.open("0.bin", ifstream::binary | ifstream::in); if (!f || !f.read((char*)box, 0x3700)) { cout << "error: read file data failed." << endl; delete[]box; return; } f.close(); for (int i = 0; i < 16; i++) { long long m = mid[i]; long long last = 0; if (i > 0) last = mid[i - 1]; for (int lev = i; lev > 0; lev--) { auto c = __transform_box(box, box2, lev - 1); long long* p = (long long*)(box2 + 0x370 * (lev - 1)); long long* q = (long long*)(box2 + 0x370 * i); m = congruence_sub(mid[lev - 1] * q[lev - 1], m); m = congruence_mul(p[lev - 1], m); last = m; } bufout[i] = (unsigned short)m; } delete[]box; delete[]box2; }
RVA_541E: 校验算法(hash2)
校验加解密算法实现如下:
//校验 static void encrypt_verify(unsigned char buf1[16], unsigned char buf2[16]) { unsigned char k1[16] = { 0x1A, 0x1C, 0x11, 0x18, 0x08, 0x0C, 0x19, 0x01, 0x20, 0x0B, 0x07, 0x10, 0x17, 0x02, 0x1D, 0x15, }; unsigned char k2[16] = { 0x15, 0x17, 0x16, 0x14, 0x13, 0x0C, 0x04, 0x12, 0x03, 0x06, 0x10, 0x0E, 0x0A, 0x18, 0x1C, 0x0F, }; unsigned char k3[16] = { 0x03, 0xEE, 0xEC, 0x11, 0x14, 0x0E, 0x05, 0x0C, 0x03, 0xED, 0xF7, 0x05, 0x00, 0xF6, 0x00, 0xE7, }; unsigned char out[16] = { 0 }; for (size_t i = 0; i < 16; i++) { unsigned char c = buf1[i]; c ^= k2[i]; unsigned char r = (unsigned char)(k1[i] & 7); __asm { mov al, c mov cl, r ror al, cl mov c, al } c += (k3[i] - buf2[i]); out[i] = c; } } static void decrypt_verify(unsigned char buf[16]) { const unsigned char act[16] = { 0x15, 0x09, 0x0C, 0x1F, 0x1C, 0x13, 0x16, 0x19, 0x1D, 0x03, 0x10, 0x0F, 0x01, 0x02, 0x1E, 0x06, }; unsigned char k1[16] = { 0x1A, 0x1C, 0x11, 0x18, 0x08, 0x0C, 0x19, 0x01, 0x20, 0x0B, 0x07, 0x10, 0x17, 0x02, 0x1D, 0x15, }; unsigned char k2[16] = { 0x15, 0x17, 0x16, 0x14, 0x13, 0x0C, 0x04, 0x12, 0x03, 0x06, 0x10, 0x0E, 0x0A, 0x18, 0x1C, 0x0F, }; unsigned char k3[16] = { 0x03, 0xEE, 0xEC, 0x11, 0x14, 0x0E, 0x05, 0x0C, 0x03, 0xED, 0xF7, 0x05, 0x00, 0xF6, 0x00, 0xE7, }; //unsigned char out[16] = { 0 }; for (size_t i = 0; i < 16; i++) { unsigned char c = act[i]; c -= (k3[i] - buf[i]); unsigned char r = (unsigned char)(k1[i] & 7); __asm { mov al, c mov cl, r rol al, cl mov c, al } c ^= k2[i]; buf[i] = c; } }
验证结果
void alg_1(unsigned char seri[0x20]) { unsigned char seri_d[16] = { 0x51, 0x0B, 0x3D, 0x82, 0xCB, 0x55, 0x77, 0xB5, 0xDC, 0x1A, 0x90, 0x82, 0x33, 0xC1, 0x2A, 0x36, }; decrypt(seri_d); cout << "STEP_1A:" << endl; for (size_t i = 0; i < 16; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_d[i] << " " << flush; } cout << endl; unsigned char seri_dl[0x20] = { 0 }; dilate(seri_d, seri_dl); cout << "STEP_2A:" << endl; for (size_t i = 0; i < 0x20; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush; } cout << endl; aes_dec(seri_dl); cout << "STEP_3A:" << endl; for (size_t i = 0; i < 0x20; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush; } cout << endl; vm_decode(seri_dl); cout << "STEP_4A:" << endl; for (size_t i = 0; i < 0x20; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_dl[i] << " " << flush; } cout << endl; memcpy(seri, seri_dl, 0x20); } void alg_2(unsigned char seri[0xc0]) { unsigned char seri_d[16] = { 0xF5, 0x0B, 0xAB, 0xE1, 0x20, 0x7E, 0x50, 0x75, 0x31, 0x2B, 0x89, 0x60, 0xC1, 0x9E, 0xF1, 0x44, }; decrypt(seri_d); cout << "STEP_1B:" << endl; for (size_t i = 0; i < 16; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_d[i] << " " << flush; } cout << endl; unsigned short seri_s[16] = { 0 }; decode(seri_d, seri_s); cout << "STEP_2B:" << endl; for (size_t i = 0; i < 16 * 2; i++) { cout << setw(2) << setfill('0') << right << hex << (int)((unsigned char*)seri_s)[i] << " " << flush; } cout << endl; unsigned char seri_c[0xc0] = { 0 }; dilate((unsigned char*)seri_s, seri_c); cout << "STEP_3B:" << endl; for (size_t i = 0; i < 0xc0; i++) { cout << setw(2) << setfill('0') << right << hex << (int)seri_c[i] << " " << flush; if ((i + 1) % 0x20 == 0) { cout << endl; } } cout << endl; memcpy(seri, seri_c, 0xc0); } int main() { unsigned char seri[0xe0] = { 0 }; alg_2(seri + 0x20); alg_1(seri); ostringstream oss; for (size_t i = 0; i < 0xe0; i++) { oss << setw(2) << hex << setfill('0') << right << (int)seri[i] << flush; } cout << "INPUT:" << endl << oss.str() << endl; cin.get(); return 0; }
[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界