[buuctf.reverse] 第52至61题

目录

052_findKey

053_[FlareOn5]Minesweeper Championship Registration

054_[网鼎杯 2020 青龙组]jocker

055_[GWCTF 2019]re3

056_[GXYCTF2019]simple CPP

057_[ACTF新生赛2020]SoulLike

058_[羊城杯 2020]easyre

059_[FlareOn5]Ultimate Minesweeper

060_[FlareOn1]Bob Doge

061_[MRCTF2020]PixelShooter


052_findKey

第1步是输入数字,与已知sha1值比较,sha1值与S异或过;第2步是用这个输入值与flag异或结果给出

LRESULT __stdcall sub_401640(HWND hWndParent, UINT Msg, WPARAM wParam, LPARAM lParam)
{
......
  LoadStringA(hInstance, 0x6Au, Buffer, 100);
  if ( Msg > 0x111 )
  {
    if ( Msg == 517 )
    {
      if ( strlen((const char *)String1) > 6 )
        ExitProcess(0);
      if ( strlen((const char *)String1) )
      {
        memset(v18, 0, sizeof(v18));
        v6 = strlen((const char *)String1);
        memcpy(v18, String1, v6);
        v7 = strlen((const char *)String1);
        sub_40101E(String1, v7, (LPSTR)String1);// str1 = sha1(str1).hex
        strcpy(Str, "0kk`d1a`55k222k2a776jbfgd`06cjjb");
        memset(v15, 0, sizeof(v15));
        v16 = 0;
        v17 = 0;
        strcpy(v11, "SS");
        *(_DWORD *)&v11[3] = 0;
        v12 = 0;
        v13 = 0;
        v8 = strlen(Str);
        sub_401005(v11, (int)Str, v8);
        if ( _strcmpi((const char *)String1, Str) )
        {
          SetWindowTextA(hWndParent, "flag{}");
          MessageBoxA(hWndParent, "Are you kidding me?", "^_^", 0);
          ExitProcess(0);
        }
        memcpy(v10, &byte_423030, 0x32u);
        v9 = strlen(v10);
        sub_401005(v18, (int)v10, v9);
        MessageBoxA(hWndParent, v10, 0, 0x32u);
      }
      ++dword_428D54;
    }
    else
    {
      if ( Msg != 520 )
        return DefWindowProcA(hWndParent, Msg, wParam, lParam);
      if ( dword_428D54 == 16 )
      {
        strcpy(String, "ctf");
        v20 = 0;
        v21 = 0;
        SetWindowTextA(hWndParent, String);
        strcpy(Text, "Are you kidding me?");
        MessageBoxA(hWndParent, Text, Buffer, 0);
      }
      ++dword_428D54;
    }
  }
  else
  {
    switch ( Msg )
    {
      case 0x111u:
        v28 = (unsigned __int16)wParam;
        v27 = HIWORD(wParam);
        if ( (unsigned __int16)wParam == 104 )
        {
          DialogBoxParamA(hInstance, (LPCSTR)0x67, hWndParent, (DLGPROC)DialogFunc, 0);
        }
        else
        {
          if ( (unsigned __int16)wParam != 105 )
            return DefWindowProcA(hWndParent, Msg, wParam, lParam);
          DestroyWindow(hWndParent);
        }
        break;
      case 2u:
        PostQuitMessage(0);
        break;
      case 0xFu:
        hdc = BeginPaint(hWndParent, &Paint);
        GetClientRect(hWndParent, &Rect);
        v5 = strlen(Buffer);
        DrawTextA(hdc, Buffer, v5, &Rect, 1u);
        EndPaint(hWndParent, &Paint);
        break;
      default:
        return DefWindowProcA(hWndParent, Msg, wParam, lParam);
    }
  }
  return 0;
}

第1步爆破得到123321,再异或得到flag

sha1 = b"0kk`d1a`55k222k2a776jbfgd`06cjjb"
a = [i^ord('S') for i in sha1]
print(bytes(a)) #123321

a =[0x57,0x5E,0x52,0x54,0x49,0x5F,0x01,0x6D,0x69,0x46,0x02,0x6E,0x5F,0x02,0x6C,0x57,0x5B,0x54,0x4C]
b = b'123321'*40
print(bytes([a[i]^b[i] for i in range(len(a))]))
#flag{n0_Zu0_n0_die}

