[프리다 역 개발] 프리다 포격 원리와 포격 도구의 사용


1. 지식 보충

1. 보강 후 APP 운영 과정

 1.    -->APP启动    
 2.        -->壳dex先加载起来    
 3.             -->壳负责把源dex文件读出来    
 4.                -->壳把源dex文件解密    
 5.                    -->把解密后的dex加载进内存 源dex运行起来
 

2. 포격의 원리

강화 된 APP가 시작된 후 최종 소스 dex 파일이 실행을 위해 메모리에로드됩니다.이 때 dex 파일은 강화 프로그램이 복호화 된 후 앱의 소스 코드 인 dex입니다.

Android 언 패킹의 목적은 복호화 된 애플리케이션 dex 파일을 메모리에서 덤프하는 것입니다.이 목적을 달성하려면 메모리에있는 dex 파일의 dex 주소와 dex 파일 크기를 알아야합니다. Android 시스템의 libart.so 라이브러리 파일은 dex 파일을로드하기 위해 내 보낸 OpenMemory 함수를 제공합니다.

여기에 사진 설명 삽입
이 함수의 첫 번째 매개 변수는 메모리에있는 dex 파일을 가리 킵니다.이 함수를 후크 할 수 있으면 dex 파일이 메모리에로드 될 때 시작 주소를 얻은 다음 파일에 저장된 dex 파일을 계산할 수 있습니다. dex 파일 형식 길이 fileSize에 따른 헤더.

dex 파일 형식 이해 : https://www.jianshu.com/p/f7f0a712ddfe

dex 시작 위치 : OpenMemory의 첫 번째 매개 변수

8个字节    magin  ---> dex 035
4个字节    校验位
20个字节   签名
-----32个字节开始------
4个字节    dex文件大小

이용 가능한 정보 :

  • dex 시작 위치 (OpenMemory의 첫 번째 매개 변수)
  • dex 파일 크기 (dex 시작 위치 + 32 바이트)

따라서 메모리의 데이터를 읽고 로컬로 쓸 수 있습니다.

// 把内存里的数据读出来,从begin(dex在内存中的起始位置)开始读,取length长度(dex_size文件的大小)
file.write(Memory.readByteArray(begin, dex_size))
// 将这段读取出来的数据写入本地
var file = new File("/data/data/%s/" + dex_size + ".dex", "wb")

2. 운영 프로세스 데모

Frida 스크립트를 작성하기 전에 libart.so 파일에서 OpenMemory의 내보내기 함수 이름을 찾아야합니다.이 함수 이름은 Android 버전 또는 아키텍처에 따라 약간 씩 다릅니다.

이 내 보낸 함수의 이름은 무엇입니까?

so 파일의 메소드에서 외부로 제공하는 인터페이스와 동일하며 Java 코드 OpenMemoryso 파일에서 메소드 호출 형식은 다음과 같습니다.

javaCode.OpenMemory的导出函数名

OpenMemory导出函数名与so文件中的OpenMemory方法存在映射关系

java代码中想要调用so库中的OpenMemory方法就以它的导出函数名调用

64 비트 libart.so 또는 32 비트가 응용 프로그램 작동 중에 사용되는지 여부에 따라 다른 librat.so를 내보낼 수 있습니다.

adb pull /system/lib/libart.so C:\Users\v_mcsong\Desktop
adb pull /system/lib64/libart.so C:\Users\v_mcsong\Desktop

32/64 비트 IDA를 사용하여 librat.so 파일을 열어 OpenMemory내보내기 방법 이름 을 확인 합니다. Android 버전에 따라 내보내기 방법 이름이 다를 수 있습니다.

여기에 사진 설명 삽입
즉, 호출 _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_이 so 라이브러리에 있습니다.OpenMemory

쉘링 스크립트 :

참조 오픈 소스 프로젝트 : 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()

여기에 사진 설명 삽입
여기에 사진 설명 삽입
jadx를 사용하여 하나씩 열면 어떤 dex 파일이 앱의 소스 코드인지 확인할 수 있습니다.

참조 기사 : https://blog.51cto.com/yeshaochen/2496524

추천

출처blog.csdn.net/weixin_44032232/article/details/109676945