[DSCTF 2022] Reverse赛题复现
比赛的时候catchme就给我卡死了,笑嘻了
catchme
MainActivity里面看一眼,发现是native类,直接去逆.so
然后赛中JNI_OnLoad里面啥都看不出来直接寄了,赛后看学长的wp发现能直接用findcrypt找(TSCTF才用了一次现在就忘了😅)
发现程序采用的是AES加密,点进去查交叉引用就能看到aes的位置,并且可以发现IV和KEY是一样的
继续交叉引用后就可以看到他在JNI_OnLoad的位置
发现他的参数和前71行没有任何关系,怪不得我赛中死命看前面的逻辑啥也没看懂,纯纯的啥b😅
我们的目的是找到apk里面check和本地交互的地方,这里我们没有发现类似check的操作,为了找到这种方法,我们继续对这个AES_Encrypt查交叉引用
在sub_B2A4里我们看到,sub_AE62很符合check类函数的一般形式,同时,sub_A740是一个base64换表
直接解发现不是很正确,猜测前面可能对这些字符串进行了修改。对着unk_1F2F0和a76572Rrrrs查一下交叉引用
这下对了,逻辑就是base64换表套一个aes加密
import base64
# enflag = [
# 0x4F, 0x1C, 0x36, 0x49, 0x09, 0x3A, 0x3F, 0x07, 0x4D, 0x3D,
# 0x22, 0x39, 0x00, 0x0A, 0x22, 0x25, 0x06, 0x09, 0x01, 0x20,
# 0x4A, 0x1B, 0x51, 0x51, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
# 0x00, 0x00]
key = [
0x24, 0x3C, 0x3D, 0x37, 0x36, 0x21, 0x35, 0x26, 0x3F, 0x37,
0x32, 0x2A, 0x72, 0x72, 0x72, 0x72, 0x53, 0x00]
# for i in range(len(enflag)):
# enflag[i] ^= 0x6C
#
# print(bytes(enflag))
enflag = b"#pZ%eVSk!QNUlfNIjemL&w=="
for i in range(len(key)):
key[i] ^= 0x53
now_table = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()+/"
ori_table = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
dec_str = base64.b64decode(bytes.translate(enflag, bytes.maketrans(now_table, ori_table)))
print(dec_str)
然后把dec_str转成hex,扔进cyberchef,试了几种AES发现
然后根据题目说的把英文逗号换成中文就行,看起来确实好怪,但大爹们也是这个flag
FFunction
打开程序,随便输了点,发现会提示长度错误,那么手动爆破一下长度
可以发现是30位的
直接逆这个.exe不是很明智,毕竟他带了那么多dll,我们考虑动调他,监控一下在每个行为后他都加载了些啥dll
可以发现,在我们输入30位长度的字符串进去后,程序加载了my_plugin.dll,猜测这里面是有check操作的。
直接开逆my_plugin.dll,发现里面有一堆sub开头的函数,我们用finger辅助识别一下,发现基本只有f不是库函数
bool __fastcall f(_BYTE *a1, const void *a2)
{
_BYTE *v2; // rbx
__int64 v3; // rdi
__int64 v5; // r9
__int64 v6; // rsi
char *v7; // rdx
char *v8; // r8
char v9; // al
char v10; // cl
_DWORD *v11; // rax
_DWORD *v12; // r14
char *v13; // rdx
char v14; // cl
int v15; // eax
__int64 i; // r10
unsigned int v17; // edx
int v18; // er9
unsigned int v19; // er8
__int64 v20; // r11
bool v21; // r15
v2 = a1;
v3 = -1i64;
do
++v3;
while ( a1[v3] );
if ( (int)v3 % 8 )
return 0;
v5 = (int)v3 / 2;
v6 = (int)v3;
if ( (int)v3 / 2 > 0 )
{
v7 = a1;
v8 = &a1[(int)v3 - 1];
do
{
v9 = *v8--;
v10 = *v7;
*v7++ = v9;
v8[1] = v10;
--v5;
}
while ( v5 );
}
v11 = malloc(2i64 * (int)v3);
v12 = v11;
if ( (int)v3 > 0 )
{
v13 = (char *)v11;
do
{
v13 += 2;
v14 = *v2++ & 0xF0;
*(v13 - 2) = v14;
*(v13 - 1) = *(v2 - 1) & 0xF;
--v6;
}
while ( v6 );
}
v15 = 2 * (int)v3 / 8;
if ( v15 > 0 )
{
for ( i = 0i64; i < v15; v12[2 * i++ + 1] = v19 )
{
v17 = v12[2 * i];
v18 = 0;
v19 = v12[2 * i + 1];
v20 = 32i64;
do
{
v18 += 2042207799;
v17 -= (v18 + v19) ^ (dword_180003000 + (v19 >> 5)) ^ (dword_180003004 + 16 * v19);
v19 -= (v18 + v17) ^ (dword_180003008 + (v17 >> 5)) ^ (dword_18000300C + 16 * v17);
--v20;
}
while ( v20 );
v12[2 * i] = v17;
}
}
v21 = memcmp(v12, a2, 2 * (int)v3) == 0;
free(v12);
return v21;
}
一眼TEA,在最后的memcmp这里我们可以发现密文就是传进来的参数a2,动调把他拿出来,按d可以把db改成dd,方便很多
然后看到tea上面,可以发现有一个高低位颠倒并且拆开再拼回去的小操作,我们用TEA解密完还要把他写出来
#include <bits/stdc++.h>
using namespace std;
void TEA(unsigned int *v, unsigned int *k)
{
unsigned int delta = 0x79B99E37;
unsigned int l = v[0], r = v[1], sum = delta * 32;
for (int i = 0; i < 32; ++i)
{
r += ((l << 4) + k[2]) ^ (l + sum) ^ ((l >> 5) + k[3]);
l += ((r << 4) + k[0]) ^ (r + sum) ^ ((r >> 5) + k[1]);
sum -= delta;
}
v[0] = l;
v[1] = r;
}
unsigned int key[4] = {0x0BABEC0FE, 0x0DEADBEEF, 0x0FACEB00C, 0xDEADC0DE};
unsigned int enc[22] =
{
0x5C15754C, 0x0D1D781E7, 0x501BF173, 0x0CB4DB222,
0x215D61F5, 0x3FCA9EE7, 0x7C76B5C7, 0x0C7DD8CB9,
0x990D23FA, 0x0BAB1AD3, 0x8E12C932, 0x0D307BAF2,
0x0E52DD123, 0x0FBB68F2C, 0x0BDD853E3, 0x892E1E4E,
0x39DD66FA, 0x87FEEC65, 0x307C5E60, 0x340C6C00
};
char flag[233];
int main()
{
for (int i = 0; i <= 20; i += 2) TEA(enc + i, key);
int len = sizeof(enc);
char *v = (char *) enc;
for (int i = 0; i < len; i += 2) flag[i >> 1] = v[i] | v[i + 1];
len >>= 1;
for (int i = 0; i < (len >> 1); ++i) swap(flag[i], flag[len - i - 1]);
printf("%s", flag);
}
不知道前面俩乱码哪来的,后面一眼base64,解密后有f}l!a!gC{_Ehmtp10ww_erre_tFt1u
当misc题做吧,奇数位和偶数位分开看,就是flag{Emp0wer_F1和}!!C_ht1w_rettu
后半部分倒过来,拼一下就是flag{Emp0wer_F1utter_w1th_C!!}
然后看了学长的wp发现做到base64密文后,应该能找到在执行f之前有这个明文置换和base64加密的代码,但是我并不会找dll里面的交叉引用。。就这样吧。。