HackBlue

Tools · Ghidra · 17 / 22

Ghidra: comparing two program versions

Version Tracking is the tool that lines up two programs already in your project and proposes which functions are the same. You use it to see what a rebuild or a vendor update changed. Matching functions is a reading aid. It does not patch either file.

17 min read · practice only with authorization

A session has two programs

Version Tracking is a separate tool from CodeBrowser. You launch it from the project window’s tool menu once both programs are in the project. A session names a source program and a destination program. Treat the earlier build as the source and the later build as the destination, and write that choice down, because every “added” and “removed” in your notes is relative to it. The session stores its matches in the project. The two executables are not opened for writing.

This is a different feature from the version history of a shared project. Shared-project history is a stack of check-ins of one analysis database. Version Tracking is a comparison of two analyses that began as two files. You can use both in a real engagement, and they answer different questions. History answers “what did our notes used to say?” Tracking answers “what did their code do between these two builds?”

Correlators propose. You accept.

A correlator is a matcher with one definition of “same.” Exact Function Bytes Match pairs functions whose bytes are identical, which catches the functions your one-line change did not touch. Exact Function Instructions Match is looser: the instructions line up after addresses and immediate offsets are allowed to differ, which is what a recompile often needs. A symbol-name correlator pairs functions that already share a name, useful when only one of the two files was stripped. Run the strict matchers first. Accept the pairs whose side-by-side view is obviously the same function. Each acceptance shrinks the set you still have to read.

The side-by-side window can show the Listing or the decompiler of the paired functions. Use it to confirm, not as a place to start editing bytes. When you accept a match, you can also apply markup: copy the names and comments you already earned on the old function onto the matching new function. That is a rename, carried across by the session. It is appropriate when the bodies really match. Copying a name onto a function that merely looks similar will poison the next hour.

Describe the change in one paragraph

The unmatched functions, and the accepted pairs whose bytes were not exact, are the change. Open each one. For harbor-check with a single added log line, you should find the file-opening function, or main if the line was inlined, referencing a new string and a new call, and you should find everything else matched. The paragraph you owe is ordinary language: what the new instructions do, which string they use, and which functions stayed the same. Addresses can sit in parentheses. They are not the paragraph.

A vendor update you are allowed to compare is the same shape at a larger size. Exact matches account for the quiet majority. The remaining functions are the change list you will actually read. Resist the urge to explain a function you have not opened. An unmatched function is a candidate, not a finding, until its body has been read with the same care as load_config.

Lab: one log line between two imports

Copy the source and add one visible behavior in the success path of the file-opening function, such as a puts of the literal config loaded. Build it as harbor-check-v2. Import it beside the original -O0 program, which is v1. Start a Version Tracking session with v1 as source and v2 as destination. Run the exact-bytes and exact-instructions correlators. Accept the pairs that match. Find the function that references the new literal.

Write the paragraph. Name the function, quote the new string, and say whether main’s bytes matched. Leave both executables unmodified. If you apply markup, apply it only onto functions whose bodies you accepted, and say in the notebook that the names on v2 came from v1.

Snippet
v1 source, v2 destination.
Accepted exact matches: most functions, including ones the log line did not touch.
Changed: the function that now references "config loaded".
Unmodified files: both executables. The session lives in the project.

Diagram

From two imports to a description of the change

  1. Two programs

    Import both builds into the same project. Version Tracking reads programs that are already databases. It does not open raw files on its own.

  2. Session

    Start a Version Tracking session from the project window, and choose the earlier program as the source and the later one as the destination.

  3. Correlators

    Correlators propose matches: identical bytes, identical instructions after addresses are normalized, and symbols that already share a name.

  4. Accept

    You accept the matches that are real. A side-by-side view shows the functions that moved. Your note says what changed, in ordinary language.

    Correlators to run before you invent differences
    Exact Function Bytes Match
    Exact Function Instructions Match
    A symbol-name match, for any name the two files still share
    
    Accept a match only when the side-by-side bodies agree.
    Then look at functions that stayed unmatched.
    Those are the candidates for "added" or "heavily changed."
Correlators to run before you invent differences
Exact Function Bytes Match
Exact Function Instructions Match
A symbol-name match, for any name the two files still share

Accept a match only when the side-by-side bodies agree.
Then look at functions that stayed unmatched.
Those are the candidates for "added" or "heavily changed."

Check yourself

1. You want to know which functions changed when you rebuilt harbor-check with one extra log line. What has to be true first?

2. Exact Function Bytes Match proposes a pair, and the side-by-side decompiler shows the same body. What do you do with the proposal?

3. A teammate asks you to use Version Tracking to make the old build behave like the new one. What is the tool actually for?