Skip to content

Instantly share code, notes, and snippets.

@FrankSpierings
Last active March 4, 2025 22:22
Show Gist options
  • Select an option

  • Save FrankSpierings/f72a7b1004d49a141d8963954787bb2b to your computer and use it in GitHub Desktop.

Select an option

Save FrankSpierings/f72a7b1004d49a141d8963954787bb2b to your computer and use it in GitHub Desktop.
Some OpenSSL hooks in Frida - Work in progress....
const utils = {
colors: {
red: function(string) {
return '\x1b[31m' + string + '\x1b[0m';
},
green: function(string) {
return '\x1b[32m' + string + '\x1b[0m';
},
blue: function(string) {
return '\x1b[34m' + string + '\x1b[0m';
},
cyan: function(string) {
return '\x1b[36m' + string + '\x1b[0m';
},
},
backtrace: function(context) {
return 'Backtrace:\n' + Thread.backtrace(context, Backtracer.FUZZY).map(DebugSymbol.fromAddress).join('\n') + '\n';
},
readstring: function(address, index) {
address = ptr(address);
if (index == undefined) {
index = 0;
}
else {
index += 1;
}
try {
var char = address.add(index).readU8();
if ((char >= 0x20) && (char <= 0x7E)) {
return this.readstring(address, index);
}
}
catch (error) {}
if (index < 4) {
return undefined;
}
return address.readUtf8String(index);
},
address_is_readable: function(address) {
address = ptr(address);
var protection = 'r--';
var ranges = Process.enumerateRanges(protection);
for (var index in ranges) {
var start = ranges[index]['base'];
var stop = start.add(ranges[index]['size']);
if ((address >= start) && (address <= stop)) {
// console.log('Range: ' + start + ' - ' + stop);
return true;
}
}
return false;
},
telescope: function(address, stack) {
address = ptr(address);
if (stack == undefined) {
stack = []
stack.push('[' + address + ']');
}
else {
stack.push(address);
}
if (this.address_is_readable(address)) {
var printable = this.readstring(address);
if (printable != undefined) {
stack.push(printable)
}
else {
try {
return this.telescope(address.readPointer(), stack);
}
catch (error) {
//Ignore
}
}
}
return stack.join(' -> ');
}
}
const openssl = {
BIO_new: function(BIO_METHOD) {
var name = "BIO_new";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'pointer', ['pointer']);
var retval = f(BIO_METHOD);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
BIO_free: function(a) {
var name = "BIO_free";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer']);
var retval = f(a);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
BIO_s_mem: function() {
var name = "BIO_s_mem";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'pointer', []);
var retval = f();
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
BIO_gets: function(b, buf, size) {
var name = "BIO_gets";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer', 'int']);
var retval = f(b, buf, size);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
EVP_PKEY_id: function(pkey) {
var name = "EVP_PKEY_id";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer']);
var retval = f(pkey);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
EVP_PKEY_get1_RSA: function(pkey) {
var name = "EVP_PKEY_get1_RSA";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'pointer', ['pointer']);
var retval = f(pkey);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
PEM_write_bio_PrivateKey: function(bp, x, enc, kstr, klen, cb, u) {
var name = "PEM_write_bio_PrivateKey";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer', 'pointer', 'pointer', 'int', 'pointer', 'pointer']);
var retval = f(bp, x, enc, kstr, klen, cb, u);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
PEM_write_bio_PUBKEY: function(bp, x) {
var name = "PEM_write_bio_PUBKEY";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer']);
var retval = f(bp, x);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
PEM_write_bio_RSAPrivateKey: function(bp, x, enc, kstr, klen, cb, u) {
var name = "PEM_write_bio_RSAPrivateKey";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer', 'pointer', 'pointer', 'int', 'pointer', 'pointer']);
var retval = f(bp, x, enc, kstr, klen, cb, u);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
PEM_write_bio_RSAPublicKey: function(bp, x) {
var name = "PEM_write_bio_RSAPublicKey";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer']);
var retval = f(bp, x);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
EVP_PKEY_print_private: function(out, pkey, indent, pctx) {
var name = "EVP_PKEY_print_private";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer', 'int', 'pointer']);
var retval = f(out, pkey, indent, pctx);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
RSA_print: function(bp, x, offset) {
var name = "RSA_print";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer', 'pointer', 'int']);
var retval = f(bp, x, offset);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
EVP_CIPHER_CTX_nid: function(ctx) {
var name = "EVP_CIPHER_CTX_nid";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'int', ['pointer']);
var retval = f(ctx);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
OBJ_nid2ln: function(n) {
var name = "OBJ_nid2ln";
var address = Module.findExportByName(null, name);
if (address) {
var f = new NativeFunction(address, 'pointer', ['int']);
var retval = f(n);
return retval;
}
else {
throw("Function '" + name + "' not found");
}
},
}
const easy = {
export_pkey: function(pkey) {
const BUFSIZE = 512;
var buffer = Memory.alloc(BUFSIZE);
var output = '';
//Create memory bio
var mem = openssl.BIO_new(openssl.BIO_s_mem());
//Export the key
openssl.EVP_PKEY_print_private(mem, pkey, 0, ptr(0));
while (openssl.BIO_gets(mem, buffer, BUFSIZE) > 0) {
output += buffer.readUtf8String();
}
if (openssl.PEM_write_bio_PUBKEY(mem, pkey) > 0) {
while (openssl.BIO_gets(mem, buffer, BUFSIZE) > 0) {
output += buffer.readUtf8String();
}
}
if (openssl.PEM_write_bio_PrivateKey(mem, pkey, ptr(0), ptr(0), 0, ptr(0), ptr(0)) > 0) {
while (openssl.BIO_gets(mem, buffer, BUFSIZE) > 0) {
output += buffer.readUtf8String();
}
}
openssl.BIO_free(mem); //Clean up
return output;
},
export_rsa: function(rsa) {
const BUFSIZE = 512;
var buffer = Memory.alloc(BUFSIZE);
var output = '';
var mem = openssl.BIO_new(openssl.BIO_s_mem());
if (rsa != ptr(0)) {
if (openssl.PEM_write_bio_RSAPublicKey(mem, rsa) > 0) {
while (openssl.BIO_gets(mem, buffer, BUFSIZE) > 0) {
output += buffer.readUtf8String();
}
}
if (openssl.PEM_write_bio_RSAPrivateKey(mem, rsa, ptr(0), ptr(0), 0, ptr(0), ptr(0)) > 0) {
while (openssl.BIO_gets(mem, buffer, BUFSIZE) > 0) {
output += buffer.readUtf8String();
}
}
}
openssl.BIO_free(mem); //Clean up
return output;
},
export_pkey_from_ctx: function(ctx) {
//This is a hack, if the structure changes, this will no longer work!
// https://github.com/openssl/openssl/blob/master/include/crypto/evp.h#L21
var pkey = ctx.add(16).readPointer();
// console.log(hexdump(ctx));
// console.log(hexdump(pkey));
return this.export_pkey(pkey);
},
evp_ciper_type_str: function(ctx) {
var pstr = openssl.OBJ_nid2ln(openssl.EVP_CIPHER_CTX_nid(ctx));
if (pstr == null){
return 'Cipher: unknown';
}
else {
return 'Cipher: ' + pstr.readUtf8String();
}
},
}
function hooks() {
(function() {
var name = 'HMAC_Init_ex';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'key=' + this.args[1] + ', ' + 'len=' + this.args[2] + ', ' + 'md=' + this.args[3] + ', ' + 'impl=' + this.args[4] + ') = ' + result);
console.log(utils.colors.cyan('Key: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[1]), {length: this.args[2].toInt32()})));
console.log(utils.colors.red(utils.backtrace(this.context)));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_PKEY_encrypt';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'out=' + this.args[1] + ', ' + 'outlen=' + this.args[2] + ', ' + 'in=' + this.args[3] + ', ' + 'inlen=' + this.args[4] + ') = ' + result);
console.log(utils.colors.red(easy.export_pkey_from_ctx(this.args[0])));
console.log(utils.colors.cyan('Buffer in: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[3]), {length: this.args[4].toInt32()})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'RSA_public_decrypt';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'flen=' + this.args[0] + ', ' + 'from=' + this.args[1] + ', ' + 'to=' + this.args[2] + ', ' + 'rsa=' + this.args[3] + ', ' + 'padding=' + this.args[4] + ') = ' + result);
console.log(utils.colors.red(easy.export_rsa(this.args[3])));
console.log(utils.colors.cyan('Buffer to: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[2]), {length: result.toInt32()})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_PKEY_keygen';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'ppkey=' + this.args[1] + ') = ' + result);
var pkey = this.args[1].readPointer();
console.log(utils.colors.red(easy.export_pkey(pkey)));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_DecryptInit_ex';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'cipher=' + this.args[1] + ', ' + 'impl=' + this.args[2] + ', ' + 'key=' + this.args[3] + ', ' + 'iv=' + this.args[4] + ') = ' + result);
console.log(utils.colors.blue(easy.evp_ciper_type_str(this.args[0])));
console.log(utils.colors.blue('Key:'));
console.log(utils.colors.blue(hexdump(this.args[3], {length: 32})));
console.log(utils.colors.blue('IV:'));
console.log(utils.colors.blue(hexdump(this.args[4], {length: 16})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_DecryptUpdate';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'out=' + this.args[1] + ', ' + 'outl=' + this.args[2] + ', ' + 'in=' + this.args[3] + ', ' + 'inl=' + this.args[4] + ') = ' + result);
console.log(utils.colors.cyan('Buffer out: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[1]), {length: this.args[2].readUInt()})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_DecryptFinal_ex';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'outm=' + this.args[1] + ', ' + 'outl=' + this.args[2] + ') = ' + result);
console.log(utils.colors.cyan('Buffer out: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[1]), {length: this.args[2].readUInt()})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_EncryptInit_ex';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'cipher=' + this.args[1] + ', ' + 'impl=' + this.args[2] + ', ' + 'key=' + this.args[3] + ', ' + 'iv=' + this.args[4] + ') = ' + result);
console.log(utils.colors.blue(easy.evp_ciper_type_str(this.args[0])));
console.log(utils.colors.blue('Key:'));
console.log(utils.colors.blue(hexdump(this.args[3], {length: 32})));
console.log(utils.colors.blue('IV:'));
console.log(utils.colors.blue(hexdump(this.args[4], {length: 16})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_EncryptUpdate';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]); this.args.push(args[3]); this.args.push(args[4]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'out=' + this.args[1] + ', ' + 'outl=' + this.args[2] + ', ' + 'in=' + this.args[3] + ', ' + 'inl=' + this.args[4] + ') = ' + result);
console.log(utils.colors.cyan('Buffer in: '));
console.log(utils.colors.cyan(hexdump(ptr(this.args[3]), {length: this.args[4].toInt32()})));
},
});
}
catch (error) {
console.error(error);
}
}
})();
(function() {
var name = 'EVP_EncryptFinal_ex';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
try {
Interceptor.attach(address, {
onEnter: function(args) {
this.args = [];
this.args.push(args[0]); this.args.push(args[1]); this.args.push(args[2]);
},
onLeave: function(result) {
console.log(name + '(' + 'ctx=' + this.args[0] + ', ' + 'out=' + this.args[1] + ', ' + 'outl=' + this.args[2] + ') = ' + result);
},
});
}
catch (error) {
console.error(error);
}
}
})();
}
function overrides() {
(function() {
var name = 'SSL_set_verify';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
Interceptor.attach(address, {
onEnter: function(args) {
this.ssl = args[0];
this.mode = args[1];
//Replace the value!
args[1] = ptr(0);
console.log(utils.colors.green('[+] Setting ' + name + ' to mode = ' + args[1]));
},
});
}
})();
(function() {
var name = 'EVP_PKEY_verify';
var address = Module.findExportByName(null, name);
if (address != null) {
console.log('[!] Hooking: ' + name + ' @ 0x' + address.toString(16));
Interceptor.attach(address, {
onLeave: function(result) {
//Replace the value!
result.replace(1);
console.log(utils.colors.green('[+] Setting ' + name + ' to result = ' + result));
}
});
}
})();
}
hooks();
overrides();
console.log(utils.colors.green('[+] Loaded'));
@visualsayed
Copy link
Copy Markdown

Hi Frank,
Thank you very much for taking time to write this excellent code.
I'm using your code to trace a tweak that connect to server using openssl and I'm wondering how can I find the location of file the app write and read from IOS device?
Any Idea?

Thanks,
Sayed

@FrankSpierings
Copy link
Copy Markdown
Author

FrankSpierings commented Jul 17, 2021 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment