攻防世界mobile新手区之easyjava write up

0x00反编译apk

拖进JEB2看看:

点击MainActivity.class

package com.a.easyjava;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.c;
import android.view.View$OnClickListener;
import android.view.View;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends c {
    public MainActivity() {
        super();
    }

    private static char a(String arg1, b arg2, a arg3) {
        return arg3.a(arg2.a(arg1));
    }

    static Boolean a(String arg1) {
        return MainActivity.b(arg1);
    }

    private static Boolean b(String arg8) {
        Boolean v0_1;
        int v0 = 0;
        if(!arg8.startsWith("flag{")) {
            v0_1 = Boolean.valueOf(false);
        }
        else if(!arg8.endsWith("}")) {
            v0_1 = Boolean.valueOf(false);
        }
        else {
            String v2 = arg8.substring(5, arg8.length() - 1);
            b v4 = new b(Integer.valueOf(2));
            a v5 = new a(Integer.valueOf(3));
            StringBuilder v3 = new StringBuilder();
            int v1 = 0;
            while(v0 < v2.length()) {
                v3.append(MainActivity.a(v2.charAt(v0) + "", v4, v5));
                Integer v6 = Integer.valueOf(v4.b().intValue() / 25);
                if(v6.intValue() > v1 && v6.intValue() >= 1) {
                    ++v1;
                }

                ++v0;
            }

            v0_1 = Boolean.valueOf(v3.toString().equals("wigwrkaugala"));
        }

        return v0_1;
    }

    protected void onCreate(Bundle arg3) {
        super.onCreate(arg3);
        this.setContentView(2130968603);
        this.findViewById(2131427446).setOnClickListener(new View$OnClickListener(((Context)this)) {
            public void onClick(View arg5) {
                if(MainActivity.a(this.a.findViewById(2131427445).getText().toString()).booleanValue()) {
                    Toast.makeText(this.a, "You are right!", 1).show();
                }
                else {
                    Toast.makeText(this.a, "You are wrong! Bye~", 1).show();
                    new Timer().schedule(new TimerTask() {
                        public void run() {
                            System.exit(1);
                        }
                    }, 2000);
                }
            }
        });
    }
}

0x01查看主要代码:

/**
*arg8:输入的flag
**/
 private static Boolean b(String arg8) {
        Boolean v0_1;     //判断结果
        int v0 = 0;
        if(!arg8.startsWith("flag{")) {      //若不以flag{开头则返回false
            v0_1 = Boolean.valueOf(false);
        }
        else if(!arg8.endsWith("}")) {     //若不以}结尾则返回false
            v0_1 = Boolean.valueOf(false);
        }
        else {
            String v2 = arg8.substring(5, arg8.length() - 1); //arg截取一定长度的子串,分析结构知是截取flag{}花括号内部的子串
            b v4 = new b(Integer.valueOf(2));                 //v4 = 2
            a v5 = new a(Integer.valueOf(3));                 //v5 = 3
            StringBuilder v3 = new StringBuilder();
            int v1 = 0;
            while(v0 < v2.length()) {               //循环遍历子串的每个字符
                v3.append(MainActivity.a(v2.charAt(v0) + "", v4, v5));
                Integer v6 = Integer.valueOf(v4.b().intValue() / 25);
                if(v6.intValue() > v1 && v6.intValue() >= 1) {
                    ++v1;
                }

                ++v0;
            }

            v0_1 = Boolean.valueOf(v3.toString().equals("wigwrkaugala"));
        }

        return v0_1;
    }

虽然代码被混淆了,但我并不想去混淆,直接分析被混淆的代码。毕竟头铁就是刚。

先分析两个类的实例化过程:

b v4 = new b(Integer.valueOf(2));
a v5 = new a(Integer.valueOf(3));

类a、b的代码如下:

package com.a.easyjava;

import java.util.ArrayList;

public class b {
    public static ArrayList a;
    static String b;
    Integer[] c;
    static Integer d;

    static {
        b.a = new ArrayList();
        b.b = "abcdefghijklmnopqrstuvwxyz";
        b.d = Integer.valueOf(0);
    }

    public b(Integer arg9) {
        super();
        this.c = new Integer[]{Integer.valueOf(8), Integer.valueOf(25), Integer.valueOf(17), Integer.valueOf(23), Integer.valueOf(7), Integer.valueOf(22), Integer.valueOf(1), Integer.valueOf(16), Integer.valueOf(6), Integer.valueOf(9), Integer.valueOf(21), Integer.valueOf(0), Integer.valueOf(15), Integer.valueOf(5), Integer.valueOf(10), Integer.valueOf(18), Integer.valueOf(2), Integer.valueOf(24), Integer.valueOf(4), Integer.valueOf(11), Integer.valueOf(3), Integer.valueOf(14), Integer.valueOf(19), Integer.valueOf(12), Integer.valueOf(20), Integer.valueOf(13)};
        int v0;
        for(v0 = arg9.intValue(); v0 < this.c.length; ++v0) {
            b.a.add(this.c[v0]);
        }

        for(v0 = 0; v0 < arg9.intValue(); ++v0) {
            b.a.add(this.c[v0]);
        }
    }

    public Integer a(String arg5) {
        int v0 = 0;
        Integer v1 = Integer.valueOf(0);
        if(b.b.contains(arg5.toLowerCase())) {
            Integer v2 = Integer.valueOf(b.b.indexOf(arg5));
            while(v0 < b.a.size() - 1) {
                if(b.a.get(v0) == v2) {
                    v1 = Integer.valueOf(v0);
                }

                ++v0;
            }
        }
        else {
            if(arg5.contains(" ")) {
                v1 = Integer.valueOf(-10);
                goto label_24;
            }

            v1 = Integer.valueOf(-1);
        }

    label_24:
        b.a();
        return v1;
    }

    public static void a() {
        int v0 = b.a.get(0).intValue();
        b.a.remove(0);
        b.a.add(Integer.valueOf(v0));
        b.b = b.b + "" + b.b.charAt(0);
        b.b = b.b.substring(1, 27);
        b.d = Integer.valueOf(b.d.intValue() + 1);
    }

    public Integer b() {
        return b.d;
    }
}

package com.a.easyjava;

import java.util.ArrayList;

public class a {
    public static ArrayList a;
    static String b;
    Integer[] c;
    static Integer d;

    static {
        a.a = new ArrayList();
        a.b = "abcdefghijklmnopqrstuvwxyz";
        a.d = Integer.valueOf(0);
    }

    public a(Integer arg8) {
        super();
        this.c = new Integer[]{Integer.valueOf(7), Integer.valueOf(14), Integer.valueOf(16), Integer.valueOf(21), Integer.valueOf(4), Integer.valueOf(24), Integer.valueOf(25), Integer.valueOf(20), Integer.valueOf(5), Integer.valueOf(15), Integer.valueOf(9), Integer.valueOf(17), Integer.valueOf(6), Integer.valueOf(13), Integer.valueOf(3), Integer.valueOf(18), Integer.valueOf(12), Integer.valueOf(10), Integer.valueOf(19), Integer.valueOf(0), Integer.valueOf(22), Integer.valueOf(2), Integer.valueOf(11), Integer.valueOf(23), Integer.valueOf(1), Integer.valueOf(8)};
        int v0;
        for(v0 = arg8.intValue(); v0 < this.c.length; ++v0) {
            a.a.add(this.c[v0]);
        }

        for(v0 = 0; v0 < arg8.intValue(); ++v0) {
            a.a.add(this.c[v0]);
        }
    }

