swpuctf—re1

re1其实是一个对二进制上的运算,就是将每个字节的二进制分为三部分——高位0+1、低位0与中间值,并记录下三部分各自的大小,再以四字节为一组进行重新填充得出验证码
swpuctf—re1_第1张图片
如上图示例,00111100被分为三部分后

高位:001
中位:111
低位: 00

这时将进行重新组合再拼接,生成两组数,既高位组与低位组拼接位一组,中间位为一组

组一:111
组二:00100

记录下所有数据并生成结构体

	typedef struct _Data_Structure
	{
		char g_flag[4];			//flag
		byte num[4];			//中间位大小
		byte high_num[4];		//高位大小
		byte low_num[4];		//低位大小
		byte mod[4];			//组一
		byte merge[4];			//组二
	}Data_Structure, * PData_Structure;

相信师傅们都知道flag的格式是^swpuctf\{\w{4}\-\w{4}\-\w{4}\-\w{4}\-\w{4}\},将每四位设置为一组进行了上述分解后进行最后的填充操作
申请一个40byte空间,同样分为两部分,其中低20字节存放重组后的flag,高20字节存放高低位大小
swpuctf—re1_第2张图片
将mod填充在高位,merge填充在低位,重新组合成新的一组四字节
swpuctf—re1_第3张图片
将高低位各自大小重新组合为一字节
在写逆算法的时候就可以通过从20位大小段中提取出各个字节高低位大小,再结合20位数据段中高位填充mod与低位填充merge的特点还原flag
推荐师傅们在解题的时候,找到结构体位置,通过观察二进制的变化,更能理清思路、发现规律

int main()
{
	byte ptable[40] = { 0x8, 0xea, 0x58, 0xde, 0x94, 0xd0, 0x3b, 0xbe, 0x88, 0xd4, 0x32, 0xb6, 0x14, 0x82, 0xb7, 0xaf, 0x14, 0x54, 0x7f, 0xcf, 0x20, 0x20, 0x30, 0x33, 0x22, 0x33, 0x20, 0x20, 0x20, 0x30, 0x20, 0x32, 0x30, 0x33, 0x22, 0x20, 0x20, 0x20, 0x24, 0x20 };
	byte flag[20] = { 0 };
	byte high[20] = { 0 };
	byte low[20] = { 0 };
	byte mod[20] = { 0 };
	byte m[20] = { 0 };
	byte bit;
	byte* table;
	DWORD num = 0;

	for (int i = 0; i < 20; i++)
	{
		high[i] = ptable[i + 20] >> 4;
		low[i] = ptable[i + 20] << 4;
		low[i] >>= 4;
		mod[i] = 8 - high[i] - low[i];
	}

	table = ptable;
	for (int i = 0; i < 5; i++)
	{
		int  n = 32, sum = 0;
		for (int j = 0; j < 4; j++)
		{
			bit = 1;
			n =32 - mod[i * 4 + j];
			num = *(DWORD*)table << sum;
			m[i * 4 + j] = num >> n;
			sum += mod[i * 4 + j];

			bit <<= (8 - high[i * 4 + j]);
			flag[i * 4 + j] = (m[i * 4 + j] << low[i * 4 + j]) | bit;
		}
		table += 4;
	}

	for (int k = 0; k < 20; k++)
	{
		printf("%c", flag[k]);
	}

	system("pause");
	return 0;
}

ps:其实在这道题中我还写了虚函数hook,为了防止师傅们通过IDA纯看的方式解题,不知道师傅们发现没有

比赛出题并非我的本意,技术交流才是正真的含义,希望对师傅们有所帮助,同时也希望能与各位师傅进行更多的交流

你可能感兴趣的:(CTF)