Merge pull request #310343 from vringar/ghidra-extensions

Ghidra extensions

authored by Jade Lovelace and committed by GitHub 1f42f627 6d447251

+413 -11
+6
maintainers/maintainer-list.nix
··· 21616 21616 name = "Kostas Karachalios"; 21617 21617 githubId = 81346; 21618 21618 }; 21619 + vringar = { 21620 + email = "git@zabka.it"; 21621 + github = "vringar"; 21622 + name = "Stefan Zabka"; 21623 + githubId = 13276717; 21624 + }; 21619 21625 vrthra = { 21620 21626 email = "rahul@gopinath.org"; 21621 21627 github = "vrthra";
+15
pkgs/tools/security/ghidra/0002-Load-nix-extensions.patch
··· 1 + diff --git a/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java b/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java 2 + index ea12a661f0..da7779b07f 100644 3 + --- a/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java 4 + +++ b/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java 5 + @@ -36,6 +36,10 @@ public class ApplicationUtilities { 6 + */ 7 + public static Collection<ResourceFile> findDefaultApplicationRootDirs() { 8 + Collection<ResourceFile> applicationRootDirs = new ArrayList<>(); 9 + + String nixGhidraHome = System.getenv("NIX_GHIDRAHOME"); 10 + + if (nixGhidraHome != null) { 11 + + applicationRootDirs.add(new ResourceFile(nixGhidraHome)); 12 + + }; 13 + ResourceFile applicationRootDir = findPrimaryApplicationRootDir(); 14 + if (applicationRootDir != null) { 15 + applicationRootDirs.add(applicationRootDir);
+26
pkgs/tools/security/ghidra/0003-Remove-build-datestamp.patch
··· 1 + diff --git a/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle b/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle 2 + index bc194f219..94b00fabd 100644 3 + --- a/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle 4 + +++ b/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle 5 + @@ -82,7 +82,7 @@ dependencies { 6 + helpPath fileTree(dir: ghidraDir + '/Features/Base', include: "**/Base.jar") 7 + } 8 + 9 + -def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}_${getCurrentDate()}" 10 + +def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}" 11 + def DISTRIBUTION_DIR = file("dist") 12 + 13 + def pathInZip = "${project.name}" 14 + diff --git a/gradle/root/distribution.gradle b/gradle/root/distribution.gradle 15 + index f44c8267b..f6231c417 100644 16 + --- a/gradle/root/distribution.gradle 17 + +++ b/gradle/root/distribution.gradle 18 + @@ -32,7 +32,7 @@ apply from: "$rootProject.projectDir/gradle/support/sbom.gradle" 19 + def currentPlatform = getCurrentPlatformName() 20 + def PROJECT_DIR = file (rootProject.projectDir.absolutePath) 21 + ext.DISTRIBUTION_DIR = file("$buildDir/dist") 22 + -ext.ZIP_NAME_PREFIX = "${rootProject.DISTRO_PREFIX}_${rootProject.BUILD_DATE_SHORT}" 23 + +ext.ZIP_NAME_PREFIX = "${rootProject.DISTRO_PREFIX}" 24 + ext.ZIP_DIR_PREFIX = "${rootProject.DISTRO_PREFIX}" 25 + ext.ALL_REPOS = [rootProject.file('.').getName()] 26 +
+78
pkgs/tools/security/ghidra/build-extension.nix
··· 1 + { lib 2 + , stdenv 3 + , unzip 4 + , jdk 5 + , gradle 6 + , ghidra 7 + }: 8 + 9 + let 10 + metaCommon = oldMeta: 11 + oldMeta // (with lib; { 12 + maintainers = (oldMeta.maintainers or []) ++ (with maintainers; [ vringar ]); 13 + platforms = oldMeta.platforms or ghidra.meta.platforms; 14 + }); 15 + 16 + buildGhidraExtension = { 17 + pname, nativeBuildInputs ? [], meta ? { }, ... 18 + }@args: 19 + stdenv.mkDerivation (args // { 20 + nativeBuildInputs = nativeBuildInputs ++ [ 21 + unzip 22 + jdk 23 + gradle 24 + ]; 25 + 26 + buildPhase = args.buildPhase or '' 27 + runHook preBuild 28 + 29 + # Set project name, otherwise defaults to directory name 30 + echo -e '\nrootProject.name = "${pname}"' >> settings.gradle 31 + 32 + export GRADLE_USER_HOME=$(mktemp -d) 33 + gradle \ 34 + --offline \ 35 + --no-daemon \ 36 + -PGHIDRA_INSTALL_DIR=${ghidra}/lib/ghidra 37 + 38 + runHook postBuild 39 + ''; 40 + 41 + installPhase = args.installPhase or '' 42 + runHook preInstall 43 + 44 + mkdir -p $out/lib/ghidra/Ghidra/Extensions 45 + unzip -d $out/lib/ghidra/Ghidra/Extensions dist/*.zip 46 + 47 + runHook postInstall 48 + ''; 49 + 50 + meta = metaCommon meta; 51 + }); 52 + 53 + buildGhidraScripts = { pname, meta ? { }, ... }@args: 54 + stdenv.mkDerivation (args // { 55 + installPhase = '' 56 + runHook preInstall 57 + 58 + GHIDRA_HOME=$out/lib/ghidra/Ghidra/Extensions/${pname} 59 + mkdir -p $GHIDRA_HOME 60 + cp -r . $GHIDRA_HOME/ghidra_scripts 61 + 62 + touch $GHIDRA_HOME/Module.manifest 63 + cat <<'EOF' > extension.properties 64 + name=${pname} 65 + description=${meta.description or ""} 66 + author= 67 + createdOn= 68 + version=${lib.getVersion ghidra} 69 + 70 + EOF 71 + 72 + runHook postInstall 73 + ''; 74 + 75 + meta = metaCommon meta; 76 + }); 77 + in 78 + { inherit buildGhidraExtension buildGhidraScripts; }
+61 -11
pkgs/tools/security/ghidra/build.nix
··· 1 1 { stdenv 2 2 , fetchFromGitHub 3 3 , lib 4 + , callPackage 4 5 , gradle_7 5 6 , perl 6 7 , makeWrapper ··· 10 11 , icoutils 11 12 , xcbuild 12 13 , protobuf 14 + , ghidra-extensions 13 15 }: 14 16 15 17 let ··· 17 19 pname = "ghidra"; 18 20 version = "11.0.3"; 19 21 22 + releaseName = "NIX"; 23 + distroPrefix = "ghidra_${version}_${releaseName}"; 20 24 src = fetchFromGitHub { 21 25 owner = "NationalSecurityAgency"; 22 26 repo = "Ghidra"; 23 27 rev = "Ghidra_${version}_build"; 24 - hash = "sha256-Id595aKYHP1R3Zw9sV1oL32nAUAr7D/K4wn6Zs7q3Jo="; 28 + hash = "sha256-IiLxaJvfJcK275FDZEsUCGp7haJjp8O2fUIoM4F9H30="; 29 + # populate values that require us to use git. By doing this in postFetch we 30 + # can delete .git afterwards and maintain better reproducibility of the src. 31 + leaveDotGit = true; 32 + postFetch = '' 33 + cd "$out" 34 + git rev-parse HEAD > $out/COMMIT 35 + # 1970-Jan-01 36 + date -u -d "@$(git log -1 --pretty=%ct)" "+%Y-%b-%d" > $out/SOURCE_DATE_EPOCH 37 + # 19700101 38 + date -u -d "@$(git log -1 --pretty=%ct)" "+%Y%m%d" > $out/SOURCE_DATE_EPOCH_SHORT 39 + find "$out" -name .git -print0 | xargs -0 rm -rf 40 + ''; 25 41 }; 26 42 27 43 gradle = gradle_7; 28 44 45 + patches = [ 46 + # Use our own protoc binary instead of the prebuilt one 47 + ./0001-Use-protobuf-gradle-plugin.patch 48 + 49 + # Override installation directory to allow loading extensions 50 + ./0002-Load-nix-extensions.patch 51 + 52 + # Remove build dates from output filenames for easier reference 53 + ./0003-Remove-build-datestamp.patch 54 + ]; 55 + 29 56 desktopItem = makeDesktopItem { 30 57 name = "ghidra"; 31 58 exec = "ghidra"; ··· 35 62 categories = [ "Development" ]; 36 63 }; 37 64 38 - # postPatch scripts. 65 + postPatch = '' 66 + # Set name of release (eg. PUBLIC, DEV, etc.) 67 + sed -i -e 's/application\.release\.name=.*/application.release.name=${releaseName}/' Ghidra/application.properties 68 + 69 + # Set build date and git revision 70 + echo "application.build.date=$(cat SOURCE_DATE_EPOCH)" >> Ghidra/application.properties 71 + echo "application.build.date.short=$(cat SOURCE_DATE_EPOCH_SHORT)" >> Ghidra/application.properties 72 + echo "application.revision.ghidra=$(cat COMMIT)" >> Ghidra/application.properties 73 + 74 + # Tells ghidra to use our own protoc binary instead of the prebuilt one. 75 + cat >>Ghidra/Debug/Debugger-gadp/build.gradle <<HERE 76 + protobuf { 77 + protoc { 78 + path = '${protobuf}/bin/protoc' 79 + } 80 + } 81 + HERE 82 + ''; 83 + 39 84 # Adds a gradle step that downloads all the dependencies to the gradle cache. 40 85 addResolveStep = '' 41 86 cat >>build.gradle <<HERE ··· 64 109 # Taken from mindustry derivation. 65 110 deps = stdenv.mkDerivation { 66 111 pname = "${pname}-deps"; 67 - inherit version src; 112 + inherit version src patches; 68 113 69 - patches = [ ./0001-Use-protobuf-gradle-plugin.patch ]; 70 114 postPatch = addResolveStep; 71 115 72 116 nativeBuildInputs = [ gradle perl ] ++ lib.optional stdenv.isDarwin xcbuild; ··· 98 142 outputHash = "sha256-nKfJiGoZlDEpbCmYVKNZXz2PYIosCd4nPFdy3MfprHc="; 99 143 }; 100 144 101 - in stdenv.mkDerivation { 102 - inherit pname version src; 145 + in stdenv.mkDerivation (finalAttrs: { 146 + inherit pname version src patches postPatch; 103 147 104 148 nativeBuildInputs = [ 105 149 gradle unzip makeWrapper icoutils protobuf ··· 107 151 108 152 dontStrip = true; 109 153 110 - patches = [ 111 - ./0001-Use-protobuf-gradle-plugin.patch 112 - ]; 154 + __darwinAllowLocalNetworking = true; 113 155 114 156 buildPhase = '' 115 157 runHook preBuild ··· 152 194 mkdir -p "$out/bin" 153 195 ln -s "${pkg_path}/ghidraRun" "$out/bin/ghidra" 154 196 wrapProgram "${pkg_path}/support/launch.sh" \ 197 + --set-default NIX_GHIDRAHOME "${pkg_path}/Ghidra" \ 155 198 --prefix PATH : ${lib.makeBinPath [ openjdk17 ]} 156 199 ''; 157 200 201 + passthru = { 202 + inherit releaseName distroPrefix; 203 + inherit (ghidra-extensions.override { ghidra = finalAttrs.finalPackage; }) buildGhidraExtension buildGhidraScripts; 204 + 205 + withExtensions = callPackage ./with-extensions.nix { ghidra = finalAttrs.finalPackage; }; 206 + }; 207 + 158 208 meta = with lib; { 159 209 description = "A software reverse engineering (SRE) suite of tools developed by NSA's Research Directorate in support of the Cybersecurity mission"; 160 210 mainProgram = "ghidra"; ··· 165 215 binaryBytecode # deps 166 216 ]; 167 217 license = licenses.asl20; 168 - maintainers = with maintainers; [ roblabla ]; 218 + maintainers = with maintainers; [ roblabla vringar ]; 169 219 broken = stdenv.isDarwin && stdenv.isx86_64; 170 220 }; 171 221 172 - } 222 + })
+14
pkgs/tools/security/ghidra/extensions.nix
··· 1 + { lib, newScope, callPackage, ghidra }: 2 + 3 + lib.makeScope newScope (self: { 4 + inherit (callPackage ./build-extension.nix { inherit ghidra; }) buildGhidraExtension buildGhidraScripts; 5 + 6 + ghidraninja-ghidra-scripts = self.callPackage ./extensions/ghidraninja-ghidra-scripts { }; 7 + 8 + gnudisassembler = self.callPackage ./extensions/gnudisassembler { inherit ghidra; }; 9 + 10 + machinelearning = self.callPackage ./extensions/machinelearning { inherit ghidra; }; 11 + 12 + sleighdevtools = self.callPackage ./extensions/sleighdevtools { inherit ghidra; }; 13 + 14 + })
+36
pkgs/tools/security/ghidra/extensions/ghidraninja-ghidra-scripts/default.nix
··· 1 + { lib 2 + , fetchFromGitHub 3 + , buildGhidraScripts 4 + , binwalk 5 + , swift 6 + , yara 7 + }: 8 + 9 + buildGhidraScripts { 10 + pname = "ghidraninja-ghidra-scripts"; 11 + version = "unstable-2020-10-07"; 12 + 13 + src = fetchFromGitHub { 14 + owner = "ghidraninja"; 15 + repo = "ghidra_scripts"; 16 + rev = "99f2a8644a29479618f51e2d4e28f10ba5e9ac48"; 17 + sha256 = "aElx0mp66/OHQRfXwTkqdLL0gT2T/yL00bOobYleME8="; 18 + }; 19 + 20 + postPatch = '' 21 + # Replace subprocesses with store versions 22 + substituteInPlace binwalk.py --replace-fail 'subprocess.call(["binwalk"' 'subprocess.call(["${binwalk}/bin/binwalk"' 23 + substituteInPlace swift_demangler.py --replace-fail '"swift"' '"${swift}/bin/swift"' 24 + substituteInPlace yara.py --replace-fail 'subprocess.check_output(["yara"' 'subprocess.check_output(["${yara}/bin/yara"' 25 + substituteInPlace YaraSearch.py --replace-fail '"yara "' '"${yara}/bin/yara "' 26 + ''; 27 + 28 + meta = with lib; { 29 + description = "Scripts for the Ghidra software reverse engineering suite"; 30 + homepage = "https://github.com/ghidraninja/ghidra_scripts"; 31 + license = with licenses; [ 32 + gpl3Only 33 + gpl2Only 34 + ]; 35 + }; 36 + }
+71
pkgs/tools/security/ghidra/extensions/gnudisassembler/default.nix
··· 1 + { lib 2 + , stdenv 3 + , fetchurl 4 + , buildGhidraExtension 5 + , ghidra 6 + , flex 7 + , bison 8 + , texinfo 9 + , perl 10 + , zlib 11 + , xcbuild 12 + }: 13 + 14 + let 15 + # Incorporates source from binutils 16 + # https://github.com/NationalSecurityAgency/ghidra/blob/7ab9bf6abffb6938d61d072040fc34ad3331332b/GPL/GnuDisassembler/build.gradle#L34-L35 17 + binutils-version = "2.41"; 18 + binutils-src = fetchurl { 19 + url = "mirror://gnu/binutils/binutils-${binutils-version}.tar.bz2"; 20 + sha256 = "sha256-pMS+wFL3uDcAJOYDieGUN38/SLVmGEGOpRBn9nqqsws="; 21 + }; 22 + in 23 + buildGhidraExtension { 24 + pname = "gnudisassembler"; 25 + version = lib.getVersion ghidra; 26 + 27 + src = "${ghidra}/lib/ghidra/Extensions/Ghidra/${ghidra.distroPrefix}_GnuDisassembler.zip"; 28 + 29 + postPatch = '' 30 + ln -s ${binutils-src} binutils-${binutils-version}.tar.bz2 31 + ''; 32 + 33 + # Don't modify ELF stub resources 34 + dontPatchELF = true; 35 + dontStrip = true; 36 + 37 + __darwinAllowLocalNetworking = true; 38 + 39 + nativeBuildInputs = [ 40 + flex 41 + bison 42 + texinfo 43 + perl 44 + ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ 45 + xcbuild 46 + ]; 47 + 48 + buildInputs = [ 49 + zlib 50 + ]; 51 + 52 + installPhase = '' 53 + runHook preInstall 54 + 55 + EXTENSIONS_ROOT=$out/lib/ghidra/Ghidra/Extensions 56 + mkdir -p $EXTENSIONS_ROOT 57 + unzip -d $EXTENSIONS_ROOT $src 58 + 59 + mkdir -p $EXTENSIONS_ROOT/GnuDisassembler/build 60 + cp -r build/os $EXTENSIONS_ROOT/GnuDisassembler/build/ 61 + 62 + runHook postInstall 63 + ''; 64 + 65 + meta = with lib; { 66 + description = "Leverage the binutils disassembler capabilities for various processors"; 67 + homepage = "https://ghidra-sre.org/"; 68 + downloadPage = "https://github.com/NationalSecurityAgency/ghidra/tree/master/GPL/GnuDisassembler"; 69 + license = licenses.gpl2Only; 70 + }; 71 + }
+34
pkgs/tools/security/ghidra/extensions/machinelearning/default.nix
··· 1 + { lib 2 + , buildGhidraExtension 3 + , ghidra 4 + }: 5 + 6 + buildGhidraExtension { 7 + pname = "machinelearning"; 8 + version = lib.getVersion ghidra; 9 + 10 + src = "${ghidra}/lib/ghidra/Extensions/Ghidra/${ghidra.distroPrefix}_MachineLearning.zip"; 11 + dontUnpack = true; 12 + 13 + # Built as part ghidra 14 + dontBuild = true; 15 + 16 + installPhase = '' 17 + runHook preInstall 18 + 19 + mkdir -p $out/lib/ghidra/Ghidra/Extensions 20 + unzip -d $out/lib/ghidra/Ghidra/Extensions $src 21 + 22 + runHook postInstall 23 + ''; 24 + 25 + meta = with lib; { 26 + inherit (ghidra.meta) homepage license; 27 + description = "Finds functions using ML"; 28 + downloadPage = "https://github.com/NationalSecurityAgency/ghidra/tree/master/Ghidra/Extensions/MachineLearning"; 29 + sourceProvenance = with sourceTypes; [ 30 + fromSource 31 + binaryBytecode # deps 32 + ]; 33 + }; 34 + }
+40
pkgs/tools/security/ghidra/extensions/sleighdevtools/default.nix
··· 1 + { lib 2 + , buildGhidraExtension 3 + , ghidra 4 + , python3 5 + }: 6 + 7 + buildGhidraExtension { 8 + pname = "sleighdevtools"; 9 + version = lib.getVersion ghidra; 10 + 11 + src = "${ghidra}/lib/ghidra/Extensions/Ghidra/${ghidra.distroPrefix}_SleighDevTools.zip"; 12 + dontUnpack = true; 13 + 14 + # Built as part ghidra 15 + dontBuild = true; 16 + buildInputs = [ python3 ]; 17 + 18 + installPhase = '' 19 + runHook preInstall 20 + 21 + mkdir -p $out/lib/ghidra/Ghidra/Extensions 22 + unzip -d $out/lib/ghidra/Ghidra/Extensions $src 23 + 24 + runHook postInstall 25 + ''; 26 + 27 + meta = with lib; { 28 + inherit (ghidra.meta) homepage license; 29 + description = "Sleigh language development tools including external disassembler capabilities"; 30 + longDescription = '' 31 + Sleigh language development tools including external disassembler capabilities. 32 + The GnuDisassembler extension may be also be required as a disassembly provider. 33 + ''; 34 + downloadPage = "https://github.com/NationalSecurityAgency/ghidra/tree/master/Ghidra/Extensions/SleighDevTools"; 35 + sourceProvenance = with sourceTypes; [ 36 + fromSource 37 + binaryBytecode # deps 38 + ]; 39 + }; 40 + }
+30
pkgs/tools/security/ghidra/with-extensions.nix
··· 1 + { lib 2 + , callPackage 3 + , symlinkJoin 4 + , makeBinaryWrapper 5 + , ghidra 6 + }: 7 + 8 + let 9 + ghidra-extensions = callPackage ./extensions.nix { inherit ghidra; }; 10 + allExtensions = lib.filterAttrs (n: pkg: lib.isDerivation pkg) ghidra-extensions; 11 + 12 + /* Make Ghidra with additional extensions 13 + Example: 14 + pkgs.ghidra.withExtensions (p: with p; [ 15 + ghostrings 16 + ]); 17 + => /nix/store/3yn0rbnz5mbrxf0x70jbjq73wgkszr5c-ghidra-with-extensions-10.2.2 18 + */ 19 + withExtensions = f: (symlinkJoin { 20 + name = "${ghidra.pname}-with-extensions-${lib.getVersion ghidra}"; 21 + paths = (f allExtensions); 22 + nativeBuildInputs = [ makeBinaryWrapper ]; 23 + postBuild = '' 24 + makeWrapper '${ghidra}/bin/ghidra' "$out/bin/ghidra" \ 25 + --set NIX_GHIDRAHOME "$out/lib/ghidra/Ghidra" 26 + ''; 27 + inherit (ghidra) meta; 28 + }); 29 + in 30 + withExtensions
+2
pkgs/top-level/all-packages.nix
··· 5384 5384 protobuf = protobuf_21; 5385 5385 }; 5386 5386 5387 + ghidra-extensions = recurseIntoAttrs (callPackage ../tools/security/ghidra/extensions.nix { }); 5388 + 5387 5389 ghidra-bin = callPackage ../tools/security/ghidra { }; 5388 5390 5389 5391 gh2md = callPackage ../tools/backup/gh2md { };