攻防世界easyJava(re Moble)

easyJava

题目考察:jeb反编译工具的使用,逆向能力,本题是基于enigma密码机的一个加密,可以参考博客https://blog.csdn.net/kyoma/article/details/51857944,大致题目使用的加密就是这个原理。

题目分析


    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);
                }
            }
        });
    }

首先,拿到题目一个apk文件,拖入jeb反编译,得到的MainActivity的大致代码如下。第一步肯定是要看到最下面的onCreate()方法,观察题目大概是要我们干什么。

可以发现,他是将我们输入的东西,传入到a()方法中,然后若返回结果是true,那么,就会输出“you are right!”。很显然我们需要令他成立。

可以看到a()方法其实并没有什么,就是调用了一下b()方法,将我们输入的传了过去。

b()方法是这个MainActivity中主要的一段代码。他有三个判断,第一个判断开头是否为“flag{”,第二个判断是否以"}"结尾。第三个比较关键,他初始化了a类和b类型为v4 v5,同时分别传入构造函数2和3.然后把我们输入的字符串的每个字符和v4,v5传入带有三个形参的a()方法中。就是去执行a.a(b.a(“字符”)),返回结果是一个字符类型的值,将每个我们输入的值执行后返回,拼接起来和”wigwrkaugala“比较,若相等就是正确的了。


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);
        }
    }
}

首先对于这个a类,我们在初始化的时候传入了3,可以看到在a的构造函数中,他实现的就是相当于enigma密码机转动了三格,然后在调用a方法的时候,最终返回的值v0_1就是"abcdefghijklmnopqrstuvwxyz"的第v0个,v0就是传入的Integer类型的值在ArrayList[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]中的索引值
同时可以发现在他给v0_1赋值前,调用了void a()方法,可以发现这个方法本身是实现对ArrayList的转动,但是由于可以发现他有一个判断条件,要令成员变量d为25的时候才执行,因为d初始赋值是0,而我们也不会调用25次,所以是不会触发到这里面的。

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;
    }
}

b类的话其实和a类是很相似的,在构造函数的初始化适合a类的初始化是一样的,不过我们一开始传的值是2,所以就是相当于转动了二格。

然后看到b类中关键的a方法的代码,可以知道传入的是我们输入的字符串的单个字符,返回的是一个Integer类型的值,在MainActivity中作为a类的a方法的传入值。

可以知道我们的返回v1是等于v0,v0是v2在ArrayList[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]中的索引
而v2就是我们输入字符在"abcdefghijklmnopqrstuvwxyz"中的索引

然后在给v1赋值后我们可以发现,他调用了b类的void a()方法,void a()方法是实现了对ArrayList的一次转动,以及对字符串"abcdefghijklmnopqrstuvwxyz"的一次转动

到这边就分析完了,只需要写出逆向的脚本就可以得到正确的输入了。

python脚本

from collections import deque#双端队列
alpha = deque("abcdefghijklmnopqrstuvwxyz") 
t1 = deque([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]) 
t2 = deque([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])

ss = 'wigwrkaugala'
for _ in range(2): 
    t1.append(t1.popleft()) #实现转动
for _ in range(3): 
    t2.append(t2.popleft()) 
print(t1) 
print(t2)

def dec(s): 
    i = t2[(ord(s) - ord('a'))] #ord(s) - ord('a')就可以得到在那个a到z的字符中的索引值
    i = t1[(i)] 
    print(alpha[i], end='')
    t1.append(t1.popleft()) 
    alpha.append(alpha.popleft())
for s in ss: dec(s)

    

你可能感兴趣的:(MOBLE)