首页
社区
课程
招聘
[原创]2019KCTF总决赛 第七题:东北奇闻 WP
发表于: 2019-12-17 22:43 3985

[原创]2019KCTF总决赛 第七题:东北奇闻 WP

2019-12-17 22:43
3985
用jadx查看apk,找到MainActivity
public class MainActivity extends AppC0mpatActivity {
    protected void onCreate(final Bundle bundle) {
        super.onCreate(bundle);
        setContentView((int) R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.ed);
        ((Button) findViewById(R.id.bt)).setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                if (editText.getText() == null || TextUtils.isEmpty(editText.getText().toString()) != null || MainActivity.this.showAssist(bundle) != null) {
                    Toast.makeText(MainActivity.this, "null", 1).show();
                }
            }
        });
    }
}

前两个条件是判空,所以直接查看MainActivity.this.showAssist,发现是个native方法,故转而分析libnative-lib.so。
so做了一些混淆以及字符串加密,干扰静态分析。


但没有反调试,可以真机调试找出showAssist的地址。
我是选择用frida hook RegisterNatives函数,输出showAssist的地址。

在00019F80处下断,运行程序输入flag就能停下了。
大致流程为,申请200字节大小的空间,将输入的flag写到那个空间 ,每8字节一组加密。再与内置的结果比较。

后面都是0加密的结果,也就是说flag加密后与"68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cf"相同则通过。
直接抠加密函数sub_9CB0代码,将下面的混淆代码nop掉就能F5了。

部分伪代码如下
  v7 = __ROR4__(*encrypt + flag4, 32 - encrypt[16]);
  v8 = flag0 ^ ((des2[(v7 >> 16) & 0xFF] ^ des1[v7 >> 24]) - S[(unsigned __int16)v7 >> 8] + S2[(unsigned __int8)v7]);
  v9 = __ROR4__(v8 ^ encrypt[1], 32 - encrypt[17]);
  v10 = (des1[v9 >> 24] - des2[(v9 >> 16) & 0xFF] + S[(unsigned __int16)v9 >> 8]) ^ flag4 ^ S2[(unsigned __int8)v9];
  v11 = __ROR4__(encrypt[2] - v10, 32 - encrypt[18]);
  v12 = (((des2[(v11 >> 16) & 0xFF] + des1[v11 >> 24]) ^ S[(unsigned __int16)v11 >> 8]) - S2[(unsigned __int8)v11]) ^ v8;
  v13 = __ROR4__(v12 + encrypt[3], 32 - encrypt[19]);
  v14 = (S2[(unsigned __int8)v13] + (des2[(v13 >> 16) & 0xFF] ^ des1[v13 >> 24]) - S[(unsigned __int16)v13 >> 8]) ^ v10;
  v15 = __ROR4__(encrypt[4] ^ v14, 32 - encrypt[20]);
  v16 = S2[(unsigned __int8)v15] ^ v12 ^ (des1[v15 >> 24] - des2[(v15 >> 16) & 0xFF] + S[(unsigned __int16)v15 >> 8]);
  v17 = __ROR4__(encrypt[5] - v16, 32 - encrypt[21]);
  v18 = v14 ^ (((des1[v17 >> 24] + des2[(v17 >> 16) & 0xFF]) ^ S[(unsigned __int16)v17 >> 8]) - S2[(unsigned __int8)v17]);
  v19 = __ROR4__(encrypt[6] + v18, 32 - encrypt[22]);
  v20 = v16 ^ ((des2[(v19 >> 16) & 0xFF] ^ des1[v19 >> 24]) - S[(unsigned __int16)v19 >> 8] + S2[(unsigned __int8)v19]);
  v21 = __ROR4__(encrypt[7] ^ v20, 32 - encrypt[23]);
  v22 = S2[(unsigned __int8)v21] ^ v18 ^ (des1[v21 >> 24] - des2[(v21 >> 16) & 0xFF] + S[(unsigned __int16)v21 >> 8]);
  v23 = __ROR4__(encrypt[8] - v22, 32 - encrypt[24]);
  v24 = v20 ^ (((des2[(v23 >> 16) & 0xFF] + des1[v23 >> 24]) ^ S[(unsigned __int16)v23 >> 8]) - S2[(unsigned __int8)v23]);
  v25 = __ROR4__(encrypt[9] + v24, 32 - encrypt[25]);
  v26 = v22 ^ ((des1[v25 >> 24] ^ des2[(v25 >> 16) & 0xFF]) - S[(unsigned __int16)v25 >> 8] + S2[(unsigned __int8)v25]);
  v27 = __ROR4__(encrypt[10] ^ v26, 32 - encrypt[26]);
  v28 = (des1[v27 >> 24] - des2[(v27 >> 16) & 0xFF] + S[(unsigned __int16)v27 >> 8]) ^ S2[(unsigned __int8)v27] ^ v24;
  v29 = __ROR4__(encrypt[11] - v28, 32 - *((_BYTE *)encrypt + 0x6C));
  v30 = ((S[(unsigned __int16)v29 >> 8] ^ (des1[v29 >> 24] + des2[(v29 >> 16) & 0xFF])) - S2[(unsigned __int8)v29]) ^ v26;
  *(_BYTE *)result = sub_DF18(v30 >> 24);
  *((_BYTE *)result + 1) = sub_DF18((v30 >> 16) & 0xFF);
  *((_BYTE *)result + 2) = sub_DF18((unsigned __int16)v30 >> 8);
  *((_BYTE *)result + 3) = sub_DF18((unsigned __int8)v30);
  *((_BYTE *)result + 4) = sub_DF18(v28 >> 24);
  *((_BYTE *)result + 5) = sub_DF18((v28 >> 16) & 0xFF);
  *((_BYTE *)result + 6) = sub_DF18((unsigned __int16)v28 >> 8);
  *((_BYTE *)result + 7) = sub_DF18((unsigned __int8)v28);

