CISCN2021初赛WriteUp

第一次打 ctf,啥也没学,赛前一道题没做过,了解了下 IDA 的使用就上了。

glass

200 分 reverse,安卓逆向,.apk 改 .zip 解压,classes.dex 转 classes.jar 后打开,找到 MainActivity 开始读代码。
CISCN2021初赛WriteUp
发现调用了 public native boolean checkFlag(String paramString); 这样一个函数,但这个函数并没有写出来。搜了一下 native 关键字,发现是用来调用本地 C 代码的。然后在 glasslibarmeabi-v7a 里 找到了 libnative-lib.so,直接拖进 IDA 打开。
CISCN2021初赛WriteUp
分析一波,发现 sub_F0C 是用来把接收的 Java String 转换成 char*。然后主要剩下 sub_FFC, sub_1088, sub_10D4, 这三个函数。进一步分析,猜测程序的主要逻辑是把 flag 经过这三个函数处理,和内存中的一段数据比较。
CISCN2021初赛WriteUp

因此只要把这段数据解密回去就行了。由于没有任何前置知识,于是只能进去一行一行读明白。

FFC:
CISCN2021初赛WriteUp
大概就是会得到 v7 这个数组。有几个疑点:

  1. 第八行为什么是 260 个字节而不是 256。
  2. 变量 v7 既没初始化也没有修改。(我就当做 v7 恒为零做的,不行)
  3. 莫名其妙的有个 sub_126C,貌似没有任何影响。

赛后才知道,事实上这是在进行 RC4 加密,而 RC4 加密 v7 应该是不停自增的。

然后 10D4 是对原文进行可逆的异或运算,很好解密。1088 是 拿已知的 v7 数组和原文进行运算,也很好解密。但 1088 里面有一个问题:
CISCN2021初赛WriteUp
这里面 a1 就是主函数的 v7,值域是 [0, 255],因此第十八行 v5 + a1[v4] 可能会越界。尝试对 256 取模,无果。赛后知道,这里确实应该取模,但因为比赛的时候上面 FFC 里面的 v7 没自增,于是没有解出。

我不知道为什么 IDA 里面会出现这种情况,里面的算法和 RC4 不完全一样,因此完全按照 IDA 里面的代码写的脚本跑不出 flag。别人都是百度 RC4 解密直接解出 flag。

插一嘴,我看别的 WP,1088 和 10D4 都是暴力枚举解密的,不是逆运算回去的。这样可能根本不需要每行代码都看明白?毕竟 RC4 应该是能一眼看出来的。

赛后修改过的脚本如下:

# include <bits/stdc++.h> # define ll long long # define db double # define ld long double # define pb push_back # define fir first # define sec second # define rep(i, l, r) for (int i = l; i <= r; i++) # define per(i, r, l) for (int i = r; i >= l; i--) using namespace std; typedef pair <int, int> P;  int read() {     int x = 0; char c = getchar(), flag = '+';     while (!isdigit(c)) flag = c, c = getchar();     while (isdigit(c)) x = x * 10 + c - '0', c = getchar();     return flag == '-' ? -x : x; } char v12[1000];  void FFC(unsigned a1[], unsigned a2[], int a3) {     const int ty = 1;     int ii = 0, jj = 0;     unsigned v12[256];     for (int i = 0; i < 256; i++) a1[i] = i, v12[i] = a2[i % 8];     while (ii != 256) {         int v10 = a1[ii];         jj = (jj + v10 + v12[ii]) % 256;         a1[ii++] = a1[jj];         a1[jj] = v10;     } }  void rev(unsigned s[], int len1, unsigned a3[], int len3) {     for (int j = 0; j < len1; j += len3) {         for (int k = 0; k < len3 && j + k < len1; k++) {             s[j + k] ^= a3[k];         }     }     for (int i = 0; i < len1; i += 3) {         unsigned a = s[i], b = s[i + 1], c = s[i + 2];         s[i] = b ^ c;         s[i + 1] = b ^ a;         s[i + 2] = b ^ a ^ c;     } } void sub_1088(unsigned result[], unsigned a2[], int a3) {     int v3 = 0, v4 = 0, v5 = 0;     int loop_39[39];     memset(loop_39, 0, sizeof(loop_39));     while(a3) {         --a3;         v4 = (v4 + 1) % 256;         v5 = result[v4];          v3 = (v3 + v5) % 256;         result[v4] = result[v3];         result[v3] = v5;         //if (v5 + result[v4] > 255) cout<<"#";         loop_39[38 - a3] = result[(v5 + result[v4]) % 256];     }     for (int i = 0; i < 39; i++) {         a2[i] ^= loop_39[i];     } } int main() {     unsigned v6[256], v7[256];     unsigned v3[] = {0xA3, 0x1A, 0xE3, 0x69, 0x2F, 0xBB, 0x1A, 0x84, 0x65, 0xC2, 0xAD, 0xAD, 0x9E, 0x96, 0x05, 0x02, 0x1F, 0x8E, 0x36, 0x4F, 0xE1, 0xEB, 0xAF, 0xF0, 0xEA, 0xC4, 0xA8, 0x2D, 0x42, 0xC7, 0x6E, 0x3F, 0xB0, 0xD3, 0xCC, 0x78, 0xF9, 0x98, 0x3F};          memset(v7, 0, sizeof(unsigned) * 256);      v6[0] = '1';     v6[1] = '2';     v6[2] = '3';     v6[3] = '4';     v6[4] = '5';     v6[5] = '6';     v6[6] = '7';     v6[7] = '8';     int v4 = 8;     FFC(v7, v6, v4);      rev(v3, 39, v6, v4);     sub_1088(v7, v3, 39);     // for (int i = 0; i < 39; i++) {     //     printf("%d ", v3[i]);     // }     // cout << endl;     for (int i = 0; i < 39; i++) {         printf("%c", v3[i]);     }     return 0; } /* Hellsegamosken */  

版权声明:玥玥 发表于 2021-05-20 15:41:52。
转载请注明:CISCN2021初赛WriteUp | 女黑客导航