逆向----有趣的位操作---笔记

在这里插入图片描述

结构很简单,
一个关键函数

伪代码

int __cdecl check_password(char *input)
{
  void *v1; // esp
  int v2; // eax
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int v6; // eax
  int v7; // eax
  int v8; // eax
  int v9; // eax
  int v10; // eax
  int v11; // eax
  int v13; // [esp+0h] [ebp-48h]
  char *s; // [esp+Ch] [ebp-3Ch]
  int v15; // [esp+10h] [ebp-38h]
  int v16; // [esp+14h] [ebp-34h]
  int i; // [esp+18h] [ebp-30h]
  int v18; // [esp+1Ch] [ebp-2Ch]
  size_t n; // [esp+20h] [ebp-28h]
  int v20; // [esp+24h] [ebp-24h]
  char *s1; // [esp+28h] [ebp-20h]
  int v22; // [esp+2Ch] [ebp-1Ch]
  int v23; // [esp+30h] [ebp-18h]
  int v24; // [esp+34h] [ebp-14h]
  unsigned int v25; // [esp+38h] [ebp-10h]
  unsigned int v26; // [esp+3Ch] [ebp-Ch]

  s = input;
  v26 = __readgsdword(0x14u);
  v18 = strlen(input);
  n = 4 * ((v18 + 2) / 3);
  v20 = 4 * ((v18 + 2) / 3);
  v1 = alloca(16 * ((4 * ((v18 + 2) / 3) + 16) / 0x10u));
  s1 = (char *)&v13;
  v15 = 0;
  v16 = 0;
  while ( v15 < v18 )
  {
    if ( v15 >= v18 )
    {
      v3 = 0;
    }
    else
    {
      v2 = v15++;
      v3 = (unsigned __int8)s[v2];
    }
    v22 = v3;
    if ( v15 >= v18 )
    {
      v5 = 0;
    }
    else
    {
      v4 = v15++;
      v5 = (unsigned __int8)s[v4];
    }
    v23 = v5;
    if ( v15 >= v18 )
    {
      v7 = 0;
    }
    else
    {
      v6 = v15++;
      v7 = (unsigned __int8)s[v6];
    }
    v24 = v7;
    v25 = (v23 << 8) + (v22 << 16) + v7;
    v8 = v16++;
    s1[v8] = alphabet[(v25 >> 18) & 0x3F];
    v9 = v16++;
    s1[v9] = alphabet[(v25 >> 12) & 0x3F];
    v10 = v16++;
    s1[v10] = alphabet[(v25 >> 6) & 0x3F];
    v11 = v16++;
    s1[v11] = alphabet[v25 & 0x3F];
  }
  for ( i = 0; mod[v18 % 3] > i; ++i )
    s1[n - 1 - i] = 61;
  return strncmp(s1, "cGljb0NURntiQXNFXzY0X2VOQ29EaU5nX2lTX0VBc1lfMjk1ODA5OTN9", n);
}

简化后

char alphabet[] = "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4A\x4B\x4C\x4D\x4E\x4F"
"\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5A\x61\x62\x63\x64"
"\x65\x66\x67\x68\x69\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x73"
"\x74\x75\x76\x77\x78\x79\x7A\x30\x31\x32\x33\x34\x35\x36\x37"
"\x38\x39\x2B\x2F";

int mod[3] = { 0,2,1 };


int getIndex(char c)
{
	int len = strlen(alphabet);
	for (int i = 0; i < len; i++)
	{
		if (alphabet[i] == c)
		{
			return i;
		}
	}
	return -1;
}

