常用Frida的API
function_address = Module.findExportByName(libname, function);
Interceptor.attach(address, func);
Interceptor.attach(address,
onEnter: function (args) {
},
onLeave: function (retval) {
}
)
File 模块 写文件流程
new File(filepath, mode)
write(data)
flush()
close()
file = new File("yuanrenxue.dex", "wb")
//data 是字符串或者 arrayBuffer // readByteArray() 返回的arrayBuffer
file.write(data)
file.flush()
file.close()
//把内存里的值转成字符串
Memory.readUtf8String()
//把内存里的值转换成整型
Memory.readInt()
//以begin为起始位置,从内存中读length长度的数据出来 返回ArrayBuffer类型
Memory.readByteArray(begin, length)
//把地址转换成NativePointer类型 frida里操作内存地址需要先转成NativePointer类型!!!
ptr()
JS api
#把其它进制转换成10进制
parseInt(num, radix)
复习dex文件格式
https://www.jianshu.com/p/f7f0a712ddfe
复习脱壳原理:
复习:加固壳是如何运行起来的?
1. -->APP启动
2. -->壳dex先加载起来
3. -->壳负责把源dex文件读出来
4. -->壳把源dex文件解密
5. -->把解密后的dex加载进内存 源dex运行起来
源dex文件最终会加载进内存
Hook加载Dex的函数(OpenMemory),把Dex从内存中dump出来
Hook DexFile::OpenMemory()
DexFile::OpenMemory(const uint8_t* base,size_t size,const std::string& location,
uint32_t location_checksum,MemMap* mem_map,//nullptrconst OatDexFile* oat_dex_file,
std::string* error_msg)
Frida代码脱壳
从手机端获取要hook的函数的so文件
用IDA打开得到OpenMemory的导出名
利用Frida的API进行导出(进行app重启非常重要device.resume(pid))
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
package = 'com.iCitySuzhou.suzhou001'
jscode = """
var openMemory_address = Module.findExportByName("libart.so","_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_")
Interceptor.attach(openMemory_address,{
onEnter:function(args){
console.log("start")
// dex文件的起始位置
var dex_begin_address = args[1]
// dex文件的前8个字节是magic字段,打印magic会显示"dex 035"这三个字符,可以验证是否为dex文件
console.log("magic:"+Memory.readUtf8String(dex_begin_address))
// 把地址转换成整形,再加32,因为dex文件的第32个字节处存放的是dex文件的大小
var address = parseInt(dex_begin_address,16) + 32
// 把address地址指向的内存读取出来,该值就是dex的文件大小
// ptr(address)转换的原因是frida只接受NativePointer类型的指针
var dex_size = Memory.readInt(ptr(address))
console.log("dex_size:"+dex_size)
// frida写文件,把内存中的数据写到本地
var timestamp = new Date().getTime();
var file = new File("/data/data/%s/"+timestamp+".dex",'wb')
// Memory.readByteArray(begin,length)把内存里的数据读出来,从begin开始读,取length的长度
file.write(Memory.readByteArray(dex_begin_address,dex_size))
file.flush()
file.close()
send("dex begin address:"+parseInt(dex_begin_address,16))
send("dex file size :"+dex_size)
},
onLeave: function (retval) {
if (retval.toInt32() > 0) {
}
}
})
"""% (package)
# 定位jar包
device= frida.get_usb_device()
pid = device.spawn(['com.iCitySuzhou.suzhou001'])
process = device.attach(pid)
# 传入上面的js代码创造脚本
script = process.create_script(jscode)
# 接受信息打印信息模块
script.on('message', on_message)
print('[*] Running')
script.load()
# 重启的方法非常重要!为了能hook到,重启一遍这样是最好不过的了
device.resume(pid)
sys.stdin.read()