While trying to perform the patch diff outlined in Maddie Stone’s talk “What’s Up with WhatsApp” with Ghidra, I encountered multiple problems, but in the end managed to recreate the patch diffing process with Ghidra.

The problems and solutions outlined hopefully help others to get better patch diffs via Ghidra’s Version Tracking.

tl;dr:

  1. Always run the Precondition Checklist.
  2. Ghidra’s Version Tracking is not yet feature complete.
  3. Patch diffing without symbols is hard.
  4. The quality of Version Tracking depends highly on good pre-analysis.

Intro

@maddiestone forgot to include Ghidra in her patch diff comparison:

https://twitter.com/maddiestone/status/1182749408703721472

https://twitter.com/maddiestone/status/1182749408703721472

I therefore patch diff the CVE-2019-3568 patch in Ghidra.

Samples

Project layout with libraries loaded

Project layout with libraries loaded

For those that haven’t read @maddiestone’s slides, she is talking about two vulnerable functions she refers to as:

Analysis

Analysis

Analysis

Ghidra detects some functions as non-returning that are actually returning and hence breaks disassembly, I disabled Non-Returning Functions - Discovered analyzer:

Non-Returning Functions - Discovered analyzer disabled

Non-Returning Functions - Discovered analyzer disabled

I previously ran the analysis with this analyzer active and it caused the Source and Destination Programs to have different number of non-returning functions. Ghidra’s Version Tracking Precondition Checklist will check for these and warn you. So always run the Precondition Checklist!!!

Specifically the issue manifests because Ghidra stops disassembly after a non-returning function. But it only detected non-returning functions in one of the programs:

Non-returning Issue

Non-returning Issue

Version Tracking Session

New Version Tracking Session

New Version Tracking Session

During the wizard you can run some Precondition Checks. These make sure that the enough of the binaries has been analyzed and also performs some sanity checks, e.g., comparing the number of non-returning functions and reporting discrepancies. You should always run these and fix all errors and investigate any warnings.

Precondition Checklist

Precondition Checklist

In this case I got one warning because the libraries had a different amount of errors during analysis:

Precondition Checklist Reporting 1 Warning

Precondition Checklist Reporting 1 Warning

If you want pristine results you are encouraged to fix as many warnings as you can.

Run Correlators

In the new Version Tracking Session you need to add, i.e., run Correlators. These Correlators compare the Source and Destination Programs and find matches, e.g., the Exact Function Bytes Match Correlator finds matches between functions that have the exact same bytes pattern.

Ghidra’s Automatic Version Tracking Command runs the included Correlators in there supposed order, accepting matches along the way, but keeping false matches to a minimum.

Automatic Version Tracking

Automatic Version Tracking

After running the Automatic Version Tracking Command, while the Size Check #1 was matched, it was not automatically accepted:

Match for Size Check #1 Function

Match for Size Check #1 Function

Size Check #2 was not even matched at all:

Match for Size Check #2 Function

Match for Size Check #2 Function

However, I decided to run the Function Reference Match Correlator, even though, at least according to the manual, the Combined Function and Data Reference Match Correlator, should already include that correlator:

Adding the Function Reference Match Correlator

Adding the Function Reference Match Correlator

After this Size Check #2 was matched via the Function Reference Match Correlator:

Match for Size Check #2 Function

Match for Size Check #2 Function

I then manually accepted the Size Check #1 and #2 functions.

Diffing

Ghidra does not offer a graph diff view.

The Decompile View in the Function Comparison Window also does not highlight the changes. The two Compile Views simply scroll with their lines being synced (via their line numbers!).

So the only included way to compare changes is via the Listing View:

Listing View Diff of Size Check #1 Functions

Listing View Diff of Size Check #1 Functions

Listing View Diff of Size Check #2 Functions

Listing View Diff of Size Check #2 Functions

It becomes quickly apparent that comparing patches via the Listing View is less clear than a graph diff view.

Ghetto-tech Graph Diff View

As a workaround, I colored changed basic blocks between the functions to provide a ghetto-tech graph diff view:

Ghetto-tech Graph Diff View of Size Check #1 Source Function

Ghetto-tech Graph Diff View of Size Check #1 Source Function

Ghetto-tech Graph Diff View of Size Check #1 Destination Function

Ghetto-tech Graph Diff View of Size Check #1 Destination Function


Ghetto-tech Graph Diff View of Size Check #2 Source Function

Ghetto-tech Graph Diff View of Size Check #2 Source Function

Ghetto-tech Graph Diff View of Size Check #2 Destination Function

Ghetto-tech Graph Diff View of Size Check #2 Destination Function



If you want to know more about the particularities of the CVE-2019-3568 patch and how to exploit the vulnerability see Maddie’s slides.

Comparison

So in the end, you can make Ghidra match the two vulnerable functions. However, if you would not know what the functions are you are trying to attack it would be very hard to find them because (for unknown reasons) Ghidra seems to have issues with ARM disassembly resulting in actually near identical functions having seemingly large changes. For example:

Function with large changes because only one program disassembly follows the b.w branch.

Function with large changes because only one program disassembly follows the b.w branch.

So you are going to hunt ghost differences that boil down to Ghidra producing different disassembly for basically unchanged functions.

Maybe this can be controlled (like the non-returning function issues) by an analyzer settings. If you know, please, let me know!

CVE-2015-8126

I previously wrote an article about patch diffing CVE-2015-8126.

It can literally be done by running one correlator of my PatchDiffCorrelator project (there is even video proof).

It is super easy compared to this. So if you want to try Ghidra Version Tracking for patch diffing I recommend trying to follow that article.

rdpcorets.dll from CVE-2019-1326 update

The same ease of diffing can be exhibited for Windows patches. For example, I again ran one of my correlators on the rdpcorets.dll from the CVE-2019-1326 update and immediately received the following results:

SMSecurityExchangeInfo() is the only changed function (with a symbol name)

SMSecurityExchangeInfo() is the only changed function (with a symbol name)

Because the function was matched by name, I can confidently examine the changes more closely knowing that the match is accurate. Also SMSecurityExchangeInfo is the only function with a symbol that has changes.1

On the case of libwhatsapp.so I won’t be sure whether I’m looking at Ghidra disassembly differences, a mismatch between functions, or a real change.

That and the fact that the CVE-2019-3568 patch includes more changes makes it harder to patch diff without at least basic knowledge of libwhatsapp.so beforehand.

Resume

Ghidra’s Version Tracking isn’t perfect.

But it can deliver results.

These results mostly depend on the quality of the pre-analysis. Hence it is crucial to properly analyze the candidate programs and fix and disassembly errors.

I am fully aware that I did not fix any disassembly errors and some issues I was seeing could very be related to those errors. I wasn’t really interested in this patch anyway, just wanted to see whether Ghidra could handle the diffing, so I wasn’t willing to manually fix 66 + 77 = 143 errors. I provided everything you need to recreate this. If you do and you get better results by fixing all errors, please, tell me!


Do you like to see a real Graph Diff View in Ghidra? Then voice your support for this feature request.





  1. This is just a random example. I haven’t fully examined CVE-2019-1326, hence don’t know if the change in SMSecurityExchangeInfo is even interesting.