Last month, an Enterprise customer reached out to report that a 3rd-party browser extension they use wasn’t working properly. Investigation of the extension revealed that the browser extension relied upon a NativeMessaging Host (NMH) companion that runs outside of the browser’s sandbox. In reviewing a Process Monitor log provided by the customer, the Support Engineer and I observed that the Native Host executable was unexpectedly exiting tens of minutes after it started. After that unexpected exit, the next time the in-browser extension tried to call it, the browser-to-native call failed, and the browser extension was unable to provide its intended functionality.
Unfortunately, I don’t have either the source (or even the binary) for the NMH executable, and there are no obvious clues in the Process Monitor log (e.g. a failed registry read or write) that reveal the underlying problem. I lamented to the Support Engineer that I really wished we could see the JSON messages being exchanged between the browser extension and the NMH to see if they might reveal the root cause.
How Hard Could It Be?
Technically, I don’t really own anything related to browser extensions, so after ruling out what few possible problems I could imagine as root causes, I moved on to other tasks.
But that vision stuck with me throughout the day and the evening that followed: Fiddler, but for Native Messaging.
How hard could it be to build that? How useful would it be?
I haven’t written much C# code since leaving Fiddler and Telerik at the end of 2015, and the few exceptions (e.g. the NetLog Importer) have mostly been plugins to Fiddler rather than standalone applications. Still, Native Messaging is far less complicated than HTTPS, so it shouldn’t be too hard, right?
We want the following features in a debugger:
- Show messages from any Browser Extension to any Native Host
- Enable logging these messages to a file
- Allow injecting arbitrary messages in either direction
- (Stretch goal) Allow modification of messages
Over the following few evenings, I dusted off my Visual Studio IDE and struggled to remember how C# async programming works in modern times (Fiddler’s implementation was heavily threaded and mostly predated more modern alternatives).
Introducing the NativeMessaging Meddler
The source and (soon) compiled code for the NativeMessaging Meddler can be downloaded from GitHub.
The NativeMessaging Meddler (NMM) is a Windows application that requires .NET 4.8. A line of tabs across the bottom enables you to switch between tabs; by default, running the
.exe directly just shows help text:
The NMM tool can respond to NativeMessages from a browser extension itself, or it can proxy messages between an existing extension and an existing NMH executable.
Configure the Demo
To test the basic functionality of the tool, you can install the Demo Extension.
about://extensionsin Chrome or Edge
- Enable the Developer Mode toggle
- Push the Load Unpacked button
- Select the
- A new “N” icon appears in the toolbar
After the demo extension is installed, you must now register the demo Native Host app. To do so, update its manifest to reflect where you placed it:
- Open the
manifest.jsonfile using Notepad or a similar editor
- Set the
pathfield to the full path to the .exe. Be sure that every backslash is doubled up.
- Set the
allowed_originsfield to contain the ID value of the extension from the
Next, update the registry so that the browser can find your Host:
- Edit the
InstallRegKeys.regfile in Notepad, updating the file path to point to the location of the
manifest.jsonfile. Be sure that each backslash is doubled up.
- Double-click the
InstallRegKeys.regfile to import it to the registry.
Run the Demo
With both the host and extension installed, you can now test out the tool. Click the “N” icon from the extension in the toolbar to navigate to its demo page. An instance of the NMM should automatically open.
Hello world! in the Outgoing Messages box and click Post Message to port. The message should appear on the Monitor tab inside the NMM app:
If you tick the Reflect to extension option at the top right and then send the message again, you should see the NMM tool receive the message and then send it back to the extension page, where it’s shown in the Incoming Messages section:
What if we want to inject a new message of our choosing from NMM?
Go to the Injector tab in NMM and type a simple JSON message in the bottom box. Then click the Send to Browser/Extension button. You’ll see the message appear inside the browser in the Incoming Messages section:
At this point, we’ve now successfully used the NMM tool to receive and send messages from our Demo extension.
While our demo is nice for testing out Native Messaging, and it might help as a mock if we’re developing a new extension that uses Native Messaging, the point of this exercise is to spy on communications with an existing extension and host.
Let’s do that.
First, go to the Configure Hosts tab, which grovels the registry to find all of the currently-registered Native Hosts on your PC:
The plan is to eventually make intercepting any Native Host a point-and-click experience, but for now, we’re just using this tab to find the file system location of the Native Host we wish to intercept. If an entry appears multiple times, pick the instance with the lowest Priority score.
For example, say we’re interested in the
BrowserCore Host which is used in some Windows-to-Web authentication scenarios in Chrome. We see the location of the manifest file, as well as the name of the EXE extracted from the manifest file:
In some cases, you might find that the
Exe field shows
Note the location of the manifest file and open it in your editor of choice. Note: If the file is in a privileged location, you may need to open your editor elevated (as Administrator).
Within the manifest, change the
path field by introducing the word
.proxy before the
.exe at the end of the filename:
Save the file.
Note: In some cases, not even an Administrator will be able to write the file by default. In such cases, you’ll need to use Administrator permissions to take ownership of the file to grant yourself permission to modify it:
There are other approaches that do not require changing filesystem permissions, but we won’t cover those here.
Next, copy the
nmf-view.exe file into the folder containing the Native Host and rename it to the filename you wrote to the manifest:
At this point, you’ve successfully installed the NMM proxy. Whenever the browser extension next tries to launch the Native Host, it will instead activate our NMM debugger, which will in turn spawn the original Native Host (in this example,
BrowserCore.exe) and proxy all messages between the two.
Now, visit a site where you can log in, like
https://office.microsoft.com. Click the login button at the top-right and observe that our debugger spawns, collects a request from the Windows 10 Accounts extension, passes it to
BrowserCore.exe, reads the Host’s reply, and passes that back to the extension. Our debugger allows us to read the full text of the JSON messages in both directions:
Pretty neat, huh?
Tampering with Messages
When I got all of this working, I was excited. But I was also disappointed… plaintext rendering of JSON isn’t super readable, and building a UI to edit messages was going to be a ton of extra work. I lamented sheesh… I already wrote all of the code I want fifteen years ago for Fiddler. It has both JSON rendering and message editing… and I briefly bemoaned the fact that I no longer own Fiddler and can’t just copy the source over.
And then I had the epiphany. I don’t need to reimplement parts of Fiddler in NMM. The tools can simply work together! NMM can pass the messages it receives from the Browser Extension and Native Host up to Fiddler as they’re received, and if Fiddler modifies the message, NMM can substitute the modified message.
First, re-edit the
manifest.json file to add a
.fiddler component to the path, and rename the
.proxy.exe file to
.proxy.fiddler.exe, like so:
This new text signals that you want NMM to start with the
Tamper using Fiddler option set. To debug “single-shot” Native Hosts like
BrowserCore.exe, we can’t simply use the checkbox at the top-right of NMM’s Monitor tab, because the debugger and Native Host spawn and complete their transaction much faster than we puny humans can click the mouse. Note: You can also specify the string
.log. to enable the option that writes the traffic log to your Desktop.
Now, start Fiddler, perhaps using the
-noattach command line argument so that it does not register as the system proxy. Type
bpu ToApp in the QuickExec box beneath the Web Sessions list and hit Enter.
This creates a request breakpoint which will fire for all requests whose urls contain the string
ToApp, which NMM uses to record requests sent to the original Native Host:
Using Fiddler’s Inspectors, we can examine the JSON of the message using the JSON treeview, or the TextView or SyntaxView Inspectors:
If we are satisfied with the message, click the Run to Completion button, and our NMM app will send the original, unmodified message to the original Native Host. However, if we want to tamper with the message, instead pick a success response like
200_SimpleHTML.dat from the dropdown:
A template response will appear in the Response TextView:
Overwrite that template text with the modified text you’d like to use instead:
… then push the green
Run to Completion button. Fiddler will return the modified text to the NMM proxy, and the NMM proxy will then pass that modified message to the original Native Host:
In this case, the original Native Host doesn’t know what to do with the
GetFiddledCookies request and returns an error which is passed back to the browser.
Tip: If your goal is to instead tamper with messages sent from the Native Host to the extension, enter
bpu ToExt in Fiddler’s QuickExec box. Alternatively, you can also use any of Fiddler’s richer tampering features, such that it breaks only on messages containing certain text, automatically rewrites certain messages, etc.