Skip to content

Instantly share code, notes, and snippets.

@FrankSpierings
Last active December 7, 2023 10:58
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save FrankSpierings/f72a7b1004d49a141d8963954787bb2b to your computer and use it in GitHub Desktop.
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

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