int __cdecl check_password(char *input)
{
	int v13;
	char *input_back;
	int j;
	int v16;
	int len;
	size_t n;
	char *s1;
	int v22;
	int v23;
	int v24;
	unsigned int v25;


	input_back = input;
	len = strlen(input);
	s1 = (char *)&v13;
	j = 0;
	v16 = 0;

	while (j < len)
	{
		if (j >= len)
		{
			v22 = 0;
		}
		else
		{
			v22 = (unsigned __int8)input_back[j];
			j++;
		}

		if (j >= len)
		{
			v23 = 0;
		}
		else
		{
			v23 = (unsigned __int8)input_back[j];
			j++;
		}
		if (j >= len)
		{
			v24 = 0;
		}
		else
		{
			v24 = (unsigned __int8)input_back[j];
			j++;
		}

		v25 = (v23 << 8) + (v22 << 16) + v24;

		s1[v16] = alphabet[(v25 >> 18) & 0x3F];
		v16++;
		s1[v16] = alphabet[(v25 >> 12) & 0x3F];
		v16++;
		s1[v16] = alphabet[(v25 >> 6) & 0x3F];
		v16++;
		s1[v16] = alphabet[v25 & 0x3F];
		v16++;
	}

					//0 2 1
	n = 4 * ((len + 2) / 3);
	for (int i = 0; mod[len % 3] > i; ++i)
		s1[n - 1 - i] = 61;
	return strncmp(s1, "cGljb0NURntiQXNFXzY0X2VOQ29EaU5nX2lTX0VBc1lfMjk1ODA5OTN9", n);
	//cout << input << endl;
	return true;
}


重点分析一下这段代码

		v25 = (v23 << 8) + (v22 << 16) + v24;

		s1[v16] = alphabet[(v25 >> 18) & 0x3F];
		v16++;
		s1[v16] = alphabet[(v25 >> 12) & 0x3F];
		v16++;
		s1[v16] = alphabet[(v25 >> 6) & 0x3F];
		v16++;
		s1[v16] = alphabet[v25 & 0x3F];

其实v22-v24 取了输入字符串的3个字符,
接着就开始了位操作,分析下来
v25 = (v23 << 8) + (v22 << 16) + v24; 这行
使得v25的32个bit分布如下

           v22	      v23   	v24
00000000 11111111  11111111    11111111

这七行
s1[v16] = alphabet[(v25 >> 18) & 0x3F];
v16++;
s1[v16] = alphabet[(v25 >> 12) & 0x3F];
v16++;
s1[v16] = alphabet[(v25 >> 6) & 0x3F];
v16++;
s1[v16] = alphabet[v25 & 0x3F];

使得s1连续的四个字符取到了alphabet字母表的四个字符。
且v25分别取不同的bit

讲述起来比较麻烦,分析一下就知道了

假设原来是这样
00000000 11111111  11111111    11111111
>>18
00000000 111111
00000000 00000000 00000000 00111111


>>12
00000000 11111111  1111
00000000 00000000 00001111 11111111


>>6
00000000 11111111  11111111    11
00000000 00000011 11111111 11111111

然后都去 与3f

还原思路

第一个数 左移18
第二个数 左移12
第三个数 左移6
第四个数 | 第三个数 |第二|第一个数

先找到cGljb0NURntiQXNFXzY0X2VOQ29EaU5nX2lTX0VBc1lfMjk1ODA5OTN9这个在字母表中的索引

	/*char cmp[] = "cGljb0NURntiQXNFXzY0X2VOQ29EaU5nX2lTX0VBc1lfMjk1ODA5OTN9";
	int arry[57] = { 0 };
	for (int i = 0; i < 57; i++)
	{
		arry[i]=getIndex(cmp[i]);
		cout << arry[i] << " ";
		if (i != 0 && i % 10 == 0)
			cout << endl;
	}*/

为了清晰 我直接复制下来了
这是所有的索引 为了统一下标多加了一个-1


	int arry[] = { -1,28,6,37,35,27,52,13,20,17,39,45,
		34,16,23,13,5,23,51,24,52,23,
		54,21,14,16,54,61,4,26,20,57,
		39,23,54,37,19,23,52,21,1,28,
		53,37,31,12,35,36,53,14,3,0,
		57,14,19,13,61 };

最后

	string str;
	for (int i = 1; i < 57; i+=4)
	{
		arry[i] = arry[i] << 18;
		arry[i+1] = arry[i+1] << 12;
		arry[i+2] = arry[i+2] << 6;
		arry[i + 3] |= arry[i + 2] | arry[i + 1] | arry[i];
		str += ((char*)&arry[i + 3])[2];
		str += ((char*)&arry[i + 3])[1];
		str += ((char*)&arry[i + 3])[0];
	}
	cout << str << endl;

flag=picoCTF{bAsE_64_eNCoDiNg_iS_EAsY_29580993}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值