Skip to content

Commit dcc069e

Browse files
committed
Initial commit
1 parent 65a9c27 commit dcc069e

File tree

13 files changed

+443
-0
lines changed

13 files changed

+443
-0
lines changed

.github/workflows/release.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Main
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*'
7+
8+
jobs:
9+
build:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v2
13+
- name: Set up JDK 1.11
14+
uses: actions/setup-java@v1
15+
with:
16+
java-version: 1.11
17+
- uses: er28-0652/setup-ghidra@master
18+
with:
19+
version: "10.1"
20+
21+
- name: Build with Gradle
22+
run: gradle buildExtension
23+
24+
- name: Release
25+
uses: softprops/action-gh-release@v1
26+
with:
27+
files: ./dist/*zip
28+
env:
29+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# This workflow will build a Java project with Gradle
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
3+
4+
name: Test
5+
6+
on:
7+
push:
8+
branches: [ main ]
9+
pull_request:
10+
branches: [ main ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v2
19+
- name: Set up JDK 1.11
20+
uses: actions/setup-java@v1
21+
with:
22+
java-version: 1.11
23+
- uses: er28-0652/setup-ghidra@master
24+
with:
25+
version: "10.1"
26+
27+
- name: Build Extension
28+
run: gradle buildExtension
29+
30+
- name: Upload built extension as artifact for debugging
31+
uses: actions/upload-artifact@v2
32+
with:
33+
path: ./dist/*zip
34+
retention-days: 1
35+
36+
- name: Install Extension
37+
run: unzip ./dist/*zip -d $GHIDRA_INSTALL_DIR/Ghidra/Extensions
38+
39+
- name: Run Tests
40+
run: echo "Execute your tests here!"

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
build/
2+
.gradle/
3+
gradlew
4+
gradlew.bat
5+
lib/*jar

.idea/fileTemplates/GhidraKotlinScript.kt

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations/Run_Ghidra.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Ghidra Extension in Kotlin using IntelliJ IDEA
2+
3+
> Write a Ghidra Extension without using Java or Eclipse!
4+
5+
## Setup
6+
7+
* Hit `Use this template` at the top of the repo on GitHub
8+
* Clone the new repo to your development machine
9+
* Add the line `GHIDRA_INSTALL_DIR=/path/to/your/ghidra_10.1_PUBLIC/` to `$HOME/.gradle/gradle.properties`
10+
* Open IntelliJ, create a new `Project from Existing Sources...` and select the `build.gradle`
11+
* If you are using the [Kotlin Jupyter Plugin](https://github.com/GhidraJupyter/ghidra-jupyter-kotlin) uncomment the line in the `dependencies` block in the `build.gradle`
12+
* Wait for IntelliJ to finish indexing and fetching dependencies, hit the build button, and then run Ghidra
13+
14+
15+
## Features
16+
17+
* Gradle Config that works out of the box with IntelliJ
18+
* IntelliJ IDEA Run Configuration for debugging of the extension
19+
* If you have are using the [Kotlin Jupyter Plugin](https://github.com/GhidraJupyter/ghidra-jupyter-kotlin) you can also set breakpoints in the script file!
20+
* GitHub CI files that
21+
* make sure the extension at least builds for each PR
22+
* will automatically build a release and publish it on GitHub if a commit is tagged with a version matching `vX.X.X`, e.g. `v1.2.3`/`v1.2.0` (`v1.2` doesn't work!)
23+
24+
25+
## Additional Development Tips
26+
27+
These aspects can not be included in the repo files itself, but make development smoother.
28+
29+
### Thread Breakpoints
30+
31+
Make sure that you use breakpoints that only suspend the thread, and not everything.
32+
This means that the breakpoint will only suspend the thread that is currently running the analysis or the script,
33+
and the GUI will keep working.
34+
* Set a breakpoint, right-click the icon, and in the `Suspend` line select `Thread` instead of `All`
35+
* IntelliJ IDEA will suggest making this the default, click this too
36+
37+
38+
### Use Scripts and the Jupyter Kernel to prototype ideas
39+
40+
With the [Kotlin Jupyter Plugin](https://github.com/GhidraJupyter/ghidra-jupyter-kotlin) you can test your new ideas first.
41+
IntelliJ IDEA can do hot reloading of classes, but this has limits and then requires an IDE restart,
42+
which take an annoying amount of time. The QT Console only is fairly basic, but the Jupyter Notebook uses nearly the same
43+
code analysis engine as IntelliJ itself.
44+
45+
### Automatic conversion to Kotlin
46+
47+
* pasting Java code into a Kotlin file you will get the suggestion for this to be converted and then pasted
48+
* right-click `.java` file in the Project Tree there is an action at the very bottom to convert the entire file
49+
50+
51+
## Issues
52+
53+
If any step in this process doesn't work as described in the README, please open an issue on GitHub.
54+
I have only tested this on Linux so there might be some aspects that work differently on macOS or Windows, though these
55+
should be minor.

build.gradle

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Builds a Ghidra Extension for a given Ghidra installation.
2+
//
3+
// An absolute path to the Ghidra installation directory must be supplied
4+
// To make this work well with IntelliJ this should be automatically resolve able and NOT an environmental variable
5+
// You can either:
6+
// * use the `gradle.properties` file in the extension folder to set it for this project
7+
// * add the line `GHIDRA_INSTALL_DIR=/path/to/ghidras/ghidra_10.1_PUBLIC/` to your global config (`.gradle/gradle.properties` in your home folder)
8+
9+
10+
plugins {
11+
id 'org.jetbrains.kotlin.jvm' version "1.6.0"
12+
id 'idea'
13+
}
14+
15+
repositories {
16+
mavenCentral()
17+
}
18+
19+
//----------------------START "DO NOT MODIFY" SECTION------------------------------
20+
def ghidraInstallDir
21+
22+
if (System.env.GHIDRA_INSTALL_DIR) {
23+
ghidraInstallDir = System.env.GHIDRA_INSTALL_DIR
24+
}
25+
else if (project.hasProperty("GHIDRA_INSTALL_DIR")) {
26+
ghidraInstallDir = project.getProperty("GHIDRA_INSTALL_DIR")
27+
}
28+
29+
if (ghidraInstallDir) {
30+
apply from: new File(ghidraInstallDir).getCanonicalPath() + "/support/buildExtension.gradle"
31+
}
32+
else {
33+
throw new GradleException("GHIDRA_INSTALL_DIR is not defined!")
34+
}
35+
//----------------------END "DO NOT MODIFY" SECTION-------------------------------
36+
37+
// Set the JVM target to 11, as described in https://stackoverflow.com/a/44297713/13220684
38+
// Ghidra requires 11 and the buildExtension.gradle sets this for Java
39+
// IntelliJ will complain about the discrepancy between the Java and the Kotlin target otherwise
40+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
41+
kotlinOptions {
42+
jvmTarget = "11"
43+
}
44+
}
45+
46+
dependencies {
47+
// If you are using the Ghidra Jupyter Plugin for Kotlin, add the following line to declare it as a dependency
48+
// This allows using the extension methods and makes sure that the required Kotlin libraries are present and not
49+
// conflicting
50+
// api fileTree(dir: ghidraInstallDir + 'Ghidra/Extensions/GhidraJupyterKotlin/', include: "**/*.jar")
51+
}
52+
53+
// Make it explicit that the compilation depends on some libraries in the `lib` folder,
54+
// otherwise gradle will issue warnings
55+
compileKotlin.dependsOn(copyDependencies)
56+
57+
// Add the ghidra_scripts directory as an additional source set, so IntelliJ IDEA treats the scripts there as part of
58+
// the module
59+
// this means that your plugin code is available for code completion and analysis and that all dependencies of the module
60+
// are inherited
61+
sourceSets {
62+
main {
63+
kotlin {
64+
srcDirs 'ghidra_scripts'
65+
}
66+
}
67+
}

extension.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name=@extname@
2+
description=Kotlin Example Extension.
3+
author=Florian Magin
4+
createdOn=2021-12-15
5+
version=@extversion@
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SCRIPT DESCRIPTION
2+
//@category Examples
3+
//@toolbar world.png
4+
5+
import ghidra.app.script.GhidraScript
6+
7+
@Suppress("unused")
8+
class KotlinExtensionExampleScript : GhidraScript() {
9+
@Throws(Exception::class)
10+
override fun run() {
11+
TODO("Script code goes here")
12+
}
13+
}

gradle.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#GHIDRA_INSTALL_DIR=/path/to/ghidras/ghidra_10.1_PUBLIC/

0 commit comments

Comments
 (0)