Skip to content

Instantly share code, notes, and snippets.

@r3ggi
Last active September 27, 2023 20:09
Show Gist options
  • Save r3ggi/4e2872172e007c314a066ef4585c9287 to your computer and use it in GitHub Desktop.
Save r3ggi/4e2872172e007c314a066ef4585c9287 to your computer and use it in GitHub Desktop.
Trace SecKeyCreateEncryptedData() calls with Frida
// Native ArrayBuffer to Base64
// https://gist.github.com/jonleighton/958841
function base64ArrayBuffer(arrayBuffer) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
var bytes = new Uint8Array(arrayBuffer)
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
var a, b, c, d
var chunk
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}
// CFDataRef SecKeyCreateEncryptedData(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef plaintext, CFErrorRef _Nullable *error);
Interceptor.attach(Module.findExportByName(null, 'SecKeyCreateEncryptedData'), {
onEnter: function (args) {
console.log("\n++++++++++++++++++++++++++++++++++++++++++++++++++")
this.key = args[0]
this.algorithm = new ObjC.Object(ptr(args[1])).toString()
this.plaintextNSData = new ObjC.Object(args[2])
this.plaintext = base64ArrayBuffer(this.plaintextNSData.bytes().readByteArray(this.plaintextNSData.length()))
this.plaintextString = ObjC.classes.NSString.alloc().initWithData_encoding_(this.plaintextNSData, 4)
this.error = args[3]
console.log("SecKeyCreateEncryptedData(key: " + this.key + ", algorithm: " + this.algorithm + ", plaintext base64: " + this.plaintext + ")")
if (this.plaintextString != null) {
console.log("Plaintext as a regular string: " + this.plaintextString)
}
},
onLeave: function(retVal) {
this.returnValue = new ObjC.Object(retVal)
console.log("SecKeyCreateEncryptedData returned base64: " + base64ArrayBuffer(this.returnValue.bytes().readByteArray(this.returnValue.length())))
console.log("++++++++++++++++++++++++++++++++++++++++++++++++++")
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment