Adworld Re Writeups

Coast23

Reversing-x64Elf-100

下载附件得到.re文件.

先用DIE看看是什么文件:

DIE1

然后再扔进IDA:

IDA1

重点是这个sub_4006FD函数:

IDA2

根本不需要分析, 直接打印*(char *)(i + a1)就行.

exp:

#include <stdio.h>
#include <stdint.h>

__int64 __fastcall sub_4006FD(__int64 a1)
{
int i; // [rsp+14h] [rbp-24h]
__int64 v3[4]; // [rsp+18h] [rbp-20h]

v3[0] = (__int64)"Dufhbmf";
v3[1] = (__int64)"pG`imos";
v3[2] = (__int64)"ewUglpt";
for ( i = 0; i <= 11; ++i )
{
// if ( *(char *)(v3[i % 3] + 2 * (i / 3)) - *(char *)(i + a1) != 1 )
// return 1LL;
printf("%c", *(char *)(v3[i % 3] + 2 * (i / 3)) - 1);
}
return 0LL;
}

int main(){
sub_4006FD(0LL);
return 0^(0-0)^0;
}

Flag: Code_Talkers


666

解压附件得到666文件.

DIE:

DIE2

IDA:

  • main函数:

IDA3

  • encode函数:

IDA4

  • key = 18, enFlag = izwhroz""w"v.K".Ni

encode是线性的, 而且只涉及简单的加减和异或, 直接逆就行了.

exp:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#define _BYTE char

#define key 18

int __fastcall encode(const char *a1, __int64 a2)
{
char v3[104]; // [rsp+10h] [rbp-70h]
int v4; // [rsp+78h] [rbp-8h]
int i; // [rsp+7Ch] [rbp-4h]

i = 0;
v4 = 0;
if ( strlen(a1) != key )
return puts("Your Length is Wrong");
for ( i = 0; i < key; i += 3 )
{
/* v3[i + 64] = key ^ (a1[i] + 6);
v3[i + 33] = (a1[i + 1] - 6) ^ key;
v3[i + 2] = a1[i + 2] ^ 6 ^ key;
*(_BYTE *)(a2 + i) = v3[i + 64];
*(_BYTE *)(a2 + i + 1LL) = v3[i + 33];
*(_BYTE *)(a2 + i + 2LL) = v3[i + 2];
*/
// 等价于如下代码
*(_BYTE *)(a2 + i) = key ^ (a1[i] + 6);
*(_BYTE *)(a2 + i + 1LL) = (a1[i + 1] - 6) ^ key;
*(_BYTE *)(a2 + i + 2LL) = a1[i + 2] ^ 6 ^ key;
}
return a2;
}

void decode(char *a2){
char flag[104] = {0};
for(int i = 0; i < key; i += 3){
flag[i] = (*(_BYTE *)(a2 + i) ^ key) - 6;
flag[i + 1] = (*(_BYTE *)(a2 + i + 1) ^ key) + 6;
flag[i + 2] = *(_BYTE *)(a2 + i + 2) ^ 6 ^ key;
}
printf("%s\n", flag);
}

int main(){
char s[] = "izwhroz\"\"w\"v.K\".Ni";
decode(s);
return 0^(0-0)^0;
}

Flag: unctf{b66_6b6_66b}


easyRE1

解压附件得到个文件: easy-32easy-64.

两个文件扔到IDA里是几乎一样的:

IDA5

直接提交db2f62a36a018bce28e46d976e3f9864, 错误.

db2f62a36a018bce28e46d976e3f9864进行解密无果, 直接搜这个字符串才知道答案要包上flag{}

显然这是个签到题.

Flag: flag{db2f62a36a018bce28e46d976e3f9864}


lucknum

解压附件得到lucknum文件.

DIE:

DIE3

IDA:

IDA6

也是一道搞笑签到题.

Flag: flag{c0ngr@tul@ti0n_f0r_luck_numb3r}


reverse_re3

reverse_re3题目描述

解压附件得到main2文件.

DIE:

DIE4

IDA:

IDA7

看到positive sp value has been detected.有点慌, 先切到main函数看看:

IDA8

重点是这个sub_940函数:

