GDOUCTF2023 Reverse题解
文章目录
题目附件
链接:https://pan.baidu.com/s/1W0GisS4R-rHYHK4Bu167_g?pwd=nw4c
Check_Your_Luck
可以看到五条方程,根据方程可以求解出对应的值
Z3库解不出来,所以用了在线解方程云算网(原名云算子)-在线求解线性方程组 (yunsuan.info)
flag: NSSCTF{4544_123_677_1754_777}
TEA
基本逻辑:
- 调用show函数,提示输入输出
- 以十六进制读取输入,可以得知共10*4=40字符
- 设置key数组
- 将input复制到arr数组中
- tea加密
- judge判断是否正确
- 输出flag
mainfun代码:
__int64 mainfun()
{char *v0; // rdi__int64 i; // rcxchar v3[32]; // [rsp+0h] [rbp-20h] BYREFchar v4; // [rsp+20h] [rbp+0h] BYREFint v5; // [rsp+24h] [rbp+4h]int result; // [rsp+44h] [rbp+24h]unsigned int key[12]; // [rsp+68h] [rbp+48h] BYREFint input[16]; // [rsp+98h] [rbp+78h] BYREFint arr[31]; // [rsp+D8h] [rbp+B8h] BYREFint j; // [rsp+154h] [rbp+134h]int k; // [rsp+174h] [rbp+154h]int m; // [rsp+194h] [rbp+174h]v0 = &v4;for ( i = 102i64; i; --i )//没作用{*v0 = 0xCCCCCCCC;v0 += 4;}sub_7FF7B3C8137F(&unk_7FF7B3C93009); //没作用v5 = 32;//tea循环次数result = 0;key[0] = 1234;key[1] = 5678;key[2] = 9012;key[3] = 3456; //设置key,但是这里设置的值是混淆的,下方会重新设置memset(input, 0, 40ui64);arr[15] = 0;arr[23] = 0;show(); //提示flag输入是以0x12345678这样的形式for ( j = 0; j < 10; ++j )scanf("%x", &input[j]); //以16进制读取,共10个,所以有10*4=40字符setKey(key); //设置keycopy(input, arr); //将input的内容复制到arrencode(input, key); //对input加密result = judge(input); //判断加密后的数组是否正确if ( result ) {printf("you are right\\n");for ( k = 0; k < 10; ++k ){for ( m = 3; m >= 0; --m )printf("%c", (arr[k] >> (8 * m))); //如果正确则输出input,即flag}}else{printf("fault!\\nYou can go online and learn the tea algorithm!");}sub_7FF7B3C81311(v3, &unk_7FF7B3C8AE90);return 0i64;
}
show函数
setKey函数
encode函数(tea算法):
__int64 __fastcall tea(unsigned int *arr, unsigned int *key)
{__int64 result; // raxint v3; // [rsp+44h] [rbp+24h]int i; // [rsp+64h] [rbp+44h]unsigned int v5; // [rsp+84h] [rbp+64h]unsigned int sum; // [rsp+C4h] [rbp+A4h]result = sub_7FF7B3C8137F(&unk_7FF7B3C93009);//没用for ( i = 0; i <= 8; ++i ){v5 = 0;sum = 0xF462900 * i;//delta与标准的tea并不同v3 = i + 1;do{++v5;arr[i] += sum ^ (arr[v3] + ((arr[v3] >> 5) ^ (16 * arr[v3]))) ^ (sum + key[sum & 3]);arr[v3] += (sum + key[(sum >> 11) & 3]) ^ (arr[i] + ((arr[i] >> 5) ^ (16 * arr[i])));sum += 0xF462900;//关键算法和tea区别不大}while ( v5 <= 32 ); // 注意这里是从0到32,共33次循环result = (i + 1);}return result;
}
judge函数
解题脚本
#include <stdio.h>
int main()
{
int v3; // [rsp+44h] [rbp+24h]
int i; // [rsp+64h] [rbp+44h]
unsigned int v5; // [rsp+84h] [rbp+64h]
int sum; // [rsp+C4h] [rbp+A4h]
int key[4] = {2233,4455,6677,8899 };
unsigned int arr[10];
arr[0] = 0x1A800BDA;
arr[1] = 0xF7A6219B;
arr[2] = 0x491811D8;
arr[3] = 0xF2013328;
arr[4] = 0x156C365B;
arr[5] = 0x3C6EAAD8;
arr[6] = 0x84D4BF28;
arr[7] = 0xF11A7EE7;
arr[8] = 0x3313B252;
arr[9] = 0xDD9FE279;
for (i = 8; i >=0; i--)
{
v5 = 0;
sum = 0xF462900 * i;
for (int j = 0; j < 33; j++)
sum += 0xF462900;
v3 = i + 1;
do
{
sum -= 0xF462900;
arr[v3] -= (sum + key[(sum >> 11) & 3]) ^ (arr[i] + ((arr[i] >> 5) ^ (16 * arr[i])));
arr[i] -= sum ^ (arr[v3] + ((arr[v3] >> 5) ^ (16 * arr[v3]))) ^ (sum + key[sum & 3]);
++v5;
} while (v5 <= 32);//33次循环
}
for (int k = 0; k < 10; ++k)
{for (int m = 3; m >= 0; --m)printf("%c", (arr[k] >> (8 * m)));
}
//HZCTF{hzCtf_94_re666fingcry5641qq}
return 0;
doublegame
进来找不到关键函数,查看strings看到类似迷宫的东西,根据字符串可以定位到关键函数
snakefun
通过patch可以修改得分判断条件,从而进入game2
__int64 __fastcall snakefun(int a1, int a2)
{char *v2; // rdi__int64 i; // rcxchar v5[32]; // [rsp+0h] [rbp-20h] BYREFchar v6; // [rsp+20h] [rbp+0h] BYREFchar chr[212]; // [rsp+24h] [rbp+4h] BYREFv2 = &v6;for ( i = 10i64; i; --i ){*(_DWORD *)v2 = -858993460;v2 += 4;}sub_7FF6BD89141A((__int64)&unk_7FF6BD8A90A6);if ( dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 2 ){++dword_7FF6BD8A0170;score += 10;sub_7FF6BD8911A9(7i64);sub_7FF6BD89130C(0i64, 22i64);printf(aD_2, (unsigned int)score); // 当前得分setFood(); // 生成食物}else if ( dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 1|| dword_7FF6BD8A1E60[42 * a2 + 42 * dword_7FF6BD8A0178 + a1 + dword_7FF6BD8A0174] == 4 ){Sleep(0x3E8u);system("cls");sub_7FF6BD8911A9(7i64);sub_7FF6BD89130C(28i64, 8i64);sub_7FF6BD8911DB(); // 分数还差一点if ( score > 16 ) // score13371337sub_7FF6BD89136B(); // jump to game 2sub_7FF6BD8910E6(); // 保存最高记录失败sub_7FF6BD89130C(28i64, 11i64);printf("GAME OVER");while ( 1 ){sub_7FF6BD89130C(28i64, 14i64);printf(asc_7FF6BD89D320); // 是否再来一局scanf_0("%c", chr);if ( chr[0] == 'y' || chr[0] == 'Y' )break;if ( chr[0] == 'n' || chr[0] == 'N' ){sub_7FF6BD89130C(28i64, 16i64);exit(0);}sub_7FF6BD89130C(28i64, 16i64);printf(asc_7FF6BD89D3A0); // 选择错误}system("cls");someidea(); // 提示}return sub_7FF6BD8913B1(v5, &unk_7FF6BD89CFC0);
}
/* Orphan comments:
打破最高记录
继续加油,最高记录分为
*/
迷宫
这是迷宫图:
注意这里多了一堵墙
下面还有一个大循环
关键循环
v24 = 0;key = 0;hang = 15;lie = 0;shang = 7; // 8行slie = 20; // 21列for ( j = 0; j <= 20; ++j )puts(&Buffer[22 * j]); // 打印迷宫printf("Please to save the cat!\\n");while ( hang != shang || lie != slie ) // 好像不是走到@的位置{chr = getchar();switch ( chr ){case 's':if ( Buffer[22 * hang + 22 + lie] != '0' ){Buffer[22 * hang++ + lie] = ' ';Buffer[22 * hang + lie] = '@';}break;case 'w':if ( Buffer[22 * hang - 22 + lie] != '0' ){Buffer[22 * hang-- + lie] = ' ';Buffer[22 * hang + lie] = '@';}break;case 'a':if ( Buffer[22 * hang - 1 + lie] != '0' ){if ( Buffer[22 * hang - 1 + lie] == '*' )// 先到*这里v7[20] = '0'; //设置墙Buffer[22 * hang + lie--] = ' ';Buffer[22 * hang + lie] = '@';}break;default:if ( chr == 'd' && Buffer[22 * hang + 1 + lie] != '0' ){Buffer[22 * hang + lie++] = ' ';Buffer[22 * hang + lie] = '@';}break;}system("cls");for ( j = 0; j <= 20; ++j )puts(&Buffer[22 * j]); // 打印迷宫puts(&v19[100 * v24]); // 请救猫if ( v7[20] == '0' ){key = judge(0i64); // 判断keyif ( key == 13376013 ){v24 = 1;v7[20] = ' '; // 打通终点前的墙Buffer[22 * hang + lie] = ' ';hang = 15;lie = 0;v11[0] = '@'; // 回到起点++v24;}else{printf("error");}}}
循环功能:
-
shang,slie是终点;hang,lie是当前位置
-
从@的位置出发,经路径dddssssddwwwwddssddwwwwwwddddssa救到小猫后回到起点;同时小猫所在位置由’*‘变为’ ',且第8行第20列的空格变为0
-
然后要求输入key,key可以根据judge函数反推出来是13371337
-
再从起点出发,经路径dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd走出迷宫
-
所以path:dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd key:13371337
-
根据提示可以求出flag:NSSCTF{811173b05afff098b4e0757962127eac13371337}
提示函数:
位置由’*‘变为’ ',且第8行第20列的空格变为0
-
然后要求输入key,key可以根据judge函数反推出来是13371337
-
再从起点出发,经路径dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd走出迷宫
-
所以path:dddssssddwwwwddssddwwwwwwddddssaassddddwwwwddwwwwddd key:13371337
-
根据提示可以求出flag:NSSCTF{811173b05afff098b4e0757962127eac13371337}