1625-5 王子昂 总结《2017年12月26日》 【连续第452天总结】
A. JarvisOJ-APK_500
B.
跟之前的APK300-DebugMe如出一辙
一大堆反调试,字符串都进行了加密,通过异或动态解密来操作
DebugMe主要的坑点在于IDA把函数的返回值识别错误了,ARM并没看懂,其他还好
这个500的坑点就比较多了..
首先用Apktool和改之理都报AndroidManifest.xml解码失败,于是整个文件都反编译不出来
拖入安卓系统安装是正常的,因此可以直接解压缩出classes.dex,用dex2jar得到jar文件,然后用jd-gui之类的工具看到java
不过为了学习,还是研究了一波
直接解压出来的xml是二进制数据,不能直接查看
但是可以通过010Editor的模板来识别
首先可以发现MagicNumber错误,修改为00030800即可
解包发现还是错误,继续对比正常的xml分析
在这里https://justanapplication.wordpress.com/category/android/android-binary-xml/
有对二进制AndroidManifest.xml的格式解析
可以看到0x20处的StylePoolOffset应该为0,此处为一个巨大的值,试着将其修改
解包就正常了
(修改完了通过压缩软件添加入apk即可)
然而动态调试还是不行,估计是反调试在作祟
直接附加会显示权限不够,通过adb start时Waitting for the debugger不会消失,于是就一直卡着无法进展
继续静态分析
lib中只有libeasy.so一个库,java代码中显示核心方法为native函数:helloword
查看函数列表,没有发现相关的内容
找了一圈,最后在JNI Onload函数中发现了东西
这个熟悉的解密字符串函数没有变,还是它们
下面第二个字符串是函数类型的声明,继续往下看
调用了JNI的RegisterNatives这个方法就很明显了,在动态注册native函数
那么函数名、函数类型都有了,函数体在哪儿?
肯定就是上面那个sub_1198咯
点进去看,果然是
抛开前面的反调试不管,这里进行了一次bytes转码,连接到一个变量中
继续往下读,发现一共有4次变换
- 第一次
input[i] ^= i - 第二次
input[i] += 1, i<4 - 第三次
前7个字符移到最后,其余字符顺序向前移动 - 第四次
异或硬编码数组
最后转16进制与一个结果字符串比较
结果字符串解出来是
ddedd4ea2e7bef168491a6cae2bc660
脚本调用bytes.fromhex的时候发现它长度不对,只有31位
转十六进制的时候是sprintf(buff, “%x”, input),注意格式化不是%02x
因此有一个0被消掉了,需要爆破
写出脚本进行逆解,还是不对
偶然看硬编码数组的时候发现有一个坑
这里进行了标识,说明有地方调用了它
查看交叉引用,发现果然有重写
写了两次,观察发现第二次和原值相同,那说明真正正确的应该是前一个值
修改硬编码脚本后即可得到flag
s = "ddedd4ea2e7bef168491a6cae2bc660"
n = []
for i in range(32):
p = s[:i] + "0" + s[i:]
n.append(bytes.fromhex(p))
b = [133, 139, 236, 131, 236, 20, 131, 141, 12, 1, 117, 95, 198, 69, 243, 80]
b[3] = 0x83
b[4] = 0x6c
b[5] = 0x9c
b[6] = 0x83
for a in n:
flag = []
flag1 = ""
for i in range(16):
p = a[i]^b[i]
flag.append(bytes((p, )))
flag = flag[-7:] + flag[:-7]
for i in range(4):
flag[i] = bytes((flag[i][0] - 1, ))
for i in range(16):
p = flag[i][0] ^ i
if(p<=32 or p>=127):
break
flag1 += chr(p)
else:
print(flag1)
得到两个全为可见字符串的flag,很明显发现其中一个为有意义的词组,提交完成
C. 明日计划
JarvisOJ Shell