__int64 sub_940()
{
int v0; // eax
int v2; // [rsp+8h] [rbp-218h]
int v3; // [rsp+Ch] [rbp-214h]
char v4[520]; // [rsp+10h] [rbp-210h] BYREF
unsigned __int64 v5; // [rsp+218h] [rbp-8h]

v5 = __readfsqword(0x28u);
v3 = 0;
memset(v4, 0, 0x200uLL);
_isoc99_scanf(&unk_1278, v4, v4);
while ( 1 )
{
do
{
v2 = 0;
sub_86C();
v0 = v4[v3];
if ( v0 == 100 ) // Coast的注释: d
{
v2 = sub_E23();
}
else if ( v0 > 100 )
{
if ( v0 == 115 ) // Coast的注释: s
{
v2 = sub_C5A();
}
else if ( v0 == 119 ) // Coast的注释: w
{
v2 = sub_A92();
}
}
else
{
if ( v0 == 27 ) // Coast的注释: ESC
return 0xFFFFFFFFLL;
if ( v0 == 97 ) // Coast的注释: a
v2 = sub_FEC();
}
++v3;
}
while ( v2 != 1 );
if ( dword_202AB0 == 2 )
break;
++dword_202AB0;
}
puts("success! the flag is flag{md5(your input)}");
return 1LL;
}

可以看出, 这应该是一个走迷宫程序, 再来看看sub_86C, sub_E23, sub_C5A, sub_A92, sub_FEC:

unsigned __int64 sub_86C()
{
int i; // [rsp+0h] [rbp-10h]
int j; // [rsp+4h] [rbp-Ch]
unsigned __int64 v3; // [rsp+8h] [rbp-8h]

v3 = __readfsqword(0x28u);
for ( i = 0; i <= 14; ++i )
{
for ( j = 0; j <= 14; ++j )
{
if ( dword_202020[225 * dword_202AB0 + 15 * i + j] == 3 )
{
dword_202AB4 = i;
dword_202AB8 = j;
break;
}
}
}
return __readfsqword(0x28u) ^ v3;
}
__int64 sub_E23()
{
if ( dword_202AB8 != 14 )
{
if ( dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] == 1 )
{
dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] = 3;
dword_202020[225 * dword_202AB0 + 15 * dword_202AB4 + dword_202AB8] = 1;
}
else if ( dword_202020[225 * dword_202AB0 + 1 + 15 * dword_202AB4 + dword_202AB8] == 4 )
{
return 1LL;
}
}
return 0LL;
}
__int64 sub_C5A()
{
if ( dword_202AB4 != 14 )
{
if ( dword_202020[225 * dword_202AB0 + 15 + 15 * dword_202AB4 + dword_202AB8] == 1 )
{
dword_202020[225 * dword_202AB0 + 15 + 15 * dword_202AB4 + dword_202AB8] = 3;
dword_202020[225 * dword_202AB0 + 15 * dword_202AB4 + dword_202AB8] = 1;
}
else if ( dword_202020[225 * dword_202AB0 + 15 + 15 * dword_202AB4 + dword_202AB8] == 4 )
{
return 1LL;
}
}
return 0LL;
}
__int64 sub_A92()
{
if ( dword_202AB4 )
{
if ( dword_202020[225 * dword_202AB0 - 15 + 15 * dword_202AB4 + dword_202AB8] == 1 )
{
dword_202020[225 * dword_202AB0 - 15 + 15 * dword_202AB4 + dword_202AB8] = 3;
dword_202020[225 * dword_202AB0 + 15 * dword_202AB4 + dword_202AB8] = 1;
}
else if ( dword_202020[225 * dword_202AB0 - 15 + 15 * dword_202AB4 + dword_202AB8] == 4 )
{
return 1LL;
}
}
return 0LL;
}
__int64 sub_FEC()
{
if ( dword_202AB8 )
{
if ( dword_202020[225 * dword_202AB0 - 1 + 15 * dword_202AB4 + dword_202AB8] == 1 )
{
dword_202020[225 * dword_202AB0 - 1 + 15 * dword_202AB4 + dword_202AB8] = 3;
dword_202020[225 * dword_202AB0 + 15 * dword_202AB4 + dword_202AB8] = 1;
}
else if ( dword_202020[225 * dword_202AB0 - 1 + 15 * dword_202AB4 + dword_202AB8] == 4 )
{
return 1LL;
}
}
return 0LL;
}

合理猜测dword_202AB4是横坐标, dword_202AB8是纵坐标, dword_202020是地图, dword_202AB0目前还不知道是啥.

看看dword_202020:

IDA9

选中这个区段的数据, 按快捷键shift + E即可导出数据. 注意要选择initialized C variables: DWORD是双节, 相当于unsigned long.

dword_202020 (25行27列)
_DWORD dword_202020[675] = 
{
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 3, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 3, 1, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1,
0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
};

通过坐标的上下限, 很容易得知地图的大小是 , 可是为什么dword_202020的大小是呢?

上面这几个函数都能看到类似dword_202020[225 * dword_202AB0 + 15 * i + j]的语句, 可以大胆猜测: dword_202020其实是保存了的地图, 由dword_202AB0表示当前是第几个地图.

sub_940的循环终止条件: if(dword_202AB0 == 2) break; ++dword_202AB0;证实了这个猜测.

dword_202020 (3 * 15 * 15)
_DWORD dword_202020[3][15][15] = 
{
{
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 3, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
},
};

显然, 3代表起点, 4代表终点. 这里可以直接走, 但我还是写了个脚本来输出路线.

反正不是比赛, 怎样优雅就怎样来.

exp:

#include <queue>
#include <cstdio>
#include <windef.h>

DWORD dword_202020[3][15][15] =
{
{
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 3, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 0, 3, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0,
1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0,
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,
},
};

char pre[3][15][15];

void get_start_pos(int maze, int* x, int* y){ // 找起点
for(int i = 0; i < 15; ++i){
for(int j = 0; j < 15; ++j){
if(dword_202020[maze][i][j] == 3){
*x = i, *y = j; return;
}
}
}
}

void print(int maze, int x, int y){ // 递归打印路径
if(pre[maze][x][y] == 'q') return;
if(pre[maze][x][y] == 'w') print(maze, x+1, y);
if(pre[maze][x][y] == 'a') print(maze, x, y+1);
if(pre[maze][x][y] =='s') print(maze, x-1, y);
if(pre[maze][x][y] == 'd') print(maze, x, y-1);
putchar(pre[maze][x][y]);
}

void bfs(int maze, int x, int y){
std::queue<std::pair<int, int>> q;
pre[maze][x][y] = 'q';
q.push({x, y});
while(q.size()){
int x = q.front().first, y = q.front().second; q.pop();
if(dword_202020[maze][x][y] == 4){print(maze, x, y); return;}
dword_202020[maze][x][y] = 0;
if(x > 0 and dword_202020[maze][x-1][y]){
q.push({x-1, y});
pre[maze][x-1][y] = 'w';
}
if(x < 14 and dword_202020[maze][x+1][y]){
q.push({x+1, y});
pre[maze][x+1][y] = 's';
}
if(y > 0 and dword_202020[maze][x][y-1]){
q.push({x, y-1});
pre[maze][x][y-1] = 'a';
}
if(y < 14 and dword_202020[maze][x][y+1]){
q.push({x, y+1});
pre[maze][x][y+1] = 'd';
}
}
}

int main(){
int maze = 0, x = -1, y = -1;
while(maze <= 2){
get_start_pos(maze, &x, &y);
bfs(maze, x, y);
++maze;
}
return 0^(0-0)^0;
}

// Output: ddsssddddsssdssdddddsssddddsssaassssdddsddssddwddssssssdddssssdddss

flag格式在sub_940的最后面: flag{md5(your input)}.

Flag: flag{aeea66fcac7fa80ed8f79f38ad5bb953}


1000Click

解压附件得到1000Click.exe.

DIE:

DIE

似乎加壳了. 用IDA打开, 发现有个函数…

IDA

果断放弃.

先用DIE直接查字符串:

DIE

一堆假flag. 还是老老实实运行程序吧.

RUN

看样子, 只需要点击Click按钮次即可拿到flag.

DBCDC很快就点到次了.

当然, 也可以写一个AutoClicker.

#include <windows.h>
int main()
{
int cnt = 0;
while(cnt < 1000)
{
if(GetAsyncKeyState('S')) // 鼠标对准按钮, 按下S键开启连点.
{
while(cnt < 1000)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
Sleep(3);
if(GetAsyncKeyState('B')) break; // 发生意外请按B键退出.
++cnt;
}
exit(0);
}
}
return 0^(0-0)^0;
}

上述代码可能需要以管理员身份运行.

点击次后会有一个弹窗:

FLAG

弹窗里的flag无法直接复制, 别傻呵呵地去辨认lI, 直接在DIE里搜.

DIE

Flag: flag{TIBntXVbdZ4Z9VRtoOQ2wRlvDNIjQ8Ra}


crypt

解压附件得到 crypt.exe.

没有壳, 直接扔进 IDA 反编译.

int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
unsigned int v4; // eax
__int64 v5; // rax
__int64 v7; // rax
int i; // [rsp+24h] [rbp-D4h]
void *v9; // [rsp+28h] [rbp-D0h]
char v10[32]; // [rsp+30h] [rbp-C8h] BYREF
char Str[32]; // [rsp+50h] [rbp-A8h] BYREF
char v12[96]; // [rsp+70h] [rbp-88h] BYREF

strcpy(Str, "12345678abcdefghijklmnopqrspxyz");
memset(v12, 0, sizeof(v12));
memset(v10, 0, 0x17ui64);
sub_1400054D0("%s", v10); // scanf
v9 = malloc(0x408ui64);
v3 = strlen(Str);
sub_140001120(v9, Str, v3); // 待分析
v4 = strlen(v10);
sub_140001240(v9, v10, v4); // 待分析
for ( i = 0; i < 22; ++i )
{
if ( ((unsigned __int8)v10[i] ^ 0x22) != (unsigned __int8)byte_14013B000[i] )
{
v5 = sub_1400015A0(&off_14013B020, "error");
_CallMemberFunction0(v5, sub_140001F10);
return 0;
}
}
v7 = sub_1400015A0(&off_14013B020, "nice job");
_CallMemberFunction0(v7, sub_140001F10);
return 0;
}

// 补充:
_BYTE byte_14013B000[24] =
{
0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B,
0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E,
0x8D, 0x2B, 0x00, 0x00
};
__int64 __fastcall sub_140001120(_DWORD *a1, __int64 a2, int a3)
{
__int64 result; // rax
int i; // [rsp+0h] [rbp-28h]
int j; // [rsp+0h] [rbp-28h]
int v6; // [rsp+4h] [rbp-24h]
int v7; // [rsp+8h] [rbp-20h]
int v8; // [rsp+Ch] [rbp-1Ch]
_DWORD *v9; // [rsp+10h] [rbp-18h]

*a1 = 0;
a1[1] = 0;
v9 = a1 + 2;
for ( i = 0; i < 256; ++i )
v9[i] = i;
v6 = 0;
result = 0i64;
LOBYTE(v7) = 0;
for ( j = 0; j < 256; ++j )
{
v8 = v9[j];
v7 = (unsigned __int8)(*(_BYTE *)(a2 + v6) + v8 + v7);
v9[j] = v9[v7];
v9[v7] = v8;
if ( ++v6 >= a3 )
v6 = 0;
result = (unsigned int)(j + 1);
}
return result;
}
_DWORD *__fastcall sub_140001240(_DWORD *a1, __int64 a2, int a3)
{
_DWORD *result; // rax
int i; // [rsp+0h] [rbp-28h]
int v5; // [rsp+4h] [rbp-24h]
int v6; // [rsp+8h] [rbp-20h]
int v7; // [rsp+Ch] [rbp-1Ch]
int v8; // [rsp+10h] [rbp-18h]
_DWORD *v9; // [rsp+18h] [rbp-10h]

v5 = *a1;
v6 = a1[1];
v9 = a1 + 2;
for ( i = 0; i < a3; ++i )
{
v5 = (unsigned __int8)(v5 + 1);
v7 = v9[v5];
v6 = (unsigned __int8)(v7 + v6);
v8 = v9[v6];
v9[v5] = v8;
v9[v6] = v7;
*(_BYTE *)(a2 + i) ^= LOBYTE(v9[(unsigned __int8)(v8 + v7)]);
}
*a1 = v5;
result = a1;
a1[1] = v6;
return result;
}

分析了一下, 这是一个 RC4 加密.

Wiki: RC4

exp:

#include <cstdio>
#include <cstring>

unsigned char key[] = "12345678abcdefghijklmnopqrspxyz"; // 密钥
unsigned char text[] = {
0x9E, 0xE7, 0x30, 0x5F, 0xA7, 0x01, 0xA6, 0x53, 0x59, 0x1B,
0x0A, 0x20, 0xF1, 0x73, 0xD1, 0x0E, 0xAB, 0x09, 0x84, 0x0E,
0x8D, 0x2B
}; // 22 字节密文

template <typename T> void swap(T *a, T *b){T temp = *a; *a = *b; *b = temp;}

void rc4_init(unsigned char *S, unsigned char *key, int key_len){
// 初始化 S-box
for(int i = 0; i < 256; ++i) S[i] = i;

for(int i = 0, j = 0; i < 256; ++i){
j = (j + S[i] + key[i % key_len]) % 256;
swap(&S[i], &S[j]);
}
}

void rc4_crypt(unsigned char *S, unsigned char *text, int text_len){
// 加密
for(int i = 0, j = 0, k = 0; k < text_len; ++k){
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(&S[i], &S[j]);
text[k] ^= S[(S[i] + S[j]) % 256];
}
}

void rc4_decrypt(unsigned char *S, unsigned char *text, int text_len){
rc4_crypt(S, text, text_len); // RC4 是对称加密算法.
}

int main(){
// 异或
for(int i = 0; i < sizeof(text); ++i) text[i] ^= 0x22;

// RC4 解密
unsigned char S[256];
rc4_init(S, key, strlen((char *)key));
rc4_decrypt(S, text, sizeof(text));

printf("%s\n", text);
return 0^(0-0)^0;
}

Flag: flag{nice_to_meet_you}


happyctf

附件是 happyctf.exehappyctf.pdb.

happyctf.exe 扔进 IDA (32位), 发现主函数非常恶心:

int __cdecl main(int argc, const char **argv, const char **envp)
{
std::ostream *v3; // eax
std::ostream *v4; // eax
std::ostream *v6; // eax
std::ostream *v7; // eax
unsigned __int8 *v8; // [esp+5Ch] [ebp-70h]
unsigned __int8 *v9; // [esp+60h] [ebp-6Ch]
main::__l2::<lambda_7686c8adb828765130ce2b0d457195d9> cmp; // [esp+68h] [ebp-64h] BYREF
unsigned __int8 key[24]; // [esp+6Ch] [ebp-60h] BYREF
char item; // [esp+87h] [ebp-45h]
char *v13; // [esp+88h] [ebp-44h]
char *v14; // [esp+8Ch] [ebp-40h]
std::string *p_str; // [esp+90h] [ebp-3Ch]
main::__l2::<lambda_1b3a4e77a09e1a7ed440bad3aa4c443b> add; // [esp+94h] [ebp-38h] BYREF
std::vector<unsigned char> v; // [esp+98h] [ebp-34h] BYREF
std::string str; // [esp+A4h] [ebp-28h] BYREF
int v19; // [esp+C8h] [ebp-4h]

std::string::string(&str);
v19 = 0;
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "please input flag");
std::ostream::operator<<(v3, std::endl<char,std::char_traits<char>>);
std::operator>><char>(&std::cin, &str);
if ( std::string::length(&str) == 24 )
{
std::vector<unsigned char>::vector<unsigned char>(&v);
LOBYTE(v19) = 1;
lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::_lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_(&add, &v);
p_str = &str;
v14 = std::string::_Unchecked_begin(&str);
v13 = std::string::_Unchecked_end(&str);
while ( v14 != v13 )
{
item = *v14;
lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::operator()(&add, item);
++v14;
}
qmemcpy(key, "rxusoCqxw{yqK`{KZqag{r`i", sizeof(key));
lambda_7686c8adb828765130ce2b0d457195d9_::_lambda_7686c8adb828765130ce2b0d457195d9_(
&cmp,
(unsigned __int8 (*)[24])key);
v9 = std::vector<unsigned char>::_Unchecked_begin(&v);
v8 = std::vector<unsigned char>::_Unchecked_end(&v);
while ( v9 != v8 )
{
if ( !lambda_7686c8adb828765130ce2b0d457195d9_::operator()(&cmp, *v9) )
{
v6 = std::operator<<<std::char_traits<char>>(&std::cout, "error");
std::ostream::operator<<(v6, std::endl<char,std::char_traits<char>>);
LOBYTE(v19) = 0;
std::vector<unsigned char>::~vector<unsigned char>(&v);
v19 = -1;
std::string::~string(&str);
return 0;
}
++v9;
}
v7 = std::operator<<<std::char_traits<char>>(&std::cout, "good job");
std::ostream::operator<<(v7, std::endl<char,std::char_traits<char>>);
LOBYTE(v19) = 0;
std::vector<unsigned char>::~vector<unsigned char>(&v);
v19 = -1;
std::string::~string(&str);
return 0;
}
else
{
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "not enought");
std::ostream::operator<<(v4, std::endl<char,std::char_traits<char>>);
v19 = -1;
std::string::~string(&str);
return 0;
}
}

