首页
社区
课程
招聘
[原创]2019看雪CTF 团队赛 第二题 变形金钢WP
2019-3-21 18:20 2923

[原创]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 被梦游枪手编辑 ,原因:
收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回