Neepu2023-部分Reserve复现

目录

Base

IKUN检查器

dnSpy

 junk code

Cheat Engine工具使用:

奇怪的ELF

mov混淆问题:

Xor 


Base

打开附件,可以看到主函数

Neepu2023-部分Reserve复现_第1张图片

先是给出一个物理题,要求输入答案,这个无关紧要,接着要求输入一串字符,经过encode_1和encode_2的加密过程后,要求等于enflag。直接进入encode_1和encode_2查看

encode_1:

char __cdecl encode_1(char *flag, int num)
{
  size_t v2; // rax
  int i; // [rsp+2Ch] [rbp-54h]

  for ( i = 0; ; ++i )
  {
    v2 = strlen(flag);
    if ( i >= v2 )
      break;
    if ( flag[i] <= 64 || flag[i] > 90 )
    {
      if ( flag[i] > 96 && flag[i] <= 122 )
        flag[i] = (flag[i] - 97 + num) % 26 + 97;
    }
    else
    {
      flag[i] = (flag[i] - 65 + num) % 26 + 65;
    }
  }
  return v2;
}

很明显的凯撒加密,偏移量是num,传进去的参数可以知道num的值为3.

再进入encode_2查看

char __cdecl encode_2(char *str, int len, char *str1)
{
  int v3; // eax
  int v4; // eax
  int v5; // eax
  int v6; // r8d
  int v7; // eax
  int v8; // r8d
  int v9; // eax
  int v10; // eax
  int v11; // eax
  int v12; // r8d
  int v13; // eax
  int v14; // eax
  int v15; // eax
  int v16; // eax
  char base64[65]; // [rsp+20h] [rbp-60h] BYREF
  char *flag; // [rsp+68h] [rbp-18h]
  int encodeStrLen; // [rsp+74h] [rbp-Ch]
  int k; // [rsp+78h] [rbp-8h]
  int i; // [rsp+7Ch] [rbp-4h]

  strcpy(base64, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
  encodeStrLen = 4 * (len / 3) + 1;
  k = 0;
  if ( len % 3 )
    v3 = 4;
  else
    v3 = 0;
  encodeStrLen += v3;
  flag = malloc(encodeStrLen);
  for ( i = 0; i < len; ++i )
  {
    if ( len - i <= 2 )
    {
      v10 = k++;
      if ( len - i == 2 )
      {
        flag[v10] = base64[str[i] >> 2];
        v11 = k++;
        v12 = 16 * (str[i++] & 3);
        flag[v11] = base64[v12 | (str[i] >> 4)];
        v13 = k++;
        flag[v13] = base64[4 * (str[i] & 0xF)];
      }
      else
      {
        flag[v10] = base64[str[i] >> 2];
        v15 = k++;
        flag[v15] = base64[16 * (str[i] & 3)];
        v16 = k++;
        flag[v16] = 61;
      }
      v14 = k++;
      flag[v14] = 61;
    }
    else
    {
      v4 = k++;
      flag[v4] = base64[str[i] >> 2];
      v5 = k++;
      v6 = 16 * (str[i++] & 3);
      flag[v5] = base64[v6 | (str[i] >> 4)];
      v7 = k++;
      v8 = 4 * (str[i++] & 0xF);
      flag[v7] = base64[v8 | (str[i] >> 6)];
      v9 = k++;
      flag[v9] = base64[str[i] & 0x3F];
    }
  }
  flag[k] = 0;
  return strcpy(str1, flag);
}

一个base64加密

最后将加密后的数据与enflag进行比较,解密过程就是先将enflag进行base64解码,然后再将得到的值进行凯撒解密,偏移量为3最后得到flag。

Neepu2023-部分Reserve复现_第2张图片

Neepu2023-部分Reserve复现_第3张图片

IKUN检查器

打开附件,可以发现是c#编写的程序,c#程序需要使用dnSpy打开

dnSpy

可以直接从官网上下载

打开可以看到主函数

// WindowsFormsApp1.From1
// Token: 0x06000006 RID: 6 RVA: 0x00002074 File Offset: 0x00000274
private void button1_Click(object sender, EventArgs e)
{
	string text = this.textBox1.Text;
	bool flag = text.Length != 34;
	if (flag)
	{
		this.label1.Text = "你不是真ikun";
	}
	else
	{
		string a = text.Substring(0, 8);
		string a2 = text.Substring(8, 1);
		string a3 = text.Substring(9, 10);
		string b = text.Substring(19, 1);
		string a4 = text.Substring(20, 14);
		int num = 0;
		int num2 = 0;
		int num3 = 0;
		int num4 = 0;
		num = this.check1(a, num);
		num2 = this.check2(a3, num2);
		num3 = this.check3(a2, b, num3);
		num4 = this.check4(a4, num4);
		bool flag2 = num + num2 + num3 + num4 == 4;
		if (flag2)
		{
			this.check5(text);
		}
	}
}

先判断flag长度是否等于34,然后会对输入的字符串分段分别经过check1,2,3,4函数进行检测,都通过时使用check5输出

check1:

public int check1(string a, int checkbox)
		{
			string value = "3eabbb3900d553d7e98a154bffa4d24a";
			char[] array = a.ToCharArray();
			MD5 md = new MD5CryptoServiceProvider();
			byte[] bytes = Encoding.Default.GetBytes(a);
			byte[] array2 = md.ComputeHash(bytes);
			md.Clear();
			string text = "";
			for (int i = 0; i < array2.Length; i++)
			{
				text += array2[i].ToString("x").PadLeft(2, '0');
			}
			bool flag = text.Equals(value);
			if (flag)
			{
				this.label1.Text = "哇,珍德食你鸭!";
				checkbox = 1;
			}
			else
			{
				this.label1.Text = "你干嘛,嗨嗨呦!";
				checkbox = 0;
			}
			return checkbox;
		}

是一个md5加密,直接爆破解密,得到 1998-8-2

check2:

		// Token: 0x0600000C RID: 12 RVA: 0x00002590 File Offset: 0x00000790
		public int check2(string a, int checkbox)
		{
			string value = "ce143362813587af5af8592984c91b5a8c11b779";
			string text = "";
			SHA1 sha = new SHA1CryptoServiceProvider();
			byte[] bytes = Encoding.Default.GetBytes(a);
			byte[] array = sha.ComputeHash(bytes);
			sha.Clear();
			for (int i = 0; i < array.Length; i++)
			{
				text += array[i].ToString("x").PadLeft(2, '0');
			}
			bool flag = text.Equals(value);
			if (flag)
			{
				this.label1.Text = "哇,珍德食你鸭!";
				checkbox = 1;
			}
			else
			{
				this.label1.Text = "你干嘛,嗨嗨呦!";
				checkbox = 0;
			}
			return checkbox;

是一个sha1加密,解密得到 jinitaimei

check3:


		// Token: 0x0600000D RID: 13 RVA: 0x0000264C File Offset: 0x0000084C
		public int check3(string a, string b, int checkbox)
		{
			string value = "-";
			bool flag = a.Equals(b) && a.Equals(value);
			if (flag)
			{
				this.label1.Text = "哇,珍德食你鸭!";
				checkbox = 1;
			}
			else
			{
				this.label1.Text = "你干嘛,嗨嗨呦!";
				checkbox = 0;
			}
			return checkbox;
		}

直接判断是一个 '-'

check4:


		// Token: 0x0600000E RID: 14 RVA: 0x000026AC File Offset: 0x000008AC
		public int check4(string a, int checkbox)
		{
			string text = "7vKrvRh4Gu7wBQn7o9VfKQ==";
			byte[] bytes = Encoding.UTF8.GetBytes("pijinchengwangbankunyuanhang!!!!");
			byte[] bytes2 = Encoding.UTF8.GetBytes(a);
			ICryptoTransform cryptoTransform = new RijndaelManaged
			{
				Key = bytes,
				Mode = CipherMode.ECB,
				Padding = PaddingMode.PKCS7
			}.CreateEncryptor();
			byte[] array = cryptoTransform.TransformFinalBlock(bytes2, 0, bytes2.Length);
			string value = Convert.ToBase64String(array, 0, array.Length);
			bool flag = text.Equals(value);
			if (flag)
			{
				this.label1.Text = "哇,珍德食你鸭!";
				checkbox = 1;
			}
			else
			{
				this.label1.Text = "你干嘛,嗨嗨呦!";
				checkbox = 0;
			}
			return checkbox;
		}

是一个AES加密.ECB,PKCS7,直接解密,得到:xiaoheizishiba

直接输入,得到flag(没想到直接输入....)

Neepu2023-部分Reserve复现_第4张图片

 junk code

看wp知道是使用cheat engine工具

Cheat Engine工具使用:

  • 首先运行程序
  • 打开Cheat Engine工具,点击如下图标,查找Process,找到要调试的程序,打开
  • Neepu2023-部分Reserve复现_第5张图片
  • 然后,可以在右边的框内输入要查找的字符串/字节
  • Neepu2023-部分Reserve复现_第6张图片
  • 下面的数据右键->浏览相关内存区域,即可得到flag

Neepu2023-部分Reserve复现_第7张图片

Neepu2023-部分Reserve复现_第8张图片

方法二:直接使用ida动态调试

在ida中打开文件,动态调试

注意:一定要在此处,因为此处是字符串经过异或运算后的flag值

Neepu2023-部分Reserve复现_第9张图片

 得到flag

奇怪的ELF

看了wp才知道是mov 混淆了

mov混淆问题:

MOV这种混淆是怎样产生的呢?剑桥大学的Stephen Dolan证明了x86的mov指令可以完成几乎所有功能了(可能还需要jmp),其他指令都是“多余的”。受此启发,有个大牛做了一个虚拟机加密编译器。它是一个修改版的LCC编译器,输入是C语言代码,输出的obj里面直接包含了虚拟机加密后的代码。如它的名字,函数的所有代码只有mov指令,没有其他任何指令。

这种题目的特征就是:汇编代码的汇编指令几乎全部就是MOV

1、 字符串的搜索是给我们最好的提示。
2、 MOV混淆是不会混淆函数的逻辑的。因此函数的逻辑还是不变的。
3、 大多数汇编代码的意思是可以猜测的。可以大概推测出具体操作了什么

具体mov混淆问题可以看:movfuscator混淆_Cherest_San的博客-CSDN博客

和这篇文章:浅析CTF中的反静态调试(二) - 先知社区

Neepu2023-部分Reserve复现_第10张图片

观察代码可以发现,flag的指令存储在R2中,直接手动搜索得到flag,search->text->R2。

Neepu2023-部分Reserve复现_第11张图片

Xor 

直接搜索字符串,找到可疑字符串

Neepu2023-部分Reserve复现_第12张图片

设置断点,动态调试

Neepu2023-部分Reserve复现_第13张图片

 一路F8,可以看到Please input flag,下面的异或部分

Neepu2023-部分Reserve复现_第14张图片

在此处创建函数

Neepu2023-部分Reserve复现_第15张图片

可以看到函数的主逻辑

  __int64 v8; // rdi
  __int64 v9; // rax
  __int64 i; // rcx
  _QWORD *v11; // rax
  __int64 v13; // [rsp-1C8h] [rbp-1D8h]
  __int64 v14; // [rsp-1C0h] [rbp-1D0h]
  unsigned __int64 v15; // [rsp-1A0h] [rbp-1B0h]
  __int64 v16; // [rsp-198h] [rbp-1A8h]
  __int64 v17; // [rsp-190h] [rbp-1A0h]
  __int64 v18; // [rsp-188h] [rbp-198h]
  __int64 v19; // [rsp-180h] [rbp-190h]
  _QWORD v20[34]; // [rsp-158h] [rbp-168h]
  __int64 v21; // [rsp-48h] [rbp-58h]
  const char *v22; // [rsp-38h] [rbp-48h]
  _QWORD *v23; // [rsp-30h] [rbp-40h]
  void *v24; // [rsp-28h] [rbp-38h]
  char **v25; // [rsp-20h] [rbp-30h]

  while ( 1 )
  {
    v19 = a6;
    v15 = a4;
    v20[32] = v6;
    sub_81A060();
    v8 = sub_819800();
    a4 = v6;
    v6 = v8;
    if ( v19 + 1 >= v16 )
      break;
    a6 = v19 + 1;
    if ( v19 + 1 - ((v19 + 1) & 0xFFFFFFFFFFFFFFFCLL) >= 4 )
      sub_82EB60(v13, v14);
  }
  v21 = sub_819DA0();
  v17 = v8;
  *(&v13 - 2) = v7;
  v9 = sub_82F0E0();
  for ( i = 0LL; i < 32; ++i )
  {
    if ( v6 <= i )
      sub_82EB60(v13, v14);
    if ( v20[i] != *(unsigned __int8 *)(v9 + i) )
    {
      v18 = i;
      v14 = sub_85F300(v13);
      v9 = v21;
      i = v18;
      v6 = v17;
    }
  }
  v24 = &unk_875580;
  v25 = &off_8ABBB0;
  sub_861F60();
  v11 = (_QWORD *)sub_7DC740();
  *v11 = 0LL;
  v22 = "\b";
  v23 = v11;
  return sub_867420();
}

函数有两个循环,第一个循环时加密过程,第二个循环是对加密的明文进行判断,所以我们需要动态调试,过第一个循环,在第二个循环中Neepu2023-部分Reserve复现_第16张图片

在此处先断点,随便输入什么跳过第一个循环,F8到第二个循环,拿到密文

Neepu2023-部分Reserve复现_第17张图片

 写脚本解密

#include
#include
#include
int main(){
	int i;
	char arr[]={0x3f,0x12,0x0,0x2,0x4,0xc,0x3d,0x42,0x3,0x28,0xc,0x1,0x2e,0x12,0x4,0x1,0x8,0x28,0x54,0x40,0x42,0x43,0x54,0x40,0x42,0x43,0x54,0x40,0x42,0x43,0x50,0xf};
    char key[]="qwer";
  for(i=0;i<40;i++){
	arr[i]=arr[i]^key[i%4];
	printf("%c",arr[i]);
   }
  
	return 0;
}
//Neepu{X0r_is_easy_1234123412345}

你可能感兴趣的:(算法,网络安全,python)