通过JADX打开酷安Coolapk.apk,发现无加固特征,能直接搜索到目标参数的键值对
用apktool反编译后用IDA静态打开libnative.so文件
搜索getAS方法发现没有解决,很有可能是开发者在JNI_OnLoad中做了处理
在JNI_OnLoad用y键还原一些寄存器后如图
因为原函数名是getAS,基本上在这里可以确认被改了名字,这里可以先不追下去,先盲猜一下,在左栏函数名那里进行搜索getA,可以看到getAuthString十分可疑,getAS就像是它的简写,这里对getAuthString进行分析
因为getAS是有返回值的,所以可以先从return入手
C语言中的NewStringUTF()
// 所以可以理解成JNI的v55赋值给result
result = ((*v4)->NewStringUTF)(v4, v55)
所以开始找v55的生成方式,发现v55的值可能是v85或者v83
这里要开始找v84和v82的初始值来获得一些线索,可以发现v84是0空值,result也就是token不可能是个空值,所以result正常情况下一定走的v82,于是要去看v82的生成方式
先去找v82初始化也就是被定义的地方(可以从下图的地方开始)
v82被遍历和赋值0
v43的追溯
v85的追溯
v61的追溯(md5那里需要点进嵌套才能显示完全…是个大坑!!)
v58的追溯
v51的追溯
v49的追溯(通过Frida的Hook)
但是没有被export的函数没办法被hook到,所以这里可以分两种情况分析,一种是需要hook的函数在export里,另一种情况则是需要hook的函数不在export里。
首先分析要hook的函数不在export里的情况
- 方法一我们用IDA动态调试,通过so文件的基地址+函数的偏移量来获得函数在内存中的绝对地址来hook
- 函数的偏移量如何获得 (可以直接在左栏搜索得到 or 可以通过点进函数可以看到)
- so文件的基地址怎么得到(用IDA动态调试)
- 方法二通过so文件内任意一个能hook得到的函数的绝对地址-该函数的偏移量=这个so文件的基地址。然后拿这个基地址+要hook函数的偏移量从而得到函数在内存的绝对地址
下面我们通过getAuthString来操作方法二。(这个函数是能被java调用的,所以他一定是在export里面,能被hook到)
# -*- coding:utf-8 -*-
# coding=utf-8
import frida
import sys
package = "com.coolapk.market"
# package = "com.iCitySuzhou.suzhou001"
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
device = frida.get_remote_device()
print(device,'device++')
# pid = device.spawn(package)
session = device.attach(package)
print(session,'session++')
src = """
// getAuthString的内存地址
var getAuthString_address = Module.getExportByName('libnative-lib.so','getAuthString');
// getAuthString的内存地址 - getAuthString的偏移量 = so文件的内存基地址
var ji_address = parseInt(getAuthString_address) - parseInt('0x66500');
send('ji_address:'+ptr(ji_address));
// b64_encode的内存地址 = so文件的基地址 + b64_encode的偏移量
var b64_encode_address = ptr((ji_address+parseInt('0x31DB8')).toString())
send('b64_encode_address:'+b64_encode_address)
Interceptor.attach(b64_encode_address,
{
onEnter: function (args) {
send("b64_encode_arg[0]"+Memory.readUtf8String(args[0]));
}
})
"""
script = session.create_script(src)
script.on("message", on_message)
script.load()
# device.resume(session)
sys.stdin.read()
hook的函数在export里的情况
# -*- coding:utf-8 -*-
# coding=utf-8
import frida
import sys
package = "com.coolapk.market"
# package = "com.iCitySuzhou.suzhou001"
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
device = frida.get_remote_device()
print(device,'device++')
# pid = device.spawn(package)
session = device.attach(package)
print(session,'session++')
src = """
var b64_encode_address = Module.getExportByName('libnative-lib.so','_Z10b64_encodePKhj');
send('b64_encode_address:'+b64_encode_address)
Interceptor.attach(b64_encode_address,
{
onEnter: function (args) {
send("b64_encode_arg[0]"+Memory.readUtf8String(args[0]));
}
})
"""
script = session.create_script(src)
script.on("message", on_message)
script.load()
# device.resume(session)
sys.stdin.read()
下面再继续追溯v49的组成,所以v49的组成和v62相关
v62的追溯
v45的追溯
但是这里会遇到一点问题,赋值给v45的都是空值,所以可能是反编译出来的代码出现了错误。我们通过frida来hook这个append函数来分析分析
# -*- coding:utf-8 -*-
# coding=utf-8
import frida
import sys
package = "com.coolapk.market"
# package = "com.iCitySuzhou.suzhou001"
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
device = frida.get_remote_device()
print(device,'device++')
# pid = device.spawn(package)
session = device.attach(package)
print(session,'session++')
src = """
// append的内存地址
var append_address = Module.getExportByName('libnative-lib.so','_ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcj')
send('append_address:'+append_address)
send("-------------------------------------");
Interceptor.attach(append_address,
{ onEnter: function (args) {
send("append_address_arg[0]:"+args[0]);
send("append_address_arg[1]:"+Memory.readUtf8String(args[1]));
send("append_address_arg[2]:"+args[2]);
send("append_address_arg[3]:"+args[3]);
},
onLeave: function (retval) {
send("result:"+retval);
}
}),
"""
script = session.create_script(src)
script.on("message", on_message)
script.load()
# device.resume(session)
sys.stdin.read()
输出结果分析
然后可以看到继续往上看可以看到一个MD5加密方法,那么等下我们同时hook住MD5加密的输出结果和传进append方法的MD5加密字符串,如果匹配,那么上面这个MD5加密方法加密后会将结果传入这个append中
未完待续…
C语言中的->