Reverse Engineering Techniques • Windows

Malware Binary Diffing with Ghidra & BinDiff: Comparing Conti and LockBit Green

Compare Conti and LockBit Green binaries using Ghidra and BinDiff to identify shared code, cryptographic overlaps, and architectural differences.

In this article I want to explain how to perform code comparison and actually walk you through an approach to identify the similarities and difference between code and two executables.

We’ll be comparing a Conti version 3 sample with a lock bit green sample.

In malware to explore the similarities and differences between them can help you identify different version of malware families now obviously you could upload a sample to virus total or another online service in order to understand the overlap with known malware families.

But there certainly are cases you may not want to provide information or the file itself to any other organization and so we’re going to assume that our comparison is going to happen in a local isolated environment.

There are few common ways to compare code between executables.

1.Call graph - A call graph represents the relationships between functions in a program, where each node corresponds to a function and each directed edge represents a function call. Rather than comparing individual instructions, this approach analyzes the overall structure of the binary.
call-graph.png
Figure: call-graph.png Click to zoom ↗
2.Control Flow Graph (CFG) Comparison - A Control Flow Graph (CFG) models the execution flow within an individual function. Each node represents a basic block, while edges represent possible execution paths. Unlike call graph comparison, CFG comparison focuses on the internal logic of a function, making it highly effective for detecting modifications to algorithms, encryption routines, and validation logic.
cfg.png
Figure: cfg.png Click to zoom ↗

In addition to call graphs and cfgs you could also compare the individual instructions in a basic block now performing any of these code comparisons is difficult and time consuming.

Thankfully programs like bindiff can help us out you can download bindiff from:

https://www.zynamics.com/software.html

As mentioned We will be comparing a Conti ransomware sample with a lockbit green sample.

SAMPLE 1 - Conti Ransomware

SAMPLE 2 - Lockbit Green

For the purpose of binary comparison we will use bindiff with ghidra we are going to take advantage of Binexport which is available on Github:

https://github.com/google/binexport

Binexport is a plug-in or extension that exports data from a supported disassembler like ghidra in the format that bindiff requires to perform it’s comparison. The documentation on ghidra tells us how to install this extension.

Next we need to process both the conti and lockbit green samples just as we would any other executable that we are loading in ghidra.

When ghidra prompts me to analyze this file I definitely want to click yes.

Screenshot 2026-07-12 at 11.25.01 PM.png
Figure: Screenshot 2026-07-12 at 11.25.01 PM.png Click to zoom ↗

Choose this option WindowsPE x86 Propagate External Parameters and press Analyze.

Screenshot 2026-07-12 at 11.26.26 PM.png
Figure: Screenshot 2026-07-12 at 11.26.26 PM.png Click to zoom ↗

While this is being processed. Go ahead and pull in the lockbit green sample as well.

Once Ghidra has completed it’s analysis of these two files we’ll go ahead and close them down and save the results .

Next we want to use binexport extension to actually export the related data necessary to perform the diff.

I’ll choose conti first.

right click and in this context menu I’ll choose Export option.

Screenshot 2026-07-12 at 11.33.24 PM.png
Figure: Screenshot 2026-07-12 at 11.33.24 PM.png Click to zoom ↗

Within export you’ll want to if it hasn’t been selected click on this pull down and choose Binary Binexport . and click OK.

Screenshot 2026-07-12 at 11.37.46 PM.png
Figure: Screenshot 2026-07-12 at 11.37.46 PM.png Click to zoom ↗

Click OK on the exports result summary.

Similarly for lock bit green.

Screenshot 2026-07-12 at 11.39.54 PM.png
Figure: Screenshot 2026-07-12 at 11.39.54 PM.png Click to zoom ↗

You’ll notice I now have my lockbit green and conti.exe Bin export files.

Screenshot 2026-07-12 at 11.41.18 PM.png
Figure: Screenshot 2026-07-12 at 11.41.18 PM.png Click to zoom ↗

Next Let’s launch BinDiff.

Create a new workspace.

Then go to right hand side panel right click —> NewDiff

Screenshot 2026-07-12 at 11.44.14 PM.png
Figure: Screenshot 2026-07-12 at 11.44.14 PM.png Click to zoom ↗

For the primary file choose the conti bin export file. And for the secondary file choose the lockbit green export file.

Screenshot 2026-07-12 at 11.45.41 PM.png
Figure: Screenshot 2026-07-12 at 11.45.41 PM.png Click to zoom ↗

