首页
社区
课程
招聘
[原创]KCTF2020秋季赛 第八题 惊天阴谋 WP
2020-12-7 10:49 6012

[原创]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世界

最后于 2020-12-7 11:41 被Anakin Stone编辑 ,原因:
上传的附件:
收藏
点赞4
打赏
分享
最新回复 (1)
雪    币: 192
活跃值: (19)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
奥古斯丁 2020-12-7 18:23
2
0
游客
登录 | 注册 方可回帖
返回