From 8750841207f5d9fbf5e282b1d017348afe3519de Mon Sep 17 00:00:00 2001
From: James <49045138+ghidracadabra@users.noreply.github.com>
Date: Thu, 7 Dec 2023 21:02:48 +0000
Subject: [PATCH] GP-4121 bsim tutorial updates and html
---
.../AddProgramToH2BSimDatabaseScript.java | 8 +-
.../BSim/BSimTutorial_BSim_Command_Line.html | 83 ++++++++
.../BSim/BSimTutorial_BSim_Command_Line.md | 6 +-
.../BSim/BSimTutorial_Basic_Queries.html | 200 ++++++++++++++++++
.../BSim/BSimTutorial_Basic_Queries.md | 32 +--
...imTutorial_Creating_Database_From_GUI.html | 38 ++++
.../BSim/BSimTutorial_Enabling.html | 22 ++
.../GhidraClass/BSim/BSimTutorial_Enabling.md | 2 +-
.../BSim/BSimTutorial_Evaluating_Matches.html | 135 ++++++++++++
.../BSim/BSimTutorial_Evaluating_Matches.md | 32 ++-
.../BSim/BSimTutorial_Exe_Results.html | 46 ++++
.../BSim/BSimTutorial_Exe_Results.md | 8 +-
.../BSim/BSimTutorial_Filters.html | 21 ++
.../GhidraClass/BSim/BSimTutorial_Filters.md | 10 +-
.../BSimTutorial_Ghidra_Command_Line.html | 56 +++++
.../BSim/BSimTutorial_Ghidra_Command_Line.md | 3 +-
.../GhidraClass/BSim/BSimTutorial_Intro.html | 116 ++++++++++
.../GhidraClass/BSim/BSimTutorial_Intro.md | 3 +-
.../BSim/BSimTutorial_Overview_Queries.html | 51 +++++
.../BSim/BSimTutorial_Overview_Queries.md | 14 +-
.../BSim/BSimTutorial_Scripting.html | 23 ++
.../BSim/BSimTutorial_Scripting.md | 10 +-
GhidraDocs/GhidraClass/BSim/README.html | 24 +++
GhidraDocs/GhidraClass/BSim/images/Plus2.png | Bin 0 -> 752 bytes
.../BSim/images/script_manager.png | Bin 148804 -> 118813 bytes
GhidraDocs/certification.manifest | 13 ++
26 files changed, 887 insertions(+), 69 deletions(-)
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Creating_Database_From_GUI.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.html
create mode 100755 GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.html
create mode 100755 GhidraDocs/GhidraClass/BSim/README.html
create mode 100644 GhidraDocs/GhidraClass/BSim/images/Plus2.png
diff --git a/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java b/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java
index f031634822..91ca083fc4 100644
--- a/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java
+++ b/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java
@@ -13,9 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-//Generate BSim signatures for the current program. The URL for the program is
-//created from the local storage location. These signatures are intended for the
-//in-memory database backend.
+//Generates and commits the BSim signatures for the currentProgram to the
+//selected H2 BSim database
//@category BSim
import java.io.File;
import java.io.IOException;
@@ -41,9 +40,6 @@ import ghidra.program.model.listing.FunctionManager;
import ghidra.util.MessageType;
import ghidra.util.Msg;
-//@category BSim
-//Generates and commits the BSim signatures for the currentProgram to the
-//selected H2 BSim database
public class AddProgramToH2BSimDatabaseScript extends GhidraScript {
private static final String DATABASE = "H2 Database";
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.html
new file mode 100755
index 0000000000..aef41cf5d3
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.html
@@ -0,0 +1,83 @@
+
BSim Databases from the Command Line
+
+The bsim
command-line utility, located in the support
directory of a Ghidra distribution, is used to create, populate, and manage BSim databases.
+It works for all BSim database backends.
+This utility offers a number of commands, many of which have several options.
+In this section, we cover only a small subset of the possibilities.
+
+Running bsim
with no arguments will print a detailed usage message.
+
+Generating Signature Files
+
+The first step is to create signature files from the binaries in the Ghidra project.
+Signature files are XML files which contain the BSim signatures and metadata needed by the BSim server.
+
+Important: It’s simplest to exit Ghidra before performing the next steps, because:
+
+ - The H2-backed database can only be accessed by one process at a time.
+ - In case you have the
postgres_object_files
project open in Ghidra, signature generation will fail.
+Non-shared projects are locked when open, and the lock will prevent the signature-generating process from accessing the project.
+
+
+To generate the signature files, execute the following commands in a shell (adjust as necessary for Windows).
+
+cd <ghidra_install_dir>/support
+mkdir ~/bsim_sigs
+./bsim generatesigs ghidra:/<ghidra_project_dir>/postgres_object_files bsim=file:/<database_dir>/example ~/bsim_sigs
+
+
+
+ - The
ghidra:/
argument is the local project which holds the analyzed binaries.
+Note that there is only one forward slash in the URL for a local project.
+ - The
bsim=
argument is the URL of the BSim database.
+This command does not add any signatures to the database, but it does query the database for its settings.
+
+
+Committing Signature Files
+
+Now, we commit the signatures to the BSim database with the following command (still in the support
directory).
+
+./bsim commitsigs file:/<database_dir>/example ~/bsim_sigs
+
+
+Once the signatures have been committed, start Ghidra again.
+
+Aside: Creating a Database
+
+We continue to use the database example
, so this step isn’t necessary for the exercises.
+
+However, if we hadn’t created example
using CreateH2BSimDatabaseScript.java
, we could have used the following command:
+
+./bsim createdatabase file:/<database_dir>/example medium_nosize
+
+
+ medium_nosize
is a database template.
+
+ - “medium” (vs. “large”) affects the vector index and is not relevant to H2 databases.
+ - “nosize” means that size differences for varnodes of size four bytes and above are not incorporated into the BSim features.
+ This is necessary to allow matching between 32-bit and 64-bit code.
+
+
+ - The
createdatabase
command can also be used to create a BSim database on a PostgreSQL or Elasticsearch server, provided the servers are configured and running.
+See the “BSim” entry in the Ghidra help for details.
+
+
+
+
+It’s worth a brief note about Executable Categories and Function Tags, although they are not used in any of the following exercises.
+
+A BSim database can record user-defined metadata about an executable (executable categories) or about a function (function tags).
+Categories and tags can then be used as filter elements in a BSim query.
+For example, you could restrict a BSim query to search only in executables of the category “OPEN_SOURCE” or to functions which have been tagged “COMPRESSION_FUNCTIONS”.
+
+Executable categories in BSim are implemented using program properties, and function tags in BSim correspond to function tags in Ghidra. Properties and tags both have uses in Ghidra which are independent of BSim.
+So, if we want a BSim database to record a particular category or tag, we must indicate that explicitly.
+
+For example, to inform the database that we wish to record the ORIGIN category, you would execute the command
+
+./bsim addexecategory file:/<database_dir>/example ORIGIN
+
+
+Executable categories can be added to a program using the script SetExecutableCategoryScript.java
.
+
+Next Section: Evaluating Matches and Applying Information
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.md
index a37261f94f..01b03cc887 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_BSim_Command_Line.md
@@ -10,7 +10,7 @@ Running ``bsim`` with no arguments will print a detailed usage message.
## Generating Signature Files
The first step is to create signature files from the binaries in the Ghidra project.
-Signature files are XML files which contain the BSim vectors and other metadata needed by the BSim server.
+Signature files are XML files which contain the BSim signatures and metadata needed by the BSim server.
**Important**: It's simplest to exit Ghidra before performing the next steps, because:
- The H2-backed database can only be accessed by one process at a time.
@@ -44,7 +44,7 @@ Once the signatures have been committed, start Ghidra again.
We continue to use the database ``example``, so this step isn't necessary for the exercises.
-However, if we hadn't created ``example`` using a script, we could have used the following command:
+However, if we hadn't created ``example`` using ``CreateH2BSimDatabaseScript.java``, we could have used the following command:
```bash
./bsim createdatabase file://example medium_nosize
@@ -60,7 +60,7 @@ See the "BSim" entry in the Ghidra help for details.
It's worth a brief note about Executable Categories and Function Tags, although they are not used in any of the following exercises.
-A BSim database can record user-defined metadata about an executable or about functions within an executable.
+A BSim database can record user-defined metadata about an executable (executable categories) or about a function (function tags).
Categories and tags can then be used as filter elements in a BSim query.
For example, you could restrict a BSim query to search only in executables of the category "OPEN_SOURCE" or to functions which have been tagged "COMPRESSION_FUNCTIONS".
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.html
new file mode 100755
index 0000000000..8a24ad16ec
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.html
@@ -0,0 +1,200 @@
+Basic BSim Queries
+
+In this section, we demonstrate some applications of our BSim database.
+
+Registering a BSim Database
+
+In order to query the database, you must register it with Ghidra:
+
+
+ - From The Code Browser, Select BSim -> Manage Servers.
+ - In the BSim Server Manager dialog, click the green plus
.
+ - Select the File radio button and use the chooser to select
example.mv.db
+ - Click OK
+ - Click Dismiss to close the dialog.
+
+
+How to Query a BSim Database
+
+Before presenting the exercises, we describe the general mechanics of querying a BSim database.
+
+Initiating a BSim Query
+
+There are a number of ways to initiate a BSim query, including:
+
+
+ - BSim -> Search Functions… from the Code Browser.
+ - Right-click in the Listing and select BSim -> Search Functions…
+ - Click on the BSim icon
in the Code Browser toolbar.
+
+
+For these cases, the function(s) being queried depend on the current selection.
+If there is no selection, the function containing the current address is queried.
+If there is a selection, all functions whose entry points are within the selection are queried.
+An easy way to query all functions in a program is to select all addresses with Ctrl-A
in the Listing window and then initiate a BSim query.
+
+It is also possible to initiate a BSim query from the Decompiler window.
+Simply right-click on a function name token and select BSim… to query the corresponding function.
+This action is available on the name token in the decompiled function’s signature as well as tokens corresponding to names of callees.
+
+All of these actions bring up the BSim Search Dialog.
+
+The BSim Search Dialog
+
+From the BSim Search Dialog, you can
+
+
+ - Select which BSim database to query.
+ - Set query thresholds.
+ - Bound the number of results returned for each function.
+ - Set query filters.
+
+
+
+
+Selecting a BSim Database
+
+To query a registered BSim database, select that server from the BSim Server drop-down.
+
+Setting Query Options
+
+Similarity and confidence are scores used to evaluate the relationship between two vectors.
+The respective fields in the dialog set lower bounds for these values for the matches returned by BSim.
+
+
+ - Similarity
+
+ - Formally, the similarity of a match is the cosine of the angle between the vectors.
+ - For BSim vectors, this value will always be between 0.0 and 1.0.
+ - The higher the similarity score, the closer the vectors.
+
+
+ - Confidence
+
+ - Intuitively, confidence quantifies the meatiness of a match.
+ - Shared features increase this score and differing features decrease this score.
+ - Sharing rare features contributes more to this score than sharing common features.
+ - There is no upper bound for confidence when considered over all pairs of vectors.
+ However, if you fix a vector v, the greatest possible confidence score for a comparison involving v occurs when v is compared to itself.
+ The resulting confidence value is called the self-significance of v.
+
+
+
+
+Confidence is used to judge the significance of a match.
+For example, many executables contain a function which simply returns a constant value.
+Given two executables, each with such a function, the similarity score between the corresponding BSim vectors will be 1.0.
+However, the confidence score of the match will be quite low, indicating that it is not very significant that the two executables “share” this code.
+
+In general, setting the thresholds involves a tradeoff: lower values mean that the database is more likely to return legitimate matches with significant differences, but also more likely to return matches which simply happen to share some features by chance.
+The results of a BSim query can be sorted by the similarity and/or confidence of each match, so a common practice is to set the thresholds relatively low and to examine the matches in descending sort order.
+
+The Matches per Function bound controls the number of results returned for a single function.
+Note that in large collections, certain small or common functions might have substantial numbers of identical matches.
+
+Filters are discussed in BSim Filters.
+
+
+
+Click the Search button in the dialog to perform a query.
+
+After successfully issuing a query, you will also see a Search Function(s) action (without the ellipsis) in certain contexts.
+This will perform a BSim query on the selected functions using the same parameters as the last query (skipping the BSim Search Dialog).
+
+Exercises
+
+The database example
contains vectors from a Linux executable used by Ghidra’s GNU demangler.
+Ghidra ships with several other versions of this executable.
+We use these different versions to demonstrate some of the capabilities of BSim.
+
+Note: Use the default query settings and autoanalysis options for the exercises unless otherwise specified.
+
+Exercise: Function Identification
+
+
+ - Import and analyze the binary
<ghidra_install_dir>/GPL/DemanglerGnu/os/win_x86_64/demangler_gnu_v2_41.exe
.
+
+ - This executable is based on the same source code as
demangler_gnu_v2_41
but compiled with Visual Studio instead of GCC.
+
+
+ - Examine this binary in Ghidra and verify that the original function names are not present.
+
+ - Note that the function names are present in
demangler_gnu_v2_41
.
+
+
+ - Using the default query options, query
example
for matches to the function at 140006760
.
+ - You should see the following search results:
+
+
+ - In this case, there is exactly one match, the similarity is 1.0, and the matching function has a non-default name (it won’t always be this easy).
+ - The results window has two tables: the function-level results (upper table) and the executable-level results (lower table).
+ The executable-level results are covered in From Matching Functions to Matching Executables.
+
+
+ - Right-click on the row of the match and perform the Compare Functions action to bring up the side-by-side comparison.
+
+ - The Listing View tab shows the disassembly.
+ - The Decompiler Diff View tab shows the decompiled code.
+ - Differences in the code are automatically highlighted in blue.
+ - Either view can be toggled between a horizontal split and a vertical split using the drop-down menu.
+
+
+ - Examine the diff views to verify that the match is valid.
+ - Using the Apply Name action in the BSim Search Results table, apply the name from the search result to the queried function.
+
+
+Note: We cover the Decompiler Diff View in greater detail and discuss the various “Apply” actions in Evaluating Matches and Applying Information.
+
+Exercise: Changes to the Source Code
+
+
+ - Import and analyze the executable
<ghidra_install_dir>/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_24
.
+
+ - This executable is based on an earlier version of the source code than the executable in
example
.
+
+
+ - Navigate to the function
expandargv
in demangler_gnu_v2_24
and issue a BSim query.
+ - What differences do you see in the decompiled code of the single match?
+
In demangler_gnu_v2_41...
The main differences are that call to dupargv is now in an if clause (and decompiler creates a related local variable) and there are two additional calls to free.
+
+ - The relevant source files are included with the Ghidra distribution:
+
+ <ghidra_install_dir>/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/argv.c
+ <ghidra_install_dir>/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/argv.c
+
+
+ - Verify that the differences you found are present in the source.
+
+
+Exercise: Cross-architectural Matching
+
+
+ - Import and analyze the executable
+
<ghidra_install_dir>/GPL/DemanglerGnu/os/mac_arm_64/demangler_gnu_v2_41
.
+
+ - This executable is based on the same source code as the executable in
example
but compiled for a different architecture.
+ - Note: this file has the same name as the one we used to populate the BSim database, so you will have to give the resulting Ghidra program a different name or import it into a different directory in your Ghidra project.
+
+
+ - Navigate to
_expandargv
and issue a BSim query.
+In the decompiler diff view of the single match, what differences do you see regarding memmove
and memcpy
?
+ In the arm64 version...
In the arm64_version, the compiler replaced these functions with __memmove_chk and __memcpy_chk. The __chk versions have an extra parameter related to preventing buffer overflows. Neither the names nor the bodies of callees are incorporated into BSim signatures, but the arguments of a call are, so this change partly explains why the BSim vectors are not identical.
+
+ - Examine the Listing View tab and verify that the architectures are indeed different.
+
+
+A Remark on Query Thresholds and Indices
+
+Q: If you set the similarity and confidence thresholds to 0.0, will a BSim query return all of the functions in the database?
+
+A: No, because
+
+ - For indexed databases (i.e., PostgreSQL and Elasticsearch), the index is designed so that vector comparisons are only performed between vectors which are likely to be close.
+Most vectors will not even be considered as potential matches for a given queried vector.
+ - Regardless of database backed, matches are only shown if the confidence score is above the confidence threshold of the query.
+The interface will not allow you to set a negative confidence threshold, but confidence scores can be negative.
+ - The Matches per Function parameter also controls how many functions are returned.
+
+
+Next Section: Ghidra from the Command Line
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.md
index c14a6885c6..c56d29908a 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Basic_Queries.md
@@ -7,7 +7,7 @@ In this section, we demonstrate some applications of our BSim database.
In order to query the database, you must register it with Ghidra:
1. From The Code Browser, Select **BSim -> Manage Servers**.
-1. In the BSim Server Manager dialog, click the green plus.
+1. In the BSim Server Manager dialog, click the green plus .
1. Select the **File** radio button and use the chooser to select ``example.mv.db``
1. Click **OK**
1. Click **Dismiss** to close the dialog.
@@ -27,7 +27,7 @@ There are a number of ways to initiate a BSim query, including:
For these cases, the function(s) being queried depend on the current selection.
If there is no selection, the function containing the current address is queried.
If there is a selection, all functions whose entry points are within the selection are queried.
-For example, to query all functions in the program, first select all addresses in the program via ``Ctrl-A`` in the Listing window.
+An easy way to query all functions in a program is to select all addresses with ``Ctrl-A`` in the Listing window and then initiate a BSim query.
It is also possible to initiate a BSim query from the Decompiler window.
Simply right-click on a function name token and select **BSim...** to query the corresponding function.
@@ -44,7 +44,7 @@ From the BSim Search Dialog, you can
- Bound the number of results returned for each function.
- Set query filters.
-
+
#### Selecting a BSim Database
@@ -86,7 +86,7 @@ Filters are discussed in [BSim Filters](BSimTutorial_Filters.md).
Click the **Search** button in the dialog to perform a query.
After successfully issuing a query, you will also see a **Search Function(s)** action (without the ellipsis) in certain contexts.
-This will perform a BSim query on the selected functions using the same parameters as the last query (skipping the BSim Seach Dialog).
+This will perform a BSim query on the selected functions using the same parameters as the last query (skipping the BSim Search Dialog).
## Exercises
@@ -96,7 +96,7 @@ We use these different versions to demonstrate some of the capabilities of BSim.
**Note**: Use the default query settings and autoanalysis options for the exercises unless otherwise specified.
-### Exercise 1: Function Identification
+### Exercise: Function Identification
1. Import and analyze the binary ``/GPL/DemanglerGnu/os/win_x86_64/demangler_gnu_v2_41.exe``.
- This executable is based on the same source code as ``demangler_gnu_v2_41`` but compiled with Visual Studio instead of GCC.
@@ -104,42 +104,42 @@ We use these different versions to demonstrate some of the capabilities of BSim.
- Note that the function names **are** present in ``demangler_gnu_v2_41``.
1. Using the default query options, query `example` for matches to the function at ``140006760``.
1. You should see the following search results:
- 
+ 
- In this case, there is exactly one match, the similarity is 1.0, and the matching function has a non-default name (it won't always be this easy).
- The results window has two tables: the function-level results (upper table) and the executable-level results (lower table).
The executable-level results are covered in [From Matching Functions to Matching Executables](BSimTutorial_Exe_Results.md).
-1. Right-click on the row of the match and select the **Compare Functions** action to bring up the side-by-side comparison.
+1. Right-click on the row of the match and perform the **Compare Functions** action to bring up the side-by-side comparison.
- The **Listing View** tab shows the disassembly.
- The **Decompiler Diff View** tab shows the decompiled code.
- Differences in the code are automatically highlighted in blue.
- Either view can be toggled between a horizontal split and a vertical split using the drop-down menu.
1. Examine the diff views to verify that the match is valid.
-1. Using the **Apply Name** action, apply the name from the search result to the queried function.
+1. Using the **Apply Name** action in the BSim Search Results table, apply the name from the search result to the queried function.
**Note**: We cover the Decompiler Diff View in greater detail and discuss the various "Apply" actions in [Evaluating Matches and Applying Information](BSimTutorial_Evaluating_Matches.md).
-### Exercise 2: Changes to the Source Code
+### Exercise: Changes to the Source Code
1. Import and analyze the executable ``/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_24``.
- This executable is based on an earlier version of the source code than the executable in ``example``.
-1. Navigate to the function ``expandargv`` in ``demangler_gnu_v2_24`` and issue a BSim query.
-1. What differences do you see in the decompiled code?
+1. Navigate to the function ``expandargv`` in ``demangler_gnu_v2_24`` and issue a BSim query.
+1. What differences do you see in the decompiled code of the single match?
In demangler_gnu_v2_41...
The main differences are that call to dupargv is now in an if clause (and decompiler creates a related local variable) and there are two additional calls to free.
1. The relevant source files are included with the Ghidra distribution:
- ``/GPL/DemanglerGnu/src/demangler_gnu_v2_24/c/argv.c``
- - ``/GPL/DemanglerGnu/src/demangler/gnu_v2_41/c/argv.c``
+ - ``/GPL/DemanglerGnu/src/demangler_gnu_v2_41/c/argv.c``
1. Verify that the differences you found are present in the source.
-### Exercise 3: Cross-architectural Matching
+### Exercise: Cross-architectural Matching
1. Import and analyze the executable
``/GPL/DemanglerGnu/os/mac_arm_64/demangler_gnu_v2_41``.
- This executable is based on the same source code as the executable in `example` but compiled for a different architecture.
- - **Note**: this file has the same name as the one used to populate the BSim database, so you will have to give the resulting Ghidra program a different name or import it into a different directory in your Ghidra project.
+ - **Note**: this file has the same name as the one we used to populate the BSim database, so you will have to give the resulting Ghidra program a different name or import it into a different directory in your Ghidra project.
1. Navigate to ``_expandargv`` and issue a BSim query.
-In the decompiler diff view, what differences do you see regarding ``memmove`` and ``memcpy``?
+In the decompiler diff view of the single match, what differences do you see regarding ``memmove`` and ``memcpy``?
In the arm64 version...
In the arm64_version, the compiler replaced these functions with __memmove_chk and __memcpy_chk. The __chk versions have an extra parameter related to preventing buffer overflows. Neither the names nor the bodies of callees are incorporated into BSim signatures, but the arguments of a call are, so this change partly explains why the BSim vectors are not identical.
-1. Examine the **Listing View** tab and verify that the architectures are different.
+1. Examine the **Listing View** tab and verify that the architectures are indeed different.
## A Remark on Query Thresholds and Indices
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Creating_Database_From_GUI.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Creating_Database_From_GUI.html
new file mode 100755
index 0000000000..bbd0342634
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Creating_Database_From_GUI.html
@@ -0,0 +1,38 @@
+Creating and Populating a BSim Database from the Ghidra GUI
+
+This section explains how to create and populate an H2-backed BSim database from the Ghidra GUI.
+
+Creating the Database
+
+To create a BSim database, first create a directory on your file system to contain the database.
+
+Next, perform the following steps from the Ghidra Code Browser:
+
+
+ - Run the Ghidra script
CreateH2BSimDatabaseScript.java
.
+ - In the resulting dialog:
+
+ - Enter “example” in the Database Name field.
+ - Select the new directory in the Database Directory field.
+ - Don’t change any of the other fields.
+
+
+ - Click OK.
+
+
+Populating the Database
+
+We now populate the database with an executable which is contained in the Ghidra distribution.
+
+
+ - Import and analyze the executable
<ghidra_install_dir>/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_41
using the default analysis options.
+ - Run the Ghidra script
AddProgramToH2BSimDatabaseScript.java
on this program.
+
+ - The script will ask you to select an H2 database file. Use
example.mv.db
in the database directory.
+
+
+ - In general you can run this script on other programs to add their signatures to this database, but that’s not necessary for the exercises in the next section.
+
+
+Next Section: Basic BSim Queries
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.html
new file mode 100755
index 0000000000..2504edf8aa
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.html
@@ -0,0 +1,22 @@
+Starting Ghidra and Enabling the BSim Plugin:
+
+To begin the tutorial, perform the following steps:
+
+
+ - Launch Ghidra.
+ - Create a new non-shared project for this tutorial.
+ - Launch the Code Browser.
+
+
+To enable BSim, perform the following steps:
+
+
+ - File -> Configure from the Code Browser.
+ - Click on the
Configure
link of the BSim
entry.
+ - In the resulting dialog, ensure that the checkbox for
BSimSearchPlugin
is checked.
+
+
+
+
+Next Section: Creating and Populating a BSim Database from the GUI
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.md
index 429a6bb36a..8737cb6561 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Enabling.md
@@ -12,7 +12,7 @@ To enable BSim, perform the following steps:
1. Click on the ``Configure`` link of the ``BSim`` entry.
1. In the resulting dialog, ensure that the checkbox for ``BSimSearchPlugin`` is checked.
-
+
Next Section: [Creating and Populating a BSim Database from the GUI](BSimTutorial_Creating_Database_From_GUI.md)
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.html
new file mode 100755
index 0000000000..f70196747b
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.html
@@ -0,0 +1,135 @@
+
+
+Summarizing what we’ve created over the last few sections, we now have:
+
+ - A stripped executable (
postgres
).
+ - A Ghidra project containing some object files with debug information used to build that executable.
+ - A BSim database containing the BSim signatures of the object files.
+
+
+We now demonstrate using BSim to help reverse engineer postgres
.
+While doing this, we’ll showcase some of the features available in the decompiler diff view.
+
+Exercise: Exploring the Highlights
+
+Import and analyze the stripped postgres
executable into the tutorial project, then perform the following steps:
+
+
+ - Select all functions in
postgres
via Ctrl-A
in the Listing.
+ - Perform a BSim query of the database
example
.
+
+ - Note: We use the results of this query in the following few exercises.
+ If you don’t close the BSim search results window, you won’t have to issue the query again.
+
+
+ - Sort the rows by confidence and find the row with
grouping_planner
as the matching function.
+The corresponding function in postgres
should have a default name.
+ - Examine this match in the side-by-side decompiler view.
+Note that the matching function has better data type information due to the debug information.
+ - Q: Why does the placement of the
double
argument between the functions?
+ Answer
Floating point values and integer/pointer values are passed in separate sets of registers.
+Neither ordering is wrong since both are consistent with the instructions of the function.
+The debug info records a specific signature (and ordering) for the function, which Ghidra applies.
+In the version without debug information, the decompiler used heuristics to determine the function's signature.
+
+
+
+For matches with a fair number of differences, the decompiler diff panel can get pretty colorful.
+Furthermore, as you click around, tokens will gain and lose highlights of various colors.
+It’s worth giving a brief explanation of when highlighting happens and what the different colors mean.
+Some terminology: if you click on a token in a decompiler panel, that token becomes the focused token.
+
+
+
+The colors:
+
+
+ - Blue is used to highlight differences between the two functions.
+ - Pink is used to highlight the focused token and its match.
+ - Lavender is used to highlight the focused token when it does not have a match.
+ - Orange is used to highlight the focused token when it is ineligible for match.
+Certain tokens, such as whitespace tokens or tokens used in variable declarations, are never assigned matching tokens.
+
+
+
+
+By default, scrolling in the diff window is synchronized.
+This means that scrolling within one window will also scroll within the other window.
+In the decompiler diff window, scrolling works by matching one line in the left function with one line in the right function.
+The two functions are aligned using those lines.
+Initially, the functions are aligned using the functions’ signatures.
+
+As you click around in either function, the “aligning lines” will change.
+If the focused token has a match, the scrolling is re-centered based on the lines containing the matched tokens.
+If the focused token does not have a match, the functions will be aligned using the closest token to the focused token which does have a match.
+
+Synchronized scrolling can be toggled using the
and
icons in the toolbar.
+
+
+ - Experiment with locking and unlocking synchronized scrolling.
+
+
+Exercise: Applying Signatures
+
+If you are satisfied with a given match, you might want to apply information about the matching function to the queried function.
+For example, you might want to apply the name or signature of the function.
+There are some subtleties which determine how much information is safe to apply.
+Hence there are three actions available under the Apply From Other menu when you right-click in the left panel:
+
+
+ - Function Name will apply the right function’s name and namespace to the function on the left.
+ - Function Signature will apply the name, namespace, and “skeleton” data types.
+ Structure and union data types are not transferred.
+ Instead, empty placeholder structures are created.
+ - Function Signature and Data Types will apply the name and signature with full data types.
+This may result in many data types being imported into the program (consider structures which refer to other structures).
+
+
+Warning: You should be absolutely certain that the datatypes are the exactly the same before applying signatures and data types.
+If there have been any changes to a datatype’s definition, you could end up bringing incorrect datatypes into a program, even using BSim matches with 1.0 similarity.
+Applying full data types is also problematic for cross-architecture matches.
+
+
+ - Since we know it’s safe, apply the function signature and data types to the left function.
+
+
+There are similarly-named actions available on rows of the Function Matches table in the BSim Search Results window.
+The Status column contains information about which rows have had their matches applied.
+
+Exercise: Comparing Callees
+
+The token matching algorithm matches a function call in one program to a function call in another by considering the data flow into and out of the CALL
instruction, but it does not do anything with the bodies of the callees.
+However, given a matched pair of calls, you can bring up a new comparison window for the callees with the Compare Matching Callees action.
+
+
+ - Click in the left panel of the decompile diff window and press
Ctrl-F
.
+ - Enter
FUN_
and search for matched function calls where the callee in the left window has a default name and the callee in the right window has a non-default name.
+ - Right-click on one of the matched tokens and perform the Compare Matching Callees action.
+ - In the comparison of the callees, apply the function signature and data types from the right function to the left function.
+Verify that the update is reflected in the decompiler diff view of the callers.
+
+
+Exercise: Multiple Comparisons
+
+The function shown in a panel is controlled by a drop-down menu at the top of the panel.
+This can be useful when you’d like to evaluate multiple matches to a single function.
+
+Exercise:
+
+
+ - In the BSim Search Results window, right-click on a table column name, select Add/Remove Columns, and enable the Matches column.
+ - Find two functions in
postgres
, each of which has exactly two matches.
+Select the corresponding four rows in the matches table and perform the Compare Functions action.
+ - Experiment with the drop-downs in each panel.
+
+
+In the next section, we discuss the Executable Results table.
+
+Next Section: From Matching Functions to Matching Executables
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.md
index 9ee4dc752d..b6e21c5e44 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Evaluating_Matches.md
@@ -3,10 +3,10 @@
Summarizing what we've created over the last few sections, we now have:
1. A stripped executable (``postgres``).
1. A Ghidra project containing some object files *with debug information*[^1] used to build that executable.
-1. A BSim database of containing the BSim signatures of the object files.
-
-[^1]: Having debug information isn't necessary to use BSim (as we've seen in a previous exercise), but it is convenient.
+1. A BSim database containing the BSim signatures of the object files.
+[^1]: Having debug information isn't necessary to use BSim (as we've seen in a previous exercise), but it is convenient. Note that applying debug information can change BSim signatures, which can negatively impact matching between functions with debug information and functions without it.
+
We now demonstrate using BSim to help reverse engineer ``postgres``.
While doing this, we'll showcase some of the features available in the decompiler diff view.
@@ -14,16 +14,16 @@ While doing this, we'll showcase some of the features available in the decompile
Import and analyze the stripped `postgres` executable into the tutorial project, then perform the following steps:
-1. Select all functions in `postgres` via Ctrl-A in the Listing.
+1. Select all functions in `postgres` via ``Ctrl-A`` in the Listing.
1. Perform a BSim query of the database ``example``.
- **Note:** We use the results of this query in the following few exercises.
- If don't close the BSim search results window, you won't have to issue the query again.
+ If you don't close the BSim search results window, you won't have to issue the query again.
1. Sort the rows by confidence and find the row with ``grouping_planner`` as the matching function.
The corresponding function in `postgres` should have a default name.
1. Examine this match in the side-by-side decompiler view.
Note that the matching function has better data type information due to the debug information.
1. Q: Why does the placement of the `double` argument between the functions?
- Answer
Floating point values and integer/pointer values are passed in separate sets registers.
+ Answer
Floating point values and integer/pointer values are passed in separate sets of registers.
Neither ordering is wrong since both are consistent with the instructions of the function.
The debug info records a specific signature (and ordering) for the function, which Ghidra applies.
In the version without debug information, the decompiler used heuristics to determine the function's signature.
@@ -57,33 +57,29 @@ If the focused token does not have a match, the functions will be aligned using
Synchronized scrolling can be toggled using the  and  icons in the toolbar.
-Exercise:
-
1. Experiment with locking and unlocking synchronized scrolling.
## Exercise: Applying Signatures
-If you are satisified with a given match, you might want to apply information about the match to the queried function.
+If you are satisfied with a given match, you might want to apply information about the matching function to the queried function.
For example, you might want to apply the name or signature of the function.
There are some subtleties which determine how much information is safe to apply.
Hence there are three actions available under the **Apply From Other** menu when you right-click in the left panel:
-1. **Function Name** will apply the function's name (and namespace) to the function on the left.
-1. **Function Signature** will apply the name and namespace and "skeleton" data types.
+1. **Function Name** will apply the right function's name and namespace to the function on the left.
+1. **Function Signature** will apply the name, namespace, and "skeleton" data types.
Structure and union data types are not transferred.
Instead, empty placeholder structures are created.
1. **Function Signature and Data Types** will apply the name and signature with full data types.
- This may result in many data types being imported into the program (e.g., structures which refer to other structures).
+ This may result in many data types being imported into the program (consider structures which refer to other structures).
**Warning**: You should be absolutely certain that the datatypes are the exactly the same before applying signatures and data types.
If there have been any changes to a datatype's definition, you could end up bringing incorrect datatypes into a program, even using BSim matches with 1.0 similarity.
Applying full data types is also problematic for cross-architecture matches.
-Exercise:
-
1. Since we know it's safe, apply the function signature and data types to the left function.
-There are similarly-named actions available on rows of Function Matches table in the BSim Search Results window.
+There are similarly-named actions available on rows of the Function Matches table in the BSim Search Results window.
The **Status** column contains information about which rows have had their matches applied.
## Exercise: Comparing Callees
@@ -93,12 +89,12 @@ However, given a matched pair of calls, you can bring up a new comparison window
1. Click in the left panel of the decompile diff window and press ``Ctrl-F``.
1. Enter ``FUN_`` and search for matched function calls where the callee in the left window has a default name and the callee in the right window has a non-default name.
-1. Right-click on one of the matched tokens and select the **Compare Matching Callees** action.
+1. Right-click on one of the matched tokens and perform the **Compare Matching Callees** action.
1. In the comparison of the callees, apply the function signature and data types from the right function to the left function.
Verify that the update is reflected in the decompiler diff view of the callers.
-# Exercise: Multiple Comparisons
+## Exercise: Multiple Comparisons
The function shown in a panel is controlled by a drop-down menu at the top of the panel.
This can be useful when you'd like to evaluate multiple matches to a single function.
@@ -113,4 +109,4 @@ Exercise:
In the next section, we discuss the Executable Results table.
-Next Section: [Executable-level Results](BSimTutorial_Exe_Results.md)
\ No newline at end of file
+Next Section: [From Matching Functions to Matching Executables](BSimTutorial_Exe_Results.md)
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.html
new file mode 100755
index 0000000000..144fb2c2e3
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.html
@@ -0,0 +1,46 @@
+From Matching Functions to Matching Executables
+
+In this section, we discuss the Executable Results table.
+Each row of this table corresponds to one executable in the database.
+The information in one row is an aggregation of all of the function-level matches into that row’s executable.
+Your Executable Results table from the previous query should look similar to the following:
+
+
+
+If you select a single row in the table and right-click on it, you will see the following actions:
+
+
+ - Load Executable
+Opens a read-only copy of the program in the Code Browser.
+ - Filter on this Executable
+Applies a filter which restricts the matches shown in the Function Matches table to matches which occur in the given executable.
+
+
+Exercise
+
+
+ - Sort the Executable results by descending Function Count.
+An entry in this column shows the number of queried functions which have at least one match in the row’s executable (if
foo
has 2 or more matches into a given executable, it still only contributes 1 to the function count).
+What position is demangler_gnu_v2_41
?
+ In this table...
It's in the first position.
+
+ - An entry in the Confidence column shows the sum of the confidence scores of all matches into the corresponding executable.
+If
foo
has more than one match into a given executable, only the one with the highest (function-level) confidence contributes to the (executable-level) confidence score.
+Sort the Executable results by descending confidence and observe that demangler_gnu_v2_41
is now much further down the list.
+ What could explain this?
If there are many function matches but the sum of all the confidences is relatively low, it is likely that many of the matches involve small functions with common BSim signatures.
+
+ - In the Executable match table, right click on
demangler_gnu_v2_41
and apply the filter action.
+Sort the filtered function matches by descending confidence.
+Starting at the top, examine some of the matches and convince yourself that the given explanation is correct.
+
+ - Note: You can remove the filter using the Filter Results icon
in the toolbar.
+ We’ll discuss this further in BSim Filters
+
+
+
+
+From this exercise, we see that unrelated functions can be duplicates of each other, either because they are small or because they perform a common generic action.
+Keep in mind that such functions can “pollute” the results of a blanket query.
+In the next section, we demonstrate a technique to restrict queries to functions which are more likely to have meaningful matches.
+
+Next Section: Overview Queries
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.md
index c0768f40f9..bbe37b0184 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Exe_Results.md
@@ -23,15 +23,15 @@ If you select a single row in the table and right-click on it, you will see the
1. An entry in the **Confidence** column shows the sum of the confidence scores of all matches into the corresponding executable.
If ``foo`` has more than one match into a given executable, only the one with the highest (function-level) confidence contributes to the (executable-level) confidence score.
Sort the Executable results by descending confidence and observe that ``demangler_gnu_v2_41`` is now much further down the list.
- What could explain this?
If there are many function matches but the sum of all the confidences is relatively low, it is likely that many of the matches involve small functions. For such a match, it is more likely that the functions agree by chance rather than being derived from the same source code.
+ What could explain this?
If there are many function matches but the sum of all the confidences is relatively low, it is likely that many of the matches involve small functions with common BSim signatures.
1. In the Executable match table, right click on ``demangler_gnu_v2_41`` and apply the filter action.
Sort the filtered function matches by descending confidence.
-Starting at the top, perform some code comparisons and convince yourself that the given explanation is correct.
- - **Note**: You can remove the filter using the **Filter Results** icon  in the upper right.
+Starting at the top, examine some of the matches and convince yourself that the given explanation is correct.
+ - **Note**: You can remove the filter using the **Filter Results** icon  in the toolbar.
We'll discuss this further in [BSim Filters](BSimTutorial_Filters.md)
From this exercise, we see that unrelated functions can be duplicates of each other, either because they are small or because they perform a common generic action.
Keep in mind that such functions can "pollute" the results of a blanket query.
In the next section, we demonstrate a technique to restrict queries to functions which are more likely to have meaningful matches.
-Next Section: [Overview Queries](BSimTutorial_Overview_Queries.md)
\ No newline at end of file
+Next Section: [Overview Queries](BSimTutorial_Overview_Queries.md)
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.html
new file mode 100755
index 0000000000..282901dfcc
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.html
@@ -0,0 +1,21 @@
+BSim Filters
+
+There are a number of filters that can be applied to BSim queries, involving names, architectures, compilers, ingest dates, user-defined executable categories, and other attributes.
+
+Filters be can applied server-side or client-side.
+Server-side filters affect the query results sent to Ghidra from a BSim server and can be applied using the Filters drop-down in the BSim Search dialog.
+Client-side filters apply to the BSim Search results table and can be added and removed at will using the Filter Results icon
.
+However, to “undo” a server-side filter, you have to issue another BSim query without the filter.
+
+Exercise: Filters
+
+
+ - Select all functions in
postgres
and bring up the BSim Search dialog.
+ - Apply an Executable name does not equal filter with
demangler_gnu_v2_41
as the name to exclude.
+ - Perform the query and verify
demangler_gnu_v2_41
is not in the list of executables with matches.
+ - Using the Search Info icon
in the BSim Search Results toolbar, you can see the server-side filters applied to the query.
+Verify that this information is correct.
+ - Using the Filter Results icon
, you can apply client-side filters to the query results. Experiment with applying and removing some client-side filters.
+
+
+Next Section: Scripting and Visualization
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.md
index 8821bf5454..c6c9d7adfd 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Filters.md
@@ -1,13 +1,13 @@
# BSim Filters
-There are a number of filters that can be applied to BSim queries, involving names, architectures, compilers, ingest dates, user-defined executable categories, and many other attributes.
+There are a number of filters that can be applied to BSim queries, involving names, architectures, compilers, ingest dates, user-defined executable categories, and other attributes.
Filters be can applied *server-side* or *client-side*.
-Server-side filters affect the query results sent to Ghidra from a BSim server.
-Client-side filters apply to the BSim Search results table and can be added and removed at will.
-However, to "undo" a server-side filter, you have to issue an additional BSim query without the filter.
+Server-side filters affect the query results sent to Ghidra from a BSim server and can be applied using the **Filters** drop-down in the BSim Search dialog.
+Client-side filters apply to the BSim Search results table and can be added and removed at will using the **Filter Results** icon .
+However, to "undo" a server-side filter, you have to issue another BSim query without the filter.
+
-Server-side filters can be applied using the **Filters** drop-down in the BSim Search dialog.
## Exercise: Filters
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.html
new file mode 100755
index 0000000000..6630087b96
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.html
@@ -0,0 +1,56 @@
+Ghidra Analysis from the Command Line
+
+For the remaining exercises, we need to populate our BSim database with a number of binaries.
+We’d like a consistent set of binaries for the tutorial, but we don’t want to clutter the Ghidra distribution with dozens of additional executables.
+Fortunately, the BSim plugin includes a script for building the PostgreSQL backend, and that build process creates hundreds of object files.
+So we can just build PostgreSQL and harvest the object files we need.
+
+Note: For the tutorial, we continue to use the H2 BSim backend.
+We do not run any PostgreSQL code, we simply analyze some files produced when building PostgreSQL.
+
+Note that these files must be built on a machine running Linux.
+Windows users can build these files in a Linux virtual machine.
+
+First, download postgresql-15.3.tar.gz
from the PostgreSQL web site.
+Put this file in <ghidra_install_dir>/Ghidra/Features/BSim
.
+
+To build the files, execute the following commands in a shell:
+
+cd <ghidra_install_dir>/Features/BSim
+export CFLAGS="-O2 -g"
+./make-postgres.sh
+mkdir ~/postgres_object_files
+cd build
+find . -name p*o -size +100000c -size -700000c -exec cp {} ~/postgres_object_files/ \;
+cd os/linux_x86_64/postgresql/bin
+strip -s postgres
+
+
+To continue on Windows, transfer the ~/postgres_object_files
directory and the stripped postgres
executable to your Windows machine.
+
+Importing and Analyzing the Exercise Files
+
+Now that we have the executables, we can analyze them with the headless analyzer.
+The headless analyzer is distinct from BSim, but using it is the only feasible way to analyze substantial numbers of binaries.
+
+To analyze the files in Linux, execute the following commands in a shell.
+
+cd <ghidra_install_dir>/support
+./analyzeHeadless <ghidra_project_dir> postgres_object_files -import ~/postgres_object_files/*
+
+(On windows, use analyzeHeadless.bat
and adjust paths accordingly.)
+
+This will create a local Ghidra project called postgres_object_files
in the directory <ghidra_project_dir>
.
+
+Next Section: BSim from the Command Line
+
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.md
index a53987e143..2a91ee261c 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Ghidra_Command_Line.md
@@ -16,8 +16,7 @@ Put this file in ``/Ghidra/Features/BSim``.
To build the files, execute the following commands in a shell: [^1]
-[^1]: You may need to install additional packages and/or change some build options in order for PostgreSQL to build successfully.
-The error messages are generally informative. See the comments in ``make-postgres.sh``.
+[^1]: You may need to install additional packages and/or change some build options in order for PostgreSQL to build successfully. The error messages are generally informative. See the comments in ``make-postgres.sh``.
```bash
cd /Features/BSim
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.html
new file mode 100755
index 0000000000..d4ca639b50
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.html
@@ -0,0 +1,116 @@
+Introduction to BSim
+
+As you’ve reverse engineered software, you’ve likely asked the following questions:
+
+
+ - Which libraries were statically linked into this executable?
+ - Does this executable share some code with another executable that I’ve analyzed?
+ - What are the differences between version 1 and version 2 of a given executable?
+ - Does this executable share code with another executable in a large collection of binaries?
+ - Was this function pulled from an open-source library?
+
+
+BSim is intended to help with these questions (and others) by providing a way to search collections of binaries for similar, but not necessarily identical, functions.
+
+How Does BSim Work?
+
+The idea behind BSim is to generate a feature vector for each function in a binary.
+The vectors are generated by Ghidra’s decompiler.
+Each feature represents a small piece of data flow and/or control flow of the associated function.
+The decompiler normalizes the feature vector representation so that different, but functionally equivalent, pieces of code often produce the same features.
+Certain attributes, such as values of constants, names of registers, and data types, are intentionally not incorporated into the features.
+
+BSim vectors are compared using cosine similarity.
+Discrepancies between the vectors for foo
and bar
which are caused by differences in compilers, target architectures, and/or small changes to the source code typically result in vectors which are close but not identical.
+
+BSim vectors can be stored in a dedicated database.
+BSim databases intended to hold large numbers of vectors maintain an index based on locality-sensitive hashing.
+The index drastically reduces the number of vector comparisons needed and allows for rapid retrieval of results.
+
+Querying foo
against a BSim database typically yields a number of potential matches.
+Each individual match for foo
can be compared to foo
in a side-by-side view, and certain information (such as function name) can be quickly copied from a match to foo
.
+
+We frequently call BSim vectors the BSim signature of a function, or just the signature when the context is clear.
+
+Why “BSim”?
+
+We can think of each feature as representing a small piece of the behavior of a function, analogous to a snippet of source code.
+Functions whose BSim vectors are close typically have many features in common, that is, they have similar behavior.
+Hence the name “BSim”: Behavioral Similiarity.
+
+BSim Clients, BSim Databases, and Ghidra Projects
+
+Using BSim involves the following components:
+
+
+ - A BSim Client, i.e., an instance of Ghidra with the BSim plugin enabled.
+
+ - This is where the reverse engineering happens.
+
+
+ - A BSim Database, which stores the BSim signatures.
+
+ - Also stores some metadata about each function and its containing executable.
+ - In particular, stores the ghidra:// URL of the associated Ghidra program.
+ - Does not store disassembly or decompiled functions.
+
+
+ - A Ghidra Project, which stores the analyzed programs used to populate the BSim database.
+
+ - Given a BSim match, the BSim client can use the ghidra:// URL to retrieve a program from a Ghidra project for side-by-side comparisons.
+ - Note that a single BSim database can reference multiple Ghidra projects.
+
+
+
+
+Database Backends
+
+There are three supported database backends for BSim:
+
+
+ -
+
PostgreSQL
+
+
+ - The Ghidra distribution includes the source for a PostgreSQL plugin for BSim along with a
+ build script.
+ - Users must download the PostgreSQL source.
+ - Populated from shared Ghidra projects (i.e., requires a Ghidra server).
+ - Server not supported on Windows (no restriction on clients).
+
+
+ -
+
Elasticsearch
+
+
+ - The
BSimElasticPlugin
extension contains an Elasticsearch plugin for BSim.
+ - This plugin must be installed into an existing Elasticsearch database.
+ - Populated from shared Ghidra projects.
+
+
+ -
+
H2
+
+
+ - Simplest way to use BSim:
+
+ - Backed by files on the user’s machine (don’t need to install database server).
+ - Can be created and populated quickly.
+ - Supported on all platforms.
+
+
+ - Does not support large collections of binaries or multiple users.
+ - Can be populated from non-shared (local) or shared Ghidra projects.
+
+
+
+
+Next Section: Starting Ghidra and Enabling BSim
+
+
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.md
index 9806728342..89c5510a7f 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Intro.md
@@ -25,8 +25,7 @@ BSim vectors can be stored in a dedicated database.
BSim databases intended to hold large[^1] numbers of vectors maintain an index based on *locality-sensitive hashing*.
The index drastically reduces the number of vector comparisons needed and allows for rapid retrieval of results.
-[^1]: Creating a database requires a *database template*, which determines the specifics of the index. Currently, Ghidra provides a *medium* template, intended for
-databases holding up to 10 million unique vectors, and a *large* template, intended for databases holding up to 100 million unique vectors.
+[^1]: Creating a database requires a *database template*, which determines the specifics of the index. Currently, Ghidra provides a *medium* template, intended for databases holding up to 10 million unique vectors, and a *large* template, intended for databases holding up to 100 million unique vectors.
Querying ``foo`` against a BSim database typically yields a number of potential matches.
Each individual match for ``foo`` can be compared to `foo` in a side-by-side view, and certain information (such as function name) can be quickly copied from a match to ``foo``.
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.html
new file mode 100755
index 0000000000..167d54c324
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.html
@@ -0,0 +1,51 @@
+Overview Queries
+
+An Overview Query queries a BSim database for the number of matches to each function in an executable.
+The matching functions themselves are not returned.
+Similarity and Confidence thresholds can be set for an Overview Query, but there is no “Matches per Function” bound and no filters can be applied.
+
+To perform an Overview Query, select BSim -> Perform Overview… from the Code Browser.
+
+Exercise: Hit Counts and Self-Significance
+
+
+ - Perform an Overview query on
postgres
using the default query thresholds.
+You should see the following result:
+
+ - Sort the table by the “Hit Count” column in ascending order. Typically, the functions with the largest hit counts will have low self-significance.
+Verify that that is the case for this table.
+ - Q: Examine the functions with the highest hit count. Why are there so many matches for these functions?
+
Answer:
These are all instances of PostgreSQL statistics-reporting functions. Their bodies are quite similar and they have identical BSim signatures.
+
+
+
+Exercise: Selections and Queries
+
+Using the hit count column, it is possible to exclude functions with large numbers of matches.
+
+
+ - In the Overview Table, select all functions whose hit count is 2 or less.
+ - Right-click on the selection and perform the Search Selected Functions action.
+Sort the query results by descending Function Count and verify that
demangler_gnu_v2_41
is far down the list.
+
+
+Exercise: Vector Hashes
+
+Suppose foo
and bar
have the same number of hits in the Overview table.
+There are two possibilities:
+
+ foo
and bar
have distinct feature vectors which happen to have the same number of matches.
+ foo
and bar
have the same feature vector.
+
+
+An optional column, Vector Hash, can be used to distinguish between these two cases.
+
+
+ - Enable the Vector Hash Column in the Overview Table.
+ - Find two functions with the same vector hash.
+ - Select the two corresponding rows in the table and then transfer the selection to the Listing using the
icon in the BSim Overview toolbar.
+ - In the Listing, press
Shift-C
or right-click and perform the Compare Selected Functions action.
+ - In the resulting Function Comparison window, convince yourself that these two functions should have the same BSim signature.
+
+
+Next Section: Queries and Filters
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.md
index 2286673cee..b2034c01bc 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Overview_Queries.md
@@ -2,11 +2,11 @@
An **Overview Query** queries a BSim database for the number of matches to each function in an executable.
The matching functions themselves are not returned.
-Similarity and Confidence thresholds can be set for an Overview query, but there is no "Matches per Function" bound and no filters can be set.
+Similarity and Confidence thresholds can be set for an Overview Query, but there is no "Matches per Function" bound and no filters can be applied.
To perform an Overview Query, select **BSim -> Perform Overview...** from the Code Browser.
-## Exercise 1: Hit Counts and Self-Significance.
+## Exercise: Hit Counts and Self-Significance
1. Perform an Overview query on ``postgres`` using the default query thresholds.
You should see the following result:
@@ -14,9 +14,9 @@ You should see the following result:
1. Sort the table by the "Hit Count" column in ascending order. Typically, the functions with the largest hit counts will have low self-significance.
Verify that that is the case for this table.
1. Q: Examine the functions with the highest hit count. Why are there so many matches for these functions?
- Answer:
These are all instances of PostgreSQL statistics-reporting functions. Their bodies are quite similar.
+ Answer:
These are all instances of PostgreSQL statistics-reporting functions. Their bodies are quite similar and they have identical BSim signatures.
-## Exercise 2: Selections and Queries
+## Exercise: Selections and Queries
Using the hit count column, it is possible to exclude functions with large numbers of matches.
@@ -24,7 +24,7 @@ Using the hit count column, it is possible to exclude functions with large numbe
1. Right-click on the selection and perform the **Search Selected Functions** action.
Sort the query results by descending **Function Count** and verify that ``demangler_gnu_v2_41`` is far down the list.
-## Exercise 3: Vector Hashes
+## Exercise: Vector Hashes
Suppose ``foo`` and ``bar`` have the same number of hits in the Overview table.
There are two possibilities:
@@ -34,9 +34,9 @@ There are two possibilities:
An optional column, **Vector Hash**, can be used to distinguish between these two cases.
1. Enable the **Vector Hash** Column in the Overview Table.
-1. Find two functions with the vector hash.
+1. Find two functions with the same vector hash.
1. Select the two corresponding rows in the table and then transfer the selection to the Listing using the  icon in the BSim Overview toolbar.
1. In the Listing, press ``Shift-C`` or right-click and perform the **Compare Selected Functions** action.
1. In the resulting Function Comparison window, convince yourself that these two functions should have the same BSim signature.
-Next Section: [Queries and Filters](BSimTutorial_Filters.md)
\ No newline at end of file
+Next Section: [Queries and Filters](BSimTutorial_Filters.md)
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.html b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.html
new file mode 100755
index 0000000000..c2d3c4c2d1
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.html
@@ -0,0 +1,23 @@
+Scripting and Visualization
+
+Finally, we briefly mention a few other topics related to BSim.
+
+Scripting BSim
+
+There are are number of example scripts in the BSim
script category, which demonstrate how to interact with BSim programmatically.
+
+
+
+Visualizing Features
+
+Finally, if you’d like to see the particular BSim features in a function, you can use the BSim Feature Visualizer.
+This plugin allows you to highlight regions of the decompiled code corresponding to a particular feature and to display a graph representing the feature.
+
+To use this plugin, first enable the BSimFeatureVisualizerPlugin
via File -> Configure from the Code Browser.
+You can then bring it up via BSim -> BSim Feature Visualizer.
+
+
+
+This is the end of the tutorial.
+
+Return to the Beginning
diff --git a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.md b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.md
index 37be02df9b..37f52720f7 100644
--- a/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.md
+++ b/GhidraDocs/GhidraClass/BSim/BSimTutorial_Scripting.md
@@ -4,9 +4,9 @@ Finally, we briefly mention a few other topics related to BSim.
## Scripting BSim
-There are are number of example scripts in the ``BSim`` script category, which demonstrate how to interact with BSim programmatically:
+There are are number of example scripts in the ``BSim`` script category, which demonstrate how to interact with BSim programmatically.
-
+
## Visualizing Features
@@ -14,10 +14,10 @@ Finally, if you'd like to see the particular BSim features in a function, you ca
This plugin allows you to highlight regions of the decompiled code corresponding to a particular feature and to display a graph representing the feature.
To use this plugin, first enable the ``BSimFeatureVisualizerPlugin`` via **File -> Configure** from the Code Browser.
-You can then bring it via **BSim -> BSim Feature Visualizer**.
+You can then bring it up via **BSim -> BSim Feature Visualizer**.
-
+
This is the end of the tutorial.
-[Return to the Beginning](README.md)
\ No newline at end of file
+[Return to the Beginning](README.md)
diff --git a/GhidraDocs/GhidraClass/BSim/README.html b/GhidraDocs/GhidraClass/BSim/README.html
new file mode 100755
index 0000000000..e6b4c0082f
--- /dev/null
+++ b/GhidraDocs/GhidraClass/BSim/README.html
@@ -0,0 +1,24 @@
+BSim Tutorial
+
+BSim is a Ghidra plugin for finding structurally similar functions in (potentially large) collections of binaries.
+It is based on Ghidra’s decompiler and can find matches across compilers, architectures, and/or small changes to source code.
+
+This tutorial demonstrates how create a small BSim database and walks through some typical use cases.
+
+Detailed information about BSim can be found in the “BSim” entry of the Ghidra Help.
+
+
+ - Introduction to BSim
+ - Starting Ghidra and Enabling BSim
+ - Creating and Populating a BSim Database from the GUI
+ - Basic BSim Queries
+ - Ghidra from the Command Line
+ - BSim from the Command Line
+ - Evaluating Matches
+ - From Matching Functions to Matching Executables
+ - Overview Queries
+ - BSim Filters
+ - Scripting and Visualization
+
+
+Next Section: Introduction to BSim
diff --git a/GhidraDocs/GhidraClass/BSim/images/Plus2.png b/GhidraDocs/GhidraClass/BSim/images/Plus2.png
new file mode 100644
index 0000000000000000000000000000000000000000..add4ad53dd68e79d7e2cdf13644dfbb51373fbfd
GIT binary patch
literal 752
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 y2|wW~%8etZx3S%_Jit
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 |