题目
查壳
先查壳(PKiD等),有壳脱壳,没壳用AndroidKiller等反编译工具打开查看JAVA代码
无壳APK
Java Decompiler - MainActivity-onCreate
答案
flag{90705bb55efb59da7fc2a5636549812a}
Writeup
解题
运行
解题思路
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”:
在Java Decompiler中,找到成功的逻辑:
MainActivity
搜不出来或者没有思路时,应该先看Android程序的入口——也就是MainActivity函数。
代码逻辑
MainActivity
主要代码为一个if判断,条件中调用了“cyberpeace.CheckString”处理输入的数据::
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:
IDA+.so库文件
SO文件查壳
查壳发现是无壳的64位ELF文件:
将.so库文件拖入64位IDA中反编译,查看CheckString函数:
代码逻辑为将传入的字符串,先前后互换,再将互换后的字符串两两按个对换:
⚠⚠⚠危险危险危险⚠⚠⚠
在打草稿的时候,我设置原字符串为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会造成溢出的问题:
还是建议老老实实按照代码还原,安全一点😵
解法
【👩💻练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 + "}")