重点是这个 lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::operator()(&add, item);, 跟进 add函数:

void __thiscall lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::operator()(
main::__l2::<lambda_1b3a4e77a09e1a7ed440bad3aa4c443b> *this,
unsigned __int8 bytee)
{
unsigned __int8 _Val[65]; // [esp+Fh] [ebp-45h] BYREF
const main::__l2::<lambda_1b3a4e77a09e1a7ed440bad3aa4c443b> *thisa; // [esp+50h] [ebp-4h]

thisa = this;
_Val[0] = bytee ^ 0x14;
std::vector<unsigned char>::push_back(this->v, _Val);
++`_lambda_1b3a4e77a09e1a7ed440bad3aa4c443b_::operator()'::`2'::index;
}

发现似乎只是异或了一下 0x14.

于是, 将 key 与 0x14 异或, 即可得到 flag.

#include <cstdio>

char str[100] = "rxusoCqxw{yqK`{KZqag{r`i";

int main(){
for(int i = 0; str[i]; ++i) str[i] ^= 0x14;
printf("%s\n", str); // flag{Welcome_to_Neusoft}
}

Flag: flag{Welcome_to_Neusoft}


xxxorrr

附件 xor, 扔进 IDA.

__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+Ch] [rbp-34h]
char s[40]; // [rsp+10h] [rbp-30h] BYREF
unsigned __int64 v6; // [rsp+38h] [rbp-8h]

v6 = __readfsqword(0x28u);
sub_A90(sub_916, a2, a3);
fgets(s, 35, stdin);
for ( i = 0; i <= 33; ++i )
s1[i] ^= s[i];
return 0LL;
}
unsigned __int64 sub_84A()
{
int i; // [rsp+Ch] [rbp-14h]
unsigned __int64 v2; // [rsp+18h] [rbp-8h]

v2 = __readfsqword(0x28u);
for ( i = 0; i <= 33; ++i )
s1[i] ^= 2 * i + 65;
return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 sub_916()
{
unsigned __int64 v1; // [rsp+8h] [rbp-8h]

v1 = __readfsqword(0x28u);
if ( !strcmp(s1, s2) )
puts("Congratulations!");
else
puts("Wrong!");
return __readfsqword(0x28u) ^ v1;
}

main 函数并没有显示调用 sub_84Asub_916 函数, 但可以合理推测 sub_84Amain函数之前调用, sub_916main 函数之后调用.

于是, 整个执行流程为: sub_84A 操作 s1[i] -> mains1[i]s[i] 异或 -> sub_916 要求 s1[i]s2[i] 相同.

exp:

#include <cstdio>

unsigned char s1[] = "qasxcytgsasxcvrefghnrfghnjedfgbhn";

unsigned char s2[] =
{
0x56, 0x4E, 0x57, 0x58, 0x51, 0x51, 0x09, 0x46, 0x17, 0x46,
0x54, 0x5A, 0x59, 0x59, 0x1F, 0x48, 0x32, 0x5B, 0x6B, 0x7C,
0x75, 0x6E, 0x7E, 0x6E, 0x2F, 0x77, 0x4F, 0x7A, 0x71, 0x43,
0x2B, 0x26, 0x89, 0xFE
};

int main(){
for(int i = 0; i < 34; ++i) s1[i] ^= 2 * i + 65;
for(int i = 0; i < 34; ++i) s1[i] ^= s2[i];
printf("%s\n", s1); // flag{c0n5truct0r5_functi0n_in_41f}
}

Flag: flag{c0n5truct0r5_functi0n_in_41f}


bad_python

做过类似题, 看一眼题目描述就知道是要修复 pyc 文件头.

010 Editor 打开一看, 果然如此.

附一份正常的 pyc 文件:

33 0D 0D 0A 25 F7 21 68 14 00 00 00 E3 00 00 00
00 00 00 00 00 00 00 00 00 02 00 00 00 40 00 00
00 73 0C 00 00 00 65 00 64 00 83 01 01 00 64 01
53 00 29 02 7A 0B 48 65 6C 6C 6F 20 57 6F 72 6C
64 4E 29 01 DA 05 70 72 69 6E 74 A9 00 72 02 00
00 00 72 02 00 00 00 FA 07 74 65 73 74 2E 70 79
DA 08 3C 6D 6F 64 75 6C 65 3E 01 00 00 00 73 00
00 00 00

把头部替换掉即可. 然后 uncompyle6 -o . pyre.cpython-36.pyc 反编译得到 py 文件.

# uncompyle6 version 3.9.2
# Python bytecode version base 3.6 (3379)
# Decompiled from: Python 3.12.3 (tags/v3.12.3:f6650f9, Apr 9 2024, 14:05:25) [MSC v.1938 64 bit (AMD64)]
# Embedded file name: pyre.py
# Compiled at: 2025-05-12 21:27:01
# Size of source mod 2**32: 20 bytes
from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes

def encrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
sum1 = c_uint32(0)
delta = 195935983
for i in range(32):
v0.value += (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[sum1.value & 3]
sum1.value += delta
v1.value += (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[sum1.value >> 9 & 3]

return (
v0.value, v1.value)


if __name__ == "__main__":
flag = input("please input your flag:")
k = [255, 187, 51, 68]
if len(flag) != 32:
print("wrong!")
exit(-1)
a = []
for i in range(0, 32, 8):
v1 = bytes_to_long(bytes(flag[i:i + 4], "ascii"))
v2 = bytes_to_long(bytes(flag[i + 4:i + 8], "ascii"))
a += encrypt([v1, v2], k)

enc = [
4006073346, 2582197823, 2235293281, 558171287, 2425328816,
1715140098, 986348143, 1948615354]
for i in range(8):
if enc[i] != a[i]:
print("wrong!")
exit(-1)

print("flag is flag{%s}" % flag)

是一个变种 TEA, 直接解就行.

exp:

from ctypes import *
from Crypto.Util.number import bytes_to_long
from Crypto.Util.number import long_to_bytes

def decrypt(v, k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
sum1 = c_uint32(195935983 * 32)
delta = 195935983
for i in range(32):
v1.value -= (v0.value << 4 ^ v0.value >> 7) + v0.value ^ sum1.value + k[sum1.value >> 9 & 3]
sum1.value -= delta
v0.value -= (v1.value << 4 ^ v1.value >> 7) + v1.value ^ sum1.value + k[sum1.value & 3]

return (v0.value, v1.value)

enc = [
4006073346, 2582197823, 2235293281, 558171287, 2425328816,
1715140098, 986348143, 1948615354]

k = [255, 187, 51, 68]

flag = b""

for i in range(0, len(enc), 2):
part1, part2 = decrypt([enc[i], enc[i+1]], k)
flag += long_to_bytes(part1)
flag += long_to_bytes(part2)

print("flag{%s}" % flag.decode("ascii"))
# flag{Th1s_1s_A_Easy_Pyth0n__R3veRse_0}

Flag: flag{Th1s_1s_A_Easy_Pyth0n__R3veRse_0}


ereere

附件 ere, 扔进 DIE 一看, wtf, MIPS 指令集?

于是决定先咕咕咕.

  • 标题: Adworld Re Writeups
  • 作者: Coast23
  • 创建于 : 2025-01-26 16:37:08
  • 更新于 : 2025-06-15 17:29:45
  • 链接: https://coast23.github.io/2025/01/26/Adworld-Re-Writeups/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论