题目大致三个步骤

长度检测,置换,对比sha1值。
SHA1那里很容易可以从chatgpt那里得出。

最关键的就是要搞清楚中间的置换逻辑。至于为什么有一个sha1检测,我首先想到的就是多解,也就是根据那个逻辑能得出多种组合,而这里只取其中一个。(当时出题就是没有考虑多解,后来经提醒想到可以用哈希值来固定答案)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| for ( i = 0; i < 48; ++i ) { v6 = input[i]; v5 = off_B69000[2 * v6]; if ( v6 - 5 == v5 ) { v9[i] = ~(v6 + 1); } else { if ( v6 + 5 != v5 ) { printf("Wrong flag\n", v4); exit(0); } v9[i] = ~(v6 - 1); } off_B69000 = (int *)off_B69000[2 * v6 + 1]; }
|
off_B69000是一个指针数组,input需要满足的条件是input[i] -/+ 5 == off_B69000[2*input[i]]
,而且每次操作之后都会由off_B69000 = (int *)off_B69000[2 * v6 + 1];
改变地址,只能采取暴破的方法。
在输入之前有一个初始化的函数

他按照值、地址、值、地址的顺序赋值了5000组,这些数据就是比较数据。在数组的位置右键,点击arry然后填写数组大小即可将其解析,再将其dump出来即可。
暴破脚本:
该脚本的要点在于偏移地址的计算和递归的运用。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #include<stdio.h> int index=0; char flag[48]; int fun(int base); void printStr(char*str,int maxlen); int offset=0; unsigned int arr[10000] = {…………}
int main() { fun(0); return 0; }
void printStr(char*str,int maxlen) { int strlen=0; while(flag[strlen]!='\0'&&strlen<maxlen) { printf("%c",flag[strlen]); strlen++; } printf("\n"); }
int fun(int index) { if(index==48) { if(flag[8]!='s'||flag[15]!='e'||flag[18]!='5'||flag[23]!='e'||flag[33]!='t'||flag[38]!='n'||flag[45]!='t') { return 1; } printStr(flag,48); return 1; } for(int chr=33;chr<127;chr++) { if((chr+5==arr[chr*2+offset])||(chr-5==arr[chr*2+offset])) { int orgoffset=offset; offset=arr[chr*2+1+offset]; int result=offset; result-=0x299078; offset=(result/4); flag[index]=chr; fun(index+1); offset=orgoffset; } }
}
|

参考:
2024年西湖论剑逆向Reverse题目MZ分析_哔哩哔哩_bilibili
【CTF&RE】2024西湖论剑–MZ_哔哩哔哩_bilibili