반응형

- CCCrypt 란?

데이터 암/복호화에 사용되는 함수입니다.

해당 함수 후킹하여 관찰 시 암복호화 알고리즘, 비밀번호, 키값 등 앱 분석에 있어 중요한 정보들을 확인 할 수 있습니다.

함수원형은 다음과 같습니다.

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);  

 

- Where is CCCrypt imported from

후킹전에 CCCrypt 함수가 어떤 모듈로부터 import되었는지 확인이 필요합니다.

// Usage: After Attaching...
// infoImportsFunction("moduleName", /pattern/i);
// ex) infoImportsFunction("hackcatmlApp", /cccrypt/i);

Process.enumerateModulesSync()
    .filter(function(m){ return m['path'].toLowerCase().indexOf('.app') !=-1 ; })
    .forEach(function(m) {
        console.log(JSON.stringify(m, null, '  '));
        // to list exports use Module.enumerateExportsSync(m.name)
});

function infoImportsFunction(moduleName, importPattern){
    Module.enumerateImportsSync(moduleName)
    .forEach(function(m){
        if(m.name.match(importPattern)){
            console.log(JSON.stringify(m, null, ' '));
        }
    })
}

 

 

위 스크립트 실행 결과 CCCrypt 함수는 "libSystem.B.dylib" 모듈로부터 import된 것을 확인 가능합니다.

 

- Hook CCCrypt Function

CCCrypt 함수를 후킹하여 암복호화 과정에 특이사항이 있는지 확인합니다.

// libSystem.B.dylib 모듈로부터 import된 CCCrypt함수 후킹
 Interceptor.attach(Module.findExportByName('libSystem.B.dylib', 'CCCrypt'), {
   onEnter: function (args) {
       // Save the arguments
       this.operation   = args[0]
       this.CCAlgorithm = args[1]
       this.CCOptions   = args[2]
       this.keyBytes    = args[3] 
       this.keyLength   = args[4]
       this.ivBuffer    = args[5]
       this.inBuffer    = args[6] 
       this.inLength    = args[7]
       this.outBuffer   = args[8] 
       this.outLength   = args[9]
       this.outCountPtr = args[10]
       
       console.log('\n\x1b[31mCCCrypt\x1b[0m(' + 
           '\x1b[34moperation: \x1b[32m'   + this.operation    +', ' +
           '\x1b[34mCCAlgorithm: \x1b[32m' + this.CCAlgorithm  +', ' +
           '\x1b[34mCCOptions: \x1b[32m'   + this.CCOptions    +', ' +
           '\x1b[34mkeyBytes: \x1b[32m'    + this.keyBytes     +', ' +
           '\x1b[34mkeyLength: \x1b[32m'   + this.keyLength    +', ' +
           '\x1b[34mivBuffer: \x1b[32m'    + this.ivBuffer     +', ' +
           '\x1b[34minBuffer: \x1b[32m'    + this.inBuffer     +', ' +
           '\x1b[34minLength: \x1b[32m'    + this.inLength     +', ' +
           '\x1b[34moutBuffer: \x1b[32m'   + this.outBuffer    +', ' +
           '\x1b[34moutLength: \x1b[32m'   + this.outLength    +', ' +
           '\x1b[34moutCountPtr: \x1b[32m' + this.outCountPtr  +'\x1b[0m)\n')
           
       if (this.operation == 0) {
           // Show the buffers here if this an encryption operation
           console.log("\x1b[31mIn buffer: \x1b[0m") 
           console.log(hexdump(ptr(this.inBuffer), {
               length: this.inLength.toInt32(),
               header: true,
               ansi: true
           }))
           console.log("\x1b[31mKey(keyBytes): \x1b[0m")
           console.log(hexdump(ptr(this.keyBytes), {
               length: this.keyLength.toInt32(),
               header: true,
               ansi: true
           }))
           console.log("\x1b[31moutCountPtr: \x1b[0m")
           console.log(hexdump(ptr(this.outCountPtr), {
               length: 64,
               header: true,
               ansi: true
           }))
           // console.log("\x1b[31mIV: \x1b[0m")
           // console.log(hexdump(ptr(this.ivBuffer), {
           //     length: this.keyLength.toInt32(),
           //     header: true,
           //     ansi: true
           // }))
       }
   },
   onLeave: function (retVal) {
       if (this.operation == 1) {
           // Show the buffers here if this a decryption operation
           console.log("\x1b[31mOut buffer: \x1b[0m")
           console.log(hexdump(ptr(this.outBuffer), {
               length: Memory.readUInt(this.outCountPtr),
               header: true,
               ansi: true
           }))
           console.log("\x1b[31mKey(keyBytes): \x1b[0m")
           console.log(hexdump(ptr(this.keyBytes), {
               length: this.keyLength.toInt32(),
               header: true,
               ansi: true
           }))
           console.log("\x1b[31moutCountPtr: \x1b[0m")
           console.log(hexdump(ptr(this.outCountPtr), {
               length: 64,
               header: true,
               ansi: true
           }))
          // console.log("\x1b[31mIV: \x1b[0m")
          // console.log(hexdump(ptr(this.ivBuffer), {
          //     length: this.keyLength.toInt32(),
          //     header: true,
          //     ansi: true
          // }))
      }
  }
})

 

 

CCCrypt함수를 후킹하여 관찰한 결과 복호화된 4자리 PIN번호("0000") 및 복호화에 사용되는 키값 확인이 가능하였습니다.

 

※ 출처

https://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/CommonCrypto/CommonCryptor.h.auto.html

https://la0s.github.io/2018/12/07/iOS_Crypto/

 

반응형

+ Recent posts