sub_DF18函数里面有更强的混淆,但是动态调试时发现只是一个字节变换,可以写个脚本抠出[0,255]的变换结果,然后写代码输出解密用的表。
加密部分的代码看起来有点乱,但是仔细钻研了下,发现其实是花式xor。返回的加密结果其实就是v28和v30,已知v28和v30可以求出v29,之后用
v26 =  ((S[(unsigned __int16)v29 >> 8] ^ (des1[v29 >> 24] + des2[(v29 >> 16) & 0xFF])) - S2[(unsigned __int8)v29]) ^ v30;
求出v26的值,以此类推,就能还原出flag了。
其他的表可以直接导出,弄一份可编译的C代码,完整代码见附件。
int decryptstring(unsigned char* buffer)
{
  int v2; // r10
  unsigned int *v3; // ST00_4
  unsigned int v4; // r5
  unsigned int v5; // r11
  unsigned int v6; // r8
  unsigned int v7; // r2
  int v8; // r11
  unsigned int v9; // r4
  int v10; // r8
  unsigned int v11; // r5
  int v12; // lr
  unsigned int v13; // r6
  int v14; // r12
  unsigned int v15; // r5
  int v16; // lr
  unsigned int v17; // r6
  int v18; // r12
  unsigned int v19; // r6
  int v20; // lr
  unsigned int v21; // r5
  int v22; // r12
  unsigned int v23; // r6
  int v24; // lr
  unsigned int v25; // r6
  int v26; // r12
  unsigned int v27; // r5
  unsigned int v28; // r4
  unsigned int v29; // r5
  unsigned int v30; // r6
  unsigned int result1;
  unsigned int result2;
  unsigned int flag0;
  unsigned int flag4;
  unsigned char enc[9]={0};
  for (int i = 0; i < 4; ++i)
  {
    enc[i]=ctable2[buffer[i]];
    enc[4+i]=ctable2[buffer[4+i]];
  }
  result1 = (enc[0]<<24)+(enc[1]<<16)+(enc[2]<<8)+enc[3];
  result2 = (enc[4]<<24)+(enc[5]<<16)+(enc[6]<<8)+enc[7];
  v30 = result1;
  v28 = result2;
  v29 = ror(encrypt[11] - v28, 32 - *((unsigned char *)encrypt + 0x6C));
  v26 = v30 ^ ((S[(unsigned short)v29 >> 8] ^ (des1[v29 >> 24] + des2[(v29 >> 16) & 0xFF])) - S2[(unsigned char)v29]);
  v27 = ror(encrypt[10] ^ v26, 32 - encrypt[26]);
  v24 = v28 ^ (des1[v27 >> 24] - des2[(v27 >> 16) & 0xFF] + S[(unsigned short)v27 >> 8]) ^ S2[(unsigned char)v27];
  v25 = ror(encrypt[9] + v24, 32 - encrypt[25]);
  v22 = v26 ^ ((des1[v25 >> 24] ^ des2[(v25 >> 16) & 0xFF]) - S[(unsigned short)v25 >> 8] + S2[(unsigned char)v25]);
  v23 = ror(encrypt[8] - v22, 32 - encrypt[24]);
  v20 = v24 ^ (((des2[(v23 >> 16) & 0xFF] + des1[v23 >> 24]) ^ S[(unsigned short)v23 >> 8]) - S2[(unsigned char)v23]);
  v21 = ror(encrypt[7] ^ v20, 32 - encrypt[23]);
  v18 = v22 ^ S2[(unsigned char)v21] ^ (des1[v21 >> 24] - des2[(v21 >> 16) & 0xFF] + S[(unsigned short)v21 >> 8]);
  v19 = ror(encrypt[6] + v18, 32 - encrypt[22]);
  v16 = v20 ^ ((des2[(v19 >> 16) & 0xFF] ^ des1[v19 >> 24]) - S[(unsigned short)v19 >> 8] + S2[(unsigned char)v19]);
  v17 = ror(encrypt[5] - v16, 32 - encrypt[21]);
  v14 = v18 ^ (((des1[v17 >> 24] + des2[(v17 >> 16) & 0xFF]) ^ S[(unsigned short)v17 >> 8]) - S2[(unsigned char)v17]);
  v15 = ror(encrypt[4] ^ v14, 32 - encrypt[20]);
  v12 = v16 ^ S2[(unsigned char)v15] ^ (des1[v15 >> 24] - des2[(v15 >> 16) & 0xFF] + S[(unsigned short)v15 >> 8]);
  v13 = ror(v12 + encrypt[3], 32 - encrypt[19]);
  v10 = v14 ^ (S2[(unsigned char)v13] + (des2[(v13 >> 16) & 0xFF] ^ des1[v13 >> 24]) - S[(unsigned short)v13 >> 8]);
  v11 = ror(encrypt[2] - v10, 32 - encrypt[18]);
  v8 = v12 ^ (((des2[(v11 >> 16) & 0xFF] + des1[v11 >> 24]) ^ S[(unsigned short)v11 >> 8]) - S2[(unsigned char)v11]);
  v9 = ror(v8 ^ encrypt[1], 32 - encrypt[17]);
  flag4 = v10 ^ (des1[v9 >> 24] - des2[(v9 >> 16) & 0xFF] + S[(unsigned short)v9 >> 8]) ^ S2[(unsigned char)v9];
  v7 = ror(*encrypt + flag4, 32 - encrypt[16]);
  flag0 = v8 ^ ((des2[(v7 >> 16) & 0xFF] ^ des1[v7 >> 24]) - S[(unsigned short)v7 >> 8] + S2[(unsigned char)v7]);
  for (int i = 0; i < 4; ++i)
  {
    enc[i]=(flag0>>((3-i)*8))&0xff;
    enc[4+i]=(flag4>>((3-i)*8))&0xff;
  }
  printf("%s",enc);
  return 0;
}
int main(int argc, char const *argv[])
{
  unsigned char buffer[9]={0};
  //"68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cf"
  unsigned char str1[8]={0x68,0xdd,0x8a,0x0f,0x70,0x65,0x60,0x9e};
  unsigned char str2[8]={0x31,0x06,0xfb,0x2b,0xb1,0x05,0x94,0x23};
  unsigned char str3[8]={0xe8,0x0f,0xb1,0x34,0x73,0x18,0xff,0xeb};
  unsigned char str4[8]={0x83,0xb8,0xa0,0x74,0xa7,0xe6,0xc9,0xcf};
  decryptstring(str1);
  decryptstring(str2);
  decryptstring(str3);
  decryptstring(str4);
  printf("\n");
  return 0;
}

将"68dd8a0f7065609e3106fb2bb1059423e80fb1347318ffeb83b8a074a7e6c9cf"拆成四组分别解密就得到flag了。
flag:flag{9eca5de49470144c1694f6}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-12-17 22:47 被梦游枪手编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//