攻防世界-moblie(新手篇1)
0x00 easyjni
JNI(Java Native Interface)即java本地接口,众所周知,android有四层结构,应用层与应用接口层是用Java写的,而C/C++核心库和linux内核层由C/C++写的,既然知道了这一点,那理解JNI就很简单了,Java和C/C++肯定是不能直接互相调用的,那么应用层肯定就不能直接调用底层的东西,比如从应用层直接用Java想调用底层C/C++开发的启动相机或NFC等肯定是不能直接实现的。
安装apk,是一个验证flag的程序。
使用jeb查看反编译代码,在主函数找到check的判断语句。初始化一个a类locala,并把输入进去的String类型的字符串穿换成Byte[]类型组传入a类locala的a方法。
程序开头加载了库,与传入的字符串进行ncheck,最后返回一个布尔型的值。
猜测调用的a类是base64变码表,循环长度为3,数组长度为4,最后补“=”。
将so文件导入ida,搜索ncheck定位到关键函数
分析第一个循环,是将前16位与后16位交换位置。
for ( i = 0; i != 16; ++i )
{
v7 = &v12[i];
v12[i] = v5[i + 16];
v8 = v5[i];
v7[16] = v8;
}
分析第二个循环,是将字符两两交换位置。
do
{
v10 = v9 < 30;
v13 = v12[v9];
v12[v9] = v12[v9 + 1];
v12[v9 + 1] = v13;
v9 += 2;
}
while ( v10 );
编写脚本如下:
|
|
maketrans和translate方法简介:
Python maketrans() 方法用于创建字符映射的转换表,translate() 方法根据参数table给出的表(包含 256 个字符)转换字符串的字符。
实例如下:
intab = "aeiou"
outtab = "12345"
trantab = str.maketrans(intab, outtab) # 制作翻译表
str = "this is string example....wow!!!"
print (str.translate(trantab))
结果:th3s 3s str3ng 2x1mpl2....w4w!!!
0x01 easy-apk
简单看下功能,也是一个验证flag的功能。
上jeb,在主函数看到它的判断逻辑。
阅读后发现Base64New类是base64变码表
编写脚本如下:
import base64
c = "5rFf7E2K6rqN7Hpiyush7E6S5fJg6rsi5NBf6NGT5rs="
changed = "vwxrstuopq34567ABCDEFGHIJyz012PQRSTKLMNOZabcdUVWXYefghijklmn89+/"
origin = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s = str.maketrans(changed, origin)
s_EnBase64 = c.translate(s)
flag = base64.b64decode(s_EnBase64)
print(flag)
得到flag
0x02 app1
按照惯例查看功能
jeb分析,在主函数发现验证的逻辑,可以发现flag的值其实就是v3的每个字符和v4异或拼凑的结果。
找到v3、v4的值,编写脚本。
v3 = "X<cP[?PHNB<P?aj"
v4 = 15
flag = ""
for i in v3:
x = ord(i)^v4
flag += chr(x)
print(flag)
得到flag
0x03 app2
这次是个登录界面。
jeb分析SecondActivity代码,ili是用户名,lil是密码,他们加密后等于需要等于VEIzd/V2UPYNdn/bxH3Xig==
加密的函数来自so文件
将so文件导入ida,搜索doRawData定位到关键函数 ,发现一个key值和AES_128_ECB_PKCS5Padding_Encrypt的字样,应该是AES加密。
文本解密后发现不正确,在XML里面发现FileDataActivity从来没有用过
点击发现有一段字符串,且使用了Encrypto的解密函数。
编写python脚本
import base64
from Crypto.Cipher import AES
c = base64.b64decode("9YuQ2dk8CSaCe7DTAmaqAA==")
key = b'thisisatestkey=='
aes = AES.new(key,AES.MODE_ECB)
flag = aes.decrypt(c)
print(flag)
0x04 app3
ab文件没见过,搜索发现https://blog.csdn.net/qq_33356474/article/details/92188491,使用abe.jar unpack app3.ab app3.tar
得到文件夹,发现apk文件和Encryto.db。
jeb分析代码,在MainActivity中能看到一些信息,怀疑flag加密在数据库文件之中,最后调用了a函数。
分析发现需要把v1.a(v2 + v1.b(v2, v0.getAsString("password"))).substring(0, 7)
的值给捋清楚。
结合下面图中的代码,分析v2
的值是Stra1234,v0.getAsString("password")
的值是123456,然后剩下的看代码是MD5和SHA-1的加密这里直接用它的代码,把v2,v0等值赋过去就好。
参考https://www.52pojie.cn/thread-1082706-1-1.html代码如下:
|
|
编译运行得到ae56f99
解密文件,得到flag的base64值。
0x05 easy-so
放到模拟器,字符串验证。
上jeb,找到关键代码,开始分析。
CheckString在so文件里面,上ida分析。
简单分析代码
第一部分代码逻辑如下:
v3 = strlen(v11);//v3是v11的字符串长度
v4 = (char *)malloc(v3 + 1);//为v4请求v3+1长度的内存空间
memset(&v4[v3], 0, v3 != -1);//将v4扩增一倍并后面扩增的部分初始化为0,v4=----0000
memcpy(v4, v11, v3);//将v11的内容复制到v4中
if ( strlen(v4) >= 2 )//若v4的长度大于等于2
{
v5 = 0;
do
{
v6 = v4[v5];
v4[v5] = v4[v5 + 16];
v4[v5++ + 16] = v6;
}
while ( v5 < strlen(v4) >> 1 );//在v5小于v4长度的一半时,将v4的第v5个字符与第v5+16个字符交换位置
}
void *memset(void *str, int c, size_t n) 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
str -- 指向要填充的内存块。
c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
n -- 要被设置为该值的字符数。
void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字节到存储区 str1。
str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
n -- 要被复制的字节数。
第二段代码逻辑如下:
v7 = *v4;//指针v7指向v4
if ( *v4 )//如果v4存在
{
*v4 = v4[1];
v4[1] = v7;
if ( strlen(v4) >= 3 )//v4的长度大于等于3
{
v8 = 2;
do
{
v9 = v4[v8];
v4[v8] = v4[v8 + 1];
v4[v8 + 1] = v9;
v8 += 2;
}
while ( v8 < strlen(v4) );//两两交换
}
}
最后的结果为f72c5a36569418a20907b55be5bf95ad,那么我们可以编程逆退回去。
c = "f72c5a36569418a20907b55be5bf95ad"
tmp = ""
#两两交换
for i in range(len(c)//2):
tmp += c[i*2+1] + c[i*2]
#前后交换
flag = tmp[16:] + tmp[:16]
print(flag)