-
-
[原创]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
被梦游枪手编辑
,原因:
赞赏
他的文章
谁下载
无
看原图
赞赏
雪币:
留言: