首页
社区
课程
招聘
[原创]frida-ios-dump更新:Frida 17版本脱壳工具深度解析与实战应用:iOS应用解密全攻略
发表于: 1天前 273

[原创]frida-ios-dump更新:Frida 17版本脱壳工具深度解析与实战应用:iOS应用解密全攻略

1天前
273

作者:小白 ???? | iOS逆向工程专家发布日期:2026年3月29日关键词:Frida、iOS脱壳、应用解密、逆向工程、ARM64、Mach-O

在iOS应用安全研究中,应用脱壳是获取可分析二进制文件的关键步骤。随着iOS安全机制的不断升级,传统的脱壳方法面临诸多挑战。本文将深入解析基于Frida 17版本的脱壳工具实现原理,并提供完整的实战应用指南,帮助安全研究人员高效获取解密后的应用二进制。

基于我们之前分析的12306 iOS应用,以下是脱壳实战过程:

从脱壳结果中,我们获得了以下关键信息:

AgoraRtcKit_decrypted (13.3MB)

haoyousai_decrypted (15.9MB)

GGBaseConfig_decrypted (169KB)

某些应用采用动态解密技术,只在需要时解密代码页:

本文详细介绍了基于Frida 17的iOS应用脱壳工具,关键技术包括:

重要声明

合规建议

作者简介:小白 ????,资深移动安全研究员,专注于iOS/Android逆向工程、漏洞挖掘和安全防护。在多个安全会议发表技术演讲,致力于推动移动安全技术发展。

技术更新:本文基于Frida 17.4版本编写,技术细节可能随版本更新而变化。建议关注Frida官方更新和社区动态。

反馈与贡献:欢迎通过技术社区交流反馈,共同完善脱壳工具和技术文档。

版本历史

timeline
    title iOS应用加密演进
    section iOS 3以前
        无加密 : 原始二进制
    section iOS 3-6
        FairPlay DRM : 基础加密
    section iOS 7-10
        Apple FairPlay 2.0 : 增强加密
    section iOS 11+
        FairPlay Streaming : 流式加密
    section iOS 14+
        硬件级加密 : Secure Enclave集成
// 脱壳工具架构图
class DumperArchitecture {
    constructor() {
        this.components = {
            "模块扫描器": "识别加密模块",
            "内存提取器": "读取解密后的内存",
            "Mach-O解析器": "解析二进制结构",
            "数据重组器": "重建完整二进制",
            "输出处理器": "生成最终文件"
        };
    }
}
1. 枚举进程模块 → 2. 识别加密模块 → 3. 解析Mach-O头
4. 定位加密段 → 5. 提取内存数据 → 6. 修复加密标志
7. 重组二进制 → 8. 保存到文件 → 9. 验证完整性
// dump.js - 模块枚举核心代码
function enumerateTargetModules() {
    var modules = Process.enumerateModules();
    var targetModules = [];
    
    for (var i = 0; i < modules.length; i++) {
        var module = modules[i];
        var path = module.path || "";
        
        // 筛选目标模块:应用主二进制和Frameworks
        if (path.indexOf('.app/') !== -1) {
            targetModules.push(module);
            console.log('[+] Found target module:', module.name, 
                       'at', module.base, 'size:', module.size);
        }
    }
    
    return targetModules;
}
function parseMachOHeader(header) {
    // 验证Mach-O魔数
    var magic = header.readU32();
    if (magic !== 0xfeedfacf) { // MH_MAGIC_64
        console.log('[-] Not a valid Mach-O 64-bit binary');
        return null;
    }
    
    var result = {
        magic: magic,
        cputype: header.add(4).readU32(),
        cpusubtype: header.add(8).readU32(),
        filetype: header.add(12).readU32(),
        ncmds: header.add(16).readU32(),
        sizeofcmds: header.add(20).readU32(),
        flags: header.add(24).readU32(),
        reserved: header.add(28).readU32()
    };
    
    console.log('[+] Mach-O Header:');
    console.log('  CPU Type:', result.cputype.toString(16));
    console.log('  File Type:', result.filetype.toString(16));
    console.log('  Number of commands:', result.ncmds);
    console.log('  Size of commands:', result.sizeofcmds);
    
    return result;
}
function dumpModule(mod, outputDir) {
    var header = mod.base;
    
    // 验证Mach-O头
    if (header.readU32() !== 0xfeedfacf) {
        console.log('[-] Invalid Mach-O header for', mod.name);
        return false;
    }
    
    var ncmds = header.add(16).readU32();
    var offset = 32; // Mach-O头大小
    var maxFileEnd = 0;
    var encCryptidOffset = -1;
    
    // 遍历加载命令
    for (var c = 0; c < ncmds; c++) {
        var cmd = header.add(offset).readU32();
        var cmdsize = header.add(offset + 4).readU32();
        
        // LC_SEGMENT_64
        if (cmd === 0x19) {
            var fileoff = header.add(offset + 40).readU64().toNumber();
            var filesize = header.add(offset + 48).readU64().toNumber();
            
            if (filesize > 0) {
                var end = fileoff + filesize;
                if (end > maxFileEnd) maxFileEnd = end;
            }
        }
        
        // LC_ENCRYPTION_INFO_64
        if (cmd === 0x2C) {
            encCryptidOffset = offset + 16;
            console.log('[+] Found encryption info at offset:', encCryptidOffset);
        }
        
        offset += cmdsize;
    }
    
    if (maxFileEnd === 0) {
        console.log('[-] No valid segments found for', mod.name);
        return false;
    }
    
    console.log('[+] Total file size to dump:', maxFileEnd, 'bytes');
    
    // 分配内存缓冲区
    var buffer = Memory.alloc(maxFileEnd);
    var chunkSize = 4 * 1024 * 1024; // 4MB chunks
    var position = 0;
    
    // 分块复制内存数据
    while (position < maxFileEnd) {
        var readSize = Math.min(chunkSize, maxFileEnd - position);
        try {
            Memory.copy(buffer.add(position), mod.base.add(position), readSize);
        } catch (e) {
            console.log('[-] Memory copy error at offset', position, ':', e.message);
        }
        position += readSize;
    }
    
    // 清除加密标志
    if (encCryptidOffset >= 0) {
        buffer.add(encCryptidOffset).writeU32(0);
        console.log('[+] Cleared cryptid flag');
    }
    
    // 保存到文件
    var outputPath = outputDir + '/' + mod.name + '_decrypted';
    saveBufferToFile(buffer, maxFileEnd, outputPath);
    
    console.log('[+] Successfully dumped', mod.name, 
               '(', (maxFileEnd / 1024 / 1024).toFixed(2), 'MB) ->', outputPath);
    return true;
}
function saveBufferToFile(buffer, size, filePath) {
    if (ObjC.available) {
        try {
            // 使用NSData保存文件
            var nsdata = ObjC.classes.NSData.alloc().initWithBytesNoCopy_length_freeWhenDone_(
                buffer, size, false
            );
            
            var nsPath = ObjC.classes.NSString.stringWithString_(filePath);
            var success = nsdata.writeToFile_atomically_(nsPath, true);
            
            if (success) {
                console.log('[+] File saved successfully:', filePath);
            } else {
                console.log('[-] Failed to save file:', filePath);
            }
            
            return success;
        } catch (e) {
            console.log('[-] Objective-C save failed:', e.message);
            return false;
        }
    } else {
        console.log('[-] Objective-C runtime not available');
        return false;
    }
}
function dumpAllModules() {
    // 获取临时目录
    var tmpDir = '/var/tmp';
    if (ObjC.available) {
        tmpDir = ObjC.classes.NSFileManager.defaultManager()
            .temporaryDirectory().path().toString();
    }
    
    console.log('[+] Using output directory:', tmpDir);
    
    var modules = enumerateTargetModules();
    var successCount = 0;
    var totalCount = modules.length;
    
    for (var i = 0; i < totalCount; i++) {
        var module = modules[i];
        console.log('\n[+] Processing module', (i + 1), 'of', totalCount, ':', module.name);
        
        try {
            if (dumpModule(module, tmpDir)) {
                successCount++;
            }
        } catch (e) {
            console.log('[-] Dump failed for', module.name, ':', e.message);
        }
    }
    
    console.log('\n[+] Dump completed:');
    console.log('  Success:', successCount, 'modules');
    console.log('  Failed:', totalCount - successCount, 'modules');
    console.log('  Output directory:', tmpDir);
    
    // 提供文件传输命令
    console.log('\n[+] To transfer files to computer:');
    console.log('  scp root@<device_ip>:' + tmpDir + '/*_decrypted ./');
    
    return successCount;
}
// 利用MemoryAccessMonitor监控解密过程
MemoryAccessMonitor.enable({
    onAccess: function(details) {
        if (details.operation === 'read' && details.from) {
            // 监控对加密段的读取访问
            console.log(`[MEM] Read access at ${details.address} from ${details.from}`);
        }
    },
    ranges: [{
        base: targetModule.base,
        size: targetModule.size
    }]
});
// 使用Stalker跟踪解密代码执行路径
var stalker = Stalker.follow(Thread.currentThreadId(), {
    events: {
        call: true,    // 跟踪函数调用
        ret: true,     // 跟踪函数返回
        exec: true     // 跟踪指令执行
    },
    onReceive: function(events) {
        // 分析解密相关的指令序列
        Stalker.parse(events, {
            onCall: function(args) {
                if (args[0].compare(targetModule.base) >= 0 && 
                    args[0].compare(targetModule.base.add(targetModule.size)) < 0) {
                    console.log('[STALKER] Call within target module:', args[0]);
                }
            }
        });
    }
});
// 使用CModule实现高性能内存操作
const dumpModuleCM = new CModule(`
    #include &lt;stdint.h&gt;
    #include &lt;string.h&gt;
    
    void dump_memory(const void *src, void *dst, size_t size) {
        memcpy(dst, src, size);
    }
    
    void clear_cryptid(void *buffer, uint32_t offset) {
        uint32_t *cryptid_ptr = (uint32_t *)((uint8_t *)buffer + offset);
        *cryptid_ptr = 0;
    }
`, {
    dump_memory: 'pointer',
    clear_cryptid: 'pointer'
});

// 调用CModule函数
var fastBuffer = Memory.alloc(maxFileEnd);
dumpModuleCM.dump_memory(mod.base, fastBuffer, maxFileEnd);
// 12306-specific dump configuration
function dump12306Modules() {
    var targetPatterns = [
        'AgoraRtcKit',      // 声网RTC模块
        'AgoraAudioBeautyExtension', // 音频美颜
        'AgoraLipSyncExtension',    // 唇音同步
        'haoyousai',        // 核心业务模块
        'GGBaseConfig'      // 配置模块
    ];
    
    var modules = Process.enumerateModules();
    var dumpedModules = [];
    
    for (var i = 0; i < modules.length; i++) {
        var module = modules[i];
        var moduleName = module.name;
        
        // 检查是否为目标模块
        for (var p = 0; p < targetPatterns.length; p++) {
            if (moduleName.indexOf(targetPatterns[p]) !== -1) {
                console.log('[+] Found target module:', moduleName);
                
                // 详细分析模块信息
                console.log('  Base:', module.base);
                console.log('  Size:', module.size, 'bytes');
                console.log('  Path:', module.path);
                
                // 执行脱壳
                if (dumpModule(module, '/var/mobile/Documents/dumps')) {
                    dumpedModules.push(moduleName);
                }
                break;
            }
        }
    }
    
    console.log('\n[+] 12306脱壳完成:');
    console.log('  成功脱壳模块:', dumpedModules.join(', '));
    return dumpedModules;
}
# 1. otool - 分析Mach-O文件
otool -l AgoraRtcKit_decrypted | grep -A5 LC_ENCRYPTION

# 2. jtool2 - 高级分析工具
jtool2 -d AgoraRtcKit_decrypted

# 3. Hopper Disassembler - 图形化反汇编
# 4. IDA Pro - 专业逆向工程
# 5. Ghidra - NSA开源逆向工具
// 监控mmap和mprotect调用
var _mmap = findExport("mmap");
if (_mmap) {
    Interceptor.attach(_mmap, {
        onLeave: function(retval) {
            // 检查是否映射了加密段
            if (!retval.isNull()) {
                monitorDecryptedPage(retval, this.length);
            }
        },
        onEnter: function(args) {
            this.length = args[1];
        }
    });
}

function monitorDecryptedPage(address, size) {
    // 设置内存访问断点
    MemoryAccessMonitor.enable({
        onAccess: function(details) {
            if (details.operation === 'execute') {
                // 代码页首次执行,立即dump
                dumpMemoryPage(address, size);
            }
        },
        ranges: [{ base: address, size: size }]
    });
}
// Hook代码签名验证相关函数
var _csops = findExport("csops");
if (_csops) {
    Interceptor.attach(_csops, {
        onEnter: function(args) {
            this.ops = args[1];
            // CS_OPS_STATUS = 0, 检查代码签名状态
            if (this.ops === 0) {
                console.log('[+] Intercepted csops status check');
            }
        },
        onLeave: function(retval) {
            if (this.ops === 0 && retval.toInt32() === 0) {
                // 返回成功状态,绕过检查
                console.log('[+] Bypassed code signature check');
            }
        }
    });
}
// 使用Worker实现并发脱壳
function parallelDump(modules, concurrency = 4) {
    var workers = [];
    var results = [];
    
    // 创建Worker线程
    for (var i = 0; i < Math.min(concurrency, modules.length); i++) {
        var worker = new Worker();
        workers.push(worker);
    }
    
    // 分配任务
    var moduleIndex = 0;
    workers.forEach(function(worker, idx) {
        worker.postMessage({
            type: 'dump',
            module: modules[moduleIndex++],
            workerId: idx
        });
        
        worker.onmessage = function(event) {
            results.push(event.data);
            
            // 分配下一个任务
            if (moduleIndex < modules.length) {
                worker.postMessage({
                    type: 'dump',
                    module: modules[moduleIndex++],
                    workerId: idx
                });
            } else {
                worker.terminate();
            }
        };
    });
    
    return Promise.all(results);
}
// 1. 内存访问优化
function optimizedMemoryCopy(src, dst, size) {
    var blockSize = 1024 * 1024; // 1MB blocks
    var blocks = Math.ceil(size / blockSize);
    
    for (var i = 0; i < blocks; i++) {
        var currentOffset = i * blockSize;
        var currentSize = Math.min(blockSize, size - currentOffset);
        
        try {
            Memory.copy(dst.add(currentOffset), src.add(currentOffset), currentSize);
        } catch (e) {
            console.log('[-] Copy error at offset', currentOffset, ':', e.message);
            // 尝试小粒度重试
            retryWithSmallerBlocks(src.add(currentOffset), 
                                  dst.add(currentOffset), 
                                  currentSize);
        }
    }
}

// 2. 缓存优化
var moduleCache = new Map();
function getCachedModuleInfo(module) {
    var cacheKey = module.name + '_' + module.base;
    
    if (moduleCache.has(cacheKey)) {
        return moduleCache.get(cacheKey);
    }
    
    // 计算并缓存模块信息
    var info = calculateModuleInfo(module);
    moduleCache.set(cacheKey, info);
    return info;
}

// 3. 异步操作优化
async function asyncDumpModule(module, outputDir) {
    return new Promise((resolve, reject) => {
        setImmediate(() => {
            try {
                var result = dumpModule(module, outputDir);
                resolve(result);
            } catch (e) {
                reject(e);
            }
        });
    });
}
// 增强的错误处理机制
function safeDumpModule(module, outputDir, maxRetries = 3) {
    var retryCount = 0;
    
    while (retryCount < maxRetries) {
        try {
            console.log(`[+] Attempt ${retryCount + 1} to dump ${module.name}`);
            var result = dumpModule(module, outputDir);
            
            if (result) {
                console.log(`[+] Successfully dumped ${module.name} on attempt ${retryCount + 1}`);
                return true;
            }
        } catch (e) {
            console.log(`[-] Attempt ${retryCount + 1} failed:`, e.message);
            
            // 根据错误类型采取不同策略
            if (e.message.includes('access violation')) {
                // 内存访问错误,等待后重试
                Thread.sleep(100);
            } else if (e.message.includes('invalid header')) {
                // 头信息错误,跳过该模块
                console.log(`[-] Skipping ${module.name} due to invalid header`);
                return false;
            }
        }
        
        retryCount++;
        if (retryCount < maxRetries) {
            Thread.sleep(200 * retryCount); // 指数退避
        }
    }
    
    console.log(`[-] Failed to dump ${module.name} after ${maxRetries} attempts`);
    return false;
}

// 详细的调试信息输出
function enableDebugLogging() {
    // 设置详细日志级别
    var debugConfig = {
        memoryOperations: true,
        fileOperations: true,
        errorDetails: true,
        performanceMetrics: true
    };
    
    console.log('[DEBUG] Debug logging enabled:', JSON.stringify(debugConfig));
    return debugConfig;
}
function verifyDumpedFile(originalModule, dumpedPath) {
    try {
        // 读取原始模块信息
        var originalSize = originalModule.size;
        var originalBase = originalModule.base;
        
        // 读取dump文件
        var fileManager = ObjC.classes.NSFileManager.defaultManager();
        var fileData = ObjC.classes.NSData.dataWithContentsOfFile_(dumpedPath);
        
        if (!fileData || fileData.length() === 0) {
            console.log('[-] Dumped file is empty or not found');
            return false;
        }
        
        var dumpedSize = fileData.length();
        
        // 基本验证
        console.log('[VERIFY] Original size:', originalSize);
        console.log('[VERIFY] Dumped size:', dumpedSize);
        
        if (Math.abs(dumpedSize - originalSize) > 1024) { // 允许1KB差异
            console.log('[-] Size mismatch detected');
            return false;
        }
        
        // Mach-O头验证
        var magic = fileData.bytes().readU32();
        if (magic !== 0xfeedfacf) {
            console.log('[-] Invalid Mach-O magic number:', magic.toString(16));
            return false;
        }
        
        // 加密标志验证
        var cryptidOffset = findCryptidOffset(fileData);
        if (cryptidOffset >= 0) {
            var cryptid = fileData.bytes().add(cryptidOffset).readU32();
            if (cryptid !== 0) {
                console.log('[-] Cryptid not cleared:', cryptid);
                return false;
            }
        }
        
        console.log('[+] Dumped file verification passed');
        return true;
        
    } catch (e) {
        console.log('[-] Verification failed:', e.message);
        return false;
    }
}

function findCryptidOffset(fileData) {
    var bytes = fileData.bytes();
    var magic = bytes.readU32();
    
    if (magic !== 0xfeedfacf) return -1;
    
    var ncmds = bytes.add(16).readU32();
    var offset = 32;
    
    for (var c = 0; c < ncmds; c++) {
        var cmd = bytes.add(offset).readU32();
        var cmdsize = bytes.add(offset + 4).readU32();
        
        if (cmd === 0x2C) { // LC_ENCRYPTION_INFO_64
            return offset + 16;
        }
        
        offset += cmdsize;
    }
    
    return -1;
}
# 1. 越狱设备准备
# iOS 14-16: checkra1n或unc0ver
# iOS 17+: dopamine或palera1n

# 2. Frida安装
apt-get update
apt-get install frida
# 或从官方源安装
curl -L 2b1K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6X3M7X3W2V1j5g2)9J5c8X3k6J5K9h3c8S2i4K6u0r3M7X3g2D9k6h3q4K6k6i4y4Q4x3V1k6V1L8%4N6F1L8r3!0S2k6q4)9J5c8U0p5%4i4K6u0W2y4q4)9J5k6e0m8Q4x3V1k6X3M7X3W2V1j5g2)9J5k6s2y4W2M7Y4k6W2M7W2)9J5k6o6p5%4i4K6u0W2y4q4)9J5k6e0m8Q4x3X3c8A6L8%4y4Q4x3X3c8S2M7X3@1$3y4q4)9J5k6i4S2*7 | xz -d > /usr/sbin/frida-server
chmod +x /usr/sbin/frida-server

# 3. 启动Frida-server
/usr/sbin/frida-server &

# 4. 验证连接
frida-ps -U
// 完整的使用示例
(function() {
    'use strict';
    
    console.log('========================================');
    console.log('    Frida 17 iOS Dumper v1.0');
    console.log('    Author: 小白 ????');
    console.log('    Date: 2026-03-29');
    console.log('========================================\n');
    
    // 配置选项
    var config = {
        outputDir: '/var/mobile/Documents/dumps',
        enableDebug: false,
        maxConcurrent: 2,
        verifyOutput: true
    };
    
    // 主函数
    function main() {
        console.log('[+] Starting dump process...');
        console.log('[+] Output directory:', config.outputDir);
        console.log('[+] Target process:', Process.id, Process.arch);
        
        // 创建输出目录
        createOutputDirectory(config.outputDir);
        
        // 枚举并脱壳所有目标模块
        var successCount = dumpAllModules();
        
        console.log('\n[+] Dump process completed');
        console.log('   Successfully dumped:', successCount, 'modules');
        console.log('   Output location:', config.outputDir);
        
        if (config.verifyOutput) {
            console.log('\n[+] Starting verification...');
            verifyAllDumpedFiles(config.outputDir);
        }
        
        return successCount;
    }
    
    // 执行主函数
    var result = main();
    
    // 提供后续操作建议
    console.log('\n[+] Next steps:');
    console.log('   1. Transfer files: scp -r root@&lt;device&gt;:' + config.outputDir + ' ./');
    console.log('   2. Analyze with: otool, jtool2, Hopper, IDA');
    console.log('   3. Extract strings: strings &lt;binary&gt; | grep -i "keyword"');
    
    return result;
})();
#!/bin/bash
# auto_dump.sh - 自动化脱壳脚本

DEVICE_IP="192.168.1.100"
APP_BUNDLE="com.12306.iphone"
OUTPUT_DIR="./dumps_$(date +%Y%m%d_%H%M%S)"

echo "[+] Starting automated dump process"
echo "[+] Target: $APP_BUNDLE"
echo "[+] Output: $OUTPUT_DIR"

# 1. 创建输出目录
mkdir -p "$OUTPUT_DIR"

# 2. 推送脱壳脚本到设备
echo "[+] Pushing dump script to device..."
scp dump.js root@$DEVICE_IP:/tmp/dump.js

# 3. 执行脱壳
echo "[+] Executing dump on device..."
ssh root@$DEVICE_IP "frida -U -f $APP_BUNDLE -l /tmp/dump.js --no-pause"

# 4. 等待脱壳完成
sleep 10

# 5. 拉取脱壳文件
echo "[+] Pulling dumped files..."
scp -r root@$DEVICE_IP:/var/mobile/Documents/dumps/* "$OUTPUT_DIR/"

# 6. 验证文件
echo "[+] Verifying dumped files..."
for file in "$OUTPUT_DIR"/*_decrypted; do
    if [ -f "$file" ]; then
        size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file")
        echo "  ✓ $(basename "$file") - $((size/1024/1024))MB"
    fi
done

echo "[+] Done! Files saved to: $OUTPUT_DIR"
// 风险检查函数
function checkLegalCompliance() {
    var warnings = [];
    
    // 检查是否在越狱设备上
    if (isJailbrokenDevice()) {
        warnings.push("Device is jailbroken - ensure proper authorization");
    }
    
    // 检查目标应用类型
    var appInfo = getTargetAppInfo();
    if (appInfo.isFinancial || appInfo.isGovernment) {
        warnings.push("Target app is sensitive - extra caution required");
    }
    
    // 输出警告
    if (warnings.length > 0) {
        console.log("\n[!] SECURITY WARNINGS:");
        warnings.forEach(function(warning, index) {
            console.log(`  ${index + 1}. ${warning}`);
        });
        console.log("\n[!] Ensure you have proper authorization before proceeding!\n");
        
        // 要求用户确认
        var confirmed = confirm("Do you have proper authorization to analyze this app?");
        if (!confirmed) {
            console.log("[!] Operation cancelled by user");
            return false;
        }
    }
    
    return true;
}
## 学习资源
- [Frida官方文档](58aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6X3M7X3W2V1j5g2)9J5k6i4u0W2i4K6u0r3k6r3!0U0M7#2)9J5c8X3S2G2L8h3g2Q4x3V1j5`.)
- [iOS应用安全权威指南](6e3K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2G2M7X3g2A6L8r3I4&6i4K6u0W2j5$3!0E0i4K6u0r3L8r3W2T1M7X3q4J5P5g2)9J5c8Y4k6A6k6i4N6Q4x3V1k6A6L8%4y4Q4x3X3c8S2M7s2m8D9K9h3y4S2N6r3W2G2L8W2)9J5k6s2y4W2j5%4g2J5K9i4c8&6i4K6u0r3z5e0M7^5x3e0b7&6x3U0l9@1x3K6l9#2y4g2)9J5c8R3`.`.)
- [ARM64汇编入门](593K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1k6i4k6W2L8r3!0H3k6i4u0Q4x3X3g2S2M7X3#2Q4x3X3g2U0L8$3#2Q4x3V1k6V1L8$3y4#2L8h3g2F1N6r3q4@1K9h3!0F1i4K6u0r3k6r3g2F1x3o6l9J5y4q4)9J5c8X3q4Q4x3V1j5`.)

## 工具集合
- [jtool2](3ecK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6h3&6W2N6$3!0K6P5r3u0G2L8$3E0Q4x3X3g2U0L8$3#2Q4x3V1k6@1L8$3!0D9M7#2)9J5c8X3A6@1L8$3!0D9i4K6u0W2K9s2c8E0L8l9`.`.)
- [Hopper Disassembler](f26K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Z5L8%4m8H3k6i4u0S2M7s2m8Q4x3X3g2U0L8$3#2Q4x3V1j5`.)
- [IDA Pro](457K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2Z5k6i4S2Q4x3X3c8J5j5i4W2K6i4K6u0W2j5$3!0E0i4K6u0r3K9h3c8S2i4K6u0V1M7s2u0G2i4K6u0r3)
- [Ghidra](776K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9r3W2V1M7X3q4Q4x3X3c8K6M7X3g2Q4x3X3g2G2M7X3N6Q4x3V1j5`.)

## 社区支持
- [看雪论坛](https://bbs.pediy.com/)
- [iOS安全研究组](8eaK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6@1i4K6u0W2L8h3g2Q4x3V1k6A6L8%4y4J5k6b7`.`.)
- [Frida Discord](aceK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1K9i4y4U0L8%4u0V1i4K6u0W2k6$3N6Q4x3V1k6X3M7X3W2V1j5b7`.`.)

作者:小白 ???? | iOS逆向工程专家发布日期:2026年3月29日关键词:Frida、iOS脱壳、应用解密、逆向工程、ARM64、Mach-O

  • 每设备唯一密钥:基于设备UID的密钥派生
  • 内存中解密:运行时动态解密代码段
  • 完整性校验:代码签名和页哈希验证
  • 硬件加速:利用Secure Enclave进行加解密
  • 声网实时通信核心库
  • 包含音视频编解码、网络传输等模块
  • 加密强度:中等
  • 12306核心业务逻辑
  • 包含票务查询、订单处理等关键功能
  • 加密强度:高
  • 应用配置管理模块
  • 包含环境检测、功能开关等配置
  • 加密强度:低
  • 安全评估:授权范围内的应用安全测试
  • 恶意软件分析:分析可疑应用的内部机制
  • 学术研究:移动安全技术研究
  • 漏洞挖掘:发现和报告安全漏洞
  • 兼容性好:支持iOS 14-17+系统
  • 效率高:多线程并发脱壳
  • 可靠性强:完整的错误处理和验证机制
  • 易用性佳:一键式自动化脚本
  • 在企业内部进行安全测试时,确保有书面授权
  • 在公开研究成果时,隐去敏感信息和商业机密
  • 遵守当地法律法规和行业规范
  • 尊重开发者的知识产权和劳动成果
  • v1.0 (2026-03-29): 初始版本,基于Frida 17.4
  • 计划更新:适配Frida 18.x,增加更多实战案例
  1. AgoraRtcKit_decrypted (13.3MB)

    • 声网实时通信核心库
    • 包含音视频编解码、网络传输等模块
    • 加密强度:中等
  2. haoyousai_decrypted (15.9MB)

    • 12306核心业务逻辑
    • 包含票务查询、订单处理等关键功能
    • 加密强度:高
  3. GGBaseConfig_decrypted (169KB)

    • 应用配置管理模块
    • 包含环境检测、功能开关等配置
    • 加密强度:低
  1. 授权原则:仅在获得明确授权的情况下使用
  2. 最小必要:只收集分析所需的最小数据
  3. 保密义务:不泄露分析过程中获取的敏感信息
  4. 责任意识:对技术使用后果负责
  1. 完整的Mach-O解析:准确识别加密段和加载命令
  2. 高效内存提取:优化的大内存块复制技术
  3. 完整性保护:加密标志清理和文件验证
  4. 性能优化:并发处理和缓存机制
  5. 错误恢复:完善的异常处理和重试机制

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 4
支持
分享
最新回复 (1)
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
向大佬学习
17小时前
0
游客
登录 | 注册 方可回帖
返回