2013 Codegate Prequel binary 100

.NET 바이너리가 주어졌다.

이 바이너리 소스인데 좀 길지만 보면 쉽다.

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Crack_Test.Properties;

namespace Crack_Test
{
	// Token: 0x02000003 RID: 3
	public class Crack_Game : Form
	{
		// Token: 0x06000004 RID: 4 RVA: 0x00002158 File Offset: 0x00000358
		public Crack_Game()
		{
			this.a();
			this.r.MaxLength = 25;
		}

		// Token: 0x06000005 RID: 5 RVA: 0x000021DC File Offset: 0x000003DC
		public bool TextInput(int txt)
		{
			bool result;
			if (this.r.MaxLength > this.r.TextLength)
			{
				TextBox textBox = this.r;
				textBox.Text += txt;
				result = true;
			}
			else
			{
				MessageBox.Show("length error!!");
				result = false;
			}
			return result;
		}

		// Token: 0x06000006 RID: 6 RVA: 0x0000223C File Offset: 0x0000043C
		private void m(object A_0, EventArgs A_1)
		{
			this.b = 1;
			this.TextInput(this.b);
		}

		// Token: 0x06000007 RID: 7 RVA: 0x00002253 File Offset: 0x00000453
		private void l(object A_0, EventArgs A_1)
		{
			this.b = 2;
			this.TextInput(this.b);
		}

		// Token: 0x06000008 RID: 8 RVA: 0x0000226A File Offset: 0x0000046A
		private void k(object A_0, EventArgs A_1)
		{
			this.b = 3;
			this.TextInput(this.b);
		}

		// Token: 0x06000009 RID: 9 RVA: 0x00002281 File Offset: 0x00000481
		private void j(object A_0, EventArgs A_1)
		{
			this.b = 4;
			this.TextInput(this.b);
		}

		// Token: 0x0600000A RID: 10 RVA: 0x00002298 File Offset: 0x00000498
		private void i(object A_0, EventArgs A_1)
		{
			this.b = 5;
			this.TextInput(this.b);
		}

		// Token: 0x0600000B RID: 11 RVA: 0x000022AF File Offset: 0x000004AF
		private void h(object A_0, EventArgs A_1)
		{
			this.b = 6;
			this.TextInput(this.b);
		}

		// Token: 0x0600000C RID: 12 RVA: 0x000022C6 File Offset: 0x000004C6
		private void g(object A_0, EventArgs A_1)
		{
			this.b = 7;
			this.TextInput(this.b);
		}

		// Token: 0x0600000D RID: 13 RVA: 0x000022DD File Offset: 0x000004DD
		private void f(object A_0, EventArgs A_1)
		{
			this.b = 8;
			this.TextInput(this.b);
		}

		// Token: 0x0600000E RID: 14 RVA: 0x000022F4 File Offset: 0x000004F4
		private void e(object A_0, EventArgs A_1)
		{
			this.b = 9;
			this.TextInput(this.b);
		}

		// Token: 0x0600000F RID: 15 RVA: 0x0000230C File Offset: 0x0000050C
		private void d(object A_0, EventArgs A_1)
		{
			this.b = 0;
			this.TextInput(this.b);
		}

		// Token: 0x06000010 RID: 16 RVA: 0x00002324 File Offset: 0x00000524
		private void c(object A_0, EventArgs A_1)
		{
			try
			{
				this.r.Text = string.Empty;
			}
			catch (Exception ex)
			{
				Trace.WriteLine(ex.Message);
			}
		}

		// Token: 0x06000011 RID: 17 RVA: 0x0000236C File Offset: 0x0000056C
		private void b(object A_0, EventArgs A_1)
		{
			this.Shadowkey = "N0\u0005\u001aO+/\fN<37JRLJ\u001e\f\u0014\u000f\u000f";
			string data = string.Empty;
			string str = string.Empty;
			if (this.r.Text != "")
			{
				this.Shadowkey += "\u0014\u000f\u000f\u0017\u001c<J\a\u001a)%M\f\u0015\u001f<2\u000fE\u001e\u00122\u0010V9\u00166H-\u0012@";
				data = AESCrypt.Encrypt(this.r.Text, Crack_Game.KeyValue);
				str = this.xorToString(data);
				Trace.WriteLine("Encrypt key:" + str);
				this.TransFormable(this.r.Text);
				if (this.r.Text.Length != 16)
				{
					string data2 = this.a.TransForm_S();
					string text = this.a.TransForm_B(data2);
					MessageBox.Show(text);
				}
			}
			else
			{
				string text2 = this.a.Md5hash(this.r.Text);
				byte[] array = this.a.stringTobyte(AESCrypt.Encrypt(this.r.Text, Crack_Game.KeyValue));
				string str2 = "";
				for (int i = 0; i < array.Length; i++)
				{
					str2 += string.Format(" {0:X2}", array[i]);
				}
				for (int i = 0; i < array.Length; i++)
				{
					array[i] ^= 67;
				}
				string data3 = this.a.ByteTostring_t(array);
				byte[] array2 = this.a.stringTobyte(this.a.TransForm());
				for (int i = 0; i < array2.Length; i++)
				{
					array2[i] ^= 67;
				}
				string text3 = AESCrypt.Decrypt(this.a.ByteTostring_t(array2), Crack_Game.KeyValue);
				this.a.TransForm_B(data3);
				Trace.WriteLine(this.a.TransForm_B(data3));
				MessageBox.Show("input password :");
			}
		}

		// Token: 0x06000012 RID: 18 RVA: 0x0000258C File Offset: 0x0000078C
		public byte[] stringTobyte(string str)
		{
			return Encoding.UTF8.GetBytes(str.ToCharArray());
		}

		// Token: 0x06000013 RID: 19 RVA: 0x000025B0 File Offset: 0x000007B0
		public string ByteTostring(byte[] bt)
		{
			string text = "";
			for (int i = 0; i < bt.Length; i++)
			{
				text += Encoding.Default.GetString(bt, i, 1);
			}
			return text;
		}

		// Token: 0x06000014 RID: 20 RVA: 0x000025F4 File Offset: 0x000007F4
		public void TransFormable(string Data)
		{
			if (Data.Length == 16)
			{
				if (this.xorToString(AESCrypt.Encrypt(this.r.Text, Crack_Game.KeyValue)) == this.lowkey)
				{
					string textToDecrypt = this.StringToXOR(this.a.ByteTostring_t(this.c));
					string text = AESCrypt.Decrypt(textToDecrypt, Crack_Game.KeyValue);
					MessageBox.Show(text);
				}
				else
				{
					string textToDecrypt2 = this.StringToXOR(this.a.ByteTostring_t(this.d));
					string str = AESCrypt.Decrypt(textToDecrypt2, Crack_Game.KeyValue);
					MessageBox.Show("Do you know ?  " + str);
				}
			}
		}

		// Token: 0x06000015 RID: 21 RVA: 0x000026B0 File Offset: 0x000008B0
		public string StringToXOR(string data)
		{
			string empty = string.Empty;
			byte[] array = new byte[data.Length];
			array = this.stringTobyte(data);
			for (int i = 0; i < array.Length; i++)
			{
				array[i] ^= 37;
				array[i] ^= 88;
			}
			return this.ByteTostring(array);
		}

		// Token: 0x06000016 RID: 22 RVA: 0x00002710 File Offset: 0x00000910
		public string xorToString(string data)
		{
			string empty = string.Empty;
			byte[] array = new byte[data.Length];
			array = this.stringTobyte(data);
			for (int i = 0; i < array.Length; i++)
			{
				array[i] ^= 21;
			}
			return this.ByteTostring(array);
		}

		// Token: 0x06000017 RID: 23 RVA: 0x00002765 File Offset: 0x00000965
		private void a(object A_0, EventArgs A_1)
		{
		}

		// Token: 0x06000018 RID: 24 RVA: 0x00002768 File Offset: 0x00000968
		protected override void Dispose(bool disposing)
		{
			if (disposing && this.e != null)
			{
				this.e.Dispose();
			}
			base.Dispose(disposing);
		}

		// Token: 0x06000019 RID: 25 RVA: 0x000027A0 File Offset: 0x000009A0
		private void a()
		{
			this.f = new Button();
			this.g = new Button();
			this.h = new Button();
			this.i = new Button();
			this.j = new Button();
			this.k = new Button();
			this.l = new Button();
			this.m = new Button();
			this.n = new Button();
			this.o = new Button();
			this.p = new Button();
			this.q = new Button();
			this.r = new TextBox();
			this.s = new Label();
			base.SuspendLayout();
			this.f.Image = Resources.num_14;
			this.f.Location = new Point(25, 62);
			this.f.Name = "button1";
			this.f.Size = new Size(56, 56);
			this.f.TabIndex = 0;
			this.f.UseVisualStyleBackColor = true;
			this.f.Click += this.m;
			this.g.Image = Resources.num_21;
			this.g.Location = new Point(101, 62);
			this.g.Name = "button2";
			this.g.Size = new Size(56, 56);
			this.g.TabIndex = 1;
			this.g.UseVisualStyleBackColor = true;
			this.g.Click += this.l;
			this.h.Image = Resources.num_3;
			this.h.Location = new Point(177, 62);
			this.h.Name = "button3";
			this.h.Size = new Size(56, 56);
			this.h.TabIndex = 2;
			this.h.UseVisualStyleBackColor = true;
			this.h.Click += this.k;
			this.i.Image = Resources.num_4;
			this.i.Location = new Point(25, 124);
			this.i.Name = "button4";
			this.i.Size = new Size(56, 56);
			this.i.TabIndex = 3;
			this.i.UseVisualStyleBackColor = true;
			this.i.Click += this.j;
			this.j.Image = Resources.num_5;
			this.j.Location = new Point(101, 124);
			this.j.Name = "button5";
			this.j.Size = new Size(56, 56);
			this.j.TabIndex = 4;
			this.j.UseVisualStyleBackColor = true;
			this.j.Click += this.i;
			this.k.Image = Resources.num_6;
			this.k.Location = new Point(177, 124);
			this.k.Name = "button6";
			this.k.Size = new Size(56, 56);
			this.k.TabIndex = 5;
			this.k.UseVisualStyleBackColor = true;
			this.k.Click += this.h;
			this.l.Image = Resources.num_7;
			this.l.Location = new Point(25, 188);
			this.l.Name = "button7";
			this.l.Size = new Size(56, 56);
			this.l.TabIndex = 6;
			this.l.UseVisualStyleBackColor = true;
			this.l.Click += this.g;
			this.m.Image = Resources.num_8;
			this.m.Location = new Point(101, 188);
			this.m.Name = "button8";
			this.m.Size = new Size(56, 56);
			this.m.TabIndex = 7;
			this.m.UseVisualStyleBackColor = true;
			this.m.Click += this.f;
			this.n.Image = Resources.num_9;
			this.n.Location = new Point(177, 188);
			this.n.Name = "button9";
			this.n.Size = new Size(56, 56);
			this.n.TabIndex = 8;
			this.n.UseVisualStyleBackColor = true;
			this.n.Click += this.e;
			this.o.Image = Resources.num_0;
			this.o.Location = new Point(101, 249);
			this.o.Name = "button10";
			this.o.Size = new Size(56, 56);
			this.o.TabIndex = 9;
			this.o.UseVisualStyleBackColor = true;
			this.o.Click += this.d;
			this.p.Font = new Font("굴림", 17f);
			this.p.Image = Resources.key_;
			this.p.Location = new Point(25, 249);
			this.p.Name = "button11";
			this.p.Size = new Size(56, 56);
			this.p.TabIndex = 10;
			this.p.UseVisualStyleBackColor = true;
			this.p.Click += this.b;
			this.q.Image = Resources.key__;
			this.q.Location = new Point(177, 249);
			this.q.Name = "Bt_Delete";
			this.q.Size = new Size(56, 56);
			this.q.TabIndex = 11;
			this.q.UseVisualStyleBackColor = true;
			this.q.Click += this.c;
			this.r.Enabled = false;
			this.r.Location = new Point(25, 25);
			this.r.MaxLength = 1;
			this.r.Name = "textBox_Input";
			this.r.Size = new Size(208, 21);
			this.r.TabIndex = 12;
			this.r.TextAlign = HorizontalAlignment.Right;
			this.s.AutoSize = true;
			this.s.Location = new Point(81, 370);
			this.s.Name = "label_Msg";
			this.s.Size = new Size(0, 12);
			this.s.TabIndex = 13;
			base.AutoScaleDimensions = new SizeF(7f, 12f);
			base.AutoScaleMode = AutoScaleMode.Font;
			this.BackgroundImage = Resources.codegate_back4;
			base.ClientSize = new Size(263, 399);
			base.Controls.Add(this.s);
			base.Controls.Add(this.r);
			base.Controls.Add(this.q);
			base.Controls.Add(this.p);
			base.Controls.Add(this.o);
			base.Controls.Add(this.n);
			base.Controls.Add(this.m);
			base.Controls.Add(this.l);
			base.Controls.Add(this.k);
			base.Controls.Add(this.j);
			base.Controls.Add(this.i);
			base.Controls.Add(this.h);
			base.Controls.Add(this.g);
			base.Controls.Add(this.f);
			this.Cursor = Cursors.Arrow;
			this.Font = new Font("굴림", 9f);
			base.FormBorderStyle = FormBorderStyle.FixedToolWindow;
			base.Name = "Crack_Game";
			base.StartPosition = FormStartPosition.CenterScreen;
			this.Text = "Door_Lock";
			base.TopMost = true;
			base.Load += this.a;
			base.ResumeLayout(false);
			base.PerformLayout();
		}

		// Token: 0x04000003 RID: 3
		private StringCrypt a = new StringCrypt();

		// Token: 0x04000004 RID: 4
		public static string KeyValue = "9e2ea73295c7201c5ccd044477228527";

		// Token: 0x04000005 RID: 5
		public string lowkey = "@DT$:~zRbD_!qFWQMAtC's[_t:&&YF\u007fWQE ^o-EBAr%(";

		// Token: 0x04000006 RID: 6
		private int b;

		// Token: 0x04000007 RID: 7
		private byte[] c = new byte[]
{63,30,57,47,20,78,50,54,51,5,37,41,82,40,69,30,42,56,36,73,60,68,79,86,24,73,76,19,9,27,42,4,82,42,28,86,79,11,17,63,23,14,48,64};

		// Token: 0x04000008 RID: 8
		private byte[] d = new byte[]
		{
22,52,4,72,40,18,41,22,23,45,21,28,42,63,23,49,75,76,39,5,9,13,8,43,37,59,42,45,5,48,10,47,7,42,12,41,20,79,37,46,39,3126,64};

		// Token: 0x04000009 RID: 9
		public string Shadowkey = string.Empty;

		// Token: 0x0400000A RID: 10
		private IContainer e = null;

		// Token: 0x0400000B RID: 11
		private Button f;

		// Token: 0x0400000C RID: 12
		private Button g;

		// Token: 0x0400000D RID: 13
		private Button h;

		// Token: 0x0400000E RID: 14
		private Button i;

		// Token: 0x0400000F RID: 15
		private Button j;

		// Token: 0x04000010 RID: 16
		private Button k;

		// Token: 0x04000011 RID: 17
		private Button l;

		// Token: 0x04000012 RID: 18
		private Button m;

		// Token: 0x04000013 RID: 19
		private Button n;

		// Token: 0x04000014 RID: 20
		private Button o;

		// Token: 0x04000015 RID: 21
		private Button p;

		// Token: 0x04000016 RID: 22
		private Button q;

		// Token: 0x04000017 RID: 23
		private TextBox r;

		// Token: 0x04000018 RID: 24
		private Label s;
	}
}

핵심 코드만 보자면 입력 받는 값의 길이는 16글자이다.

public void TransFormable(string Data)
		{
			if (Data.Length == 16)
			{
				if (this.xorToString(AESCrypt.Encrypt(this.r.Text, Crack_Game.KeyValue)) == this.lowkey)
				{
					string textToDecrypt = this.StringToXOR(this.a.ByteTostring_t(this.c));
					string text = AESCrypt.Decrypt(textToDecrypt, Crack_Game.KeyValue);
					MessageBox.Show(text);
				}
				else
				{
					string textToDecrypt2 = this.StringToXOR(this.a.ByteTostring_t(this.d));
					string str = AESCrypt.Decrypt(textToDecrypt2, Crack_Game.KeyValue);
					MessageBox.Show("Do you know ?  " + str);
				}
			}
		}

public string StringToXOR(string data)
		{
			string empty = string.Empty;
			byte[] array = new byte[data.Length];
			array = this.stringTobyte(data);
			for (int i = 0; i < array.Length; i++)
			{
				array[i] ^= 37;
				array[i] ^= 88;
			}
			return this.ByteTostring(array);
		}

public static string KeyValue = "9e2ea73295c7201c5ccd044477228527";

public string lowkey = "@DT$:~zRbD_!qFWQMAtC's[_t:&&YF\u007fWQE ^o-EBAr%(";

private byte[] c = new byte[]{ 63,30,57,47,20,78,50,54,51,5,37,41,82,40,69,30,42,56,36,73,60,68,79,86,24,73,76,19,9,27,42,4,82,42,28,86,79,11,17,63,23,14,48,64};

private byte[] d = new byte[]{
22,52,4,72,40,18,41,22,23,45,21,28,42,63,23,49,75,76,39,5,9,13,8,43,37,59,42,45,5,48,10,47,7,42,12,41,20,79,37,46,39,31,26,64};

우선 16글자만 맞추고 입력하면 아래와 같은 글자를 출력해준다. 그러므로 우리는 lowkey랑 입력받은 걸 AES Encrypt하고 xor한 값이 같으면 c 를 XOR연산 후에 AES Decrypt 해준다. 길이만 맞고 lowkey랑은 다르면 d를 Decrypt 해준다. 우리는 이를 이용해서 풀 수 있다.

만약 c와 d를 바꾸고 길이만 16으로 맞춘 후 아무거나 입력한다면 플래그가 담인 것을 Decrypt하게 된다. 우선은 푸는 방법은 여러개가 있다. 바이너리를 패치해서 c와 d를 바꾸거나 이 .cs 파일을 변수를 서로 바꿔주고 컴파일 하면 된다.

나는 바이너리 패치를 했다. 그냥 d를 c로 바꿔서 c가 Decrypt 되게 했다.

이제 이 바이너리를 길이만 맞추고 실행해주면 c가 Decrypt 되서 MessageBox로 출력된다.

다른 방법으로는 c의 테이블 값을 가져오고 역연산 해주면 된다.

# -*- coding:utf-8 -*-
import base64

# length = 16
c=[63,30,57,47,20,78,50,54,51,5,37,41,82,40,69,30,42,56,36,73,60,68,79,86,24,73,76,19,9,27,42,4,82,42,28,86,79,11,17,63,23,14,48,64]
enc = []
for i in c:
	enc.append(i^37^88)
a = ''.join(chr(i) for i in enc)
a = base64.b64decode(a)
print a

우선은 StringToXOR의 값을 먼저 구해주었다. BcDRi3OKNxXT/U8cWEY4A92+e41ntfWy/Wa+2vlBjsM=

AES-256-CBC Decrypt 하는 것을 찾다가 php의 crypt_decrypt를 이용해서 풀었다.

<?php
$text = "BcDRi3OKNxXT/U8cWEY4A92+e41ntfWy/Wa+2vlBjsM=";
$algorithm = MCRYPT_RIJNDAEL_256;       
$mode = MCRYPT_MODE_CBC;
$keyvalue = '9e2ea73295c7201c5ccd044477228527';
$bytes = $keyvalue;
$iv = $key = $bytes;
$flag = mcrypt_decrypt($algorithm, $key, base64_decode($text),$mode, $iv);
print $flag;
?>

그냥 C# 변수 서로 바꿔주고 몇개 바꾸고 컴파일 해주면 된다. 그러면 passcode는 198711102130301 이렇게 나온다.

FLAG : code9ate2013 Start