I am trying to learn how to hook into the browser memory. The Frida tool is a good start to this. My goal is to extract the client-random, server-random and symmetric session keys established at the end of a TLS handshake. By setting the SSLKEYLOGFILE environment I can extract the client-random and the master key, however it does not output the server-random key.

After going through the source code for Firefox, this can be fixed easily by printing out the server-random key in the function static void ssl3_RecordKeyLog(sslSocket *ss) at <firefox src/security/nss/lib/ssl/ssl3conn.c>

However, this is not a viable solution in my project as it makes deploy-ability poor, i.e. compiling Firefox every time there is a new update is generally not good practice to make changes to browser code and redistribute it.

Is there a better way to do this? More specifically, are any of these two options viable? I do not have much knowledge on the architecture of the browser.

  • A. Using native C++ calls in a Firefox extension to call this function/any function from the file src/security/nss/lib/ssl/ssl3conn.c.

  • B. Use a browser hook to call my own code every time this function is called in the browser.

Context: Using the three value of server random, client random and master secret, I want to generate the keyblock which is further used to generate encryption keys used in a TLS session.

I am aware wireshark has this feature, and with minimal change I can output the keys, but I would not like to use wireshark as it is would consume more resources on the host computer for a simple process like key generation.

I can write my own libpcap code to parse through traffic, but I would like to keep this as the last option.

  • Is this just for fun? Dec 24, 2016 at 12:48
  • Not really. It is one of the ways I could have taken in a project Iwas working on
    – user124499
    Dec 25, 2016 at 15:13
  • 2
    @AbhimanyuKhanna Be aware that the Client Hello Random, Server Hello Random and Master Secret are not always sufficient to calculate the session keys. With the TLS Extended Master Secret extension you need to hash the full handshake. And with the upcoming TLS 1.3 you are given the client/server traffic secrets (which is sufficient to derive decryption keys).
    – Lekensteyn
    Jan 9, 2017 at 10:46
  • Will you be publishing the project afterward or is it for personal use?
    – J.A.K.
    Jan 9, 2017 at 19:38

1 Answer 1


You may want to try this with frida:

import frida
import sys

session = frida.attach("firefox.exe")
script = session.create_script("""
"use strict";
const PR_Read = Module.findExportByName("nss3.dll", "PR_Read");

Interceptor.attach(PR_Read, {
    onEnter: function (args) {
        let length = args[2].toInt32();
        let buffer = Memory.readByteArray(args[1], length - 1);


Note that I haven't tried this code, but as you seem to have managed to get the client-random and the master key, with PR_Write (which is what firefox outputs), you probably will get the server random with PR_Read (which is what the server responds).


How I found that:

  • looked at the page you linked.
  • found that the way to get what firefox output is using PR_Write
  • looked at what the function is on MDN
  • guessed that if there's a write, there might be a read
  • searched PR_Read on MDN
  • found it has the same signature as PR_Write
  • replaced PR_Write with PR_Read
  • if the signature was different, I might have had to change some more things around (like the args[])
  • Might I know what is wrong with my answer? I don't bite.
    – satibel
    Jan 16, 2017 at 6:21
  • 1
    Hi satibel - I also haven't tested the code, but your answer seems reasonable to me, so I am not sure why the downvotes. Maybe people tested it and it didn't work?
    – Rory Alsop
    Feb 14, 2017 at 15:05

You must log in to answer this question.