逆向_base64_rc4_----笔记

新人…
学校比赛,没什么经验,上去见见世面

某公司的月赛题 资源就不放了,只是当笔记

Ida打开 有点小陷阱 巧妙的堆栈运用导致载入ida分析不了 得不到函数的边界

比较幸运win32的程序
od打开

走一遍流程感受下

00AD12E7   .  52            push edx
00AD12E8   .  68 C821AD00   push 5ba358a4.00AD21C8                   ; /%50s
00AD12ED   .  FF15 A420AD00 call dword ptr ds:[<&MSVCR100.scanf>]    ; \scanf
00AD12F3   .  83C4 24       add esp,0x24
00AD12F6   .  50            push eax
00AD12F7   .  33C0          xor eax,eax
00AD12F9   .  74 03         je short 5ba358a4.00AD12FE
00AD12FB   .  83C4 1E       add esp,0x1E
00AD12FE   >  58            pop eax                                  ;  5ba358a4.00AD21B8
00AD12FF   .  8D45 C8       lea eax,dword ptr ss:[ebp-0x38]
00AD1302   .  8D50 01       lea edx,dword ptr ds:[eax+0x1]
00AD1305   >  8A08          mov cl,byte ptr ds:[eax]
00AD1307   .  40            inc eax
00AD1308   .  84C9          test cl,cl
00AD130A   .^ 75 F9         jnz short 5ba358a4.00AD1305
00AD130C   .  2BC2          sub eax,edx                              ;  计算长度 33
00AD130E   .  83F8 21       cmp eax,0x21
00AD1311   .  75 7D         jnz short 5ba358a4.00AD1390
00AD1313   .  8D45 C8       lea eax,dword ptr ss:[ebp-0x38]
00AD1316   .  E8 45FEFFFF   call 5ba358a4.00AD1160
00AD131B   .  8BF0          mov esi,eax
00AD131D   .  8D85 C8FEFFFF lea eax,dword ptr ss:[ebp-0x138]         ;  对比 flag{this_is_not_the_flag_hahaha}
00AD1323   .  8D50 01       lea edx,dword ptr ds:[eax+0x1]
00AD1326   >  8A08          mov cl,byte ptr ds:[eax]
00AD1328   .  40            inc eax
00AD1329   .  84C9          test cl,cl                               ;  计算对比的长度
00AD132B   .^ 75 F9         jnz short 5ba358a4.00AD1326
00AD132D   .  2BC2          sub eax,edx
00AD132F   .  50            push eax
00AD1330   .  8D85 C8FEFFFF lea eax,dword ptr ss:[ebp-0x138]         ;  对比长度 和对比地址 此时esi为输入变化后的
00AD1336   .  50            push eax
00AD1337   .  8DBD C8FDFFFF lea edi,dword ptr ss:[ebp-0x238]
00AD133D   .  E8 BEFCFFFF   call 5ba358a4.00AD1000
00AD1342   .  8BC6          mov eax,esi                              ;  5ba358a4.00AD21B6
00AD1344   .  83C4 08       add esp,0x8
00AD1347   .  8D50 01       lea edx,dword ptr ds:[eax+0x1]
00AD134A   .  8D9B 00000000 lea ebx,dword ptr ds:[ebx]
00AD1350   >  8A08          mov cl,byte ptr ds:[eax]
00AD1352   .  40            inc eax
00AD1353   .  84C9          test cl,cl
00AD1355   .^ 75 F9         jnz short 5ba358a4.00AD1350
00AD1357   .  2BC2          sub eax,edx                              ;  计算变化后的长度
00AD1359   .  50            push eax                                 ;  长度
00AD135A   .  56            push esi                                 ;  第一次变化结果
00AD135B   .  8D85 C8FDFFFF lea eax,dword ptr ss:[ebp-0x238]
00AD1361   .  E8 7AFDFFFF   call 5ba358a4.00AD10E0                   ;  第二次变化的函数
00AD1366   .  83C4 08       add esp,0x8
00AD1369   .  33C0          xor eax,eax
00AD136B   .  81EE 0421AD00 sub esi,5ba358a4.00AD2104
00AD1371   >  8A8C06 0421AD>mov cl,byte ptr ds:[esi+eax+0xAD2104]    ;  esi 在前面变化 索引着数组
00AD1378   .  3A88 0421AD00 cmp cl,byte ptr ds:[eax+0xAD2104]
00AD137E      75 23         jnz short 5ba358a4.00AD13A3
00AD1380   .  40            inc eax
00AD1381   .  83F8 2C       cmp eax,0x2C                             ;  数组长度为44  正好是变化后的长度
00AD1384   .^ 7C EB         jl short 5ba358a4.00AD1371
00AD1386   .  68 7C21AD00   push 5ba358a4.00AD217C                   ;  Congratulation!!!!!!\n
00AD138B   .  FFD3          call ebx                                 ;  msvcr100.printf
00AD138D   .  83C4 04       add esp,0x4
00AD1390   >  8B4D FC       mov ecx,dword ptr ss:[ebp-0x4]
00AD1393   .  5F            pop edi                                  ;  5ba358a4.00AD21B8
00AD1394   .  5E            pop esi                                  ;  5ba358a4.00AD21B8
00AD1395   .  33CD          xor ecx,ebp
00AD1397   .  33C0          xor eax,eax
00AD1399   .  5B            pop ebx                                  ;  5ba358a4.00AD21B8
00AD139A   .  E8 0D000000   call 5ba358a4.00AD13AC
00AD139F   .  8BE5          mov esp,ebp
00AD13A1   .  5D            pop ebp                                  ;  5ba358a4.00AD21B8
00AD13A2   .  C3            retn
00AD13A3   >  6A 00         push 0x0                                 ; /status = 0x0
00AD13A5   .  FF15 9820AD00 call dword ptr ds:[<&MSVCR100.exit>]     ; \exit
00AD13AB   .  CC            int3
00AD13AC   $  3B0D 0030AD00 cmp ecx,dword ptr ds:[0xAD3000]
00AD13B2   .  75 02         jnz short 5ba358a4.00AD13B6
00AD13B4   .  F3:           prefix rep:
00AD13B5   .  C3            retn


