目录
053_[FlareOn5]Minesweeper Championship Registration
059_[FlareOn5]Ultimate Minesweeper
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);
}
前边存的一堆写完了。以后可以一句句写了