Now click Diff It will start performing the binary comparison to take a look at the results on the top left click conti.exe vs lockbitgreen.exe .

Screenshot 2026-07-12 at 11.48.25 PM.png
Figure: Screenshot 2026-07-12 at 11.48.25 PM.png Click to zoom ↗

Now this is a comparison at the highest level describing how the Conti sample and the lockbit sample compare to one another.

The left hand side we have an overall functions percentage of 85.7% and on the right hand side a similarity value of 0.91 or 91%

Screenshot 2026-07-12 at 11.49.51 PM.png
Figure: Screenshot 2026-07-12 at 11.49.51 PM.png Click to zoom ↗

I tend to focus more on the functions percentage so let me just spend a moment what that really means.

BinDiff

1.png
Figure: 1.png Click to zoom ↗
CategoryFunctionsPercentage
Matched Functions63685.7%
Modified / Partial Matches7910.6%
Unmatched Functions273.6%
Total74299.9%*

BinDiff found 636 pairs of Functions meaning one in conti and one on lockbit that it believes do match in some way.

It also found 27 functions on the conti sample that it did not find a match for within lockbit green.

Similarly it found 79 functions in lockbit green that it did not find a match for in Conti.

So if you add up 636 + 79 + 27 = 742

and that is the overall number that all of these percentages are based off 85.7% does seem to indicate that these programs are quite similar. But let’s dig deeper.

In order to do that I can double click conti.exe vs lockbitgreen.exe in the left hand side and this opens four different views or ways to identifies these similarities and differences between these two programs.

Screenshot 2026-07-13 at 12.12.49 AM.png
Figure: Screenshot 2026-07-13 at 12.12.49 AM.png Click to zoom ↗

Call Graph

First we have the call graph view and this does include the functions percentage of 85.7% as well as the similarity value of 0.91. Now there are some other breakdowns here in some values.

Screenshot 2026-07-13 at 12.13.52 AM.png
Figure: Screenshot 2026-07-13 at 12.13.52 AM.png Click to zoom ↗

Matched Functions

Next one is matched functions. These are functions that bindiff decided are a match between lockbit green and conti.

So each of these matches bindiff lists a similarity between 0 and 1 and a confidence value between 0 and 1.

Screenshot 2026-07-13 at 12.16.54 AM.png
Figure: Screenshot 2026-07-13 at 12.16.54 AM.png Click to zoom ↗

Sort by descending confidence.

Single click on the Confidence column. and you’ll see that each of the rows here has an address and a primary name as well as an address and a secondary name.

Screenshot 2026-07-13 at 12.22.02 AM.png
Figure: Screenshot 2026-07-13 at 12.22.02 AM.png Click to zoom ↗

Okay so the addresses correspond with the locations of the functions that it believes do match and then the actual names associated with each of those functions in the primary file which again is the conti sample and the secondary file which is the lockbit green sample.

In terms of the colors the green tones generally indicates functions that have a closer similarity to one another and a higher confidence while the yellow and red tones indicates that the functions are less similar with a lower confidence.

Functions that you see listed here that do in fact have a non-generic name is a result of ghidra’s FID or functions ID feature. Which basically identifies embedded Library code.

So in order to look for functions that have not been renamed I’m going to search for sub_ .

When you’re looking at a function that has not been labeled or named automatically it usually begins with an fun_ .

But BinDiff displays that as sub_ .

By searching for sub_ in this case I can look for functions that have not been named and in other words in this case I’m trying to focus on non-library functions.

Now I have a list of functions that are generally not going to be a Library code and this is where I want to focus my attention.

Screenshot 2026-07-13 at 12.35.01 AM.png
Figure: Screenshot 2026-07-13 at 12.35.01 AM.png Click to zoom ↗

Now if i were to now go ahead and double click on any of these rows. for example the first one.

BinDiff will show me a closer comparison of these functions.

Screenshot 2026-07-13 at 12.37.52 AM.png
Figure: Screenshot 2026-07-13 at 12.37.52 AM.png Click to zoom ↗

Allowing me to get into the details of the actual instructions

Now in this case i clicked into two functions that were a very close match. So I wouldn’t except to see many differences here. But this is just an example of how you can start doing the function to function comparison.

Now go back to workspace and scrolling down eventually you’ll see some other colors show up here and towards the bottom you’ll see more of those red tones. Which again indicates functions that have a lower similarity.

