第二题:变形金钢

解压得到一个apk

模拟器运行   是一个登陆注册  账号直接就有了  还是一个手机号(好奇就百度了一下)

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

随意输入iqiqiya    会弹出消息框  并且登录按钮不可用  必须重启应用

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

好了  载入解压下apk   并没有发现什么奇怪的  比如jar文件之类的

直接载入jeb进行查看    奔向MainActivity中的onCreate方法    右键反编译成java代码   发现理论上会调用login方法

但是实际上并没有   "登陆中。。。"这个字符串运行中并未出现

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

而且也没有字符串"error"   并且没有什么运算

赛后看WP    了解到这里改变了Activity的方法和调用顺序。因为onStart在onCreate之后执行,所以重写了父类的onStart方法,并在onStart方法中覆盖了onCreate的逻辑,进而最后生效的是onStart内的逻辑。

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

MainActivity 继承的 AppCompiatActivity 比原生的 AppCompatActivity 中间多了个 i   并且有加载名为oo000oo的so文件

双击进去可以发现

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

OnStart()的实现如下

protected native boolean eq(String arg1) {
    }
protected void onStart() {
        super.onStart();
        this.login = this.findViewById(2131165260);
        this.login.setOnClickListener(new View$OnClickListener() {
            public void onClick(View arg5) {
                AppCompiatActivity.this.mName = AppCompiatActivity.this.name.getText().toString();
                AppCompiatActivity.this.mPassword = AppCompiatActivity.this.password.getText().toString();
                if(!TextUtils.isEmpty(AppCompiatActivity.this.mName) && !TextUtils.isEmpty(AppCompiatActivity
                        .this.mPassword)) {
                    int v1 = 0;
                    AppCompiatActivity.this.login.setEnabled(false);
                    if(AppCompiatActivity.this.eq(AppCompiatActivity.this.mPassword)) {//eq方法
                        byte[] v5 = AppCompiatActivity.this.mPassword.getBytes();
                        int v3 = 24;
                        if(v5.length != v3) {
                            byte[] v2 = new byte[v3];
                        label_38:
                            if(v1 < v2.length) {
                                byte v3_1 = v1 < v5.length ? v5[v1] : ((byte)v1);
                                v2[v1] = v3_1;
                                ++v1;
                                goto label_38;
                            }

                            v5 = v2;
                        }

                        v5 = AppCompiatActivity.dec(v5, "2ggdrsLgM7iPNYPQrD58Rg==".getBytes());
                        AppCompiatActivity v1_1 = AppCompiatActivity.this;
                        StringBuilder v2_1 = new StringBuilder();
                        v2_1.append("flag{");
                        v2_1.append(new String(v5));
                        v2_1.append("}");
                        Toast.makeText(((Context)v1_1), v2_1.toString(), 1).show();
                    }
                    else {
                        Toast.makeText(AppCompiatActivity.this, "error", 1).show();
                    }

                    return;
                }

                Toast.makeText(AppCompiatActivity.this, "用户名或密码为空", 1).show();
            }
        });

可以看到有一个native的方法

我们接着分析oo000oo.so

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

载入IDA

查看函数列表  可以看到datadiv_decode5009363700628197108()中是几个字符串的初始化操作  且都是异或运算

char *datadiv_decode5009363700628197108()
{
  int v0; // r0
  int v1; // r0
  int v2; // r0
  char *result; // r0

  v0 = 0;
  do
  {
    byte_4020[v0] ^= 0xA5u;    //记作s1
    ++v0;
  }
  while ( v0 != 37 );
  v1 = 0;
  do
    byte_4050[v1++] ^= 0xA5u;   //记作s2
  while ( v1 != 66 );
  v2 = 0;
  do
    byte_40A0[v2++] ^= 0x84u;   //记作s3
  while ( v2 != 42 );
  result = &byte_40D0;
  byte_40CA ^= 0xFCu;            //记作s4
  byte_40CB ^= 0xFCu;
  byte_40CC ^= 0xFCu;
  byte_40D0 ^= 0x62u;
  byte_40D1 ^= 0x62u;
  byte_40D2 ^= 0x62u;
  byte_40D3 ^= 0x62u;
  byte_40D4 ^= 0x62u;
  byte_40D5 ^= 0x62u;
  byte_40D6 = __PAIR__(HIBYTE(byte_40D6), (unsigned __int8)(byte_40D6 ^ 0x62)) ^ 0x6200;
  byte_40D8 ^= 0x62u;
  byte_40D9 ^= 0x62u;
  byte_40DA ^= 0x62u;
  byte_40DB ^= 0x62u;
  byte_40DC ^= 0x62u;
  byte_40DD ^= 0x62u;
  byte_40DE ^= 0x62u;
  byte_40DF ^= 0x62u;
  byte_40E0 ^= 0x62u;
  byte_40E1 ^= 0x62u;
  byte_40E2 ^= 0x62u;
  byte_40E3 ^= 0x62u;
  byte_40E4 ^= 0x62u;
  byte_40E5 ^= 0x62u;
  return result;
}

python解密可以得到

# -*- coding: utf-8 -*-
s1 =[
  0x93, 0x90, 0x95, 0xC3, 0x9C, 0x95, 0x9C, 0xC6, 0x88, 0x92, 
  0x97, 0x94, 0x92, 0x88, 0x96, 0x93, 0x91, 0x92, 0x88, 0x9C, 
  0x96, 0x96, 0x94, 0x88, 0xC6, 0x9D, 0x97, 0xC1, 0xC3, 0x9D, 
  0xC7, 0x9C, 0x9D, 0xC0, 0x9C, 0x9D, 0xA5]#xor 0xa5
s2 = [
  0x84, 0x9F, 0x86, 0x81, 0x80, 0x83, 0x8D, 0x8C, 0x8E, 0x88, 
  0x8F, 0x8A, 0xC5, 0xDB, 0xFA, 0xFE, 0xF8, 0xDE, 0xD8, 0x9A, 
  0x99, 0x9B, 0x89, 0x8B, 0xE5, 0xFB, 0xC4, 0xC7, 0xC6, 0xC1, 
  0xC0, 0xC3, 0xC2, 0xCD, 0xCC, 0xCF, 0xCE, 0xC9, 0xC8, 0xCB, 
  0xCA, 0xD5, 0xD4, 0xD7, 0xD6, 0xD1, 0xD0, 0xD3, 0xD2, 0xDD, 
  0xDC, 0xDF, 0x95, 0x94, 0x97, 0x96, 0x91, 0x90, 0x93, 0x92, 
  0x9D, 0x9C, 0xF9, 0x82, 0x9E, 0xA5]#xor 0xa5
s3 = [
  0xE5, 0xEA, 0xE0, 0xF6, 0xEB, 0xED, 0xE0, 0xAB, 0xF7, 0xF1, 
  0xF4, 0xF4, 0xEB, 0xF6, 0xF0, 0xAB, 0xF2, 0xB3, 0xAB, 0xE5, 
  0xF4, 0xF4, 0xAB, 0xC5, 0xF4, 0xF4, 0xC7, 0xEB, 0xE9, 0xF4, 
  0xED, 0xE5, 0xF0, 0xC5, 0xE7, 0xF0, 0xED, 0xF2, 0xED, 0xF0, 
  0xFD, 0x84]#xor 0x84
s4 = [
  0x99, 0x8D, 0xFC, 0x4A, 0x2E, 0x08, 0x03, 0x14, 0x03, 0x4D,
  0x0E, 0x03, 0x0C, 0x05, 0x4D, 0x31, 0x16, 0x10, 0x0B, 0x0C,
  0x05, 0x59, 0x4B, 0x38, 0x62]#xor 0xfc   0x62
ds1 = ''
ds2 = ''
ds3 = ''
ds4 = ''
for i in range(len(s1)):
  ds1+=chr(s1[i]^0xa5)
print ds1
for i in range(len(s2)):
  ds2+=chr(s2[i]^0xa5)
print ds2
for i in range(len(s3)):
  ds3+=chr(s3[i]^0x84)
print ds3
for i in range(len(s4)):
  if i<2:
    ds4+=chr(s4[i]^0xfc)
  else:
    ds4+=chr(s4[i]^0x62)
print ds4
#ds1 = 650f909c-7217-3647-9331-c82df8b98e98
#ds2 = !!:#$%&()+-*/`~_[]{}?<>,[email protected]^abcdefghijklmnopqrstuvwxyz0123456789\';
#ds3 = android/support/v7/app/AppCompiatActivity
#ds4 = eq゙(Ljava/lang/String;)Z

可以看到ds1像是一个***   ds2是base64变化的编码表   而ds3,ds4指的是我们的eq()方法

那么现在就要找eq()在哪里定义

我们接着看JNI_Onload()   里边有两个off_4010  off_4014   分别对应前面我们得到的ds3,ds4

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

也就是说这里调用了eq()     我们查看字符串数组引用    可以发现除了那个初始化函数  还有一个sub_784()

Kanxue看雪KCTF2019-Q1第二题【变形金钢】Writeup

双击进入查看

 

实际注册是APP调用so时,虚拟机会自动首先寻找JNI_OnLoad(JNIEnv*...)函数的,自动从这个函数进行执行,所以注册或者初始化一些信息可以在这里进行

参考链接:

https://bbs.pediy.com/thread-250376.htm

https://bbs.pediy.com/thread-250395.htm

相关文章:

  • 2021-12-17
  • 2021-06-22
  • 2021-05-03
  • 2022-02-04
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-10-21
猜你喜欢
  • 2021-10-31
  • 2021-04-19
  • 2021-08-20
  • 2022-01-31
  • 2021-11-09
  • 2021-12-05
  • 2021-07-25
相关资源
相似解决方案