蜀道山2024复现笔记
Map_maze
PE32文件,ida分析,由题名可知是一道迷宫题
initial
函数是地图的初始化,sub_101C40是验证函数
先看验证部分
char __cdecl sub_101C40(_DWORD *a1, _DWORD *a2, int a3)
{char result; // alint i; // [esp+0h] [ebp-8h]for ( i = 0; *(_BYTE *)(i + a3); ++i ){if ( *(_BYTE *)(i + a3) == 'U' && a1[1] && !*(_DWORD *)a1[1] ){a1 = (_DWORD *)a1[1];//上}else if ( *(_BYTE *)(i + a3) == 'D' && a1[2] && !*(_DWORD *)a1[2] ){a1 = (_DWORD *)a1[2];//下}else if ( *(_BYTE *)(i + a3) == 'L' && a1[3] && !*(_DWORD *)a1[3] ){a1 = (_DWORD *)a1[3];//左}else{if ( *(_BYTE *)(i + a3) != 'R' || !a1[4] || *(_DWORD *)a1[4] )return 0;a1 = (_DWORD *)a1[4];//右}}result = (char)a2;if ( a1[2] == a2[2] ){result = (char)a2;if ( a1[1] == a2[1] ){result = (char)a2;if ( a1[3] == a2[3] ){result = (char)a2;if ( a1[4] == a2[4] )return 1;}}}return result;
}
上下左右移动可以猜出来,但是具体的验证逻辑有点看不懂
继续看initial
int __cdecl initial(_DWORD *a1, _DWORD *a2)
{_DWORD *v2; // eax_DWORD *v3; // eaxint result; // eax_DWORD v5[105]; // [esp+0h] [ebp-424h] BYREF_DWORD v6[119]; // [esp+1A4h] [ebp-280h]//事实上,v5和v6都是地图的一部分,查看内存可知它们是连在一起的,105+119+[0]=225也可以验证这一点_DWORD *v7; // [esp+380h] [ebp-A4h]int i28; // [esp+384h] [ebp-A0h]int i27; // [esp+388h] [ebp-9Ch]int i26; // [esp+38Ch] [ebp-98h]int i25; // [esp+390h] [ebp-94h]int i24; // [esp+394h] [ebp-90h]int i23; // [esp+398h] [ebp-8Ch]int i22; // [esp+39Ch] [ebp-88h]int i21; // [esp+3A0h] [ebp-84h]int i20; // [esp+3A4h] [ebp-80h]int i19; // [esp+3A8h] [ebp-7Ch]int i18; // [esp+3ACh] [ebp-78h]int i17; // [esp+3B0h] [ebp-74h]int i16; // [esp+3B4h] [ebp-70h]int i15; // [esp+3B8h] [ebp-6Ch]int i14; // [esp+3BCh] [ebp-68h]int i13; // [esp+3C0h] [ebp-64h]int i12; // [esp+3C4h] [ebp-60h]int i11; // [esp+3C8h] [ebp-5Ch]int i10; // [esp+3CCh] [ebp-58h]int i9; // [esp+3D0h] [ebp-54h]int i8; // [esp+3D4h] [ebp-50h]int i7; // [esp+3D8h] [ebp-4Ch]int i6; // [esp+3DCh] [ebp-48h]int i5; // [esp+3E0h] [ebp-44h]int i4; // [esp+3E4h] [ebp-40h]int i3; // [esp+3E8h] [ebp-3Ch]int i2; // [esp+3ECh] [ebp-38h]int i1; // [esp+3F0h] [ebp-34h]int nn; // [esp+3F4h] [ebp-30h]int mm; // [esp+3F8h] [ebp-2Ch]int kk; // [esp+3FCh] [ebp-28h]int jj; // [esp+400h] [ebp-24h]int ii; // [esp+404h] [ebp-20h]int n; // [esp+408h] [ebp-1Ch]int m; // [esp+40Ch] [ebp-18h]int k; // [esp+410h] [ebp-14h]int j; // [esp+414h] [ebp-10h]int i; // [esp+418h] [ebp-Ch]int i30; // [esp+41Ch] [ebp-8h]int i29; // [esp+420h] [ebp-4h]for ( i = 0; i < 15; ++i ){for ( j = 0; j < 15; ++j )v5[15 * i + j] = sub_101080(0);//初始化为0(墙),15x15的map}for ( k = 1; k < 15; ++k )*(_DWORD *)v5[k] = 1;for ( m = 9; m < 15; ++m )*(_DWORD *)v5[m + 15] = 1;for ( n = 0; n < 2; ++n )*(_DWORD *)v5[n + 30] = 1;for ( ii = 3; ii < 8; ++ii )*(_DWORD *)v5[ii + 30] = 1;for ( jj = 9; jj < 15; ++jj )*(_DWORD *)v5[jj + 30] = 1;for ( kk = 0; kk < 2; ++kk )*(_DWORD *)v5[kk + 45] = 1;for ( mm = 3; mm < 8; ++mm )*(_DWORD *)v5[mm + 45] = 1;for ( nn = 12; nn < 15; ++nn )*(_DWORD *)v5[nn + 45] = 1;for ( i1 = 0; i1 < 2; ++i1 )*(_DWORD *)v5[i1 + 60] = 1;for ( i2 = 7; i2 < 10; ++i2 )*(_DWORD *)v5[i2 + 60] = 0;*(_DWORD *)v5[67] = 1;for ( i3 = 11; i3 < 15; ++i3 )*(_DWORD *)v5[i3 + 60] = 1;for ( i4 = 0; i4 < 2; ++i4 )*(_DWORD *)v5[i4 + 75] = 1;for ( i5 = 3; i5 < 6; ++i5 )*(_DWORD *)v5[i5 + 75] = 1;for ( i6 = 11; i6 < 15; ++i6 )*(_DWORD *)v5[i6 + 75] = 1;for ( i7 = 0; i7 < 2; ++i7 )*(_DWORD *)v5[i7 + 90] = 1;*(_DWORD *)v5[92] = 0;for ( i8 = 3; i8 < 6; ++i8 )*(_DWORD *)v5[i8 + 90] = 1;for ( i9 = 7; i9 < 10; ++i9 )*(_DWORD *)v5[i9 + 90] = 1;for ( i10 = 11; i10 < 15; ++i10 )*(_DWORD *)v5[i10 + 90] = 1;*(_DWORD *)v6[0] = 1;*(_DWORD *)v6[1] = 0;*(_DWORD *)v6[2] = 0;*(_DWORD *)v6[3] = 1;for ( i11 = 4; i11 < 6; ++i11 )*(_DWORD *)v6[i11] = 1;for ( i12 = 7; i12 < 10; ++i12 )*(_DWORD *)v6[i12] = 1;for ( i13 = 11; i13 < 15; ++i13 )*(_DWORD *)v6[i13] = 1;for ( i14 = 0; i14 < 2; ++i14 )*(_DWORD *)v6[i14 + 15] = 1;for ( i15 = 7; i15 < 10; ++i15 )*(_DWORD *)v6[i15 + 15] = 1;for ( i16 = 11; i16 < 15; ++i16 )*(_DWORD *)v6[i16 + 15] = 1;for ( i17 = 0; i17 < 6; ++i17 )*(_DWORD *)v6[i17 + 30] = 1;for ( i18 = 7; i18 < 10; ++i18 )*(_DWORD *)v6[i18 + 30] = 1;for ( i19 = 11; i19 < 15; ++i19 )*(_DWORD *)v6[i19 + 30] = 1;for ( i20 = 0; i20 < 6; ++i20 )*(_DWORD *)v6[i20 + 45] = 1;for ( i21 = 11; i21 < 15; ++i21 )*(_DWORD *)v6[i21 + 45] = 1;for ( i22 = 0; i22 < 9; ++i22 )*(_DWORD *)v6[i22 + 60] = 1;for ( i23 = 13; i23 < 15; ++i23 )*(_DWORD *)v6[i23 + 60] = 1;for ( i24 = 0; i24 < 9; ++i24 )*(_DWORD *)v6[i24 + 75] = 1;*(_DWORD *)v6[84] = 0;*(_DWORD *)v6[85] = 1;*(_DWORD *)v6[86] = 1;*(_DWORD *)v6[87] = 0;for ( i25 = 13; i25 < 15; ++i25 )*(_DWORD *)v6[i25 + 75] = 1;for ( i26 = 0; i26 < 9; ++i26 )*(_DWORD *)v6[i26 + 90] = 1;*(_DWORD *)v6[99] = 0;*(_DWORD *)v6[100] = 1;*(_DWORD *)v6[101] = 1;*(_DWORD *)v6[102] = 0;for ( i27 = 13; i27 < 15; ++i27 )*(_DWORD *)v6[i27 + 90] = 1;for ( i28 = 0; i28 < 12; ++i28 )*(_DWORD *)v6[i28 + 105] = 1;for ( i29 = 0; i29 < 15; ++i29 ){for ( i30 = 0; i30 < 15; ++i30 ){if ( i29 > 0 )*(_DWORD *)(v5[15 * i29 + i30] + 4) = v5[15 * i29 - 15 + i30];if ( i29 < 14 )*(_DWORD *)(v5[15 * i29 + i30] + 8) = v5[15 * i29 + 15 + i30];if ( i30 > 0 )*(_DWORD *)(v5[15 * i29 + i30] + 12) = v5[15 * i29 - 1 + i30];if ( i30 < 14 )*(_DWORD *)(v5[15 * i29 + i30] + 16) = v5[15 * i29 + 1 + i30];}}//确定上下左右的指针逻辑,这段代码的主要目的是构建一个包含方向信息的15x15网格结构,使得每个格子都知道它在四个基本方向上的邻居是谁。v2 = (_DWORD *)v5[0];*a1 = *(_DWORD *)v5[0];a1[1] = v2[1];a1[2] = v2[2];a1[3] = v2[3];a1[4] = v2[4];v3 = v7;*a2 = *v7;a2[1] = v3[1];a2[2] = v3[2];a2[3] = v3[3];result = v3[4];a2[4] = result;return result;
}
事实上,这里的v5
,v6
即map[]
是结构体类型的数据,具体定义如下
typedef enum{NotWall,IsWall
} WallState;
struct Cell{WallState isWall;//是否为墙的枚举值struct Cell* U;//指向上方的指针struct Cell* D;//指向下方的指针struct Cell* L;//指向左方的指针struct Cell* R;//指向右方的指针
}
因此,对于一个Cell类型的数据a1,从内存上,
a1[0]=a1.isWall;
a1[1]=a1.U;
a1[2]=a1.D;
a1[3]=a1.L;
a1[4]=a1.R;
逻辑很清晰了,接下来就是拿到map
'''
011111111111111
000000000111111
110111110111111
110111110000111
110000010001111
110111000001111
110111011101111
100111011101111
110000011101111
111111011101111
111111000001111
111111111000011
111111111011011
111111111011011
111111111111000
'''
地图有多解,flag只有唯一解,多尝试几次,正确答案是
#DRRDDDDDDDRRRRDDRRRDRRRDDDRR
Potato Toolkit
运行程序,发现要输入http指令和参数
ida分析,查找关键字符串Complie Error
定位到关键逻辑代码
往上看,找到两个字符串1wesa234
,qwe123998244353
,输进去执行发现直接闪退
找到exit(0)
,下断点动调,这里应该是数据操作部分
重点看加密部分
v10 = v20;
do
{v12 = QString::length((QString *)v17);//获取字符串长度v13 = (QChar *)QString::operator[](v17, v2 % v12);//根据索引v2%length访问v17中的特定字符给v13v14 = QChar::unicode(v13);//获取v13(char型)的unicode值v15 = QChar::QChar((QChar *)&v16, *(_BYTE *)v10 ^ *(_BYTE *)v14);//对v10指向的数据和v14处的字符的字节表示进行按字节的异或,结果存在v15(QChar对象)QString::operator+=(v18, *(unsigned __int16 *)v15);//将新生成的字符存在v18所指向的QString对象中
//更新循环变量++v2;v10 = (__int128 *)((char *)v10 + 4);--v11;
}
while ( v11 );
逻辑很清晰,就是循环异或,这里已经动调到exit(0)
处,直接进v18,注意,这里的v18是一个指针,其指向的内容才是flag
0x8处按d,得到指向的flag