欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

bugku-逆向-10、SafeBox(NJCTF)

程序员文章站 2022-06-26 15:22:35
文章目录一、反编译查看源代码二、源代码分析三、方法1:正向暴力破解四、方法二:按照筛选条件,逐步缩小范围先下载软件,发现是个安卓的apk安装包,安装之后打开:一、反编译查看源代码只有一个输入框,其他的点不了。应该是要输入某个字符串然后判断是否正确,之后返回flag。打开apk反编译:发现有两个Activity,而且代码高度相似,查看AndroidManifest.xml:多个Activity可以显示多个不同的界面,setContentView就是设置一个Activity的显示界面,使用s...

先下载软件,发现是个安卓的apk安装包,安装之后打开:
bugku-逆向-10、SafeBox(NJCTF)

一、反编译查看源代码

只有一个输入框,其他的点不了。应该是要输入某个字符串然后判断是否正确,之后返回flag。
打开apk反编译:
bugku-逆向-10、SafeBox(NJCTF)
bugku-逆向-10、SafeBox(NJCTF)

发现有两个Activity,而且代码高度相似,查看AndroidManifest.xml:
bugku-逆向-10、SafeBox(NJCTF)

多个Activity可以显示多个不同的界面,setContentView就是设置一个Activity的显示界面,使用setContentView可以在Activity中动态切换显示的View,这样,不需要多个Activity就可以显示不同的界面。
其中它们调用的id:2130968603 = 0x7F04001B,2130968604 = 0x7F04001C,
在public.xml中找到相应id对应的资源:


bugku-逆向-10、SafeBox(NJCTF)

打开layout文件夹,找到activity_main.xml和build.xml文件:
bugku-逆向-10、SafeBox(NJCTF)
bugku-逆向-10、SafeBox(NJCTF)
发现两个文件一模一样:
bugku-逆向-10、SafeBox(NJCTF)

二、源代码分析

再查看两个类的源代码:
MainActivity.class

package com.geekerchina.hi;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity
  extends AppCompatActivity
{
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2130968603);
    ((Button)findViewById(2131427415)).setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
        int i1 = Integer.parseInt(this.val$Et1.getText().toString());
        int k;
        int i;
        int n;
        int j;
        if ((i1 > 10000000) && (i1 < 99999999))
        {
          k = 1;
          i = 10000000;
          n = 1;
          if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
            j = 0;
          }
        }
        for (;;)
        {
          int m = n;
          if (j < 4)
          {
            if (i1 / k % 10 != i1 / i % 10) {
              m = 0;
            }
          }
          else
          {
            if (m == 1)
            {
              char c1 = (char)(i1 / 1000000);
              char c2 = (char)(i1 / 10000 % 100);
              char c3 = (char)(i1 / 100 % 100);
              this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");
            }
            return;
          }
          k *= 10;
          i /= 10;
          j += 1;
        }
      }
    });
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu)
  {
    getMenuInflater().inflate(2131558400, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem)
  {
    if (paramMenuItem.getItemId() == 2131427439) {
      return true;
    }
    return super.onOptionsItemSelected(paramMenuItem);
  }
}

androidTest.class

package com.geekerchina.hi;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class androidTest
  extends AppCompatActivity
{
  protected void onCreate(Bundle paramBundle)
  {
    super.onCreate(paramBundle);
    setContentView(2130968604);
    ((Button)findViewById(2131427415)).setOnClickListener(new View.OnClickListener()
    {
      public void onClick(View paramAnonymousView)
      {
        int i1 = Integer.parseInt(this.val$Et1.getText().toString());
        int k;
        int i;
        int n;
        int j;
        if ((i1 > 10000000) && (i1 < 99999999))
        {
          k = 1;
          i = 10000000;
          n = 1;
          if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
            j = 0;
          }
        }
        for (;;)
        {
          int m = n;
          if (j < 3)
          {
            if (i1 / k % 10 != i1 / i % 10) {
              m = 0;
            }
          }
          else
          {
            if (m == 1)
            {
              char c1 = (char)(i1 / 1000000);
              char c2 = (char)(i1 / 10000 % 100);
              char c3 = (char)(i1 / 100 % 100 + 10);
              this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");
            }
            return;
          }
          k *= 10;
          i /= 10;
          j += 1;
        }
      }
    });
  }
  
  public boolean onCreateOptionsMenu(Menu paramMenu)
  {
    getMenuInflater().inflate(2131558400, paramMenu);
    return true;
  }
  
  public boolean onOptionsItemSelected(MenuItem paramMenuItem)
  {
    if (paramMenuItem.getItemId() == 2131427439) {
      return true;
    }
    return super.onOptionsItemSelected(paramMenuItem);
  }
}

两个类主要的差别就是:
MainActivity.class
bugku-逆向-10、SafeBox(NJCTF)
bugku-逆向-10、SafeBox(NJCTF)

androidTest.class
bugku-逆向-10、SafeBox(NJCTF)
bugku-逆向-10、SafeBox(NJCTF)

androidTest相比于MainActivity,就是为了不限制中间4,5两位的数字必须相等,而且出c3有加10再转换成字符。

三、方法1:正向暴力破解

直接用反编译的class代码暴力破解:
MainActivity.java

public class MainActivity {
    public static void main(String[] args) {
        int k;
        int i;
        int n;
        int j;
        for(int i1 = 10000001; i1 < 99999999 ; i1++){
            k = 1;
            i = 10000000;
            n = 1;
            if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
                j = 0;
            }else {
                continue;
            }

            for (;;) {
                int m = n;
                if (j < 3) {
                    if (i1 / k % 10 != (i1 / i % 10) ) {
                        //m = 0;
                        //当m = 0 时,表明当前的i1已经不符合条件,直接break;否则程序还会进入下一层循环,m又会重新等于n,导致程序还会继续运行,在j=4时始终会输出
                        break;
                    }
                } else {
                    if (m == 1) {
                        char c1 = (char) (i1 / 1000000);
                        char c2 = (char) (i1 / 10000 % 100);
                        char c3 = (char) (i1 / 100 % 100 + 10);
                        System.out.println(i1);
                        System.out.println("NJCTF{have" + c1 + c2 + c3 + "f4n}");
                    }
                    break;
                }
                k *= 10;
                i /= 10;
                j += 1;
            }
        }
    }
}

运行结果截图:
bugku-逆向-10、SafeBox(NJCTF)

得到的flag为NJCTF{05#f4n}。
androidTest.java

public class androidTest {
    public static void main(String[] args) {

        int k;
        int i;
        int n;
        int j;
        for(int i1 = 10000001; i1 < 99999999 ; i1++)
        {
            k = 1;
            i = 10000000;
            n = 1;
            if ((Math.abs(i1 / 1000 % 100 - 36) == 3) && (i1 % 1000 % 584 == 0)) {
                j = 0;
            }else {
                continue;
            }

            for (;;)
            {
                int m = n;
                if (j < 3)
                {
                    if (i1 / k % 10 != i1 / i % 10) {
                        m = 0;
                        break;
                    }
                }
                else
                {
                    if (m == 1)
                    {
                        char c1 = (char)(i1 / 1000000);
                        char c2 = (char)(i1 / 10000 % 100);
                        char c3 = (char)(i1 / 100 % 100 + 10);
                        System.out.println(i1);
                        System.out.println("NJCTF{have" + c1 + c2 + c3 + "f4n}");
                    }
                    return;
                }
                k *= 10;
                i /= 10;
                j += 1;
            }
        }
    }
}

运行结果截图:
bugku-逆向-10、SafeBox(NJCTF)

得到的flag为:NJCTF{have05-f4n}和NJCTF{have05if4n}。
Bugku的提示:flag格式NJCTF{xxx} 并且 xxx只包含[a-z][A-Z][0-9]。
所以真正的flag是NJCTF{have05if4n}。
其实网鼎杯原题的题目提示是:tips:Don’t believe what you saw.
The flag’s format is NJCTF{xxx} and xxx only include [a-z][A-Z][0-9].让我们不要相信看到的,意思就是程序的入口MainActivity这个表面上的类得到的答案是错误的,隐藏在它后面相似的androidTest才是真正的答案。

四、方法二:按照筛选条件,逐步缩小范围

il要满足的条件:
1、首先范围是在10000000到99999999之间,一个8位数
2、之后是满足Math.abs(i1 / 1000 % 100 - 36) == 3 && (i1 % 1000 % 584 == 0):
Math.abs(i1 / 1000 % 100 - 36) == 3:il/1000得到的就是前5位的数字,i1 / 1000 % 100得到的就是第4、5位的数字,Math.abs(i1 / 1000 % 100 - 36) == 3就是第4、5位的数字减36的绝对值是3,所以第4、5位是33或者39,符合条件的数格式为ABC33EFG或者ABC39EFG;
i1 % 1000 % 584 == 0:i1 % 1000,得到的就是后面的第6、7、8位的数字,i1 % 1000 % 584 == 0就是第6、7、8位的数字是584的倍数,第6、7、8位就是一个三位数所以就是584,符合条件的数格式为ABC33584或者ABC39584。
3、这里就是MainActivity和androidTest有差异的地方:
MainActivity.class:

for (;; )
{
  int m = n;
  if (j < 4)
  {
    if (i1 / k % 10 != i1 / i % 10) {
      m = 0;
    }
  }
  else
  {
    if (m == 1)
    {
      char c1 = (char)(i1 / 1000000);
      char c2 = (char)(i1 / 10000 % 100);
      char c3 = (char)(i1 / 100 % 100);
      this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");
    }
    return;
  }
  k *= 10;
  i /= 10;
  j += 1;
}

androidTest.class:

for (;; )
{
  int m = n;
  if (j < 3)
  {
    if (i1 / k % 10 != i1 / i % 10) {
      m = 0;
    }
  }
  else
  {
    if (m == 1)
    {
      char c1 = (char)(i1 / 1000000);
      char c2 = (char)(i1 / 10000 % 100);
      char c3 = (char)(i1 / 100 % 100 + 10);
      this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");
    }
    return;
  }
  k *= 10;
  i /= 10;
  j += 1;
}

这两段代码的主要判断是相似的,在MainActivity类中就是if (j < 4){ if (i1 / k % 10 != i1 / i % 10) { m = 0;}}
k *= 10;
i /= 10;
j += 1;
k的初始值是1,i的初始值是10000000,所以i1 / k % 10就是分别获得第8、7、6、5位上的数字,i1 / i % 10就是分别获得第1、2、3、4位上的数字,再要求它们分别相等,也就是ABCDDCBA的形式,结合上面的条件,符合条件的数为48533584。
48533584经过

char c1 = (char)(i1 / 1000000);//第1、2位数字
char c2 = (char)(i1 / 10000 % 100);//第3、4位数字
char c3 = (char)(i1 / 100 % 100);//第3、4位数字
this.val$Et1.setText("NJCTF{" + c1 + c2 + c3 + "f4n}");

得到的字符串为NJCTF{05#f4n}。

而在androidTest类中,androidTest相比于MainActivity,就是j<4变成j<3,目的是为了不限制中间4,5两位的数字必须相等,这样就只用第8、7、6位上的数字和第1、2、3位的数字分别相等了,也就是ABCDECBA的形式,结合上面的条件得到了符合条件的两个数为48533584和48539584。
48533584和48539584经过

char c1 = (char)(i1 / 1000000);//第1、2位数字
char c2 = (char)(i1 / 10000 % 100);//第3、4位数字
char c3 = (char)(i1 / 100 % 100 + 10);//第5、6位数字再加10
this.val$Et1.setText("NJCTF{have" + c1 + c2 + c3 + "f4n}");

得到的字符串为NJCTF{have05-f4n}和NJCTF{have05if4n}。 其中c3字符有额外加10再转换成字符,是为了让第5、6位上的数字转化的字符#和_变成字符-和i,从而让i在[a-z][A-Z][0-9]的范围内,得到唯一一个满足题目提示flag格式NJCTF{xxx} 并且 xxx只包含[a-z][A-Z][0-9]的flag:NJCTF{have05if4n}。

本文地址:https://blog.csdn.net/Onlyone_1314/article/details/108877257