攻防世界-easyjava-Writeup

easyjava

[collapse title=“展开查看详情” status=“false”]

考点:手撕算法

部分函数名已重命名,懒得再找一份原题QAQ

开门见山,mainactivity 就能找到加密算法入口。函数将输入值剔除flag{} ,然后传入加密函数。

private static Boolean b(String string) {  // 结尾}
    Boolean result;
    int index = 0;
    if(!string.startsWith("flag{")) {  // 开头flag{
        result = Boolean.valueOf(false);
    }
    else if(!string.endsWith("}")) {
        result = Boolean.valueOf(false);
    }
    else {
        String string_1 = string.substring(5, string.length() - 1);  // 分割字符串去除flag{}
        Mb v4 = new Mb(Integer.valueOf(2));
        Ma v5 = new Ma(Integer.valueOf(3));
        StringBuilder c_string = new StringBuilder();
        int v1 = 0;
        while(index < string_1.length()) {
            c_string.append(MainActivity.a(string_1.charAt(index) + "", v4, v5));	//加密函数
            Integer v6 = Integer.valueOf(v4.b().intValue() / 25);
            if(v6.intValue() > v1 && v6.intValue() >= 1) {
                ++v1;
            }

            ++index;
        }

        result = Boolean.valueOf(c_string.toString().equals("wigwrkaugala"));
    }

    return result;
}

加密函数有两层最后调用为:

private static char a(String string, Mb b, Ma a) {
    return a.a(b.a(string));
}

a b 加密逻辑大致一样,处理对象都是单字符,进行混淆后,对密钥进行更新。

b 加密函数主要如下:(忽略处理空格和字符不存在情况)

Mb.key_list = "abcdefghijklmnopqrstuvwxyz";
public Integer a(String string) {
    int v0 = 0;
    Integer v1 = Integer.valueOf(0);
    if(Mb.key_list.contains(string.toLowerCase())) {  // 转为小写,然后查询在不在key中
        Integer index = Integer.valueOf(Mb.key_list.indexOf(string));
        while(v0 < Mb.a_ArrayList.size() - 1) {
            if(Mb.a_ArrayList.get(v0) == index) {
                v1 = Integer.valueOf(v0);
            }

            ++v0;
        }
    }
…………
	Mb.a();
	return v1;
}

加密操作为:检索字符在keylisit的下标,记为index,然后检索indexa_ArrayList的下标,记为v1,检索成功就调用Mb.a()生成新的密钥keylista_ArrayList,然后返回v1

a_ArrayList不是一个静态变量,是经由public Mb(Integer arg9)生成的,一开始以为动态生成的,然后动态调试了一下,发现是第一次调用时生成好了,后续字符加密沿用上一字符密钥。生成的偏移为 2 。

攻防世界-easyjava-Writeup_第1张图片

攻防世界-easyjava-Writeup_第2张图片

Mb.a()处理逻辑就是:每一轮加密完成后,将两个密钥的首元素放置到最后一位。

public static void a() {
    int v0 = Mb.a_ArrayList.get(0).intValue();
    Mb.a_ArrayList.remove(0);
    Mb.a_ArrayList.add(Integer.valueOf(v0));  // 将列表首个元素放到最后
    Mb.key_list = Mb.key_list + "" + Mb.key_list.charAt(0);
    Mb.key_list = Mb.key_list.substring(1, 27);  // 将列表首个元素放到最后
    Mb.d = Integer.valueOf(Mb.d.intValue() + 1);  // 某个计算位加1
}

a.a(b.a(string)) b 函数加密完成后,返回值作为参数传入 a ,加密方式与 b 相近,较大不同点是每轮加密不会随机化密钥,密钥初始偏移为 3 。因为从最后判断函数可知 flag 中间字符为 12 位,不足以触发 a 随机化密钥函数要求。

解密EXP

from collections import deque # 双端队列简化随机密钥实现
alpha = deque("abcdefghijklmnopqrstuvwxyz") 
#key_b = 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]) 
#key_a = 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])
key_b = deque([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])
key_a = deque([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])
c = 'wigwrkaugala'

def decode(s): 
    i = key_a[(ord(s) - ord('a'))]
    i = key_b[(i)] 
    print(alpha[i], end='')
    key_b.append(key_b.popleft()) 
    alpha.append(alpha.popleft())

print("flag{",end='')
for s in c: decode(s)
print("}")

提交 flag 后看评论区好像题目有多解。

[/collapse]

你可能感兴趣的:(攻防世界-easyjava-Writeup)