Screenshot 2026-07-13 at 12.43.49 AM.png
Figure: Screenshot 2026-07-13 at 12.43.49 AM.png Click to zoom ↗

Typically scroll back to the top where I have some closer matches with higher confidence. and start to dig into some of these matches. To understand if any of this overlapping code is associated with significant functionality.

Now just to show you an example here I have one row here that I’ll focus on and this is a function within the conti sample located at address 00405740 and in lockbit at 00405760 .

Screenshot 2026-07-13 at 12.48.56 AM.png
Figure: Screenshot 2026-07-13 at 12.48.56 AM.png Click to zoom ↗

I wanted to take a closer look i’ll double click.

similar to the previous scenario brings up the sid by side function now because this function is bigger and has more instructions as well as more basic blocks you can see the initial view doesn’t actually show me any individual instructions.

Screenshot 2026-07-13 at 12.52.47 AM.png
Figure: Screenshot 2026-07-13 at 12.52.47 AM.png Click to zoom ↗

But of i click and scroll with my mouse here I will get a different perspective and here I can start actually comparing some of the individual instructions.

Screenshot 2026-07-13 at 12.56.17 AM.png
Figure: Screenshot 2026-07-13 at 12.56.17 AM.png Click to zoom ↗

Now what you’ll see is a combination od add xor as well as rotate instructions. and closer examination of these instructions.

Perhaps some additional research would indicate that this is a implementation of a Cha-Cha encryption algorithm so it turns out to be the case that Conti and lockbit use the same file encryption algorithm which again is Cha-Cha.

We won’t go in deep. the point is BinDiff allows me to perform function to function comparisons and in this case would allow me to confirm that both samples use the sample file encryption.

Now go back to Work Space and choose Primary unmatched Functions .

Primary Unmatched Functions

primary unmatched functions which are functions found in the conti sample but not in the lockbit green sample.

Screenshot 2026-07-13 at 1.04.14 AM.png
Figure: Screenshot 2026-07-13 at 1.04.14 AM.png Click to zoom ↗

Similar to the search and filtering I did in the previous View.

I’m gonna search for sub_ and hit enter. allowing me to focus on non-library functions.

Screenshot 2026-07-13 at 1.06.50 AM.png
Figure: Screenshot 2026-07-13 at 1.06.50 AM.png Click to zoom ↗

The number of basic blocks is some indication of the complexity of the actual code in this function so this is something. i wanted to look.

Double click on the first. and start reviewing the actual code.

Screenshot 2026-07-13 at 1.09.42 AM.png
Figure: Screenshot 2026-07-13 at 1.09.42 AM.png Click to zoom ↗

Now in this case i do in fact see five basic blocks and most interestingly I see this green arrow here on the right.

Screenshot 2026-07-13 at 1.11.38 AM.png
Figure: Screenshot 2026-07-13 at 1.11.38 AM.png Click to zoom ↗

This indicates a loop.

I wanted to take a closer look at a function like this I would probably go ahead and bounce back to ghidra and jump to the associated address well.

If you more closely examined this function within ghidra. and perhaps supported it with a bit of debugging using x32 dbg is that this function is actually responsible for decoding strings. So it is possible that this string decoding algorithm exists only in conti and not in lockbit green. Or at least that is a theory that I clould proceed to investigate with some more analysis.

Again my goal here is to use BinDiff to introduce how you can perform this sort of binary comparison and the results should be some additional pivot points for investigations.

Next I could go back to the Workspace. and click on the Secondary Unmatched Functions .

Secondary Unmatched Functions

secondary unmatched functions are the functions found in the lockbit green sample for which BinDiff did not find a match in Conti.

Screenshot 2026-07-13 at 1.20.36 AM.png
Figure: Screenshot 2026-07-13 at 1.20.36 AM.png Click to zoom ↗

I could again filter by sub_ . To focus on non-library code.

Screenshot 2026-07-13 at 1.22.15 AM.png
Figure: Screenshot 2026-07-13 at 1.22.15 AM.png Click to zoom ↗

At this point i can perhaps sort by basic blocks.

Functions that have more basic blocks possibly indicating that they are more complex and perhaps do something a bit more significant and I’ll leave the actual investigation of individual functions in this view as an opportunity for you to perform some further analysis.

So in summary this article introduced an approach to comparing the code in two malware samples using ghidra and BinDiff.

Copied