From f23fcf81a97059726ee91da62a58964403eeb13e Mon Sep 17 00:00:00 2001 From: Christian Blichmann Date: Thu, 4 Apr 2019 16:13:02 +0200 Subject: [PATCH] Add SHA256 hash to `Program` interface Implements the first part of #291 Signed-off-by: Christian Blichmann --- .../util/opinion/AbstractProgramLoader.java | 9 ++++++ .../ghidra/program/database/ProgramDB.java | 28 +++++++++++++++++-- .../ghidra/program/model/listing/Program.java | 12 ++++++++ .../program/model/ProgramTestDouble.java | 10 +++++++ .../ghidra/server/remote/ServerTestUtil.java | 12 ++++---- 5 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java index c4ac06b46a..8aeb2eff10 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/opinion/AbstractProgramLoader.java @@ -41,6 +41,7 @@ import ghidra.program.util.DefaultLanguageService; import ghidra.program.util.GhidraProgramUtilities; import ghidra.util.InvalidNameException; import ghidra.util.MD5Utilities; +import ghidra.util.HashUtilities; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; @@ -285,6 +286,8 @@ public abstract class AbstractProgramLoader implements Loader { } String md5 = computeBinaryMD5(provider); prog.setExecutableMD5(md5); + String sha256 = computeBinarySHA256(provider); + prog.setExecutableSHA256(sha256); if (shouldSetImageBase(prog, imageBase)) { try { @@ -465,6 +468,12 @@ public abstract class AbstractProgramLoader implements Loader { } } + private String computeBinarySHA256(ByteProvider provider) throws IOException { + try (InputStream in = provider.getInputStream(0)) { + return HashUtilities.getHash(HashUtilities.SHA256_ALGORITHM, in); + } + } + private boolean shouldSetImageBase(Program prog, Address imageBase) { if (imageBase == null || imageBase instanceof SegmentedAddress) { return false; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index 1652471336..6a536dda2e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -128,6 +128,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM private static final String EXECUTABLE_PATH = "Executable Location"; private static final String EXECUTABLE_FORMAT = "Executable Format"; private static final String EXECUTABLE_MD5 = "Executable MD5"; + private static final String EXECUTABLE_SHA256 = "Executable SHA256"; private static final String TABLE_NAME = "Program"; private static final String EXECUTE_PATH = "Execute Path"; private static final String EXECUTE_FORMAT = "Execute Format"; @@ -716,7 +717,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } /** - * * @see ghidra.program.model.listing.Program#setExecutableFormat(java.lang.String) */ @Override @@ -742,7 +742,6 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } /** - * * @see ghidra.program.model.listing.Program#setExecutableMD5(java.lang.String) */ @Override @@ -752,6 +751,31 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM changed = true; } + /** + * @see ghidra.program.model.listing.Program#getExecutableSHA256() + */ + @Override + public String getExecutableSHA256() { + String format = null; + try { + Options pl = getOptions(PROGRAM_INFO); + format = pl.getString(EXECUTABLE_SHA256, (String) null); + } + catch (Exception e) { + } + return format == null ? UNKNOWN : format; + } + + /** + * @see ghidra.program.model.listing.Program#setExecutableSHA256(java.lang.String) + */ + @Override + public void setExecutableSHA256(String sha256) { + Options pl = getOptions(PROGRAM_INFO); + pl.setString(EXECUTABLE_SHA256, sha256); + changed = true; + } + /** * @see ghidra.program.model.listing.Program#getCreationDate() */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java index 0429b915da..ab99d72d18 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/Program.java @@ -190,6 +190,18 @@ public interface Program extends DataTypeManagerDomainObject { */ public void setExecutableMD5(String md5); + /** + * Sets the value corresponding to the original binary file SHA256 hash. + * @param sha256 SHA256 binary file hash + */ + public void setExecutableSHA256(String sha256); + + /** + * Returns a value corresponding to the original binary file SHA256 hash. + * May be null if program source did not correspond to a binary file. + */ + public String getExecutableSHA256(); + /** * Returns the creation date of this program. * If the program was created before this property diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ProgramTestDouble.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ProgramTestDouble.java index 662c10ac1b..fdbd8ed09a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ProgramTestDouble.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ProgramTestDouble.java @@ -406,6 +406,16 @@ public class ProgramTestDouble implements Program { throw new UnsupportedOperationException(); } + @Override + public String getExecutableSHA256() { + throw new UnsupportedOperationException(); + } + + @Override + public void setExecutableSHA256(String sha256) { + throw new UnsupportedOperationException(); + } + @Override public Date getCreationDate() { throw new UnsupportedOperationException(); diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/server/remote/ServerTestUtil.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/server/remote/ServerTestUtil.java index f38f7db0c6..197627e482 100644 --- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/server/remote/ServerTestUtil.java +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/server/remote/ServerTestUtil.java @@ -786,7 +786,7 @@ public class ServerTestUtil { funcAddr += 2; } - setProgramMd5(program); + setProgramHashes(program); ContentHandler contentHandler = DomainObjectAdapter.getContentHandler(program); long checkoutId = contentHandler.createFile(repoFilesystem, null, folderPath, name, @@ -856,15 +856,17 @@ public class ServerTestUtil { } /** - * Sets a dummy MD5 value for the given program. - * + * Sets dummy hash values for the given program. + * * @param program the current program */ - private static void setProgramMd5(Program program) { - int id = program.startTransaction("setmd5"); + private static void setProgramHashes(Program program) { + int id = program.startTransaction("sethashes"); try { String md5 = RandomStringUtils.randomNumeric(32); program.setExecutableMD5(md5); + String sha256 = RandomStringUtils.randomNumeric(64); + program.setExecutableSHA256(sha256); } finally { program.endTransaction(id, true);