mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 10:49:34 +02:00
GP-4128 Adjust construction of SQL statements in OptionalTable
This commit is contained in:
parent
ce5c48eba9
commit
4ca724e6d2
2 changed files with 82 additions and 24 deletions
|
@ -13,33 +13,87 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
// Calculate similarity/signifigance scores between executables by
|
// Calculate similarity/significance scores between executables by
|
||||||
// combining their function scores.
|
// combining their function scores.
|
||||||
//@category BSim
|
//@category BSim
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.features.bsim.query.BSimClientFactory;
|
import ghidra.features.bsim.query.BSimClientFactory;
|
||||||
import ghidra.features.bsim.query.FunctionDatabase;
|
import ghidra.features.bsim.query.FunctionDatabase;
|
||||||
import ghidra.features.bsim.query.client.*;
|
import ghidra.features.bsim.query.client.*;
|
||||||
import ghidra.features.bsim.query.description.ExecutableRecord;
|
import ghidra.features.bsim.query.description.ExecutableRecord;
|
||||||
|
import ghidra.features.bsim.query.protocol.QueryExeInfo;
|
||||||
|
import ghidra.features.bsim.query.protocol.ResponseExe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An example script using {@link ExecutableComparison} to compare executables within a BSim database.
|
||||||
|
* The user provides the URL of the database and the name of an executable within the database that
|
||||||
|
* will be compared against every other executable.
|
||||||
|
*
|
||||||
|
* Executables are considered similar if they share similar functions, as determined by the BSim similarity metric.
|
||||||
|
* Functions that are too common (high hitcount) or are too small (low self signficance) are not included
|
||||||
|
* in the score. A score of 1.0 means that all functions included in the score are shared between the two
|
||||||
|
* executables and each have a (function) similarity of 1.0.
|
||||||
|
*
|
||||||
|
* The script also computes a "library" score, which achieves 1.0 if the functions in the smaller of the two
|
||||||
|
* executables all have a perfect match in the bigger executable. The bigger executable may have many functions
|
||||||
|
* with no match in the smaller executable.
|
||||||
|
*
|
||||||
|
* For larger databases, repeated runs of this script can be made more efficient by allowing it to cache executable
|
||||||
|
* "self-scores" between runs. Uncomment one of two lines instantiating the {@link ScoreCaching} object below. The
|
||||||
|
* cache can be stored in the local file system or in an additional table/column in the BSim database.
|
||||||
|
*/
|
||||||
public class CompareExecutablesScript extends GhidraScript {
|
public class CompareExecutablesScript extends GhidraScript {
|
||||||
|
|
||||||
private ExecutableComparison exeCompare;
|
private ExecutableComparison exeCompare;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void run() throws Exception {
|
protected void run() throws Exception {
|
||||||
URL url = BSimClientFactory.deriveBSimURL("ghidra://localhost/repo");
|
String urlString = askString("Enter BSim database URL", "URL: ");
|
||||||
|
String execName =
|
||||||
|
askString("Enter name of executable to compare against database", "Name: ");
|
||||||
|
URL url = BSimClientFactory.deriveBSimURL(urlString);
|
||||||
try (FunctionDatabase database = BSimClientFactory.buildClient(url, true)) {
|
try (FunctionDatabase database = BSimClientFactory.buildClient(url, true)) {
|
||||||
// FileScoreCaching cache = new FileScoreCaching("/tmp/test_scorecacher.txt");
|
QueryExeInfo exeInfo = new QueryExeInfo();
|
||||||
TableScoreCaching cache = new TableScoreCaching(database);
|
exeInfo.filterExeName = execName;
|
||||||
exeCompare = new ExecutableComparison(database, 1000000,
|
ResponseExe exeResult = exeInfo.execute(database);
|
||||||
"11111111111111111111111111111111", cache, monitor);
|
if (exeResult == null) {
|
||||||
// Specify the list of executables to compare by giving their md5 hash
|
String message = database.getLastError() != null ? database.getLastError().message
|
||||||
|
: "Unrecoverable error";
|
||||||
|
throw new IOException(message);
|
||||||
|
}
|
||||||
|
else if (exeResult.recordCount == 0) {
|
||||||
|
throw new InvalidParameterException(
|
||||||
|
"Executable " + execName + " is not present in database");
|
||||||
|
}
|
||||||
|
else if (exeResult.recordCount > 1) {
|
||||||
|
println("Multiple executables with the name - " + execName);
|
||||||
|
ExecutableRecord exeRecord = exeResult.records.get(0);
|
||||||
|
print("Using ");
|
||||||
|
println(exeRecord.printRaw());
|
||||||
|
}
|
||||||
|
String baseMd5 = exeResult.records.get(0).getMd5();
|
||||||
|
|
||||||
|
ScoreCaching cache = null; // If null, self scores will not be cached
|
||||||
|
|
||||||
|
// Scores can be cached in the local file system by using FileScoreCaching
|
||||||
|
// cache = new FileScoreCaching("/tmp/test_scorecacher.txt");
|
||||||
|
|
||||||
|
// Scores can be cached in a dedicated table within the database by using TableScoreCaching
|
||||||
|
// TableScoreCaching is currently only supported for the PostgreSQL back-end.
|
||||||
|
// cache = new TableScoreCaching(database);
|
||||||
|
|
||||||
|
exeCompare = new ExecutableComparison(database, 1000000, baseMd5, cache, monitor);
|
||||||
|
// Its possible to specify the executables to compare with the base executable by
|
||||||
|
// specifying their md5 hashes directly.
|
||||||
// exeCompare.addExecutable("22222222222222222222222222222222"); // 32 hex-digit string
|
// exeCompare.addExecutable("22222222222222222222222222222222"); // 32 hex-digit string
|
||||||
// exeCompare.addExecutable("33333333333333333333333333333333");
|
// exeCompare.addExecutable("33333333333333333333333333333333");
|
||||||
|
|
||||||
|
// Otherwise specify that we should compare the base executable against all executables
|
||||||
exeCompare.addAllExecutables(5000);
|
exeCompare.addAllExecutables(5000);
|
||||||
ExecutableScorer scorer = exeCompare.getScorer();
|
ExecutableScorer scorer = exeCompare.getScorer();
|
||||||
if (!exeCompare.isConfigured()) {
|
if (!exeCompare.isConfigured()) {
|
||||||
|
|
|
@ -27,14 +27,15 @@ import java.sql.*;
|
||||||
*/
|
*/
|
||||||
public class OptionalTable {
|
public class OptionalTable {
|
||||||
|
|
||||||
private final String TABLE_EXISTS_STMT = "SELECT schemaname FROM pg_tables where tablename='#'";
|
private String TABLE_EXISTS_STMT = "SELECT schemaname FROM pg_tables where tablename='#'";
|
||||||
private final String GRANT_STMT = "GRANT SELECT ON # TO PUBLIC";
|
private String GRANT_STMT = "GRANT SELECT ON # TO PUBLIC";
|
||||||
private final String DELETE_ALL_STMT = "DELETE FROM #";
|
private String DELETE_ALL_STMT = "DELETE FROM #";
|
||||||
|
|
||||||
private final String INSERT_STMT = "INSERT INTO # (key,value) VALUES(?,?)";
|
private String INSERT_STMT = "INSERT INTO # (key,value) VALUES(?,?)";
|
||||||
private final String UPDATE_STMT = "UPDATE # SET value = ? WHERE key = ?";
|
private String UPDATE_STMT = "UPDATE # SET value = ? WHERE key = ?";
|
||||||
private final String SELECT_STMT = "SELECT value FROM # WHERE key = ?";
|
private String SELECT_STMT = "SELECT value FROM # WHERE key = ?";
|
||||||
private final String DELETE_STMT = "DELETE FROM # WHERE key = ?";
|
private String DELETE_STMT = "DELETE FROM # WHERE key = ?";
|
||||||
|
private String LOCK_STMT = "LOCK TABLE # IN SHARE ROW EXCLUSIVE MODE";
|
||||||
|
|
||||||
private Connection db = null; // Connection to the database
|
private Connection db = null; // Connection to the database
|
||||||
|
|
||||||
|
@ -43,7 +44,6 @@ public class OptionalTable {
|
||||||
private final CachedStatement<PreparedStatement> selectStatement = new CachedStatement<>();
|
private final CachedStatement<PreparedStatement> selectStatement = new CachedStatement<>();
|
||||||
private final CachedStatement<PreparedStatement> deleteStatement = new CachedStatement<>();
|
private final CachedStatement<PreparedStatement> deleteStatement = new CachedStatement<>();
|
||||||
private final CachedStatement<Statement> reusableStatement = new CachedStatement<>();
|
private final CachedStatement<Statement> reusableStatement = new CachedStatement<>();
|
||||||
private final String lockString;
|
|
||||||
|
|
||||||
private String name = null; // name of the table
|
private String name = null; // name of the table
|
||||||
private int keyType = -1; // Type of the key column
|
private int keyType = -1; // Type of the key column
|
||||||
|
@ -61,7 +61,14 @@ public class OptionalTable {
|
||||||
keyType = kType;
|
keyType = kType;
|
||||||
valueType = vType;
|
valueType = vType;
|
||||||
db = d;
|
db = d;
|
||||||
lockString = "LOCK TABLE " + nm + " IN SHARE ROW EXCLUSIVE MODE";
|
TABLE_EXISTS_STMT = generateSQLCommand(TABLE_EXISTS_STMT, nm);
|
||||||
|
GRANT_STMT = generateSQLCommand(GRANT_STMT, nm);
|
||||||
|
DELETE_ALL_STMT = generateSQLCommand(DELETE_ALL_STMT, nm);
|
||||||
|
INSERT_STMT = generateSQLCommand(INSERT_STMT, nm);
|
||||||
|
UPDATE_STMT = generateSQLCommand(UPDATE_STMT, nm);
|
||||||
|
SELECT_STMT = generateSQLCommand(SELECT_STMT, nm);
|
||||||
|
DELETE_STMT = generateSQLCommand(DELETE_STMT, nm);
|
||||||
|
LOCK_STMT = generateSQLCommand(LOCK_STMT, nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Statement getReusableStatement() throws SQLException {
|
private Statement getReusableStatement() throws SQLException {
|
||||||
|
@ -73,7 +80,7 @@ public class OptionalTable {
|
||||||
* @throws SQLException if the server reports an error
|
* @throws SQLException if the server reports an error
|
||||||
*/
|
*/
|
||||||
public void lockForWrite() throws SQLException {
|
public void lockForWrite() throws SQLException {
|
||||||
getReusableStatement().execute(lockString);
|
getReusableStatement().execute(LOCK_STMT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +105,7 @@ public class OptionalTable {
|
||||||
* @param ptr is the string to be modified
|
* @param ptr is the string to be modified
|
||||||
* @return the modified string
|
* @return the modified string
|
||||||
*/
|
*/
|
||||||
private String generateSQLCommand(String ptr) {
|
private static String generateSQLCommand(String ptr, String name) {
|
||||||
int first = ptr.indexOf('#');
|
int first = ptr.indexOf('#');
|
||||||
int second = ptr.indexOf('#', first + 1);
|
int second = ptr.indexOf('#', first + 1);
|
||||||
String res;
|
String res;
|
||||||
|
@ -160,8 +167,7 @@ public class OptionalTable {
|
||||||
String sqlstring = buffer.toString();
|
String sqlstring = buffer.toString();
|
||||||
Statement st = getReusableStatement();
|
Statement st = getReusableStatement();
|
||||||
st.executeUpdate(sqlstring);
|
st.executeUpdate(sqlstring);
|
||||||
sqlstring = generateSQLCommand(GRANT_STMT);
|
st.executeUpdate(GRANT_STMT);
|
||||||
st.executeUpdate(sqlstring);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,8 +175,7 @@ public class OptionalTable {
|
||||||
* @throws SQLException for problems with the connection
|
* @throws SQLException for problems with the connection
|
||||||
*/
|
*/
|
||||||
public void clearTable() throws SQLException {
|
public void clearTable() throws SQLException {
|
||||||
String sqlString = generateSQLCommand(DELETE_ALL_STMT);
|
getReusableStatement().executeUpdate(DELETE_ALL_STMT);
|
||||||
getReusableStatement().executeUpdate(sqlString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,9 +184,8 @@ public class OptionalTable {
|
||||||
* @throws SQLException for problems with the connection
|
* @throws SQLException for problems with the connection
|
||||||
*/
|
*/
|
||||||
public boolean exists() throws SQLException {
|
public boolean exists() throws SQLException {
|
||||||
String sqlString = generateSQLCommand(TABLE_EXISTS_STMT);
|
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
try (ResultSet rs = getReusableStatement().executeQuery(sqlString)) {
|
try (ResultSet rs = getReusableStatement().executeQuery(TABLE_EXISTS_STMT)) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
result = rs.getString(1).equals("public");
|
result = rs.getString(1).equals("public");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue