SCTF simple Write Up Reverse

分析:

直接先用JEB对这个APK进行逆向,通过解密后的AndroidManifest.xml文件发现入口是MainActivity,但是并没有这个文件,考虑到可能被加密,阅读已有的代码中,发现程序运行后会对test.zip进行解密,解压这个APK,找到这个文件,无法对这个文件直接解压,于是push到虚拟机,运行,在data文件夹下面可以把load.dex文件pull下来,然后重新使用JEB对pull下来的文件进行反编译,拿到了MainActivity(这里我先用了dex2jar再用jd-gui拿了Java级源码,发现结果是一坨翔。。。)。

通过阅读代码可以知道,要输入24个ASCII字符,然后每八个作为一组来生成square,每个字符生成一个square,并且每组内的字符要求前面的小于后边的。square是一个5*5的网格,包含25个点。square生成的时候有如下规则:

v0[v2] = new Square((v1[v5 + v2] << 8) + v12 + 255, v5 / 2 + 4);

其中,v12=828309504,一定要转换为16进制。。v12+255=0X315F00FF,注意低位第二个字节为零,注意到v1将会左移八位,实质上是将ASCII码填充到这个第二个字节中,第二个参数是循环的次数,可以取4,8,12。

注意到最后的检测是要每个square的check均为true才可以,通过分析check函数可以知道这里是要求它的主副对角线均为1。

另外还要注意一点,square在生成的时候如果check为true,会调用turnpoint,也就是说要求square在turnpoint前后的check均为true。turnpoint是将每个点的坐标x-1,如果在边界上则y-1。

下面给出代码:

c = [0 for i in range(25)]
move = [4, 8, 12]
a = []

def fill_one(v):
    for i in range(5):
        v[i * 5 + i] = 1
        v[(i + 1) * 4] = 1
    for i in range(5):
        print(v[i * 5 : i * 5 + 5])
    print()
    
def getr(v):
    return v[8:16][::-1]

fill_one(c)
for x in move:
    a.append(c[-x:] + c[:-x])
for l in a:
    fill_one(l)
    ans = getr(l)
    print(ans)
    print()

首先生成一个主副对角线均为1的square,然后经过三种不同循环次数的turnpoint,拿到square,之后将变换后的square的主副对角线填充为1,再在ans中取出低位第二个字节。

下面枚举符合条件的字符:

b=[0b00010101, 0b01010001, 0b00011001]
print("SCTF{", end="")
for t in b:
    k = 48
    for i in range(8):
        while((k & t) < t):
            k += 1
        print(chr(k), end="")
        k += 1
print("}")
其中b列表是通过前边那段程序拿到的,这样可以获取flag。
实际上我太弱鸡了。。这道题看了夜影大佬的WP。。

猜你喜欢

转载自blog.csdn.net/wannafly1995/article/details/80840066