首页
社区
课程
招聘
[原创]Frida 拦截 iOS 所有(已知)密码学函数 ( Frida-iOS-Cipher )
发表于: 2023-7-27 14:24 19078

[原创]Frida 拦截 iOS 所有(已知)密码学函数 ( Frida-iOS-Cipher )

2023-7-27 14:24
19078

之前网上找了几个拦截加密函数的脚本,都只是拦截了部分加密函数,之前也就凑合用了,反正能解决问题就行,不过最近遇到一个应用,之前的脚本都没拦截到,导致我以为是什么自实现加密或者使用的第三方加密库,然后一阵分析,才发现还是调用的iOS的官方加密函数,搞得我一阵***,原来是之前的脚本没拦截全,所以就想着研究下,发现iOS的相关加密函数并不是很多,看看能不能把它们整合到一块。不漏掉任何一个加密函数(这个仅指官方公开的函数,至于内部的函数就不在此类了)(当然仅限我目前已知的加密函数,至于还有没有其他的加密函数,目前还没找到,若有大佬遇到了,可以评论区分享下)。省的以后再出现这种问题,emmm....

image

配置在脚本开头,这里单独提取出来下,方便介绍

因为打印堆栈可能会导致程序执行异常,所以printStack默认是关闭的,有需要可以自行开启

frida-ios-cipher

脚本是用ts写的,若想用js脚本,可以自己构建生成即可,当然,为了方便,上面已提供了一份根据默认配置构建好的js脚本。

使用Frida以来,第一个自己写的开源实用小工具,希望对大家有所帮助,有写的不好的,欢迎批评指正。

当然还有几个函数没有做拦截,如下所示:

/*************************************************************************************
 * Name: frida-ios-cipher
 * OS: iOS
 * Author: @humenger
 * Source: https://github.com/humenger/frida-ios-cipher
 * Desc: Intercept all cryptography-related functions on iOS with Frida Api.
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_MD5.3cc.html#//apple_ref/doc/man/3cc/CC_MD5
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_SHA.3cc.html#//apple_ref/doc/man/3cc/CC_SHA
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CCCryptor.3cc.html#//apple_ref/doc/man/3cc/CCCryptor
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/CommonCrypto/CommonKeyDerivation.h.auto.html
 * refs:https://www.cnblogs.com/cocoajin/p/6150203.html
 * refs:https://frida.re/docs/javascript-api/
 * refs:https://codeshare.frida.re/@xperylab/cccrypt-dump/
 * refs:https://github.com/federicodotta/Brida
 * refs:https://github.com/sensepost/objection/blob/master/agent/src/ios/crypto.ts
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60118.200.6/lib/CommonCryptor.c.auto.html
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60026/CommonCrypto/CommonCryptor.h.auto.html
 * refs:https://www.jianshu.com/p/8896ed432dff
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60118.200.6/lib/
 * refs:https://blog.csdn.net/q187543/article/details/103920969
 **************************************************************************************/
//config
const CIPHER_CONFIG={
    "enable":true,//global enable
    "crypto":{
        "enable":true,//crypto enable
        "maxDataLength":240,//Maximum length of single data printout
        "printStack":false,
        "aes":true,
        "des":true,
        "3des":true,
        "cast":true,
        "rc4":true,
        "rc2":true,
        "blowfish":true,
    },
    "hash":{
        "enable":true,//hash enable
        "maxInputDataLength":240,
        "printStack":false,
        "md2":true,
        "md4":true,
        "md5":true,
        "sha1":true,
        "sha224":true,
        "sha256":true,
        "sha384":true,
        "sha512":true
    },
    "hmac":{
        "enable":true,//hmac enable
        "maxInputDataLength":240,
        "printStack":false,
        "sha1":true,
        "md5":true,
        "sha224":true,
        "sha256":true,
        "sha384":true,
        "sha512":true,
    },
    "pbkdf":{
        "enable":true,
        "printStack":false,
    }
}
 
 
 
//common
const COLORS = {
    "resetColor": "\x1b[0m",
    "green": "\x1b[32m",
    "yellow": "\x1b[33m",
    "red": "\x1b[31m"
};
const CC_MD2_DIGEST_LENGTH = 16
const CC_MD4_DIGEST_LENGTH = 16
const CC_MD5_DIGEST_LENGTH = 16
const CC_SHA1_DIGEST_LENGTH=20;
const CC_SHA224_DIGEST_LENGTH=28;
const CC_SHA256_DIGEST_LENGTH=32;
const CC_SHA384_DIGEST_LENGTH=48;
const CC_SHA512_DIGEST_LENGTH=64;
 
const CCOperation:{[key:number]:string}={
    0:"kCCEncrypt",
    1:"kCCEncrypt",
};
const CCAlgorithm:{[key:number]:string}={
    0:"kCCAlgorithmAES128",
    1:"kCCAlgorithmDES",
    2:"kCCAlgorithm3DES",
    3:"kCCAlgorithmCAST",
    4:"kCCAlgorithmRC4",
    5:"kCCAlgorithmRC2",
    6:"kCCAlgorithmBlowfish"
};
 
const CCOptions:{[key:number]:string}={
    1:"kCCOptionPKCS7Padding",
    2:"kCCOptionECBMode"
};
const CCMode:{[key:number]:string}={
    1:"kCCModeECB",
    2:"kCCModeCBC",
    3:"kCCModeCFB",
    4:"kCCModeCTR",
    5:"kCCModeF8", // Unimplemented for now (not included)
    6:"kCCModeLRW", // Unimplemented for now (not included)
    7:"kCCModeOFB",
    8:"kCCModeXTS",
    9:"kCCModeRC4",
    10:"kCCModeCFB8",
}
const CCPadding:{[key:number]:string}={
    0:"ccNoPadding",
    1:"ccPKCS7Padding",
}
const CCModeOptions:{[key:number]:string}={
    0x0001:"kCCModeOptionCTR_LE",
    0x0002:"kCCModeOptionCTR_BE"
}
const CCKeySize:{[key:number]:string}={
    16:"kCCKeySizeAES128|kCCKeySizeMaxCAST",
    24:"kCCKeySizeAES192|kCCKeySize3DES",
    32:"kCCKeySizeAES256",
    8:"kCCKeySizeDES|kCCKeySizeMinBlowfish",
    5:"kCCKeySizeMinCAST",
    1:"kCCKeySizeMinRC4|kCCKeySizeMinRC2",
    512:"kCCKeySizeMaxRC4",
    128:"kCCKeySizeMaxRC2",
    56:"kCCKeySizeMaxBlowfish"
}
const CCHmacAlgorithm:{[key:number]:string}={
    0:"kCCHmacAlgSHA1",
    1:"kCCHmacAlgMD5",
    2:"kCCHmacAlgSHA256",
    3:"kCCHmacAlgSHA384",
    4:"kCCHmacAlgSHA512",
    5:"kCCHmacAlgSHA224",
}
const CCHmacAlgorithmLength:{[key:number]:number}={
    0:CC_SHA1_DIGEST_LENGTH,
    1:CC_MD5_DIGEST_LENGTH,
    2:CC_SHA256_DIGEST_LENGTH,
    3:CC_SHA384_DIGEST_LENGTH,
    4:CC_SHA512_DIGEST_LENGTH,
    5:CC_SHA224_DIGEST_LENGTH,
}
 
const CCPseudoRandomAlgorithm:{[key:number]:string}={
    1:"kCCPRFHmacAlgSHA1",
    2:"kCCPRFHmacAlgSHA224",
    3:"kCCPRFHmacAlgSHA256",
    4:"kCCPRFHmacAlgSHA384",
    5:"kCCPRFHmacAlgSHA512",
}
const CCPBKDFAlgorithm:{[key:number]:string}={
    2:"kCCPBKDF2"
}
 
// @ts-ignore
function print_arg(addr,len=240) {
    try {
        if(addr==null)return "\n";
        return "\n"+hexdump(addr,{length:len}) + "\n";
    } catch (e) {
        if(e instanceof Error){
            console.error("print_arg error:",e.stack);
        }
        return addr + "\n";
    }
}
function pointerToInt(ptr:NativePointer){
    try {
        if(ptr==null)return 0;
        return parseInt(ptr.toString());
    }catch (e){
        if(e instanceof Error){
            console.error("pointerToInt error:",e.stack);
        }
        return 0;
    }
}
 
