table des matières
1. Supplément de connaissances
1. Processus de fonctionnement de l'APP après le renforcement
1. -->APP启动
2. -->壳dex先加载起来
3. -->壳负责把源dex文件读出来
4. -->壳把源dex文件解密
5. -->把解密后的dex加载进内存 源dex运行起来
2. Le principe des bombardements
Après le démarrage de l'application renforcée, le fichier dex source final sera chargé dans la mémoire pour exécution. À ce stade, le fichier dex est le fichier dex après le décryptage du programme de durcissement, qui est le code source de l'application.
Le déballage d'Android a pour but de vider le fichier dex de l'application déchiffré de la mémoire.Pour atteindre cet objectif, nous devons connaître l'adresse dex et la taille du fichier dex du fichier dex dans la mémoire. Le fichier de bibliothèque libart.so du système Android fournit une fonction OpenMemory exportée pour charger le fichier dex.
Le premier paramètre de cette fonction pointe vers le fichier dex dans la mémoire. Si nous pouvons accrocher cette fonction, nous pouvons obtenir l'adresse de départ du fichier dex lorsqu'il est chargé en mémoire, puis calculer le fichier dex enregistré dans le fichier en-tête selon le format de fichier dex Length fileSize.
Comprenez le format de fichier dex: https://www.jianshu.com/p/f7f0a712ddfe
position de départ dex: le premier paramètre d'OpenMemory
8个字节 magin ---> dex 035
4个字节 校验位
20个字节 签名
-----从32个字节开始------
4个字节 dex文件大小
Informations disponibles:
- position de départ dex (le premier paramètre d'OpenMemory)
- taille du fichier dex (position de départ dex + 32 octets)
Nous pouvons donc lire les données dans la mémoire et les écrire localement
// 把内存里的数据读出来,从begin(dex在内存中的起始位置)开始读,取length长度(dex_size文件的大小)
file.write(Memory.readByteArray(begin, dex_size))
// 将这段读取出来的数据写入本地
var file = new File("/data/data/%s/" + dex_size + ".dex", "wb")
2. Démonstration du processus d'exploitation
Avant d'écrire le script Frida, nous devons trouver le nom de la fonction d'exportation d'OpenMemory dans le fichier libart.so. Ce nom de fonction variera légèrement selon la version ou l'architecture d'Android.
Quel est le nom de cette fonction exportée?
Elle équivaut à l'interface fournie par la méthode dans le fichier so vers l'extérieur OpenMemory
. La forme d'appel de la méthode dans le fichier so dans le code Java est:
javaCode.OpenMemory的导出函数名
OpenMemory导出函数名与so文件中的OpenMemory方法存在映射关系
java代码中想要调用so库中的OpenMemory方法就以它的导出函数名调用
Différents librat.so peuvent être exportés selon que le libart.so 64 bits ou 32 bits est utilisé pendant l'opération d'application.
adb pull /system/lib/libart.so C:\Users\v_mcsong\Desktop
adb pull /system/lib64/libart.so C:\Users\v_mcsong\Desktop
Utilisez IDA 32/64 bits pour ouvrir le fichier librat.so afin d'afficher OpenMemory
le nom de la méthode d'exportation. Différentes versions d'Android peuvent avoir des noms de méthode d'exportation différents.
Autrement dit, l'appel _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_
est dans la bibliothèque soOpenMemory
Script de bombardement:
Projet open source de référence: https://github.com/dstmath/frida-unpack/blob/master/frida_unpack.py
#-*- coding:utf-8 -*-
# coding=utf-8
import frida
import sys
def on_message(message, data):
base = message['payload']['base']
size = int(message['payload']['size'])
print(hex(base),size)
# print session
# dex_bytes = session.read_bytes(base, size)
# f = open("1.dex","wb")
# f.write(dex_bytes)
# f.close()
### libart.so
# 9.0 arm 需要拦截 _ZN3art13DexFileLoader10OpenCommonEPKhjS2_jRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS0_12VerifyResultE
# 7.0 arm:_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_
# android 10: libdexfile.so
# #_ZN3art13DexFileLoader10OpenCommonEPKhjS2_jRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPKNS_10OatDexFileEbbPS9_NS3_10unique_ptrINS_16DexFileContainerENS3_14default_deleteISH_EEEEPNS0_12VerifyResultE
# 获取包名
package = sys.argv[1]
print("dex 导出目录为: /data/data/%s"%(package))
device = frida.get_usb_device()
pid = device.spawn(package)
session = device.attach(pid)
src = """
Interceptor.attach(Module.findExportByName("libart.so", "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_"), {
onEnter: function (args) {
//dex文件的起始位置
var begin = args[1]
//dex文件的前8个字节是magic字段 看dex的文件格式说明
//打印magic(会显示 "dex 035") 三个字符 可以验证是否为dex文件
console.log("magic : " + Memory.readUtf8String(begin))
//把地址转换成整型 再加32
//因为dex文件的第32个字节处存放的是 dex文件的大小
var address = parseInt(begin,16) + 0x20
//把address地址指向的内存值读出来 该值就是dex的文件大小
//ptr(address)转换的原因是 frida只接受 NativePointer类型指针
var dex_size = Memory.readInt(ptr(address))
console.log("dex_size :" + dex_size)
//frida写文件 把内存中的数据 写到本地
var file = new File("/data/data/%s/" + dex_size + ".dex", "wb")
//Memory.readByteArray(begin, length)
//把内存里的数据读出来,从begin开始读,取length长度(dex_size文件的大小)
file.write(Memory.readByteArray(begin, dex_size))
file.flush()
file.close()
var send_data = {}
send_data.base = parseInt(begin,16)
send_data.size = dex_size
send(send_data)
},
onLeave: function (retval) {
if (retval.toInt32() > 0) {
}
}
});
"""%(package)
script = session.create_script(src)
script.on("message" , on_message)
script.load()
device.resume(pid)
sys.stdin.read()
Utilisez jadx pour ouvrir un par un pour voir quel fichier dex est le code source de l'application.
Article de référence: https://blog.51cto.com/yeshaochen/2496524