    public char a(Integer arg5) {
        char v0_1;
        int v0 = 0;
        Integer v1 = Integer.valueOf(0);
        if(arg5.intValue() == -10) {
            a.a();
            v0_1 = " ".charAt(0);
        }
        else {
            while(v0 < a.a.size() - 1) {
                if(a.a.get(v0) == arg5) {
                    v1 = Integer.valueOf(v0);
                }

                ++v0;
            }

            a.a();
            v0_1 = a.b.charAt(v1.intValue());
        }

        return v0_1;
    }

    public static void a() {
        a.d = Integer.valueOf(a.d.intValue() + 1);
        if(a.d.intValue() == 25) {
            int v0 = a.a.get(0).intValue();
            a.a.remove(0);
            a.a.add(Integer.valueOf(v0));
            a.d = Integer.valueOf(0);
        }
    }
}

v4实例化之后,其包含的

变量a=数组{17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,17,23},

变量b="abcdefghijklmnopqrstuvwxyz";

变量c={8,25,17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13},

变量d=0。

其实a就是根据传入构造器的整数截取的数组c的一部分,这里传入的是2,则截取的是c[2-c.length]的部分。

然后再做一个循环,再加入c的[0-2]两个整型。

相当于是将c的头两个数字截断后放到尾巴上。

v5实例化过程:

变量a={21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16}

变量b="abcdefghijklmnopqrstuvwxyz";

变量c={7,14,16,21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8}

变量d=0。

至此,上述两个类的实例化分析清楚了。

------------------------------------------------------------分割线----------------------------------------------------------------------------------------------

0x03分析嵌套方法

接下来继续分析MainActivity.a()方法,发现指向一个新方法arg3.a(arg2.a(arg1)):

来分析这个嵌套:MainActivity.a(v2.charAt(v0) + "", v4, v5);

先看arg2.a(String arg1),这是对传入的flag的字符逐一处理的方法:

    public Integer a(String arg5) {
        int v0 = 0;                              //v0=0
        Integer v1 = Integer.valueOf(0);         //v1=0
        if(b.b.contains(arg5.toLowerCase())) {   //判断条件:arg5全部转为小写形式,数字不受影响,若类b的变量b包含该字符则进入花括号内的代码,其中,变量b是小写字母表
            //b.b="abcdefghijklmnopqrstuvwxyz";
            Integer v2 = Integer.valueOf(b.b.indexOf(arg5)); //v2=arg5所在的字母表的索引位置
            while(v0 < b.a.size() - 1) {     //遍历b.a,其中b.a是一个数组
            //在a中查找v2的位置
                if(b.a.get(v0) == v2) {
                    v1 = Integer.valueOf(v0);
                }

                ++v0;
            }
        }         //如果传入的字符串不是字母,而是数字或者其他字符
        else {
            if(arg5.contains(" ")) {  //如果传入的是空格,跳转到label_24
                v1 = Integer.valueOf(-10);
                goto label_24;
            }
            //传入的不是空格,返回-1

            v1 = Integer.valueOf(-1);
        }

    label_24:
        b.a();     //传入的是空格,执行一个同名无参的重载方法a()
        return v1;
    }

0x04总结一下b.a()方法的作用:

在b中有一个数表a={17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,17,23},a方法接收到传入的单个字符后,会对该字符检查是否是字母

1.是字母:读取该字符的字母序,根据这个字母序从数表a中返回对应下标的数字。比如传入的是"a",则字母序为0,返回a[0]中的值=17。

2.不是字母:

2.1是空格,执行一个重载方法a().返回 -10

2.2不是空格:返回-1

这里来看看label_24底下的这个重载方法a()做了些什么:

public static void a() {  
        int v0 = b.a.get(0).intValue();   //v0=数表a的第一位的值
        b.a.remove(0);   //a数组移除开头第一位,此行代码结束后a[1]取代a[0]的位置
        b.a.add(Integer.valueOf(v0));    //数表a添加v0到表尾
        b.b = b.b + "" + b.b.charAt(0);  //字符串b+=b的第一个字符
        b.b = b.b.substring(1, 27);      //b.b截取下标为1-27的子串
        b.d = Integer.valueOf(b.d.intValue() + 1);  //变量d自增1
    }