//crypto
interface CCCryptorModel{
    enable:boolean,
    cRef:NativePointer,
    dataMap:{
        data:NativePointer,
        len:number
    }[],
    dataOutMap:{
        data:NativePointer,
        len:number,
    }[],
    totalLen:number,
    totalOutLen:number,
    originalLen:number,
    originalOutLen:number,
    log:string
}
function commonCryptoInterceptor() {
    function checkCryptoAlgorithmEnable(algorithm: number) {
        switch (algorithm){
            case 0:
                return CIPHER_CONFIG.crypto.aes;
            case 1:
                return CIPHER_CONFIG.crypto.des;
            case 2:
                return CIPHER_CONFIG.crypto["3des"];
            case 3:
                return CIPHER_CONFIG.crypto.cast;
            case 4:
                return CIPHER_CONFIG.crypto.rc4;
            case 5:
                return CIPHER_CONFIG.crypto.rc2;
            case 6:
                return CIPHER_CONFIG.crypto.blowfish;
            default:
                return true;
        }
    }
    //CCCryptorStatus CCCrypt(
    //  CCOperation op,         /* kCCEncrypt, etc. */
    //  CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
    //  CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
    //  const void *key,
    //  size_t keyLength,
    //  const void *iv,         /* optional initialization vector */
    //  const void *dataIn,     /* optional per op and alg */
    //  size_t dataInLength,
    //  void *dataOut,          /* data RETURNED here */
    //  size_t dataOutAvailable,
    //  size_t *dataOutMoved);
    let func=Module.findExportByName("libSystem.B.dylib","CCCrypt");
    if(func==null){
        console.error("CCCrypt func is null");
        return;
    }
    Interceptor.attach(func,
        {
            onEnter: function(args) {
                this.enable=checkCryptoAlgorithmEnable(args[1].toInt32());
                if(!this.enable)return;
                this.log="";
                this.log=this.log.concat(COLORS.green,"[*] ENTER CCCrypt",COLORS.resetColor);
                this.log=this.log.concat(COLORS.yellow,"[+] CCOperation: " + CCOperation[args[0].toInt32()],COLORS.resetColor,"\n");
                this.log=this.log.concat(COLORS.yellow,"[+] CCAlgorithm: " + CCAlgorithm[args[1].toInt32()],COLORS.resetColor,"\n");
                this.log=this.log.concat("[+] CCOptions: " + CCOptions[args[2].toInt32()],"\n");
                this.log=this.log.concat("[+] KeySize: " + CCKeySize[args[4].toInt32()],"\n");
                this.log=this.log.concat("[+] Key: \n" + print_arg(args[3],args[4].toInt32()),"\n");
                this.log=this.log.concat("[+] IV: \n" + print_arg(args[5],16),"\n");
                let dataInLength = pointerToInt(args[7]);
                let printLength=Math.min(dataInLength,CIPHER_CONFIG.crypto.maxDataLength);
                this.log=this.log.concat("[+] Data len: ",printLength,"/",dataInLength,"\n");
                this.log=this.log.concat("[+] Data : \n","\n");
                this.log=this.log.concat(print_arg(args[6],printLength));
                this.dataOut = args[8];
                this.dataOutLength = args[10];
 
            },
 
            onLeave: function(retval) {
                if(!this.enable)return;
                let dataOutLen=pointerToInt(this.dataOutLength.readPointer());
                let printOutLen=Math.min(dataOutLen,CIPHER_CONFIG.crypto.maxDataLength);
                this.log=this.log.concat("[+] Data out len: ",printOutLen,"/",dataOutLen,"\n");
                this.log=this.log.concat("[+] Data out: \n",print_arg(this.dataOut,printOutLen),"\n");
                if(CIPHER_CONFIG.crypto.printStack) {
                    this.log = this.log.concat("[+] stack:\n", Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"), "\n");
                }
                this.log=this.log.concat("[*] EXIT CCCrypt","\n");
            }
 
        });
    let cRefCache:{[key:number]:CCCryptorModel}={};
    //CCCryptorStatus CCCryptorCreate(CCOperation op, CCAlgorithm alg, CCOptions options, const void *key, size_t keyLength, const void *iv,CCCryptorRef *cryptorRef);
    let CCCryptorCreate=Module.findExportByName("libSystem.B.dylib","CCCryptorCreate");
    if(CCCryptorCreate==null){
        console.error("CCCryptorCreate func is null ")
        return;
    }
    Interceptor.attach(CCCryptorCreate,
        {
            onEnter: function(args) {
                this.cRefPtr=args[6];
                this.operation=args[0];
                this.algorithm=args[1];
                this.options=args[2];
                this.key=args[3];
                this.keyLen=args[4];
                this.iv=args[5];
            },
            onLeave:function (reval) {
                let model:CCCryptorModel={enable:checkCryptoAlgorithmEnable(this.algorithm),cRef:this.cRefPtr.readPointer(),dataMap:[],dataOutMap:[],totalLen:0,totalOutLen:0,originalLen:0,originalOutLen:0,log:""};
                cRefCache[pointerToInt(model.cRef)]=model;
                if(!model.enable)return;
                model.log=model.log.concat("[*] ENTER CCCryptorCreate","\n");
                model.log=model.log.concat("[+] CCOperation: " + CCOperation[this.operation.toInt32()],"\n");
                model.log=model.log.concat("[+] CCAlgorithm: " + CCAlgorithm[this.algorithm.toInt32()],"\n");
                model.log=model.log.concat("[+] CCOptions: " + CCOptions[this.options.toInt32()],"\n");
                model.log=model.log.concat("[+] Key len: " + CCKeySize[this.keyLen.toInt32()],"\n");
                model.log=model.log.concat("[+] Key: \n" + print_arg(this.key,pointerToInt(this.keyLen)),"\n");
                if(pointerToInt(this.iv)!=0){
                    model.log=model.log.concat("[+] Iv:\n" + print_arg(this.iv,16),"\n");
                }else {
                    model.log=model.log.concat(COLORS.red,"[!] Iv: null","\n",COLORS.resetColor);
                }
            }
        });
    //CCCryptorStatus CCCryptorCreateWithMode(
    //     CCOperation  op,             /* kCCEncrypt, kCCEncrypt */
    //     CCMode           mode,
    //     CCAlgorithm      alg,
    //     CCPadding        padding,
    //     const void       *iv,            /* optional initialization vector */
    //     const void       *key,           /* raw key material */
    //     size_t           keyLength,
    //     const void       *tweak,         /* raw tweak material */  //for mode: XTS
    //     size_t           tweakLength,
    //     int              numRounds,      /* 0 == default */
    //     CCModeOptions    options,
    //     CCCryptorRef *cryptorRef)    /* RETURNED */
    let CCCryptorCreateWithMode=Module.findExportByName("libSystem.B.dylib","CCCryptorCreateWithMode");
    if(CCCryptorCreateWithMode==null){
        console.error("CCCryptorCreateWithMode func is null ")
        return;
    }
    Interceptor.attach(CCCryptorCreateWithMode,
        {
            onEnter: function(args) {
                this.cRefPtr=args[11];
                this.operation=args[0];
                this.mode=args[1];
                this.algorithm=args[2];
                this.padding=args[3];
                this.iv=args[4];
                this.key=args[5];
                this.keyLen=args[6];
                this.tweak=args[7];
                this.tweakLen=args[8];
                this.numRounds=args[9];
                this.options=args[10];
 
            },
            onLeave:function (reval) {
                let model:CCCryptorModel={enable:checkCryptoAlgorithmEnable(this.algorithm),cRef:this.cRefPtr.readPointer(),dataMap:[],dataOutMap:[],totalLen:0,totalOutLen:0,originalLen:0,originalOutLen:0,log:""};
                cRefCache[pointerToInt(model.cRef)]=model;
                if(!model.enable)return;
                model.log=model.log.concat("[*] ENTER CCCryptorCreateWithMode","\n");
                model.log=model.log.concat("[+] CCOperation: " + CCOperation[this.operation.toInt32()],"\n");
                model.log=model.log.concat("[+] CCMode: " + CCMode[this.mode.toInt32()],"\n");
                model.log=model.log.concat("[+] CCAlgorithm: " + CCAlgorithm[this.algorithm.toInt32()],"\n");
                model.log=model.log.concat("[+] CCPadding: " + CCPadding[this.padding.toInt32()],"\n");
                model.log=model.log.concat("[+] CCModeOptions: " + CCModeOptions[this.options.toInt32()],"\n");
                let tweakLen=this.tweakLen.toInt32();
                if(tweakLen>0&&pointerToInt(this.tweak)!=0){
                    model.log=model.log.concat("[+] tweak len: " + tweakLen,"\n");
                    model.log=model.log.concat("[+] tweak: \n" + print_arg(this.tweak,pointerToInt(this.tweakLen)),"\n");
                }
                model.log=model.log.concat("[+] numRounds: " + this.numRounds.toInt32(),"\n");
                model.log=model.log.concat("[+] Key len: " + CCKeySize[this.keyLen.toInt32()],"\n");
                model.log=model.log.concat("[+] Key: \n" + print_arg(this.key,pointerToInt(this.keyLen)),"\n");
                if(pointerToInt(this.iv)!=0){
                    model.log=model.log.concat("[+] Iv:\n" + print_arg(this.iv,16),"\n");
                }else {
                    model.log=model.log.concat(COLORS.red,"[!] Iv: null","\n",COLORS.resetColor);
                }
            }
        });
 
    //CCCryptorStatus CCCryptorUpdate(CCCryptorRef cryptorRef, const void *dataIn,size_t dataInLength, void *dataOut, size_t dataOutAvailable,size_t *dataOutMoved);
    let CCCryptorUpdate=Module.findExportByName("libSystem.B.dylib","CCCryptorUpdate");
    if(CCCryptorUpdate==null){
        console.error("CCCryptorUpdate func is null");
        return;
    }
    Interceptor.attach(CCCryptorUpdate,
        {
            onEnter: function(args) {
                this.outLen = args[5];
                this.out = args[3];
                this.cRef=args[0];
                this.dataLen=args[2];
                this.data=args[1];
            },
 
            onLeave: function(retval) {
                let model:CCCryptorModel=cRefCache[pointerToInt(this.cRef)];
                if(model==null){
                    console.error("CCCryptorUpdate model is null");
                    return;
                }
                if(!model.enable)return;
                model.originalLen+=this.dataLen;
                model.originalOutLen+=this.outLen;
                let remainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalLen;
                let dataLen = pointerToInt(this.dataLen);
                if(dataLen>0&&remainingSpace>0){
                    let copyLength = Math.min(dataLen, remainingSpace);
                    let tmpData=Memory.alloc(copyLength);
                    Memory.copy(tmpData,this.data,copyLength);
                    model.dataMap.push({data:tmpData,len:copyLength})
                    model.totalLen+=copyLength;
                }
                let outRemainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalOutLen;
                let outLen=pointerToInt(this.outLen.readPointer());
                if(outLen>0&&outRemainingSpace>0){
                    let copyLength = Math.min(outLen, outRemainingSpace);
                    let tmpDataOut=Memory.alloc(copyLength);
                    Memory.copy(tmpDataOut,this.out,copyLength);
                    model.dataOutMap.push({data:tmpDataOut,len:copyLength});
                    model.totalOutLen+=copyLength;
                }
            }
 
        });
    //CCCryptorStatus CCCryptorFinal(CCCryptorRef cryptorRef, void *dataOut,size_t dataOutAvailable, size_t *dataOutMoved);
    let CCCryptorFinal=Module.findExportByName("libSystem.B.dylib","CCCryptorFinal");
    if(CCCryptorFinal==null){
        console.error("CCCryptorFinal func is null");
        return;
    }
    Interceptor.attach(CCCryptorFinal,
        {
            onEnter: function(args) {
                this.cRef=args[0];
                this.dataOut=args[1];
                this.dataOutLen=args[3];
            },
            onLeave: function(retval) {
                let model:CCCryptorModel=cRefCache[pointerToInt(this.cRef)];
                if(model==null){
                    console.error("CCCryptorFinal model is null");
                    return;
                }
                if(!model.enable)return;
                model.originalOutLen+=this.dataOutLen;
                if(model.totalOutLen<CIPHER_CONFIG.crypto.maxDataLength){
                    let outRemainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalOutLen;
                    let outLen=pointerToInt(this.dataOutLen.readPointer());
                    if(outLen>0&&outRemainingSpace>0){
                        let copyLength=Math.min(outLen,outRemainingSpace);
                        let tmpDataOut=Memory.alloc(copyLength);
                        Memory.copy(tmpDataOut,this.dataOut,copyLength);
                        model.dataOutMap.push({data:tmpDataOut,len:copyLength});
                        model.totalOutLen+=copyLength;
                    }
                }
                let totalData=Memory.alloc(model.totalLen);
                var offset=0;
                model.dataMap.forEach(function (value){
                    Memory.copy(totalData.add(offset),value.data,value.len)
                    offset+=value.len;
                });
                let totalOutData=Memory.alloc(model.totalOutLen);
                var offsetOut=0;
                model.dataOutMap.forEach(function (value){
                    Memory.copy(totalOutData.add(offsetOut),value.data,value.len)
                    offsetOut+=value.len;
                });
                model.log=model.log.concat("[+] Data len: "+model.totalLen+"/"+model.originalLen+"\n");
                model.log=model.log.concat("[+] Data : \n",print_arg(totalData,model.totalLen),"\n");
                model.log=model.log.concat("[+] Data out len: "+model.totalOutLen+"/"+model.originalOutLen+"\n");
                model.log=model.log.concat("[+] Data out: \n",print_arg(totalOutData,model.totalOutLen),"\n");
                if(CIPHER_CONFIG.crypto.printStack){
                    model.log=model.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
                }
                model.log=model.log.concat("[*] EXIT CCCryptorFinal ","\n");
                console.log(model.log);
            }
 
        });
 
}
 
 
//hash
interface CCHashModel{
    ctx:NativePointer,
    dataMap:{
        data:NativePointer,
        len:number }[],
    totalLen:number,
    originalLen:number,
    log:string
}
 
function commonHashInterceptor(name:string, length:number){
    let hash=Module.findExportByName("libSystem.B.dylib",name);
    if(hash==null){
        console.error(name+" func is null");
        return;
    }
    Interceptor.attach(hash,{
        onEnter:function (args){
            this.log="";
            this.log=this.log.concat("[*] ENTER ",name,"\n");
            let dataLen=args[1].toInt32();
            let printLen=Math.min(dataLen,CIPHER_CONFIG.hash.maxInputDataLength);
            this.log=this.log.concat("[+] Data len:",printLen,"/",dataLen,"\n");
            this.log=this.log.concat("[+] Data: \n",print_arg(args[0],printLen),"\n")
 
        },
        onLeave:function (reval){
            this.log=this.log.concat(COLORS.green,"[+] Data out len: "+length,COLORS.resetColor,"\n");
            this.log=this.log.concat(COLORS.green,"[+] Data out:\n",print_arg(reval,length),COLORS.resetColor,"\n");
            if(CIPHER_CONFIG.hash.printStack){
                this.log=this.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
            }
            this.log=this.log.concat("[*] EXIT",name,"\n");
            console.log(this.log);
        }
    });
    (function (){
        let ctxCache :{[key:number]:CCHashModel}={}
        //CC_SHA1_Init(CC_SHA1_CTX *c);
        let init=Module.findExportByName("libSystem.B.dylib",name+"_Init");
        if (init==null){
            console.error(name+"_Init func is null")
            return;
        }
        Interceptor.attach(init,
            {
                onEnter: function(args) {
                    let model={ctx:args[0],dataMap:[],totalLen:0,originalLen:0,log:""};
                    ctxCache[pointerToInt(args[0])]=model;
                    model.log=model.log.concat("[*] ENTER "+name+"_Init\n");
                }
            });
 
        //CC_SHA1_Update(CC_SHA1_CTX *c, const void *data, CC_LONG len);
        let update=Module.findExportByName("libSystem.B.dylib",name+"_Update");
        if(update==null){
            console.error(name+"_Update func is null");
            return;
        }
        Interceptor.attach(update,
            {
                onEnter: function(args) {
                    let model=ctxCache[pointerToInt(args[0])];
                    if(model==null){
                        console.error("model is null");
                        return;
                    }
                    let len=pointerToInt(args[2]);
                    let remainingSpace=CIPHER_CONFIG.hash.maxInputDataLength-model.totalLen;
                    if(len>0&&remainingSpace>0){
                        model.originalLen+=len;
                        let copyLen=Math.min(len,remainingSpace);
                        let tmpData=Memory.alloc(copyLen);
                        Memory.copy(tmpData,args[1],copyLen);
                        model.dataMap.push({data:tmpData,len:copyLen});
                        model.totalLen+=copyLen;
                    }
 
                }
            });
 
        //CC_SHA1_Final(unsigned char *md, CC_SHA1_CTX *c);
        let final=Module.findExportByName("libSystem.B.dylib",name+"_Final");
        if(final==null){
            console.error(name+"_Final func is null");
            return;
        }
        Interceptor.attach(final,
            {
                onEnter: function(args) {
                    this.mdSha = args[0];
                    this.ctxSha = args[1];
                },
                onLeave: function(retval) {
                    let model=ctxCache[pointerToInt(this.ctxSha)];
                    if(model==null){
                        console.error(name+"_Final model is null");
                        return;
                    }
                    if(model.totalLen<=0){
                        console.error("totalLen :",model.totalLen);
                        return;
                    }
                    let totalData=Memory.alloc(model.totalLen);
                    var offset=0;
                    model.dataMap.forEach(function (value){
                        Memory.copy(totalData.add(offset),value.data,value.len)
                        offset+=value.len;
                    });
                    model.log=model.log.concat("[+] Data len: "+model.totalLen+"/"+model.originalLen+"\n");
                    model.log=model.log.concat("[+] Data :\n");
                    model.log=model.log.concat(print_arg(totalData,model.totalLen),"\n");
 
                    if(pointerToInt(this.mdSha) !== 0) {
                        model.log=model.log.concat(COLORS.green,"[+] Data out len: "+length+"\n");
                        model.log=model.log.concat("[+] Data out:\n");
                        model.log=model.log.concat(print_arg(ptr(this.mdSha),length),"\n",COLORS.resetColor);
                    } else {
                        model.log=model.log.concat(COLORS.red,"[!]: Data out: null\n",COLORS.resetColor);
                    }
                    if(CIPHER_CONFIG.hash.printStack){
                        model.log=model.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
                    }
                    model.log=model.log.concat("[*] EXIT "+name+"_Final"+"\n");
 
                    console.log(model.log);
                }
            });
    })();
}
 
//hmac
 
interface CCHMacModel extends CCHashModel{
    mdLen:number,
    enable:boolean,
}
function commonHMACInterceptor(){
    function checkHMACAlgorithmEnable(algorithm: number) {
        switch (algorithm){
            case 0:
                return CIPHER_CONFIG.hmac.sha1;
            case 1:
                return CIPHER_CONFIG.hmac.md5;
            case 2:
                return CIPHER_CONFIG.hmac.sha256;
            case 3:
                return CIPHER_CONFIG.hmac.sha384;
            case 4:
                return CIPHER_CONFIG.hmac.sha512;
            case 5:
                return CIPHER_CONFIG.hmac.sha224;
            default:
                return true;
        }
    }
    let name="CCHmac";
    //void CCHmac(CCHmacAlgorithm algorithm, const void *key, size_t keyLength,const void *data, size_t dataLength, void *macOut);
    let hmac=Module.findExportByName("libSystem.B.dylib",name);
    if(hmac==null){
        console.error(name+" func is null");
        return;
    }
    Interceptor.attach(hmac,{
        onEnter:function (args){
            this.enable=checkHMACAlgorithmEnable(args[0].toInt32());
            if(!this.enable)return;
            this.mdLen=CCHmacAlgorithmLength[args[0].toInt32()];
            this.log="";
            this.log=this.log.concat("[*] ENTER ",name,"\n");
            this.log=this.log.concat(COLORS.yellow,"[+] Algorithm: ",CCHmacAlgorithm[args[0].toInt32()],"\n",COLORS.resetColor);
            this.log=this.log.concat("[+] Key len: ",args[2].toInt32(),"\n");
            this.log=this.log.concat(COLORS.green,"[+] Key : \n",print_arg(args[1],args[2].toInt32()),"\n",COLORS.resetColor);
 
            let dataLen=args[4].toInt32();
            let printLen=Math.min(dataLen,CIPHER_CONFIG.hmac.maxInputDataLength);
            this.log=this.log.concat("[+] Data len:",printLen,"/",dataLen,"\n");
            this.log=this.log.concat("[+] Data: \n",print_arg(args[3],printLen),"\n")
            this.macOut=args[5];
        },
        onLeave:function (reval){
            if(!this.enable)return;
            this.log=this.log.concat("[+] Data out len: "+this.mdLen,"\n");
            this.log=this.log.concat(COLORS.green,"[+] Data out:\n",print_arg(reval,this.mdLen),COLORS.resetColor,"\n");
            if(CIPHER_CONFIG.hmac.printStack){
                this.log=this.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
            }
            this.log=this.log.concat("[*] EXIT",name,"\n");
            console.log(this.log);
        }
    });
    (function (){
        let ctxCache :{[key:number]:CCHMacModel}={}
        //void
        //      CCHmacInit(CCHmacContext *ctx, CCHmacAlgorithm algorithm,
        //          const void *key, size_t keyLength);
        let init=Module.findExportByName("libSystem.B.dylib",name+"Init");
        if(init==null){
            console.error(name+"Init func is null");
            return;
        }
        Interceptor.attach(init,
            {
                onEnter: function(args) {
                    let model={ctx:args[0],dataMap:[],totalLen:0,originalLen:0,log:"",mdLen:CCHmacAlgorithmLength[args[1].toInt32()],enable:checkHMACAlgorithmEnable(args[1].toInt32())};
                    ctxCache[pointerToInt(args[0])]=model;
                    if(!model.enable)return;
                    model.log=model.log.concat("[*] ENTER "+name+"Init\n");
                    model.log=model.log.concat(COLORS.yellow,"[+] Algorithm: "+CCHmacAlgorithm[args[1].toInt32()]+"\n",COLORS.resetColor);
                    model.log=model.log.concat("[+] Key len: "+args[3].toInt32()+"\n");
                    model.log=model.log.concat(COLORS.green,"[+] Key: \n"+print_arg(args[2],pointerToInt(args[3]))+"\n",COLORS.resetColor);
                }
            });
 
        //void
        //      CCHmacUpdate(CCHmacContext *ctx, const void *data, size_t dataLength);
        let update=Module.findExportByName("libSystem.B.dylib",name+"Update");
        if(update==null){
            console.error(name+"Update func is null");
            return;
        }
        Interceptor.attach(update,
            {
                onEnter: function(args) {
                    let model=ctxCache[pointerToInt(args[0])];
                    if(model==null){
                        console.error(name+"Update model is null");
                        return;
                    }
                    if(!model.enable)return;
                    let len=pointerToInt(args[2]);
                    let remainingSpace=CIPHER_CONFIG.hmac.maxInputDataLength-model.totalLen;
                    if(len>0&&remainingSpace>0){
                        model.originalLen+=len;
                        let copyLen=Math.min(len,remainingSpace);
                        let tmpData=Memory.alloc(copyLen);
                        Memory.copy(tmpData,args[1],copyLen);
                        model.dataMap.push({data:tmpData,len:copyLen});
                        model.totalLen+=copyLen;
                    }
 
                }
            });
 
        //void
        //      CCHmacFinal(CCHmacContext *ctx, void *macOut);
        let final=Module.findExportByName("libSystem.B.dylib",name+"Final");
        if(final==null){
            console.error(name+"Final func is null");
            return;
        }
        Interceptor.attach(final,
            {
                onEnter: function(args) {
                    this.mdOut = args[1];
                    this.ctx = args[0];
                },
                onLeave: function(retval) {
                    let model=ctxCache[pointerToInt(this.ctx)];
                    if(model==null){
                        console.error(name+"Final model is null");
                        return;
                    }
                    if(!model.enable)return;
                    if(model.totalLen<=0){
                        console.error("totalLen :",model.totalLen);
                        return;
                    }
                    let totalData=Memory.alloc(model.totalLen);
                    var offset=0;
                    model.dataMap.forEach(function (value){
                        Memory.copy(totalData.add(offset),value.data,value.len)
                        offset+=value.len;
                    });
                    model.log=model.log.concat("[+] Data len: "+model.totalLen+"/"+model.originalLen+"\n");
                    model.log=model.log.concat("[+] Data :\n");
                    model.log=model.log.concat(print_arg(totalData,model.totalLen),"\n");
 
                    model.log=model.log.concat("[+] Data out len: "+model.mdLen+"\n");
                    model.log=model.log.concat(COLORS.green,"[+] Data out:\n");
                    model.log=model.log.concat(print_arg(ptr(this.mdOut),model.mdLen),COLORS.resetColor,"\n");
                    if(CIPHER_CONFIG.hmac.printStack){
                        model.log=model.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
                    }
                    model.log=model.log.concat("[*] EXIT "+name+"Final"+"\n");
 
                    console.log(model.log);
                }
            });
    })();
}
 
//pbkdf
function commonPBKDFInterceptor(){
    //int
    // CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
    //                       const uint8_t *salt, size_t saltLen,
    //                       CCPseudoRandomAlgorithm prf, uint rounds,
    //                       uint8_t *derivedKey, size_t derivedKeyLen)
    let CCKeyDerivationPBKDF=Module.findExportByName("libSystem.B.dylib","CCKeyDerivationPBKDF");
    if(CCKeyDerivationPBKDF==null){
        console.error("CCKeyDerivationPBKDF func is null");
        return;
    }
    Interceptor.attach(CCKeyDerivationPBKDF,{
        onEnter:function (args){
            this.derivedKey=args[7];
            this.derivedKeyLen=args[8];
            this.log="";
            this.log=this.log.concat("[*] ENTER CCKeyDerivationPBKDF","\n");
            this.log=this.log.concat(COLORS.yellow,"[+] Algorithm: ",CCPBKDFAlgorithm[args[0].toInt32()],"\n",COLORS.resetColor);
            this.log=this.log.concat(COLORS.yellow,"[+] PseudoRandomAlgorithm: ",CCPseudoRandomAlgorithm[args[5].toInt32()],"\n",COLORS.resetColor);
            this.log=this.log.concat(COLORS.yellow,"[+] Rounds: ",pointerToInt(args[6]),"\n",COLORS.resetColor);
            this.log=this.log.concat("[+] Password len: ",args[2].toInt32(),"\n");
            this.log=this.log.concat(COLORS.green,"[+] Password : \n",print_arg(args[1],args[2].toInt32()),"\n",COLORS.resetColor);
            this.log=this.log.concat("[+] Salt len: ",args[4].toInt32(),"\n");
            this.log=this.log.concat(COLORS.green,"[+] Salt : \n",print_arg(args[3],args[4].toInt32()),"\n",COLORS.resetColor);
            this.log=this.log.concat("[+] DerivedKey len: ",args[8].toInt32(),"\n");
        },
        onLeave:function (reval){
            this.log=this.log.concat(COLORS.green,"[+] DerivedKey : \n",print_arg(this.derivedKey,this.derivedKey.toInt32()),"\n",COLORS.resetColor);
            if(CIPHER_CONFIG.pbkdf.printStack){
                this.log=this.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
            }
            this.log=this.log.concat("[*] EXIT CCKeyDerivationPBKDF","\n");
            console.log(this.log);
        }
    });
    //uint
    // CCCalibratePBKDF(CCPBKDFAlgorithm algorithm, size_t passwordLen, size_t saltLen,
    //                  CCPseudoRandomAlgorithm prf, size_t derivedKeyLen, uint32_t msec)
    let CCCalibratePBKDF=Module.findExportByName("libSystem.B.dylib","CCCalibratePBKDF");
    if(CCCalibratePBKDF==null){
        console.error("CCCalibratePBKDF func is null");
        return;
    }
    Interceptor.attach(CCCalibratePBKDF,{
        onEnter:function (args){
            this.log="";
            this.log=this.log.concat("[*] ENTER CCCalibratePBKDF","\n");
            this.log=this.log.concat(COLORS.yellow,"[+] Algorithm: ",CCPBKDFAlgorithm[args[0].toInt32()],"\n",COLORS.resetColor);
            this.log=this.log.concat(COLORS.yellow,"[+] PseudoRandomAlgorithm: ",CCPseudoRandomAlgorithm[args[3].toInt32()],"\n",COLORS.resetColor);
            this.log=this.log.concat("[+] Password len: ",args[1].toInt32(),"\n");
            this.log=this.log.concat("[+] Salt len: ",args[2].toInt32(),"\n");
            this.log=this.log.concat("[+] DerivedKey len: ",args[4].toInt32(),"\n");
            this.log=this.log.concat("[+] Msec : ",pointerToInt(args[5]),"\n");
        },
        onLeave:function (reval){
            this.log=this.log.concat("[+] IterNum : \n",pointerToInt(reval),"\n");
            if(CIPHER_CONFIG.pbkdf.printStack){
                this.log=this.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
            }
            this.log=this.log.concat("[*] EXIT CCCalibratePBKDF","\n");
            console.log(this.log);
        }
    });
}
 
//start
(function (){
    if(!CIPHER_CONFIG.enable){
        return
    }
    if(CIPHER_CONFIG.crypto.enable){
        commonCryptoInterceptor();
    }
    if(CIPHER_CONFIG.hash.enable){
        if(CIPHER_CONFIG.hash.sha1){
            //extern unsigned char *CC_SHA1(const void *data, CC_LONG len, unsigned char *md)
            commonHashInterceptor("CC_SHA1",20);
        }
        if(CIPHER_CONFIG.hash.sha224){
            //extern unsigned char *CC_SHA224(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_SHA224",28);
        }
        if(CIPHER_CONFIG.hash.sha256){
            //extern unsigned char *CC_SHA256(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_SHA256",32);
        }
        if(CIPHER_CONFIG.hash.sha384){
            //extern unsigned char *CC_SHA384(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_SHA384",48);
        }
        if(CIPHER_CONFIG.hash.sha512){
            //extern unsigned char *CC_SHA512(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_SHA512",64);
        }
        if(CIPHER_CONFIG.hash.md2){
            //extern unsigned char *CC_MD2(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_MD2",16);
        }
        if(CIPHER_CONFIG.hash.md4){
            //extern unsigned char *CC_MD4(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_MD4",16);
        }
        if(CIPHER_CONFIG.hash.md5){
            //extern unsigned char *CC_MD5(const void *data, CC_LONG len, unsigned char *md);
            commonHashInterceptor("CC_MD5",16);
        }
        if(CIPHER_CONFIG.hmac.enable){
            commonHMACInterceptor();
        }
        if(CIPHER_CONFIG.pbkdf.enable){
            commonPBKDFInterceptor();
        }
 
    }
})();
/*************************************************************************************
 * Name: frida-ios-cipher
 * OS: iOS
 * Author: @humenger
 * Source: https://github.com/humenger/frida-ios-cipher
 * Desc: Intercept all cryptography-related functions on iOS with Frida Api.
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_MD5.3cc.html#//apple_ref/doc/man/3cc/CC_MD5
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CC_SHA.3cc.html#//apple_ref/doc/man/3cc/CC_SHA
 * refs:https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/CCCryptor.3cc.html#//apple_ref/doc/man/3cc/CCCryptor
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/CommonCrypto/CommonKeyDerivation.h.auto.html
 * refs:https://www.cnblogs.com/cocoajin/p/6150203.html
 * refs:https://frida.re/docs/javascript-api/
 * refs:https://codeshare.frida.re/@xperylab/cccrypt-dump/
 * refs:https://github.com/federicodotta/Brida
 * refs:https://github.com/sensepost/objection/blob/master/agent/src/ios/crypto.ts
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60118.200.6/lib/CommonCryptor.c.auto.html
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60026/CommonCrypto/CommonCryptor.h.auto.html
 * refs:https://www.jianshu.com/p/8896ed432dff
 * refs:https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60118.200.6/lib/
 * refs:https://blog.csdn.net/q187543/article/details/103920969
 **************************************************************************************/
//config
const CIPHER_CONFIG={
    "enable":true,//global enable
    "crypto":{
        "enable":true,//crypto enable
        "maxDataLength":240,//Maximum length of single data printout
        "printStack":false,
        "aes":true,
        "des":true,
        "3des":true,
        "cast":true,
        "rc4":true,
        "rc2":true,
        "blowfish":true,
    },
    "hash":{
        "enable":true,//hash enable
        "maxInputDataLength":240,
        "printStack":false,
        "md2":true,
        "md4":true,
        "md5":true,
        "sha1":true,
        "sha224":true,
        "sha256":true,
        "sha384":true,
        "sha512":true
    },
    "hmac":{
        "enable":true,//hmac enable
        "maxInputDataLength":240,
        "printStack":false,
        "sha1":true,
        "md5":true,
        "sha224":true,
        "sha256":true,
        "sha384":true,
        "sha512":true,
    },
    "pbkdf":{
        "enable":true,
        "printStack":false,
    }
}
 
 
 
//common
const COLORS = {
    "resetColor": "\x1b[0m",
    "green": "\x1b[32m",
    "yellow": "\x1b[33m",
    "red": "\x1b[31m"
};
const CC_MD2_DIGEST_LENGTH = 16
const CC_MD4_DIGEST_LENGTH = 16
const CC_MD5_DIGEST_LENGTH = 16
const CC_SHA1_DIGEST_LENGTH=20;
const CC_SHA224_DIGEST_LENGTH=28;
const CC_SHA256_DIGEST_LENGTH=32;
const CC_SHA384_DIGEST_LENGTH=48;
const CC_SHA512_DIGEST_LENGTH=64;
 
const CCOperation:{[key:number]:string}={
    0:"kCCEncrypt",
    1:"kCCEncrypt",
};
const CCAlgorithm:{[key:number]:string}={
    0:"kCCAlgorithmAES128",
    1:"kCCAlgorithmDES",
    2:"kCCAlgorithm3DES",
    3:"kCCAlgorithmCAST",
    4:"kCCAlgorithmRC4",
    5:"kCCAlgorithmRC2",
    6:"kCCAlgorithmBlowfish"
};
 
const CCOptions:{[key:number]:string}={
    1:"kCCOptionPKCS7Padding",
    2:"kCCOptionECBMode"
};
const CCMode:{[key:number]:string}={
    1:"kCCModeECB",
    2:"kCCModeCBC",
    3:"kCCModeCFB",
    4:"kCCModeCTR",
    5:"kCCModeF8", // Unimplemented for now (not included)
    6:"kCCModeLRW", // Unimplemented for now (not included)
    7:"kCCModeOFB",
    8:"kCCModeXTS",
    9:"kCCModeRC4",
    10:"kCCModeCFB8",
}
const CCPadding:{[key:number]:string}={
    0:"ccNoPadding",
    1:"ccPKCS7Padding",
}
const CCModeOptions:{[key:number]:string}={
    0x0001:"kCCModeOptionCTR_LE",
    0x0002:"kCCModeOptionCTR_BE"
}
const CCKeySize:{[key:number]:string}={
    16:"kCCKeySizeAES128|kCCKeySizeMaxCAST",
    24:"kCCKeySizeAES192|kCCKeySize3DES",
    32:"kCCKeySizeAES256",
    8:"kCCKeySizeDES|kCCKeySizeMinBlowfish",
    5:"kCCKeySizeMinCAST",
    1:"kCCKeySizeMinRC4|kCCKeySizeMinRC2",
    512:"kCCKeySizeMaxRC4",
    128:"kCCKeySizeMaxRC2",
    56:"kCCKeySizeMaxBlowfish"
}
const CCHmacAlgorithm:{[key:number]:string}={
    0:"kCCHmacAlgSHA1",
    1:"kCCHmacAlgMD5",
    2:"kCCHmacAlgSHA256",
    3:"kCCHmacAlgSHA384",
    4:"kCCHmacAlgSHA512",
    5:"kCCHmacAlgSHA224",
}
const CCHmacAlgorithmLength:{[key:number]:number}={
    0:CC_SHA1_DIGEST_LENGTH,
    1:CC_MD5_DIGEST_LENGTH,
    2:CC_SHA256_DIGEST_LENGTH,
    3:CC_SHA384_DIGEST_LENGTH,
    4:CC_SHA512_DIGEST_LENGTH,
    5:CC_SHA224_DIGEST_LENGTH,
}
 
const CCPseudoRandomAlgorithm:{[key:number]:string}={
    1:"kCCPRFHmacAlgSHA1",
    2:"kCCPRFHmacAlgSHA224",
    3:"kCCPRFHmacAlgSHA256",
    4:"kCCPRFHmacAlgSHA384",
    5:"kCCPRFHmacAlgSHA512",
}
const CCPBKDFAlgorithm:{[key:number]:string}={
    2:"kCCPBKDF2"
}
 
// @ts-ignore
function print_arg(addr,len=240) {
    try {
        if(addr==null)return "\n";
        return "\n"+hexdump(addr,{length:len}) + "\n";
    } catch (e) {
        if(e instanceof Error){
            console.error("print_arg error:",e.stack);
        }
        return addr + "\n";
    }
}
function pointerToInt(ptr:NativePointer){
    try {
        if(ptr==null)return 0;
        return parseInt(ptr.toString());
    }catch (e){
        if(e instanceof Error){
            console.error("pointerToInt error:",e.stack);
        }
        return 0;
    }
}
 
//crypto
interface CCCryptorModel{
    enable:boolean,
    cRef:NativePointer,
    dataMap:{
        data:NativePointer,
        len:number
    }[],
    dataOutMap:{
        data:NativePointer,
        len:number,
    }[],
    totalLen:number,
    totalOutLen:number,
    originalLen:number,
    originalOutLen:number,
    log:string
}
function commonCryptoInterceptor() {
    function checkCryptoAlgorithmEnable(algorithm: number) {
        switch (algorithm){
            case 0:
                return CIPHER_CONFIG.crypto.aes;
            case 1:
                return CIPHER_CONFIG.crypto.des;
            case 2:
                return CIPHER_CONFIG.crypto["3des"];
            case 3:
                return CIPHER_CONFIG.crypto.cast;
            case 4:
                return CIPHER_CONFIG.crypto.rc4;
            case 5:
                return CIPHER_CONFIG.crypto.rc2;
            case 6:
                return CIPHER_CONFIG.crypto.blowfish;
            default:
                return true;
        }
    }
    //CCCryptorStatus CCCrypt(
    //  CCOperation op,         /* kCCEncrypt, etc. */
    //  CCAlgorithm alg,        /* kCCAlgorithmAES128, etc. */
    //  CCOptions options,      /* kCCOptionPKCS7Padding, etc. */
    //  const void *key,
    //  size_t keyLength,
    //  const void *iv,         /* optional initialization vector */
    //  const void *dataIn,     /* optional per op and alg */
    //  size_t dataInLength,
    //  void *dataOut,          /* data RETURNED here */
    //  size_t dataOutAvailable,
    //  size_t *dataOutMoved);
    let func=Module.findExportByName("libSystem.B.dylib","CCCrypt");
    if(func==null){
        console.error("CCCrypt func is null");
        return;
    }
    Interceptor.attach(func,
        {
            onEnter: function(args) {
                this.enable=checkCryptoAlgorithmEnable(args[1].toInt32());
                if(!this.enable)return;
                this.log="";
                this.log=this.log.concat(COLORS.green,"[*] ENTER CCCrypt",COLORS.resetColor);
                this.log=this.log.concat(COLORS.yellow,"[+] CCOperation: " + CCOperation[args[0].toInt32()],COLORS.resetColor,"\n");
                this.log=this.log.concat(COLORS.yellow,"[+] CCAlgorithm: " + CCAlgorithm[args[1].toInt32()],COLORS.resetColor,"\n");
                this.log=this.log.concat("[+] CCOptions: " + CCOptions[args[2].toInt32()],"\n");
                this.log=this.log.concat("[+] KeySize: " + CCKeySize[args[4].toInt32()],"\n");
                this.log=this.log.concat("[+] Key: \n" + print_arg(args[3],args[4].toInt32()),"\n");
                this.log=this.log.concat("[+] IV: \n" + print_arg(args[5],16),"\n");
                let dataInLength = pointerToInt(args[7]);
                let printLength=Math.min(dataInLength,CIPHER_CONFIG.crypto.maxDataLength);
                this.log=this.log.concat("[+] Data len: ",printLength,"/",dataInLength,"\n");
                this.log=this.log.concat("[+] Data : \n","\n");
                this.log=this.log.concat(print_arg(args[6],printLength));
                this.dataOut = args[8];
                this.dataOutLength = args[10];
 
            },
 
            onLeave: function(retval) {
                if(!this.enable)return;
                let dataOutLen=pointerToInt(this.dataOutLength.readPointer());
                let printOutLen=Math.min(dataOutLen,CIPHER_CONFIG.crypto.maxDataLength);
                this.log=this.log.concat("[+] Data out len: ",printOutLen,"/",dataOutLen,"\n");
                this.log=this.log.concat("[+] Data out: \n",print_arg(this.dataOut,printOutLen),"\n");
                if(CIPHER_CONFIG.crypto.printStack) {
                    this.log = this.log.concat("[+] stack:\n", Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"), "\n");
                }
                this.log=this.log.concat("[*] EXIT CCCrypt","\n");
            }
 
        });
    let cRefCache:{[key:number]:CCCryptorModel}={};
    //CCCryptorStatus CCCryptorCreate(CCOperation op, CCAlgorithm alg, CCOptions options, const void *key, size_t keyLength, const void *iv,CCCryptorRef *cryptorRef);
    let CCCryptorCreate=Module.findExportByName("libSystem.B.dylib","CCCryptorCreate");
    if(CCCryptorCreate==null){
        console.error("CCCryptorCreate func is null ")
        return;
    }
    Interceptor.attach(CCCryptorCreate,
        {
            onEnter: function(args) {
                this.cRefPtr=args[6];
                this.operation=args[0];
                this.algorithm=args[1];
                this.options=args[2];
                this.key=args[3];
                this.keyLen=args[4];
                this.iv=args[5];
            },
            onLeave:function (reval) {
                let model:CCCryptorModel={enable:checkCryptoAlgorithmEnable(this.algorithm),cRef:this.cRefPtr.readPointer(),dataMap:[],dataOutMap:[],totalLen:0,totalOutLen:0,originalLen:0,originalOutLen:0,log:""};
                cRefCache[pointerToInt(model.cRef)]=model;
                if(!model.enable)return;
                model.log=model.log.concat("[*] ENTER CCCryptorCreate","\n");
                model.log=model.log.concat("[+] CCOperation: " + CCOperation[this.operation.toInt32()],"\n");
                model.log=model.log.concat("[+] CCAlgorithm: " + CCAlgorithm[this.algorithm.toInt32()],"\n");
                model.log=model.log.concat("[+] CCOptions: " + CCOptions[this.options.toInt32()],"\n");
                model.log=model.log.concat("[+] Key len: " + CCKeySize[this.keyLen.toInt32()],"\n");
                model.log=model.log.concat("[+] Key: \n" + print_arg(this.key,pointerToInt(this.keyLen)),"\n");
                if(pointerToInt(this.iv)!=0){
                    model.log=model.log.concat("[+] Iv:\n" + print_arg(this.iv,16),"\n");
                }else {
                    model.log=model.log.concat(COLORS.red,"[!] Iv: null","\n",COLORS.resetColor);
                }
            }
        });
    //CCCryptorStatus CCCryptorCreateWithMode(
    //     CCOperation  op,             /* kCCEncrypt, kCCEncrypt */
    //     CCMode           mode,
    //     CCAlgorithm      alg,
    //     CCPadding        padding,
    //     const void       *iv,            /* optional initialization vector */
    //     const void       *key,           /* raw key material */
    //     size_t           keyLength,
    //     const void       *tweak,         /* raw tweak material */  //for mode: XTS
    //     size_t           tweakLength,
    //     int              numRounds,      /* 0 == default */
    //     CCModeOptions    options,
    //     CCCryptorRef *cryptorRef)    /* RETURNED */
    let CCCryptorCreateWithMode=Module.findExportByName("libSystem.B.dylib","CCCryptorCreateWithMode");
    if(CCCryptorCreateWithMode==null){
        console.error("CCCryptorCreateWithMode func is null ")
        return;
    }
    Interceptor.attach(CCCryptorCreateWithMode,
        {
            onEnter: function(args) {
                this.cRefPtr=args[11];
                this.operation=args[0];
                this.mode=args[1];
                this.algorithm=args[2];
                this.padding=args[3];
                this.iv=args[4];
                this.key=args[5];
                this.keyLen=args[6];
                this.tweak=args[7];
                this.tweakLen=args[8];
                this.numRounds=args[9];
                this.options=args[10];
 
            },
            onLeave:function (reval) {
                let model:CCCryptorModel={enable:checkCryptoAlgorithmEnable(this.algorithm),cRef:this.cRefPtr.readPointer(),dataMap:[],dataOutMap:[],totalLen:0,totalOutLen:0,originalLen:0,originalOutLen:0,log:""};
                cRefCache[pointerToInt(model.cRef)]=model;
                if(!model.enable)return;
                model.log=model.log.concat("[*] ENTER CCCryptorCreateWithMode","\n");
                model.log=model.log.concat("[+] CCOperation: " + CCOperation[this.operation.toInt32()],"\n");
                model.log=model.log.concat("[+] CCMode: " + CCMode[this.mode.toInt32()],"\n");
                model.log=model.log.concat("[+] CCAlgorithm: " + CCAlgorithm[this.algorithm.toInt32()],"\n");
                model.log=model.log.concat("[+] CCPadding: " + CCPadding[this.padding.toInt32()],"\n");
                model.log=model.log.concat("[+] CCModeOptions: " + CCModeOptions[this.options.toInt32()],"\n");
                let tweakLen=this.tweakLen.toInt32();
                if(tweakLen>0&&pointerToInt(this.tweak)!=0){
                    model.log=model.log.concat("[+] tweak len: " + tweakLen,"\n");
                    model.log=model.log.concat("[+] tweak: \n" + print_arg(this.tweak,pointerToInt(this.tweakLen)),"\n");
                }
                model.log=model.log.concat("[+] numRounds: " + this.numRounds.toInt32(),"\n");
                model.log=model.log.concat("[+] Key len: " + CCKeySize[this.keyLen.toInt32()],"\n");
                model.log=model.log.concat("[+] Key: \n" + print_arg(this.key,pointerToInt(this.keyLen)),"\n");
                if(pointerToInt(this.iv)!=0){
                    model.log=model.log.concat("[+] Iv:\n" + print_arg(this.iv,16),"\n");
                }else {
                    model.log=model.log.concat(COLORS.red,"[!] Iv: null","\n",COLORS.resetColor);
                }
            }
        });
 
    //CCCryptorStatus CCCryptorUpdate(CCCryptorRef cryptorRef, const void *dataIn,size_t dataInLength, void *dataOut, size_t dataOutAvailable,size_t *dataOutMoved);
    let CCCryptorUpdate=Module.findExportByName("libSystem.B.dylib","CCCryptorUpdate");
    if(CCCryptorUpdate==null){
        console.error("CCCryptorUpdate func is null");
        return;
    }
    Interceptor.attach(CCCryptorUpdate,
        {
            onEnter: function(args) {
                this.outLen = args[5];
                this.out = args[3];
                this.cRef=args[0];
                this.dataLen=args[2];
                this.data=args[1];
            },
 
            onLeave: function(retval) {
                let model:CCCryptorModel=cRefCache[pointerToInt(this.cRef)];
                if(model==null){
                    console.error("CCCryptorUpdate model is null");
                    return;
                }
                if(!model.enable)return;
                model.originalLen+=this.dataLen;
                model.originalOutLen+=this.outLen;
                let remainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalLen;
                let dataLen = pointerToInt(this.dataLen);
                if(dataLen>0&&remainingSpace>0){
                    let copyLength = Math.min(dataLen, remainingSpace);
                    let tmpData=Memory.alloc(copyLength);
                    Memory.copy(tmpData,this.data,copyLength);
                    model.dataMap.push({data:tmpData,len:copyLength})
                    model.totalLen+=copyLength;
                }
                let outRemainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalOutLen;
                let outLen=pointerToInt(this.outLen.readPointer());
                if(outLen>0&&outRemainingSpace>0){
                    let copyLength = Math.min(outLen, outRemainingSpace);
                    let tmpDataOut=Memory.alloc(copyLength);
                    Memory.copy(tmpDataOut,this.out,copyLength);
                    model.dataOutMap.push({data:tmpDataOut,len:copyLength});
                    model.totalOutLen+=copyLength;
                }
            }
 
        });
    //CCCryptorStatus CCCryptorFinal(CCCryptorRef cryptorRef, void *dataOut,size_t dataOutAvailable, size_t *dataOutMoved);
    let CCCryptorFinal=Module.findExportByName("libSystem.B.dylib","CCCryptorFinal");
    if(CCCryptorFinal==null){
        console.error("CCCryptorFinal func is null");
        return;
    }
    Interceptor.attach(CCCryptorFinal,
        {
            onEnter: function(args) {
                this.cRef=args[0];
                this.dataOut=args[1];
                this.dataOutLen=args[3];
            },
            onLeave: function(retval) {
                let model:CCCryptorModel=cRefCache[pointerToInt(this.cRef)];
                if(model==null){
                    console.error("CCCryptorFinal model is null");
                    return;
                }
                if(!model.enable)return;
                model.originalOutLen+=this.dataOutLen;
                if(model.totalOutLen<CIPHER_CONFIG.crypto.maxDataLength){
                    let outRemainingSpace = CIPHER_CONFIG.crypto.maxDataLength - model.totalOutLen;
                    let outLen=pointerToInt(this.dataOutLen.readPointer());
                    if(outLen>0&&outRemainingSpace>0){
                        let copyLength=Math.min(outLen,outRemainingSpace);
                        let tmpDataOut=Memory.alloc(copyLength);
                        Memory.copy(tmpDataOut,this.dataOut,copyLength);
                        model.dataOutMap.push({data:tmpDataOut,len:copyLength});
                        model.totalOutLen+=copyLength;
                    }
                }
                let totalData=Memory.alloc(model.totalLen);
                var offset=0;
                model.dataMap.forEach(function (value){
                    Memory.copy(totalData.add(offset),value.data,value.len)
                    offset+=value.len;
                });
                let totalOutData=Memory.alloc(model.totalOutLen);
                var offsetOut=0;
                model.dataOutMap.forEach(function (value){
                    Memory.copy(totalOutData.add(offsetOut),value.data,value.len)
                    offsetOut+=value.len;
                });
                model.log=model.log.concat("[+] Data len: "+model.totalLen+"/"+model.originalLen+"\n");
                model.log=model.log.concat("[+] Data : \n",print_arg(totalData,model.totalLen),"\n");
                model.log=model.log.concat("[+] Data out len: "+model.totalOutLen+"/"+model.originalOutLen+"\n");
                model.log=model.log.concat("[+] Data out: \n",print_arg(totalOutData,model.totalOutLen),"\n");
                if(CIPHER_CONFIG.crypto.printStack){
                    model.log=model.log.concat("[+] stack:\n",Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join("\n"),"\n");
                }
                model.log=model.log.concat("[*] EXIT CCCryptorFinal ","\n");
                console.log(model.log);
            }
 
        });
 
}
 
 
//hash
interface CCHashModel{
    ctx:NativePointer,
    dataMap:{

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-7-31 10:37 被逆向涉猎编辑 ,原因:
收藏
免费 4
支持
分享
最新回复 (13)
雪    币: 3907
活跃值: (5817)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
2
Objection内置就有 宝
2023-7-27 15:02
1
雪    币: 437
活跃值: (188)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
roysue Objection内置就有 宝
https://github.com/sensepost/objection/blob/master/agent/src/ios/crypto.ts 这个?目前只找到这个,若是仅是这个的话,依然在我上面所说的“都只是拦截了部分加密函数”的范围内,并且看起来还有几处小错误,对于流加密的处理好像也是分散的
2023-7-27 16:06
0
雪    币: 3907
活跃值: (5817)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
4
逆向涉猎 https://github.com/sensepost/objection/blob/master/agent/src/ios/crypto.ts 这个?目前只找到这个,若是仅是这个的话,依然在我上 ...
看来还是你的更全面 666
2023-7-27 17:00
1
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
很强
2023-8-4 09:39
1
雪    币: 187
活跃值: (182)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6

RSA的在 Security 中

var Security = Module.enumerateExportsSync("Security");
var SecKeyRawSign = undefined;
var SecKeyEncrypt = undefined;
var SecKeyDecrypt = undefined;
var SecKeyGeneratePair = undefined;
var SecKeyCreateWithData = undefined;
var SecCertificateCreateWithData = undefined;
var SecTrustCopyPublicKey = undefined;
for (var i = 0; i < Security.length; i++) {
    if (Security[i].name == "SecKeyRawSign") {
        SecKeyRawSign = Security[i].address;
        console.log("RSA签名函数 SecKeyRawSign is at " + SecKeyRawSign);
    } else if (Security[i].name == "SecKeyEncrypt") {
        SecKeyEncrypt = Security[i].address;
        console.log("RSA加密函数 SecKeyEncrypt is at " + SecKeyEncrypt);
    } else if (Security[i].name == "SecKeyDecrypt") {
        SecKeyDecrypt = Security[i].address;
        console.log("RSA解密函数 SecKeyDecrypt is at " + SecKeyDecrypt);
    } else if (Security[i].name == "SecKeyGeneratePair") {
        SecKeyGeneratePair = Security[i].address;
        console.log("RSA生成密钥函数 SecKeyGeneratePair is at " + SecKeyGeneratePair);
    } else if (Security[i].name == "SecKeyCreateWithData") {
        SecKeyCreateWithData = Security[i].address;
        console.log("RSA载入密钥函数 SecKeyCreateWithData is at " + SecKeyCreateWithData);
    } else if (Security[i].name == "SecCertificateCreateWithData") {
        SecCertificateCreateWithData = Security[i].address;
        console.log("RSA载入密钥证书 SecCertificateCreateWithData is at " + SecCertificateCreateWithData);
    } else if (Security[i].name == "SecTrustCopyPublicKey") {
        SecTrustCopyPublicKey = Security[i].address;
        console.log("RSA证书提取公钥 SecTrustCopyPublicKey is at " + SecTrustCopyPublicKey);
    }
};
最后于 2023-8-14 11:14 被酷伯编辑 ,原因:
2023-8-14 11:11
0
雪    币: 32
活跃值: (140)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
还有ecdh之类的常见加密木有
2023-11-28 08:03
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
能将加密后的结果输出吗
2024-6-10 21:22
0
雪    币: 100
活跃值: (165)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
怎么看加密原文和加密后的明文啊。我在你的dis社区里面提问没人回答呢。
2024-7-20 11:24
0
雪    币: 437
活跃值: (188)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
mb_nujmhtke 能将加密后的结果输出吗
有输出的呀
2024-8-1 18:30
0
雪    币: 437
活跃值: (188)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
牛牛很牛 怎么看加密原文和加密后的明文啊。我在你的dis社区里面提问没人回答呢。
可以看下上面效果预览,Data字段下面就是原文,Data out就是加/解密后的输出
2024-8-1 18:37
0
雪    币: 2280
活跃值: (3823)
能力值: ( LV6,RANK:81 )
在线值:
发帖
回帖
粉丝
12
牛批啊
2024-10-31 14:57
0
雪    币: 4460
活跃值: (6706)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
不来个android的大市场,期待
2024-10-31 16:18
0
雪    币: 565
活跃值: (3024)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
2024-11-6 21:52
0
游客
登录 | 注册 方可回帖
返回
//