bugku-逆向-5、Timer

下载下来,是一个apk文件,就是安卓手机软件的安装包,先把它安装看一下:
在这里插入图片描述

只有一个界面,上面有个200000在倒计时,应该是等时间到了,就会显示flag。
接下来我们反编译,可以自己逐步解压缩,用apktools、dex2jar转化为jar包,也可以直接用集成工具打开
刚开始用JAD打开jar包,查看到的.class文件的代码是这样子的:
在这里插入图片描述

public class MainActivity
  extends AppCompatActivity
{
  int beg = (int)(System.currentTimeMillis() / 1000L) + 200000;//之前的当前时间+200000
  int k = 0;
  int now;
  long t = 0L;
  
  static
  {
    System.loadLibrary("lhm");
  }
  
  public static boolean is2(int paramInt)
  {
    boolean bool1 = true;
    boolean bool2;
    if (paramInt <= 3) {
      if (paramInt > 1) {
        bool2 = bool1;
      }
    }
    for (;;)
    {
      return bool2;
      bool2 = false;
      continue;
      if ((paramInt % 2 != 0) && (paramInt % 3 != 0)) {
        break;
      }
      bool2 = false;
    }
    for (int i = 5;; i += 6)
    {
      bool2 = bool1;
      if (i * i > paramInt) {
        break;
      }
      if ((paramInt % i == 0) || (paramInt % (i + 2) == 0))
      {
        bool2 = false;
        break;
      }
    }
  }
  
  protected void onCreate(final Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2130968600);
    final TextView localTextView1 = (TextView)findViewById(2131492944);
    final TextView localTextView2 = (TextView)findViewById(2131492945);
    paramBundle = new Handler();
    paramBundle.postDelayed(new Runnable()
    {
      public void run()
      {
        MainActivity.this.t = System.currentTimeMillis();
        MainActivity.this.now = ((int)(MainActivity.this.t / 1000L));//当前时间的秒数(毫秒/1000)
        MainActivity.this.t = (1500L - MainActivity.this.t % 1000L);
        localTextView2.setText("AliCTF");
        if (MainActivity.this.beg - MainActivity.this.now <= 0)
        {
          localTextView1.setText("The flag is:");
          localTextView2.setText("alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}");
        }
        MainActivity localMainActivity;
        if (MainActivity.is2(MainActivity.this.beg - MainActivity.this.now)) {
          localMainActivity = MainActivity.this;
        }
        for (localMainActivity.k += 100;; localMainActivity.k -= 1)
        {
          localTextView1.setText("Time Remaining(s):" + (MainActivity.this.beg - MainActivity.this.now));//剩下的时间是:
          paramBundle.postDelayed(this, MainActivity.this.t);
          return;
          localMainActivity = MainActivity.this;
        }
      }
    }, 0L);
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu)
  {
    getMenuInflater().inflate(2131558400, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem)
  {
    if (paramMenuItem.getItemId() == 2131492959) {}
    for (boolean bool = true;; bool = super.onOptionsItemSelected(paramMenuItem)) {
      return bool;
    }
  }
  
  public native String stringFromJNI2(int paramInt);
}

主要的函数的逻辑就是时间从200000秒开始逐秒减少计时,每减少一秒,就判断一下之前的时间beg减当前的时间now是否小于等于0,这里的beg=之前的当前时间+200000,所以判断条件也就是从之前到现在是否过了200000秒,过了200000就输出flag。
flag是由

localTextView2.setText("alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}");

这行代码输出的,其中stringFromJNI2函数是Native层的函数,所以我们主要就是先算出它的实参k,这是下面和k有关的代码:

if (MainActivity.is2(MainActivity.this.beg - MainActivity.this.now)) {
          localMainActivity = MainActivity.this;
        }
        for (localMainActivity.k += 100;; localMainActivity.k -= 1)
        {
          localTextView1.setText("Time Remaining(s):" + (MainActivity.this.beg - MainActivity.this.now));//剩下的时间是:
          paramBundle.postDelayed(this, MainActivity.this.t);
          return;
          localMainActivity = MainActivity.this;
        }

但它的实参k我开始看了半天都不知该怎么算出来,然后把k转换成flag。后来我换了两个打开class文件的软件:
在这里插入图片描述

发现打开的.class文件反编译出来的代码竟然不一样:
在这里插入图片描述

主要就是对k的值的计算的代码不一样了:

