-
-
[原创]2019看雪CTF 团队赛 第二题 变形金钢WP
-
2019-3-21 18:20 2923
-
用jadx打开apk,找到MainActivity
看起来挺简单的,但是在手机上测试的结果却不是这样,随便输入点什么按登陆是提示error。
在MainActivity里也没有什么线索,尝试搜索"error",发现在 android.support.v7.app.AppCompiatActivity.onStart() 有另外的实现
protected void onStart() { super.onStart(); this.login = (Button) findViewById(R.id.login_button); this.login.setOnClickListener(new OnClickListener() { public void onClick(View view) { AppCompiatActivity.this.mName = AppCompiatActivity.this.name.getText().toString(); AppCompiatActivity.this.mPassword = AppCompiatActivity.this.password.getText().toString(); if (TextUtils.isEmpty(AppCompiatActivity.this.mName) == null) { if (TextUtils.isEmpty(AppCompiatActivity.this.mPassword) == null) { int i = 0; AppCompiatActivity.this.login.setEnabled(false); if (AppCompiatActivity.this.eq(AppCompiatActivity.this.mPassword) != null) { view = AppCompiatActivity.this.mPassword.getBytes(); if (view.length != 24) { byte[] bArr = new byte[24]; while (i < bArr.length) { bArr[i] = i < view.length ? view[i] : (byte) i; i++; } view = bArr; } view = AppCompiatActivity.dec(view, "2ggdrsLgM7iPNYPQrD58Rg==".getBytes()); Context context = AppCompiatActivity.this; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("flag{"); stringBuilder.append(new String(view)); stringBuilder.append("}"); Toast.makeText(context, stringBuilder.toString(), 1).show(); } else { Toast.makeText(AppCompiatActivity.this, "error", 1).show(); } return; } } Toast.makeText(AppCompiatActivity.this, "用户名或密码为空", 1).show(); } }); this.name = (EditText) findViewById(R.id.name); this.name.setEnabled(false); this.password = (EditText) findViewById(R.id.password); }
查看eq方法
protected native boolean eq(String str); static { System.loadLibrary("oo000oo"); }
具体验证在so里实现,那我们先用readelf看下init_array的地址
用IDA打开so定位到函数
异或解密数据,可以写个IDC脚本
auto i, x,addr=0x4020; auto q=0xA5; for ( i=0; i < 37; i=i+1 ) { x = Byte(addr+i); x = (x^q); PatchByte(addr+i,x); }
其他同理
解密以后发现有这个,可能是base64的码表
查看引用,定位到sub_784
在这里下断,用真机调试,输入点什么后按登陆后程序停下,这里应该就是验证处了。
...//省略 v23 = strlen(password); v24 = v23; v25 = (unsigned __int8)newguid[3]; v43 = 8 * (3 - -3 * (v23 / 3)); v42 = v25 + v43 / 6; encryptresult = malloc(v42 + 1); if ( v24 ) { v28 = 0; pos = 0; v30 = 0; v44 = v25; do { v28 = (v28 + 1) % 0x100; v35 = (unsigned __int8)encrypttable[v28]; v30 = (v30 + v35) % 0x100; encrypttable[v28] = encrypttable[v30]; encrypttable[v30] = v35; v17 = (char *)(unsigned __int8)encrypttable[v28]; val = encrypttable[(unsigned __int8)(v35 + (_BYTE)v17)] ^ password[pos]; if ( pos && (v27 = 0xAAAAAAAB * (unsigned __int64)pos >> 0x20, round = 3 * (pos / 3), round != pos) ) { v31 = pos == 1; if ( pos != 1 ) // pos%3==1 v31 = round + 1 == pos; if ( v31 ) { v32 = aAbcdefghijklmn; encryptresult[v44 + pos] = aAbcdefghijklmn[(unsigned __int8)encryptresult[v44 + pos] | ((unsigned int)val >> 4)]; v17 = &encryptresult[v44 + pos]; v27 = 4 * val & 0x3C; v17[1] = v27; if ( pos + 1 >= v24 ) goto LABEL_53; } else { v33 = pos == 2; if ( pos != 2 ) v33 = round + 2 == pos; if ( v33 ) { v17 = (char *)(val & 0xC0); // pos%3==2 v34 = v44++ + pos; encryptresult[v34] = aAbcdefghijklmn[(unsigned __int8)encryptresult[v34] | ((unsigned int)v17 >> 6)] ^ 0xF; v27 = (int)&encryptresult[v34]; *(_BYTE *)(v27 + 1) = aAbcdefghijklmn[val & 0x3F]; } } } else { encryptresult[v44 + pos] = aAbcdefghijklmn[(unsigned int)val >> 2] ^ 7;// pos%3==0 v17 = &encryptresult[v44 + pos]; v27 = 16 * val & 0x30; v17[1] = v27; if ( pos + 1 >= v24 ) //最后一位 { v38 = aAbcdefghijklmn[v27]; *((_WORD *)v17 + 1) = ';;'; goto LABEL_43; } } ++pos; } while ( pos < v24 ); } while ( 1 ) { if ( v43 ) { v32 = (_BYTE *)1; v17 = (char *)v42; v39 = " {9*8ga*l!Tn?@#fj'j$\\g;;"; do { v27 = (unsigned __int8)encryptresult[v25++]; v40 = *(unsigned __int8 *)v39++; // 比较相等则成功 if ( v40 != v27 ) v32 = 0; } while ( v25 < v42 ); } else { v32 = (_BYTE *)1; } ...//省略 LABEL_53: v38 = v32[v27]; v17[2] = '4'; LABEL_43: v17[1] = v38; }
先是用encrypttable异或password,再用变异的base64编码异或后的结果,与标准base64编码的改动是:
码表是 !:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\\' ,\\只表示一个\ 。
"=="变为";;","="变为"4",编码后每4位的第1位异或0x7,第3位异或0xF,不过LABEL_53处没有异或0xF。
注意在编码的时候
encrypttable
还会交换成员的位置
编码后与" {9*8ga*l!Tn?@#fj'j$\\g;;"比较,注意'{'前面有空格,以及\\。
提取初始的encrypttable,实现交换成员,再修改下base64就可以得到结果了,我手头没有base64的代码,只有一份以前IDA F5的伪代码,改改拿来用了
#include <stdio.h> #include <stdlib.h> #include <string.h> char b64_chr[] = "!:#$%&()+-*/`~_[]{}?<>,.@^abcdefghijklmnopqrstuvwxyz0123456789\\'"; unsigned int b64_decode(unsigned char* in, unsigned int in_len, unsigned char* out) { unsigned int i=0, k=0; unsigned char j ,v7; unsigned char* decode=out; do{ if ( !*(in+k) || *(in+k) == ';' ||((k==in_len-1)&&(*(in+k) == '4' ))){ break; } unsigned int index=0; if(k%4==0){ (*(in+k))^=7; } else if(((k & 3) == 2)&&k!=in_len-2){ (*(in+k))^=0xF; } char* temp=strchr(b64_chr,*(in+k)); if(temp){ index=temp-(char *)b64_chr; } v7 =index; if ( k & 3 ) { if ( (k & 3) == 1 ) { *decode++ |= v7 >> 4; j = 16 * v7; } else { if ( (k & 3) != 2 ) { if ( (k & 3) == 3 ) *decode++ |= v7; goto LABEL_14; } *decode++ |= v7 >> 2; j = v7 << 6; } } else { j = 4 * v7; } *decode = j; LABEL_14: ++k; } while ( k < in_len ); decode[in_len-1]=0; return decode-out; } int main(){ unsigned char out[256]; unsigned char in2[]=" {9*8ga*l!Tn?@#fj'j$\\g;;"; unsigned char tmp=0,pos1=0,pos2=0; unsigned char *text; unsigned char table[0xFF]={ 0xF0,0x37,0xE1,0x9B,0x2A,0x15,0x17,0x9F,0xD7,0x58,0x4D,0x6E,0x33,0xA0,0x39, 0xAE,0x04,0xD0,0xBE,0xED,0xF8,0x66,0x5E,0x00,0xD6,0x91,0x2F,0xC3,0x10,0x4C, 0xF7,0xA6,0xC1,0xEC,0x6D,0x0B,0x50,0x65,0xBB,0x34,0xFA,0xA4,0x2D,0x3B,0x23, 0xA1,0x96,0xD5,0x1D,0x38,0x56,0x0A,0x5D,0x4F,0xE4,0xCC,0x24,0x0D,0x12,0x87, 0x35,0x85,0x8E,0x6F,0xC6,0x13,0x9A,0xD3,0xFC,0xE7,0x08,0xAC,0xB7,0xE9,0xB0, 0xE8,0x41,0xAA,0x55,0x53,0xC2,0x42,0xBC,0xE6,0x0F,0x8A,0x86,0xA8,0xCF,0x84, 0xC5,0x48,0x74,0x36,0x07,0xEB,0x88,0x51,0xF6,0x7F,0x57,0x05,0x63,0x3E,0xFE, 0xB8,0xC9,0xF5,0xAF,0xDF,0xEA,0x82,0x44,0xF9,0xCD,0x06,0xBA,0x30,0x47,0x40, 0xDE,0xFD,0x1C,0x7C,0x11,0x5C,0x02,0x31,0x2C,0x9C,0x5F,0x46,0x27,0xC4,0x83, 0x73,0x16,0x90,0x20,0x76,0x7B,0xF2,0xE3,0xF3,0x77,0x52,0x80,0x25,0x09,0x26, 0x3F,0xC7,0x18,0x1B,0xA3,0xFF,0xFB,0xCB,0xA9,0x8C,0x54,0x7A,0x68,0xB4,0x70, 0x4B,0xE2,0x49,0x22,0x7E,0xA5,0xB6,0x81,0x9D,0x4E,0x67,0xF1,0xA7,0x3C,0xD9, 0x94,0xEF,0x32,0x6B,0x1F,0xB1,0x60,0xB9,0x64,0x59,0x01,0xB3,0x7D,0xE0,0x6C, 0xAD,0x97,0x19,0xB5,0x3A,0xF4,0xD8,0x8D,0x98,0x03,0x93,0x1A,0xDC,0x1E,0x4A, 0xC0,0x5A,0xE5,0xD1,0x3D,0x14,0xC8,0x79,0xBD,0x43,0xDB,0x69,0xD2,0x61,0x95, 0x9E,0x21,0x45,0x89,0x2B,0xAB,0x29,0xA2,0x8B,0x2E,0xD4,0x0E,0x62,0xCA,0x28, 0xDA,0x5B,0x72,0x8F,0x99,0x75,0xEE,0x78,0x0C,0x71,0xBF,0xDD,0xCE,0x92,0x6A }; int len=b64_decode(in2,sizeof(in2)-1,out); printf("b64_decode:"); for (int i = 0; i < len; ++i) { printf("%02X",*(out+i)); } printf("\nxor:"); text=(unsigned char *)malloc(len+1); for (int i = 0; i < len; ++i) { pos1 = (pos1 + 1) % 0x100; tmp = table[pos1]; pos2 = (pos2 + tmp) % 0x100; table[pos1] = table[pos2]; table[pos2] = tmp; printf("%02X",table[(tmp+table[pos1])%0x100]); text[i]=table[(tmp+table[pos1])%0x100]^(*(out+i)); } text[len]='\0'; printf("\nresult:%s\n",text); free(text); return 0; }
输出:
b64_decode:FD1E8A4E09CA9003E7F1859F9BF7833E
xor:9B6BBA257382E0318680F1C5DA82DA08
result:fu0kzHp2aqtZAuY6
输入到密码框,按登陆。
emmm,没看懂啥意思,一开始我以为是提交的flag,但是提交了"flag{android4-9}","
android4-9
"之类的flag都没有成功,最后提交了"
fu0kzHp2aqtZAuY6"才成功。
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法
最后于 2019-3-24 11:58
被梦游枪手编辑
,原因:
赞赏
他的文章
看原图