-
-
Notifications
You must be signed in to change notification settings - Fork 13.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ghidra: refactor #60664
ghidra: refactor #60664
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,9 @@ | ||
{ stdenv, fetchurl, unzip, lib, makeWrapper, autoPatchelfHook | ||
, openjdk11, pam | ||
}: let | ||
|
||
pkg_path = "$out/lib/ghidra"; | ||
|
||
in stdenv.mkDerivation { | ||
|
||
name = "ghidra-9.0"; | ||
|
||
src = fetchurl { | ||
url = https://ghidra-sre.org/ghidra_9.0_PUBLIC_20190228.zip; | ||
sha256 = "3b65d29024b9decdbb1148b12fe87bcb7f3a6a56ff38475f5dc9dd1cfc7fd6b2"; | ||
}; | ||
|
||
nativeBuildInputs = [ | ||
makeWrapper | ||
autoPatchelfHook | ||
unzip | ||
]; | ||
|
||
buildInputs = [ | ||
stdenv.cc.cc.lib | ||
pam | ||
]; | ||
|
||
dontStrip = true; | ||
|
||
installPhase = '' | ||
mkdir -p "${pkg_path}" | ||
cp -a * "${pkg_path}" | ||
''; | ||
|
||
postFixup = '' | ||
mkdir -p "$out/bin" | ||
makeWrapper "${pkg_path}/ghidraRun" "$out/bin/ghidra" \ | ||
--prefix PATH : ${lib.makeBinPath [ openjdk11 ]} | ||
''; | ||
|
||
meta = with lib; { | ||
description = "A software reverse engineering (SRE) suite of tools developed by NSA's Research Directorate in support of the Cybersecurity mission"; | ||
homepage = "https://ghidra-sre.org/"; | ||
platforms = [ "x86_64-linux" ]; | ||
license = licenses.asl20; | ||
maintainers = [ maintainers.ck3d ]; | ||
}; | ||
|
||
} | ||
{callPackage}: | ||
let | ||
packages = callPackage ./packages.nix {}; | ||
in | ||
# For ergonomics | ||
packages.ghidra // { | ||
inherit (packages) withPlugins extend; # For ergonomics and overrides | ||
pkgs = packages; # For access | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Overriding | ||
---------- | ||
For the moment, the API documentation is the tests. | ||
Documentation will be added in at most a few weeks. | ||
|
||
Tests | ||
----- | ||
Tests can be run with `nix-shell testname.nix`. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Expected result: | ||
# An Eclipse instance should start, with the GhidraDev | ||
# plugin asking for consent to open ports | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage eclipses; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
|
||
eclipse = eclipses.eclipseWithPlugins { | ||
eclipse = eclipses.eclipse-java; | ||
plugins = [ ghidra.pkgs.ghidraDev ]; | ||
}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ eclipse ]; | ||
shellHook = '' | ||
exec eclipse -data "$(mktemp -d)" | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Expected result: | ||
# An Eclipse instance should start, with the GhidraDev | ||
# plugin attached as a debugger to a headless Ghidra | ||
# that is built with an out-of-tree plugin. The debugger | ||
# should stop in a breakpoint in the plugin source code | ||
# and display the appropriate source location. | ||
|
||
#TODO not yet implemented | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say either implement this right away or do not check in this stubbed test for now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Giving up on this for the moment, possible starting points: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{callPackage}: | ||
callPackage ../../default.nix {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Expected result: | ||
# A running Ghidra GUI instance | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ ghidra ]; | ||
shellHook = '' | ||
exec ghidraRun | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Expected result: | ||
# A Ghidra GUI instance should start with the scala loader plugin listed under | ||
# File -> Install Extensions | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ (ghidra.withPlugins (p: with p; [ ghidra-scala-loader ])) ]; | ||
shellHook = '' | ||
exec ghidraRun | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Expected result: | ||
# Some trace output, the build, and then | ||
# Listening for transport dt_socket at address: 18001 | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
|
||
newOpts = self: super: { | ||
tracing = true; | ||
config = super.pkgs.lib.recursiveUpdate super.config ({ | ||
defaultOpts.debug = { | ||
enable = true; | ||
}; | ||
}); | ||
}; | ||
newGh = self: super: { | ||
ghidra = super.ghidra.override { | ||
extraLaunchers = { | ||
"myGhidraDebug" = self.lib.mkRunline { debug = { suspend = true; }; }; | ||
}; | ||
}; | ||
}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ | ||
(((ghidra.extend newOpts).extend newGh).withPlugins (p: with p; [ ghidra-scala-loader ])) | ||
]; | ||
shellHook = '' | ||
exec myGhidraDebug | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Expected result: | ||
# It should dump the headless analyzer usage information | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
newGh = self: super: { | ||
ghidra = super.ghidra.override { | ||
extraLaunchers = { | ||
"myGhidra" = self.lib.mkRunline { | ||
args = self.config.defaultOpts.args.headless; | ||
}; | ||
}; | ||
}; | ||
}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ | ||
((ghidra.extend newGh).withPlugins (p: with p; [ ghidra-scala-loader ])) | ||
]; | ||
shellHook = '' | ||
exec myGhidra | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Expected result: | ||
# INFO HelloWorldScript.scala> Hello world, I'm written in Scala! (GhidraScript) | ||
|
||
let pkgs = import ./nixpkgs.nix; in | ||
|
||
let | ||
inherit (pkgs) mkShell callPackage; | ||
|
||
ghidra = callPackage ./ghidra.nix {}; | ||
newGh = self: super: { | ||
ghidra = super.ghidra.override { | ||
extraLaunchers = { | ||
"myGhidra" = self.lib.mkRunline { | ||
args = self.config.defaultOpts.args.headless; | ||
}; | ||
}; | ||
}; | ||
}; | ||
in | ||
mkShell { | ||
name = "ghidra"; | ||
buildInputs = [ | ||
((ghidra.extend newGh).withPlugins (p: with p; [ ghidra-scala-loader ])) | ||
]; | ||
shellHook = '' | ||
exec myGhidra $(mktemp -d) TestProj -noanalysis -preScript HelloWorldScript.scala | ||
''; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import ../../../../../.. {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{pkgs, lib}: | ||
self: { | ||
# Don't pollute the namespace (for e.g. tab completion) | ||
inherit pkgs; | ||
|
||
# Thus we can take dependencies from both pkgs and Ghidra nevertheless. | ||
# Packages from ghidra take precedence on collision. | ||
callPackage = lib.callPackageWith ( self.pkgs // self ); | ||
|
||
|
||
tracing = false; | ||
trace = str: val: | ||
if self.tracing then | ||
lib.traceValFn (v: "${str}\n${lib.generators.toPretty {} v}") val | ||
else | ||
val; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
self: super: { | ||
config = { | ||
pkg_path = "lib/ghidra"; | ||
ghidraDevPath = self.config.pkg_path + "/Extensions/Eclipse/GhidraDev/GhidraDev-2.0.0.zip"; | ||
ghidraDevVersion = "2.0.0"; | ||
launchers = [ | ||
"ghidraRun" "support/analyzeHeadless" "support/buildGhidraJar" | ||
"support/convertStorage" "support/dumpGhidraThreads" "support/ghidraDebug" | ||
"support/pythonRun" "support/sleigh" | ||
]; | ||
defaultOpts = import ../lib/defaultOpts.nix; | ||
}; | ||
|
||
|
||
lib = { | ||
# nix-shell -p nix-prefetch-github --run "nix-prefetch-github owner repo > ./plugins/json/theplugin.json" | ||
fetchGitHubJSON = {JSONfile, ...}@args: | ||
self.pkgs.fetchFromGitHub ({ inherit (self.pkgs.lib.importJSON JSONfile) owner repo rev sha256; } // ( | ||
builtins.removeAttrs args [ "JSONfile" ] | ||
)); | ||
|
||
# { args ? defaultOpts.args, debug ? defaultOpts.debug }: # The signature | ||
mkRunline = self.callPackage ((import ../lib/mkRunline.nix) self.config.defaultOpts) {}; | ||
|
||
poorMkGradle = self.callPackage ../lib/poorMkGradle.nix {}; | ||
|
||
jdkWrapper = src: dst: '' | ||
makeWrapper "$out/${src}" "$out/${dst}" \ | ||
--prefix PATH : '${self.pkgs.lib.makeBinPath [ self.jdk ]}' \ | ||
--run '. ${self.jdk}/nix-support/setup-hook' #set JAVA_HOME | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We not setting JAVA_HOME directly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't really sure what to do about this. It makes some kind of sense to me to delegate setting whatever environment stuff a dependency implies, by relying on the dependency's scripts? |
||
''; | ||
|
||
writeCustomLauncher = name: content: '' | ||
cp -- "${self.pkgs.writeShellScriptBin name content}/bin/${name}" "$out/bin/.${name}" | ||
${self.lib.jdkWrapper "bin/.${name}" "bin/${name}" } | ||
''; | ||
|
||
# hash-name -> name | ||
nameOf = i: with self.pkgs.lib; | ||
let dropHash = s: concatStringsSep "-" (tail (splitString "-" s)); in | ||
dropHash (removeSuffix ".zip" (builtins.baseNameOf i)); | ||
|
||
unpackPlugin = pluginZip: | ||
self.pkgs.stdenv.mkDerivation { | ||
name = builtins.unsafeDiscardStringContext (self.lib.nameOf pluginZip); | ||
phases = [ "unpackPhase" "installPhase" ]; | ||
buildInputs = [ self.pkgs.unzip ]; | ||
src = pluginZip; | ||
installPhase = '' | ||
mkdir -p -- "$out" | ||
cp -r -- ./* "$out" | ||
''; | ||
}; | ||
|
||
#TODO mk extracted plugin derivation and ln that? <--use multiple output? | ||
installPlugin = plugin: '' | ||
ln -s -- "${plugin}" "$out/${self.config.pkg_path}/Ghidra/Extensions/${self.lib.nameOf (builtins.baseNameOf plugin)}" | ||
''; | ||
}; | ||
|
||
|
||
withPlugins = f: self.ghidra.override { plugins = f self; }; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
self: super: { | ||
jdk = self.pkgs.jdk11; | ||
gradleGen = (self.pkgs.gradleGen.override {jdk = self.jdk;}).gradle_latest; | ||
|
||
ghidra = self.callPackage ../lib/ghidra.nix {}; | ||
# For use with `eclipses.eclipseWithPlugins`, see tests/eclipse-00.nix | ||
ghidraDev = self.pkgs.eclipses.plugins.buildEclipseUpdateSite rec { | ||
name = "GhidraDev"; | ||
version = self.config.ghidraDevVersion; | ||
|
||
sourceRoot = "."; | ||
|
||
src = self.ghidra + "/" + self.config.ghidraDevPath; | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# NOTE to maintainers: please check whether plugins include binaries or JARs in their distributions, | ||
# as opposed to getting them from proper sources - accepting this is highly discouraged! | ||
# The plugin building code will check for files with .jar extensions, but not more than that. | ||
self: super: { | ||
ghidra-scala-loader = self.callPackage ./4_plugins/ghidra-scala-loader.nix { scala = self.pkgs.scala_2_11; }; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{scala, lib}: | ||
let | ||
src = lib.fetchGitHubJSON { JSONfile = ./json/ghidra-scala-loader.json; }; | ||
in | ||
(lib.poorMkGradle "ghidra-scala-loader" src).overrideAttrs (a: { | ||
removeJars = '' | ||
pushd lib | ||
rm -- * | ||
popd | ||
''; | ||
addJars = '' | ||
pushd lib | ||
unpacked=$(mktemp -d) | ||
pushd -- $unpacked | ||
cp -- ${scala.src} . | ||
tar axvf "$(basename -- *)" | ||
mv -- scala-*/* . | ||
popd | ||
cp -- "$unpacked/lib/scala-compiler.jar" ./scala-compiler-2.11.12.jar | ||
cp -- "$unpacked/lib/scala-library.jar" ./scala-library-2.11.12.jar | ||
cp -- "$unpacked/lib/scala-reflect.jar" ./scala-reflect-2.11.12.jar | ||
popd | ||
''; | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"owner": "edmcman", | ||
"repo": "ghidra-scala-loader", | ||
"rev": "392a2af0441f3c53dbbd749ec8d86539e7bcb901", | ||
"sha256": "0drphh7fjvlkqwwk0lcr3818vk7mqs6xkm6iv3xp6c7vl3d32b1c" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# This is essentially for mkRunline, but if it becomes useful to have | ||
# default arguments for something else, this is where they should go. | ||
{ | ||
debug = { | ||
enable = false; | ||
suspend = false; | ||
port = "18001"; | ||
# host = "127.0.0.1"; #TODO for implementation when ghidra version is updated | ||
}; | ||
|
||
args = { | ||
name = "Ghidra"; | ||
maxMemory = ""; | ||
vmArgs = ""; | ||
class = "ghidra.GhidraRun"; | ||
extraArgs = ""; | ||
enableUserShellArgs = true; | ||
|
||
#Convenience, see tests/headless-00.nix for an example. | ||
headless = { | ||
name = "Ghidra-Headless"; | ||
class = "ghidra.app.util.headless.AnalyzeHeadless"; | ||
}; | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Famous last words.