053_[FlareOn5]Minesweeper Championship Registration

附件是个jar文件,用jadx打开看到 GoldenTicket2018@flare-on.com

#flag{GoldenTicket2018@flare-on.com}

054_[网鼎杯 2020 青龙组]jocker

上来就看到一串简单的加密

  puts("please input you flag:");
  if ( !VirtualProtect(encrypt, 0xC8u, 4u, &flOldProtect) )
    exit(1);
  scanf("%40s", Str);
  v67 = strlen(Str);
  if ( v67 != 24 )
  {
    puts("Wrong!");
    exit(0);
  }
  strcpy(Destination, Str);
  wrong(Str);
  omg(Str);

wrong加密很简单

char *__cdecl wrong(char *a1)
{
  char *result; // eax
  int i; // [esp+Ch] [ebp-4h]

  for ( i = 0; i <= 23; ++i )
  {
    result = &a1[i];
    if ( (i & 1) != 0 )
      a1[i] -= i;
    else
      a1[i] ^= i;
  }
  return result;
}

计算结果发现错了

#2 omg
a = list(b'fkcd\x7fagd;Vka{&;Pc_MZq\x0c7f')
#1 wrong
for i in range(24):
    if (i&1) != 0:
	    a[i]+=i 
    else:
	    a[i]^=i 

print(bytes(a))
#flag{fak3_alw35_sp_me!!} XXX

再仔细看有个函数修改了程序

  for ( i = 0; i <= 186; ++i )
    *((_BYTE *)encrypt + i) ^= 0x41u;

先把这段改过来,再用ida看

data = list(open('jocker.exe','rb').read())
for i in range(186):
    data[0x900+i]^=0x41

open('j2.exe', 'wb').write(bytes(data))

encrypt是第一段flag是个异或

int __cdecl encrypt(char *a1)
{
  int v2[19]; // [esp+1Ch] [ebp-6Ch] BYREF
  int v3; // [esp+68h] [ebp-20h]
  int i; // [esp+6Ch] [ebp-1Ch]

  v3 = 1;
  qmemcpy(v2, &unk_403040, sizeof(v2));
  for ( i = 0; i <= 18; ++i )
  {
    if ( (char)(a1[i] ^ aHahahahaDoYouF[i]) != v2[i] )
    {
      puts("wrong ~");
      v3 = 0;
      exit(0);
    }
  }
  puts("come here");
  return v3;
}

finally是第2段,v3[5]是0第2段只是比较,但显然不对,结合第1段,猜也是xor最后位应该是}与密文:异或得到密钥

int __cdecl finally(char *a1)
{
  unsigned int v1; // eax
  int result; // eax
  char v3[9]; // [esp+13h] [ebp-15h] BYREF
  int v4; // [esp+1Ch] [ebp-Ch]

  strcpy(v3, "%tp&:");
  v1 = time((__time32_t *const)0x41000000);
  srand(v1);
  v4 = rand() % 100;
  if ( (v3[*(_DWORD *)&v3[5]] != a1[*(_DWORD *)&v3[5]]) == v4 )
    result = puts("Really??? Did you find it?OMG!!!");
  else
    result = puts("I hide the last part, you will not succeed!!!");
  return result;
}

解得

a = b'hahahaha_do_you_find_me?'
b = b'\x0e\x0d\x09\x06\x13\x05\x58\x56\x3e\x06\x0c\x3c\x1f\x57\x14\x6b\x57\x59\x0d'
print(bytes([a[i]^b[i] for i in range(19)]), end='')
#flag{d07abccf8a410c

a = b"%tp&:"
key = ord(':')^ord('}')
print(bytes([i^key for i in a]))
#b37a}
#flag{d07abccf8a410cb37a}

055_[GWCTF 2019]re3

跟上题一样也是修改了程序