接下来看外层函数arg3.a(),该方法是a类中的a()方法,代码如下:

    public char a(Integer arg5) {
        char v0_1;                      //定义处理结果
        int v0 = 0;                     
        Integer v1 = Integer.valueOf(0); 
        if(arg5.intValue() == -10) {    //如果传入的值为-10,即char是空格,执行一个同名无参的重载方法a()
            a.a();
            v0_1 = " ".charAt(0);    //然后返回一个空格
        }
        else {             //传入的值不是空格
            while(v0 < a.a.size() - 1) {      //遍历数表a
                if(a.a.get(v0) == arg5) {   //若数表中有传入的数值,则v1=数表中该数值的下标
                    v1 = Integer.valueOf(v0);
                }

                ++v0;
            }

            a.a();    //执行重载方法a()
            v0_1 = a.b.charAt(v1.intValue());  //返回a类的成员变量b中v1下标的字符
        }

        return v0_1;
    }

该方法做了什么:

对传入的整型参数()就是上述分析的数表的值或者0或者-1做如下处理:

1.若传入的值为-10:执行无参的重载方法a();然后返回一个空格。

2.传入的值不是-10:遍历数组a,查找是否有该整型参数,如果有,则返回a类的成员变量b中该整型下标的对应字符,然后执行重载方法a().

2.1如果没有该整型参数,则返回变量b中的第一个字符。因为最开始v1=0。

现在来看看a类中这个重载方法a()做了些什么:

public static void a() {
        a.d = Integer.valueOf(a.d.intValue() + 1); //变量d自增1
        if(a.d.intValue() == 25) {                //若d自增1后等于25
            int v0 = a.a.get(0).intValue();       //数组a将头部第一个元素移动到数组尾部
            a.a.remove(0);
            a.a.add(Integer.valueOf(v0));
            a.d = Integer.valueOf(0);           //d重置为0
        }
    }

上述逻辑分析完毕。大概的描述就是根据传入的字符串,逐个进行查表变换然后拼接成一个新的字符串。

0x05走流程看看变量怎么变化

当然,上述分析都是扯淡,我们以输入flag{abcd}为例子,解析这串字符串是怎么变化的:

1.将花括号内的子串"abcd"提取出来,丢进去处理:

2.此时,v4,v5实例化完成。

3.四轮循环第一轮,取子串"abcd"的第一个字符‘a’:v4.a(a)

此时,v4中变量如下:

变量a=数组{17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,8,25},

变量b="abcdefghijklmnopqrstuvwxyz";

变量c={8,25,17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13},

变量d=0。

当v4.a('a')执行完,v4中变量如下:

变量a={23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,8,25,17}

变量b="bcdefghijklmnopqrstuvwxyza";

变量c={8,25,17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13}

变量d=0。

函数返回值为9

将执行结果作为输入,执行v5.a(9)

代码执行前,v5中变量如下:

变量a={21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16}

变量b="abcdefghijklmnopqrstuvwxyz";

变量c={7,14,16,21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8}

变量d=0。

代码执行完毕后,v5中变量如下:

变量a={21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16}

变量b="abcdefghijklmnopqrstuvwxyz";

变量c={7,14,16,21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8}

变量d=1。

返回值为'h'

一轮循环走完,输出了字符'h'

0x06处理子串"abcd"流程分析

对于输入字符 'a':

1.在字母表A"abcdefghijklmnopqrstuvwxyz"中查表,查找a所在的下标0

2.将下标0在数表a[17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,8,25]中查表,查找到0所在的下标9

3.查表完毕将数表a表头移动到表尾

4.字母表A表头第一个元素移动到表尾

5.将该下标9在数表b[21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16]中查表,查找到9所在的下标7

