一些自认为典型的题
RE区
maze GFSJ0497
接触到的第一道maze题
伪代码部分
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| __int64 __fastcall main(__int64 a1, char **a2, char **a3) { signed __int64 i; // rbx signed int chr; // eax bool sign; // bp bool sign1; // al const char *v7; // rdi __int64 matrix; // [rsp+0h] [rbp-28h] matrix = 0LL; puts("Input flag:"); scanf("%s", &input_flag_str, 0LL); if ( strlen(&input_flag_str) != 24 || strncmp(&input_flag_str, "nctf{", 5uLL) || *(&byte_6010BF + 24) != '}' ) { Wrong_jmp: puts("Wrong flag!"); exit(-1); } i = 5LL; if ( strlen(&input_flag_str) - 1 > 5 ) { while ( 1 ) { chr = *(&input_flag_str + i); sign = 0; if ( chr > 78 ) { chr = (unsigned __int8)chr; if ( (unsigned __int8)chr == 'O' ) { sign1 = left((_DWORD *)&matrix + 1); // matrix 指针 + 1 就是旁边 的 dword 值 也就是 v9 的高8 位的值 goto LABEL_14; } if ( chr == 'o' ) { // matrix 的低8位用来存储迷宫的行 高8位用来存储迷宫的列它是一个 __int64位的数据 方向函数matix 向左和向右操控的是高32位的值 sign1 = right((int *)&matrix + 1); goto LABEL_14; } } else { chr = (unsigned __int8)chr; if ( (unsigned __int8)chr == '.' ) { sign1 = up(&matrix); goto LABEL_14; } if ( chr == '0' ) { sign1 = down((int *)&matrix); LABEL_14: sign = sign1; goto LABEL_15; } } LABEL_15: if ( !(unsigned __int8)sub_400690((__int64)maze_data, SHIDWORD(matrix), matrix) )// 判断当前位置是否为0x20或0x23#不是则错误flag goto Wrong_jmp; if ( ++i >= strlen(&input_flag_str) - 1 ) // 当 长度 达到的时候 { if ( sign ) break; Wrong_Jmp1: v7 = "Wrong flag!"; goto puts_wrong; } } } if ( maze_data[8 * (signed int)matrix + SHIDWORD(matrix)] != '#' )// 最后一层判断是否到达指定位置 goto Wrong_Jmp1; v7 = "Congratulations!"; puts_wrong: puts(v7); return 0LL; }
bool __fastcall left(_DWORD *a1) { } int v1; // eax v1 = (*a1)--; return v1 > 0; //对应 O //高8 位-1迷宫向左移动一位 bool __fastcall right(int *a1) //对应 o { int v1; // eax v1 = *a1 + 1; *a1 = v1; return v1 < 8; }
bool __fastcall up(_DWORD *a1) { } int v1; // eax v1 = (*a1)--; return v1 > 0; //对应 . bool __fastcall down(int *a1) //对应 0 { int v1; // eax v1 = *a1 + 1; *a1 = v1; return v1 < 8; }
|
碰撞检测函数一眼就看得出来,不贴了
进去直接shift+F12查找字符串,找到迷宫数据
由于有64个字符,将其8*8分割画出迷宫
重点在于阅读移动函数,Oo0.确定上下左右
最后直接手写迷宫走出方法得wp
simple-unpack NO.GFSJ0490
一道非常典型的UPX无魔改脱壳,可以留着作为upx范本文件一遍应付以后的魔改,也可以练习手动脱壳
方法1:upx脱壳软件一键脱壳,不多赘述
方法2:手动脱壳
打开x64dbg将文件拖入
找到文件开始行,在开头打上断点
开始动调,一步步往下直至有一大堆出栈行为的时候尝试脱壳
多次尝试后脱壳成功,拖入ida发现显示正常
getit NO.GFSJ0495
一道经典的linux动调题
DIE查壳后用ida打开
进来先进入main函数扫一眼主要逻辑
看到关键函数fseek用来改变读写函数的位置指针
阅读代码逻辑可知 代码将flag赋值后remove掉
在remove上下断点动调发现输出一大堆号
这些号将原本应该输出的flag覆写
找到关键储存点t
在循环过程中关注t再次动调,发现flag
Valgrind NO.GFSJ1148
分析文档写脚本
‘’’
s = “t1me_y0u_enj0y_wa5t1ng_wa5_not_wa5ted”
key = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”
flag = “”
for i in range(len(s)):
if(ord(s[i]) + 3 < 0x5a):
flag += chr(ord(s[i]) + 3 )
else:
flag += key[ (ord(s[i]) + 3 - 0x5a) % 0x1a -1 ]
print(flag)
‘’’
whats-the-hell-500 NO.GFSJ0124
有点意思
画了几个长方形和长方体
通过改代码,在每个等式后取值可得
p[0] + p[1] = 101
p[1] + p[2]= 143
p[0] * p[2] = 5035
p[3] + p[5] = 163
p[3] + p[4] = 226
p[4] * p[5] = 5814
p[7] + p[8] = 205
p[6] + p[8] = 173
p[6] * p[7] = 9744
p[9] + p[10] * p[11] = 5375
p[10] + p[9] * p[11] = 4670
p[9] + p[10] = 205
回到python用z3对等式求个解
就能求出所有p[]的值
最后可得flag:50_pr3TtYn_0
Android区
Android 2.0
入门Android逆向
用jadx打开apk,发现入口在

跟进,发现主要函数逻辑JNI在so层
用ida32打开lib中的so文件
直奔目标函数Java_com_example_test_ctf03_JNI_getResult
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
| bool __fastcall Java_com_example_test_ctf03_JNI_getResult(int a1, int a2, int a3) { int v3; // r4 const char *v4; // r8 char *v5; // r6 char *v6; // r4 char *v7; // r5 int i; // r0 int j; // r0
v3 = 0; v4 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0); if ( strlen(v4) == 15 ) { v5 = (char *)malloc(1u); v6 = (char *)malloc(1u); v7 = (char *)malloc(1u); Init(v5, v6, v7, v4, 15); if ( !First(v5) ) return 0; for ( i = 0; i != 4; ++i ) v6[i] ^= v5[i]; if ( !strcmp(v6, a5) ) { for ( j = 0; j != 4; ++j ) v7[j] ^= v6[j]; return strcmp(v7, "AFBo}") == 0; } else { return 0; } } return v3; }
|
跟进Init函数
发现就是将整段字符串以3个字符为一次循环分给v5,v6,v7
分别跟进First,Second,Third
发现均为简单的单个字符逻辑运算
根据伪代码写出脚本
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
| a="LN^dl" flag="" for i in range(0,len(a)-1): flag=flag + chr((ord(a[i]) ^ 0x80) // 2) flag=flag+a[-1] print(flag)
a5=[ord(' '),ord('5'),ord('-'),0x16,ord('a')] v5="fgorl" v6="" for i in range(4): v6=v6+chr(a5[i] ^ ord(a[i])) v6=v6+'a' print(v6)
v7="" a7="AFBo}" for i in range(0,len(a7)-1): v7=v7+chr(ord(a7[i]) ^ a5[i]) v7=v7+a7[-1] print(v7)
for i in range(0,len(a7)): print(v5[i],end="") print(v6[i],end="") print(v7[i],end="")
|
运行可得flag{sosorryla}