void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int i; // [rsp+8h] [rbp-48h]
  char s[40]; // [rsp+20h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+48h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  __isoc99_scanf("%39s", s);
  if ( (unsigned int)strlen(s) != 32 )
  {
    puts("Wrong!");
    exit(0);
  }
  mprotect(&dword_400000, 0xF000uLL, 7);
  for ( i = 0; i <= 223; ++i )
    *((_BYTE *)sub_402219 + i) ^= 0x99u;
  sub_40207B(&unk_603170);
  sub_402219();
}

改回后再放入ida用findcrypt发现是个AES加密,密钥是由几个数的md5

void __fastcall __noreturn main(int a1, char **a2, char **a3)
{
  int i; // [rsp+8h] [rbp-48h]
  char s[40]; // [rsp+20h] [rbp-30h] BYREF
  unsigned __int64 v5; // [rsp+48h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  __isoc99_scanf("%39s", s);
  if ( (unsigned int)strlen(s) != 32 )
  {
    puts("Wrong!");
    exit(0);
  }
  mprotect(&dword_400000, 0xF000uLL, 7);
  for ( i = 0; i <= 223; ++i )
    *((_BYTE *)sub_402219 + i) ^= 0x99u;
  sub_40207B((__int64)&unk_603170);             // md5(md5+md5..)
  if ( (unsigned int)sub_402219((__int64)s) )   // aes
    puts("Correct!");
  else
    puts("Wrong!");
  exit(0);
}

unsigned __int64 __fastcall sub_40207B(__int64 a1)
{
  char v2[16]; // [rsp+10h] [rbp-50h] BYREF
  __int64 v3; // [rsp+20h] [rbp-40h] BYREF
  __int64 v4; // [rsp+30h] [rbp-30h] BYREF
  __int64 v5; // [rsp+40h] [rbp-20h] BYREF
  unsigned __int64 v6; // [rsp+58h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  sub_401CF9(&BASE64_table_603120, 0x40uLL, (__int64)v2);// md5
  sub_401CF9(&CRC32_table_603100, 0x14uLL, (__int64)&v3);
  sub_401CF9(&Prime_Constants_char_6030C0, 0x35uLL, (__int64)&v4);
  sub_401CF9(MD5_Constants_4025C0, 0x100uLL, (__int64)&v5);
  sub_401CF9(v2, 0x40uLL, a1);
  return __readfsqword(0x28u) ^ v6;
}

先得到密钥再解AES

'''
data = list(open('attachment','rb').read())
for i in range(223):
    data[0x2219+i]^=0x99

open('a2.elf', 'wb').write(bytes(data))
'''
data = open('attachment','rb').read()

s = [data[0x3120: 0x3120+0x40],data[0x3100: 0x3100+0x14],data[0x30c0: 0x30c0+0x35],data[0x25c0: 0x25c0+0x100]]
from hashlib import md5
s = b''.join([md5(i).digest() for i in s])
print(len(s), s)
s = md5(s).digest()
from base64 import b16encode
print(b16encode(s))

#AES
key = s 
byte_6030A0 = data[0x30a0: 0x30a0+32]
from Crypto.Cipher import AES 
cipher = AES.new(key,  AES.MODE_ECB)
flag = cipher.decrypt(byte_6030A0)
print(flag)
#flag{924a9ab2163d390410d0a1f670}

056_[GXYCTF2019]simple CPP

这个看不去不复杂,但没作出来,搜了网上的WP也没作出来

  v22 = y & x;
  *v21 = y & x;
  v23 = z & ~x;
  v21[1] = v23;
  v24 = ~y;
  v25 = z & v24;
  v21[2] = z & v24;
  v26 = x & v24;
  v21[3] = v26;
  if ( v23 != 1176889593874i64 )
  {
    v21[1] = 0i64;
    v23 = 0i64;
  }
  v27 = v23 | v22 | v25 | v26;
  v28 = v18[1];
  v29 = v18[2];
  v30 = v25 & *v18 | v29 & (v22 | v28 & ~*v18 | ~(v28 | *v18));
  v31 = 0;
  if ( v30 == 577031497978884115i64 )
    v31 = v27 == 4483974544037412639i64;
  if ( (v27 ^ v18[3]) == 4483974543195470111i64 )
    v3 = v31;
  if ( (v23 | v22 | v28 & v29) == (~*v18 & v29 | 864693332579200012i64) && v3 )
  {
    v32 = sub_1400019C0(std::cout, (__int64)"Congratulations!flag is GXY{");
    v33 = Block;
    if ( v41 >= 0x10 )
      v33 = (void **)Block[0];
    v34 = (__int64 *)sub_140001FD0(v32, v33, v40);
    sub_1400019C0(v34, (__int64)"}");
    j_j_free(v6);
  }
  else
  {
    sub_1400019C0(std::cout, (__int64)"Wrong answer!try again");
    j_j_free(v6);
  }

题目就是几个式子计算几个结果,用z3求解发现多解,而且解有多少不详

#3
from z3 import *
 
x,y,z,w=BitVecs('x y z w',64)
s=Solver()

s.add((~x)&z==1176889593874)
s.add(((z&(~y))&x|z&((x&y)|y&~x|~(y|x)))==577031497978884115)
s.add(((z&(~x))|(x&y)|(z&~y)|(x&~y))==4483974544037412639)
s.add(((z&(~x))|(x&y)|(z&(~y))|(x&(~y)))^w==4483974543195470111)
s.add(((z&(~x)) | (x&y) | y & z) == (((~x)& z)|864693332579200012))

key = b"i_will_check_is_debug_or_not"

while s.check() == sat:
    m = s.model()
    li = ''
    for i in [x,y,z,w]:
        #print("%s = 0x%x"%(i,m[i].as_long()))
        if i == w:
            li+=hex(m[i].as_long())[2:].rjust(8,'0')
        else:
            li+=hex(m[i].as_long())[2:].rjust(16,'0')
    
    opcode = bytes.fromhex(li)
    #xyzw 
    flag = ""
    ok = True
    for i in range(len(opcode)-1):
        v = key[i] ^ opcode[i]
        flag += chr(v)
        if v<0x20 or v>0x7f:
            ok = False
            break
    tmpy = m[y].as_long()
    s.add(y != tmpy)
    
    if len(flag)>24 or flag[8] != 'e' or flag[9] != '!':
        ok = False 
    if ok:
        print(flag)

        
#We1l_D0ne!P0or_algebra_am_i   #半天也得不到这个

057_[ACTF新生赛2020]SoulLike

这个也看上去不难,就是个异或,只不过次数多,ida需要改函数最大值才能打开。打开以后包含到c程序里,再去运行一下

__int64 __fastcall sub_83A(_DWORD *a1)
{
  int i; // [rsp+1Ch] [rbp-44h]
  int v3[14]; // [rsp+20h] [rbp-40h]
  unsigned __int64 v4; // [rsp+58h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  *a1 ^= 0x2Bu;
  a1[1] ^= 0x6Cu;
......
  v3[11] = 56;
  for ( i = 0; i <= 11; ++i )
  {
    if ( v3[i] != a1[i] )
    {
      printf("wrong on #%d\n", (unsigned int)i);
      return 0LL;
    }
  }
  return 1LL;
}

中间三千行直接复制

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int v3[] = {126,50,37,88,89,107,53,110,0,19,30,56};

int sub_83A(char *a1, int i)
{
  *a1 ^= 0x2Bu;
  a1[1] ^= 0x6Cu;
......
  a1[11] ^= 0x3Bu;
  
  return v3[i] == a1[i];
}

int main()
{
    char tmp[13] = "";
	char flag[13] = "";
    for(int i=0;i<12;i++){
	    for(int j=0x20;j<0x7f;j++){
	        strcpy(tmp,flag);
			tmp[i]= (char)j;
		    if(sub_83A(tmp,i)){
			    flag[i] = (char)j;
				break;
			}
		}
	}
	puts(flag);
}
//#flag{b0Nf|Re_LiT!}

058_[羊城杯 2020]easyre

分三步分别是base64,换顺序和换表(分大小字和数字左移3字符)

str2 = b"EmBmP5Pmn7QcPU4gLYKv5QcMmB3PWHcP5YkPq3=cT6QckkPckoRG"

#encode_three
tmp = []
for b in str2:
    if b>=ord('A') and b<=ord('Z'):
        tmp.append(((b-65+23)%26+65))
    elif b>=ord('a') and b<=ord('z'):
        tmp.append(((b-97+23)%26+97))
    elif b>=ord('0') and b<=ord('9'):
        tmp.append(((b-48+7)%10+48))
    else:
        tmp.append(b)

#encode_two
tmp = tmp[13:13+13]+tmp[39:39+13]+tmp[:13]+tmp[26:26+13]

#encode_one
from base64 import b64decode 
print(b64decode(bytes(tmp)))

#GWHT{672cc4778a38e80cb362987341133ea2}
#flag{672cc4778a38e80cb362987341133ea2}

059_[FlareOn5]Ultimate Minesweeper

这个不清楚怎么弄,搜了搜,原来dnSpy还可以改

这是个扫雷游戏,不过雷是固定的,只要扫成功就可以得到flag,雷有点多,1000的空间有997个雷。先用dnSpy把失败后的结束干掉不退出,然后点完记录下位置。再在原文件上点3个位置,即可得到。

8,-2
-2,-6
-10,8
在原程序点对应位置点出数字,得到flag
#Ch3aters_Alw4ys_W1n@flare-on.com
#flag{Ch3aters_Alw4ys_W1n@flare-on.com}

060_[FlareOn1]Bob Doge

又上个.net的程序,用dnSpy打开,找到加密函数就是高低位互换后再异或,第2步再奇偶互换再异或。发现flag在第1次加密的时候

		private void btnDecode_Click(object sender, EventArgs e)
		{
			this.pbRoge.Image = Resources.bob_roge;
			byte[] dat_secret = Resources.dat_secret;
			string text = "";
			foreach (byte b in dat_secret)
			{
				text += (char)((b >> 4 | ((int)b << 4 & 240)) ^ 41);
			}
			text += "\0";
			string text2 = "";
			for (int j = 0; j < text.Length; j += 2)
			{
				text2 += text[j + 1];
				text2 += text[j];
			}
			string text3 = "";
			for (int k = 0; k < text2.Length; k++)
			{
				char c = text2[k];
				text3 += (char)((byte)text2[k] ^ 102);
			}
			this.lbl_title.Text = text3;
		}
data = open('rev_challenge_1.dat_secret.encode', 'rb').read()

text = [((i>>4)|((i<<4)&0xf0))^41 for i in data]
print(bytes(text))  #3rmahg3rd.b0b.d0ge@flare-on.com
text2 = []
for i in range(0,len(text)-1,2):
    text2 +=[text[i+1], text[i]]

print(bytes(text2))

print(bytes([i^102 for i in text2]))

#flag{3rmahg3rd.b0b.d0ge@flare-on.com}

061_[MRCTF2020]PixelShooter

是个apk的包,打开后发现有Unity的名字,应该还是Unity的游戏,于是找到assets\bin\Data\Managed下的Assembly-CSharp.dll文件用dnSpy打开,在UIContral里找到flag

public class UIController : MonoBehaviour
{
	// Token: 0x06000288 RID: 648 RVA: 0x0000B6F8 File Offset: 0x000098F8
	public void GameOver(int score, int bestScore)
	{
		this.pad.SetActive(false);
		Time.timeScale = 0f;
		string text = "您的飞机已坠毁\n";
		if (bestScore < score)
		{
			string text2 = text;
			text = string.Concat(new object[]
			{
				text2,
				"获得最高分:",
				score,
				"!\n"
			});
			PlayerPrefs.SetInt("bestScore", score);
		}
		if (score < 20)
		{
			text += "少年继续努力!要拿到flag还差亿点点\n";
		}
		else if (score < 100)
		{
			text += "战绩不错!但是要拿到flag还差亿点";
		}
		else if (score < 500)
		{
			text += "惊人的成绩!!但是要拿到flag还差一点\n";
		}
		else
		{
			text += "MRCTF{Unity_1S_Fun_233}\n";
		}
		if (Time.time - this.lastTime < 15f)
		{
			text += "以及,别作死啊!\n";
		}
		else if (Time.time - this.lastTime < 60f)
		{
			text += "以及注意闪避!";
		}
		this.gameOverText.text = text;
		this.gameOverUI.SetActive(true);
	}

前边存的一堆写完了。以后可以一句句写了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值