题目

CSDN免积分下载

查壳

先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK

Java Decompiler - MainActivity-onCreate

image.png

答案

flag{90705bb55efb59da7fc2a5636549812a}

Writeup

解题

运行

image.png

解题思路

SO

SO文件是Linux下共享库文件,它的文件格式被称为ELF文件格式。由于Android操作系统的底层基于Linux系统,所以SO文件可以运行在Android平台上。
Android系统也同样开放了C/C++接口供开发者开发Native程序。由于基于虚拟机的编程语言JAVA更容易被人反编译,因此越来越多的应用将其中的核心代码以C/C++为编程语言,并且以SO文件的形式供上层JAVA代码调用,以保证安全性。
SO文件格式即ELF文件格式,它是Linux下可执行文件,共享库文件和目标文件的统一格式。根据看待ELF文件的不同方式,ELF文件可以分为链接视图和装载视图。链接视图是链接器从链接的角度看待静态的ELF文件。从链接视图看ELF文件,ELF文件由多个section组成,不同的section拥有不同的名称,权限。而装载视图是操作系统从加载ELF文件到内存的角度看待动态的ELF文件。从装载视图看ELF文件,ELF文件由多个segment,每一个segment都拥有不同的权限,名称。实际上如上图所示,一个segment是对多个具有相同权限的section的集合。

搜索字符串

使用反编译工具的字符串搜索功能,中文字符串注意要转为UniCode格式,即“\u9a8c\u8bc1\u5931\u8d25”:
image.png
在Java Decompiler中,找到成功的逻辑:
image.png

MainActivity

搜不出来或者没有思路时,应该先看Android程序的入口——也就是MainActivity函数。

代码逻辑

MainActivity

主要代码为一个if判断,条件中调用了“cyberpeace.CheckString”处理输入的数据::

  1. if (cyberpeace.CheckString(((EditText)MainActivity.this.findViewById(2131165233)).getText().toString()) == 1)

cyberpeace.CheckString

点击“MainActivity”中的“cyberpeace”或“CheckString”,跳转到代码:

package com.testjava.jack.pingan2;

public class cyberpeace
{
    static
    {
        System.loadLibrary("cyberpeace");
    }

    public static native int CheckString(String paramString);
}

System.loadLibrary动态加载库文件

System.loadLibrary(String libname)则只会从指定lib目录下查找,并加上lib前缀和.so后缀

System.loadLibrary("cyberpeace");
……省略……
public static native int CheckString(String paramString);

传进来的“cyberpeace”,处理后返回的是libcyberpeace.so:
image.png

IDA+.so库文件

SO文件查壳

查壳发现是无壳的64位ELF文件:
image.png
将.so库文件拖入64位IDA中反编译,查看CheckString函数:
image.png
代码逻辑为将传入的字符串,先前后互换,再将互换后的字符串两两按个对换:
image.png

⚠⚠⚠危险危险危险⚠⚠⚠

在打草稿的时候,我设置原字符串为1234,前后一半对换后为:3412,再按个前后对换为:4321,我这时得出的结论是字符串逆序(Python用reverse),结果一直不对。
再设置原字符串为01234567,前后一半对换后为:45670123,再按个前后对换为:54761032——很明显并不是逆序😥
我还是强行计算了一下规律:

下标从0开始 下标<一半(half = len(str)/2 = 4) 下标=>一半(half = len(str)/2 = 4)
偶数下标 原下标+half+1 [0] = 0+4+1 = 5 原下标-half+1 [4] = 4-4+1 = 1
奇数下标 原下标+half-1 [1] = 1+4-1 = 4 原下标-half-1 [5] = 5-4-1 = 0
#字符串处理
def ArraySwap(str2Change):
    time = 0
    half = int(len(str2Change)/2)
    arrBefore = list(str2Change)
    arrAfter = list(str2Change)

    # 0 < 下标 < 一半
    while time < half :
        arrAfter[time] = arrBefore[time + half + 1]
        arrAfter[time + 1] = arrBefore[time + half]
        # ⚠步长为2⚠
        time += 2
    else:
        # 一半 < 下标 < 总长
        while half <= time < len(str2Change) :
            arrAfter[time] = arrBefore[time - half + 1]
            arrAfter[time + 1] = arrBefore[time - half]
            time += 2
    return "".join(arrAfter)

str2Change = "f72c5a36569418a20907b55be5bf95ad"
strChanged = ArraySwap(str2Change)

print("flag{" + strChanged + "}")

结果,危险再次出现!😡😡😡
如果字符串设置为len(str) = 10,也就是half = 5,此时上述代码会出现超出范围的报错。因为字长不是4的整数倍,也就是half是奇数,步长为2会造成溢出的问题:
image.png
还是建议老老实实按照代码还原,安全一点😵

解法

【👩‍💻练Python推荐⌨】Python脚本

Python - 切片

Python - decode()方法

#字符串处理
def ArraySwap(str2Swap):
    time = 0
    half = int(len(str2Swap)/2)

    #1.1 前后两半互换
    str2Swap = str2Swap[half:] + str2Swap[:half]
    arr = list(str2Swap)

    #1.2 前后两个互换
    while ( time < len(str2Swap) ):
        arr[time],arr[time+1] = arr[time+1],arr[time]
        time += 2
    return "".join(arr)

strChange = "f72c5a36569418a20907b55be5bf95ad"
strChanged = ArraySwap(strChange)
print("填到APP中:" + strChanged)
print("填到XCTF答题框中:\r\nflag{" + strChanged + "}")

💯You are right!💯

image.png