6.将该下标7在字母表B"abcdefghijklmnopqrstuvwxyz"中查表,查到第7位为'h'

7.返回'h'

如此循环4次。

为了便于理解,给出化简重命名版的字符变换代码:

public static String encrypt(String input) {
		int[] a = {17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,8,25};
		int[] b = {21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16};
		String alphbatA = "abcdefghijklmnopqrstuvwxyz";
		String alphbatB = "abcdefghijklmnopqrstuvwxyz";
		char[] chars = input.toCharArray();
		StringBuffer sb = new StringBuffer();
		for(int i=0;i<chars.length;i++) {
			int alphbat_index = alphbatA.indexOf(chars[i]);  //查字母表下标
			//查字母表下标所在位置的下标
			int anum = -1;
			for(int j=0;j<a.length;j++) {
				if(a[j]==alphbat_index) {
					anum = j;
					break;
				}			
			}
			if(anum==-1) return "error1";
			//数表a表头移动到表尾
			int mid = a[0];
			for(int j=1;j<a.length;j++) a[j-1] = a[j];
			a[a.length-1] = mid;
			//字母表A表头移动到表尾
			alphbatA+=alphbatA.charAt(0);
			alphbatA = alphbatA.substring(1,27);
			//anum在数表b中查表
			int b_index = -1;
			for(int j=0;j<b.length;j++) {
				if(b[j]==anum) {
					b_index = j;
					break;
				}
			}
			if(b_index==-1) return "error2";
			//将下标b_index在字母表B中查表
			sb.append(alphbatB.charAt(b_index));
		}
		return sb.toString();
	}

执行这段方法可以看到输出:

根据上述流程就可以得出逆推回去的Java代码:

public static String decrypt(String input) {
		if(input.length()>25) return "此代码不考虑字符长度大于25的情况";
		int[] a = {17,23,7,22,1,16,6,9,21,0,15,5,10,18,2,24,4,11,3,14,19,12,20,13,8,25};
		int[] b = {21,4,24,25,20,5,15,9,17,6,13,3,18,12,10,19,0,22,2,11,23,1,8,7,14,16};
		String alphbatA = "abcdefghijklmnopqrstuvwxyz";
		String alphbatB = "abcdefghijklmnopqrstuvwxyz";
		StringBuffer sb = new StringBuffer();
		//将数表A\字母表A移动至处理结束前的状态
		for(int i=0;i<input.length();i++) {
			int[] mid = new int[a.length];
			for(int j=0;j<mid.length-1;j++) mid[j] = a[j+1];
			mid[mid.length-1] = a[0];
			a = mid;
			alphbatA+=alphbatA.charAt(0);
			alphbatA = alphbatA.substring(1,27);
		}
		//开始逆推数表A\字母表A
		String nx = new StringBuffer(input).reverse().toString();
		char[] nxchar = nx.toCharArray();
		for(int i=0;i<nxchar.length;i++) {
			//查找字母表B下标7
			int nxc_index = alphbatB.indexOf(nxchar[i]);
			//根据nxc_index查找该下标所在的值9
			int num_B = b[nxc_index]; //num_B = 9
			//移动数表A\字母表A表尾到表头
			int mid = a[a.length-1];
			for(int j=a.length-1;j>0;j--) a[j] = a[j-1];
			a[0] = mid;
			char last = alphbatA.charAt(alphbatA.length()-1);
			String mids = alphbatA.substring(0,25);
			alphbatA = last+mids;
			//根据num_B查数表a
			int num_A = a[num_B];
			sb.append(alphbatA.charAt(num_A));
		}
		return sb.reverse().toString();
	}

执行这段代码就可以得到flag{}内部的内容:

这段字符串加上flag{}就是flag了。

 

 

 

-----end------------

-----------菜得真实,这种纯Java的代码一般静下心来慢慢分析,一步步还原就好------------

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值