od走一遍过下来暂时得到的结论

两个关键函数  1 2;
1:把输入的字符串33字节 经过运算重新 申请空间 变成 44字节的字符串  
2:  把44字节字符串 再次运算 变成 44字节的其他字符串 设为res

于是再次ida找到那两个函数 看看能不能看伪代码(能简单的就不要搞复杂)
特别棒可以得到伪代码

这是第一个关键函数

char *__usercall sub_401160@<eax>(const char *a1@<eax>)
{
  const char *v1; // ebx
  signed int v2; // esi
  int v3; // edi
  unsigned int v4; // eax
  char *v5; // ecx
  unsigned int v6; // edx
  signed int v7; // ecx
  int v8; // esi
  unsigned int v9; // eax
  signed int v10; // ecx
  bool v11; // zf
  signed int v13; // [esp+Ch] [ebp-14h]
  const char *v14; // [esp+10h] [ebp-10h]
  char *v15; // [esp+14h] [ebp-Ch]
  char Dest[4]; // [esp+18h] [ebp-8h]
  char *v17; // [esp+1Ch] [ebp-4h]

  v1 = a1;
  v2 = strlen(a1) / 3 + (strlen(a1) % 3 != 0);
  v15 = (char *)malloc(4 * v2 + 1);
  memset(v15, 0, 4 * v2 + 1);
  if ( v2 > 0 )
  {
    v17 = v15;
    v14 = v1;
    v13 = v2;
    do
    {
      v3 = 0;
      *(_DWORD *)Dest = 0;
      strncpy(Dest, v1, 3u);
      v4 = 0;
      v5 = &Dest[strlen(Dest) + 1];
      v6 = v5 - &Dest[1];
      if ( v5 != &Dest[1] )
      {
        v7 = 16;
        do
        {
          v8 = Dest[v4++] << v7;
          v7 -= 8;
          v3 |= v8;
        }
        while ( v4 < v6 );
      }
      v9 = 0;
      v10 = 18;
      do
      {
        if ( v6 + 1 <= v9 )
          v17[v9] = 61;
        else
          v17[v9] = byte_402138[(v3 >> v10) & 0x3F];
        v10 -= 6;
        ++v9;
      }
      while ( v10 > -6 );
      v17 += 4;
      v1 = v14 + 3;
      v11 = v13-- == 1;
      v14 += 3;
    }
    while ( !v11 );
  }
  return v15;
}

这是第二个关键函数

int __usercall sub_4010E0@<eax>(int result@<eax>, int a2, unsigned int a3)
{
  int v3; // ecx
  int v4; // esi
  unsigned int v5; // edi
  unsigned __int8 v6; // dl

  v3 = 0;
  v4 = 0;
  v5 = 0;
  if ( a3 )
  {
    do
    {
      v3 = (v3 + 1) % 256;
      v6 = *(_BYTE *)(v3 + result);
      v4 = (v6 + v4) % 256;
      *(_BYTE *)(v3 + result) = *(_BYTE *)(v4 + result);
      *(_BYTE *)(v4 + result) = v6;
      *(_BYTE *)(v5++ + a2) ^= *(_BYTE *)((v6 + *(unsigned __int8 *)(v3 + result)) % 256 + result);
    }
    while ( v5 < a3 );
  }
  return result;
}

由于我是新手,对已有的加密算法还不太敏感于是乎。。。
手动转成了C/C++代码

第一个函数 (简化版)转换
(把输入的33个字符运算转换为新的44个字符)

void first(char* orgin_buf) {


	char beiBuf[] = "ABCDEFGHIJSTUVWKLMNOPQRXYZabcdqrstuvwxefghijklmnopyz0123456789+/";

	char *v5;
	int v6;
	int i = 0;
	int k = 0;
	char change_buf[45] = { 0 };
	bool nbk = false;
	int v13 = 11;
	while (!nbk)
	{
		int v3 = 0;
		char Change4Buf[4] = { 0 };
		strncpy(Change4Buf, &orgin_buf[i], 3);
		v5 = Change4Buf + 4;

			if (v5 != &Change4Buf[1])
			{
				int bit = 16;

				for (int i_ = 0; i_<3; i_++)
				{
					int temp = Change4Buf[i_] << bit;
					bit -= 8;
					v3 |= temp;
				}
			}

		for (int i_ = 18, j_ = 0; i_>-6; i_ -= 6, j_++) {

			if (4 <= j_)
				change_buf[k + j_] = 61;
			else
				change_buf[k + j_] = beiBuf[(v3 >> i_) & 0x3F];
		}

		i += 3;
		k += 4;
		nbk = (v13 == 1);
		v13--;
	}

	cout << change_buf << endl;

}

第二个函数 (简化版转换,已经把用到的data段初始化好数据直接cp了)
其中 first_addr 这个地址里的数据由第一个函数 得到的44字符

void  Eff4010e0(char* first_addr)
{
	char result[] = "\x66\x32\xCA\xA0\xBF\x98\x2D\x76\xF1\x59\x2A\x4A\xF4\x30\xAD\xD2"
		"\x1D\x02\xD8\x23\x89\x5D\x83\x38\x09\xF2\x74\x65\x40\x19\xC6\xDD"
		"\x18\xD3\x8F\x6C\x8B\xC0\xC5\x54\x2E\x81\x10\xC4\x26\x56\x5F\x53"
		"\x80\x43\x27\x62\xEA\x3D\xE6\x00\xE7\xB7\x50\x94\x90\x4C\x3F\x9D"
		"\x07\xE0\xA3\x9C\x4E\x0F\x9F\xFE\x5B\x8E\xDE\x88\x72\x2F\xC1\x67"
		"\x31\x70\x8D\xFD\xBE\x64\xC3\xBD\x6B\x7A\xCF\x0C\x34\x1F\x6F\x01"
		"\xF0\x7C\x5E\xA4\x1E\x49\x8C\x75\x1C\xE3\x20\x48\x28\x79\xA5\x7F"
		"\xF5\xEC\x4F\x78\x58\x11\xF7\xCD\x91\x13\xFC\xB8\x2C\x04\xEE\xD5"
		"\x08\x44\xA9\xE1\xB1\x42\x84\x29\xA7\x47\x97\x7E\xE8\xB3\x60\x0B"
		"\xF9\x4B\x3C\x77\x17\x03\x82\x69\x87\xD4\x95\x1A\x33\x25\x6E\xCC"
		"\xD6\xBB\x99\xB0\x85\x41\xB2\x0D\xDB\x35\x3B\x5C\xF8\xED\x9E\xA6"
		"\x96\x39\x63\x0A\x1B\x93\x21\x46\x12\xD0\xB4\x22\x51\xC9\x61\xD1"
		"\x2B\xAA\x45\x06\x05\xCE\xFA\x92\x68\xAB\x36\xDA\xC8\xE2\x37\xD9"
		"\xA2\x5A\xD7\x6A\xB5\xFF\xE9\xBA\x52\x15\xF6\xBC\x9A\xB6\xEF\x6D"
		"\xCB\x4D\xAE\xE4\xA1\xAC\xEB\x0E\x71\x7B\xF3\x24\xC2\xFB\x7D\x86"
		"\x55\xAF\x3A\xDF\x3E\x14\xB9\x9B\x16\xDC\x73\x57\xE5\xC7\x8A\xA8"
		"\x66";


	int i = 0;
	int v3 = 0; // ecx
	int v4 = 0; // esi
	unsigned char v6; // dl

	for (i; i<44; i++) {

		v3 = (v3 + 1) % 256;
		v6 =  result[v3];
		v4 = (v6 + v4) % 256;
		result[v3] = result[v4];
		result[v4] = v6;

		unsigned char t = result[v3];
		unsigned char temp = (v6 + t);
		temp = temp % 256;
		first_addr[i] ^= result[temp];
	}

	cout << first_addr << endl;

	return;
}

分析发现
第二个函数下来后的结果设为res,res的44位 必须 和
byte_402104 44位一致
“\x20\xC3\x1A\xAE\x97\x3C\x7A\x41\xDE\xF6\x78\x15\xCB\x4B\x4C\xDC”
“\x26\x55\x8B\x55\xE5\xE9\x55\x75\x40\x3D\x82\x13\xA5\x60\x13\x3B”
“\xF5\xD8\x19\x0E\x47\xCF\x5F\x5E\xDE\x9D\x14\xBD”

又发现第二个函数是xor 所以直接把这段44长度的数据带入 自己写的Eff4010e0()函数

得到字符串
ZeptZ3l5UHQra25nd19yYzMrYR5wX2Jtc2P2VF9gYNM9

在分析的过程中有怀疑第一个函数是base64编码,
但是 程序里把
000000000000000000000000000000000
编码为:
UDAoUDAoUDAoUDAoUDAoUDAoUDAoUDAoUDAoUDAoUDAo
正确的结果应该为:MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw

所以怀疑第一个函数是base64加了一点点手脚,
于是 又有怀疑又有源码的我
char beiBuf[] = “ABCDEFGHIJSTUVWKLMNOPQRXYZabcdqrstuvwxefghijklmnopyz0123456789+/”;
感觉这个备选字符有问题
按26个字母的顺序摆摆正

	//char beiBuf[] = "ABCDEFGHIJSTUVWKLMNOPQRXYZabcdqrstuvwxefghijklmnopyz0123456789+/";
	char beiBuf[] =   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

发现 这个函数出来的结果正式base64 所以确定动了手脚的地方就是这;
于是 只要把

"ZeptZ3l5UHQra25nd19yYzMrYR5wX2Jtc2P2VF9gYNM9"

转换成正确的base64 即可解码得到flag

	char beiBuf2[] = "ABCDEFGHIJSTUVWKLMNOPQRXYZabcdqrstuvwxefghijklmnopyz0123456789+/"; //错误
	char beiBuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; //正确

	char check[] = "ZeptZ3l5UHQra25nd19yYzMrYR5wX2Jtc2P2VF9gYNM9";


	for (int i = 0; i < strlen(check); i++)
	{
		
		int index = 0;
		for (int j = 0; j < strlen(beiBuf2); j++)
		{
			if (beiBuf2[j] == check[i])
			{
				index = j;
				break;
			}
		}

		cout << beiBuf[index];
	
	}

	cout << endl;

正确的结果

ZmxhZ3t5MHVfa25vd19yYzRfYW5kX2Jhc2U2NF9oYSR9

然后解码base64就是flag

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值