if(MainActivity.is2(beg - now))
                {
                    MainActivity mainactivity = MainActivity.this;
                    mainactivity.k = mainactivity.k + 100;
                } else
                {
                    MainActivity mainactivity1 = MainActivity.this;
                    mainactivity1.k = mainactivity1.k - 1;
                }

所以现在程序的逻辑就是时间从200000到0,每一秒钟判断当前的时间过去了多久,然后判断MainActivity.is2(beg - now),之后对k进行一次计算。最后时间到0的时候,k也计算出了一个值,用k作实参输入stringFromJNI2(k)函数计算出flag。
我们要得到flag就要先算出时间到0时k的值,直接按照反编译出来的代码计算k的值:

Timer.java

/**
 * 文件注释:
 *
 * @auther: Legends
 * @Date: 2018/9/21 09:19
 * @Description:
 */
public class Timer {
    public static void main(String[] args) {
        int k = 0 ;
        for(int i = 200000 ; i > 0 ; i-- ){
            if (is2(i)) {
                k += 100;
            } else {
                --k;
            }
        }
        System.out.println(k);
    }

    public static boolean is2(int var0) {
        if (var0 <= 3) {
            if (var0 <= 1) {
                return false;
            } else {
                return true;
            }
        } else if (var0 % 2 != 0 && var0 % 3 != 0) {
            for(int var1 = 5; var1 * var1 <= var0; var1 += 6) {
                if (var0 % var1 == 0 || var0 % (var1 + 2) == 0) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }
}

运行结果:
在这里插入图片描述

得到的k的值为:1616384。接下来的flag就是把k=1616384作为实参输入stringFromJNI2(k)函数即可计算出flag。
这时候有两种思路:
1、一种是复现stringFromJNI2(k)函数,再按部就班的计算出flag。
2、另一种是修改apk中k的值,把k的值修改为1616384,让软件自己计算出flag显示出来。

方法1先用IDA打开反编译出来的lib文件夹下面armeabi文件夹的liblhm.so:armeabi是指Android 设备的CPU类型,文件夹下用来存放.so库,主要针对不同的设备兼容,也可以说是专门针对不同Android手机下CPU架构的兼容。不同版本的so文件反编译的结果可能不同。
• mips / mips64: 极少用于手机可以忽略
• x86 / x86_64: x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现 对 arm .so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 .so 也是可以忽略的
• armeabi: ARM v5 这是相当老旧的一个版本,缺少对浮点数计算的硬件支持,在需要大量计算时有性能瓶颈
• armeabi-v7a: ARM v7 目前主流版本
• arm64-v8a: 64位支持
再IDA找到Java_net_bluelotus_tomorrow_easyandroid_MainActivity_stringFromJNI2函数:
在这里插入图片描述

发现打开的stringFromJNI2函数十分复杂,调用的函数也很多,所以这种方法并不是一种好的解题思路,于是我们采用方法2。

首先是要先通过逻辑判断MainActivity.this.beg - MainActivity.this.now <= 0,才能输出flag,这里就可以把beg的值改小200000、把now的值改大200000、把<=0改成>=0或者把整个判断去掉都行。我们这里就直接把beg加上的200000改成0了:
在这里插入图片描述

0x30d40=200000,上面就是int beg = (int)(System.currentTimeMillis() / 1000L) + 200000;的smili代码;我们把0x30d40改为0就可以让判断MainActivity.this.beg - MainActivity.this.now <= 0一直成立了。
在这里插入图片描述

之后再找到

localTextView2.setText("alictf{" + MainActivity.this.stringFromJNI2(MainActivity.this.k) + "}");

这一行的smali代码:
在这里插入图片描述

在iget v3, v3, Lnet/bluelotus/tomorrow/easyandroid/MainActivity;->k:I(读取int型k到v3(第一个v3),v3(第二个v3)寄存器中是 Lnet/bluelotus/tomorrow/easyandroid/MainActivity实例的引用,I表示int型),再下一行加上const v3,0x18aa00把k的值一直赋值为1616384 = 0x18aa00,smali代码的int型变量默认都是16进制,就算改成1616384,它编译之后也会自己改成0x18aa00。之后每次就能计算显示正确的flag:
在这里插入图片描述

之后保存全部,编译生成apk,安装,运行:
在这里插入图片描述

flag果然显示出来了:alictf{Y0vAr3TimerMa3te7}。上面的Time Remaining(s):-3是因为我们把beg从当前时间+200000改成了当前时间,所以之后每过一秒就会-1。

©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页