[DSCTF 2022] Reverse赛题复现

比赛的时候catchme就给我卡死了,笑嘻了

catchme

MainActivity里面看一眼,发现是native类,直接去逆.so

然后赛中JNI_OnLoad里面啥都看不出来直接寄了,赛后看学长的wp发现能直接用findcrypt找(TSCTF才用了一次现在就忘了😅)

发现程序采用的是AES加密,点进去查交叉引用就能看到aes的位置,并且可以发现IV和KEY是一样的

继续交叉引用后就可以看到他在JNI_OnLoad的位置

1658131918533

发现他的参数和前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里面的交叉引用。。就这样吧。。

nothing

posted @ 2022-07-18 21:30  iPlayForSG  阅读(417)  评论(0编辑  收藏  举报