Skip to content

Commit

Permalink
add groovy (#28)
Browse files Browse the repository at this point in the history
Adds support for Groovy scripts and an interactive Groovy terminal,
both with version 4.0.6.

Also corrects an issue with help pages not being found when pressing
F1 while hovering over an interpreter window.
  • Loading branch information
goatshriek authored Nov 20, 2022
1 parent 5714ec3 commit 6f43810
Show file tree
Hide file tree
Showing 37 changed files with 1,173 additions and 39 deletions.
22 changes: 16 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ jobs:
runs-on: "ubuntu-latest"
strategy:
matrix:
ghidra: ["10.2"]
ghidra: ["10.2.2"]
include:
- ghidra: "10.2"
ghidra-url: "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_10.2_build/ghidra_10.2_PUBLIC_20221101.zip"
ghidra-sha256: "a5163f50bd6ce725c4c8638f7505b64bb603ea6bfe3f7d9ed4e403236716f787"
ghidra-filename: "ghidra_10.2_PUBLIC_20221101.zip"
ghidra-folder: "ghidra_10.2_PUBLIC"
- ghidra: "10.2.2"
ghidra-url: "https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_10.2.2_build/ghidra_10.2.2_PUBLIC_20221115.zip"
ghidra-sha256: "feb8a795696b406ad075e2c554c80c7ee7dd55f0952458f694ea1a918aa20ee3"
ghidra-filename: "ghidra_10.2.2_PUBLIC_20221115.zip"
ghidra-folder: "ghidra_10.2.2_PUBLIC"

env:
GHIDRA_INSTALL_DIR: /home/runner/ghidra/${{ matrix.ghidra-folder }}
Expand Down Expand Up @@ -73,6 +73,11 @@ jobs:
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript GhidraBasicsScriptKts.kts HeadlessTest -deleteProject | sed -n "s/^INFO GhidraBasicsScriptKts.kts> \(.*\) (GhidraScript).*$/\1/p" > actual.txt
diff actual.txt src/test/resources/expected/GhidraBasicsScript.txt
rm actual.txt
- name: Ghidra Basics Groovy Script
run: |
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript GhidraBasicsScriptGroovy.groovy HeadlessTest -deleteProject | sed -n "s/^INFO GhidraBasicsScriptGroovy.groovy> \(.*\) (GhidraScript).*$/\1/p" > actual.txt
diff actual.txt src/test/resources/expected/GhidraBasicsScript.txt
rm actual.txt
- name: Ghidra Basics Clojure Script
run: |
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript GhidraBasicsScriptClj.clj HeadlessTest -deleteProject | awk '/^INFO SCRIPT:/{flag=1;next}/^INFO /{flag=0}flag' > actual.txt
Expand All @@ -88,6 +93,11 @@ jobs:
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript SaveStringsScriptKts.kts TestStringsKotlin.txt -deleteProject
grep "Hello Ghidra!" TestStringsKotlin.txt
rm TestStringsKotlin.txt
- name: Save Strings Groovy Script
run: |
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript SaveStringsScriptGroovy.groovy TestStringsGroovy.txt -deleteProject
grep "Hello Ghidra!" TestStringsGroovy.txt
rm TestStringsGroovy.txt
- name: Save Strings Clojure Script
run: |
$GHIDRA_INSTALL_DIR/support/analyzeHeadless ~/projects/ RubyDragonTest -import ./src/test/resources/bin/HelloGhidra.exe -postScript SaveStringsScriptClj.clj TestStringsClojure.txt -deleteProject
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [2.1.0] - 2022-11-20
### Added
- Groovy script capability (uses Groovy 4.0.6)

### Fixed
- F1 now properly resolves help page for interpreter under pointer


## [2.0.0] - 2022-11-06
### Changed
- Upgrade to JRuby 9.3.9.0 (Ruby 2.6.8)
Expand Down
6 changes: 5 additions & 1 deletion NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ to the project repository at https://github.com/jruby/jruby. The full terms of
the license can be found at
https://github.com/jruby/jruby/blob/master/COPYING.

The Java log included in the src/main/resources/images folder is Copyright (c)
The Java logo included in the src/main/resources/images folder is Copyright (c)
Oracle.

The Kotlin logo included in the src/main/resources/images folder is
Expand All @@ -16,6 +16,10 @@ For more details on the language and its resources, see https://kotlinlang.org/.
For the full terms of the license included with Kotlin, see
https://github.com/JetBrains/kotlin/blob/master/license/LICENSE.txt.

The image included at src/main/resources/images/groovy.png is based on the logo
for the Groovy programming language, which is licensed by the Apache Software
Foundation under the Apache Software License 2.0.

The Clojure logo included in the src/main/resources/images folder is from the
Clojure project, Copyright (c) Rich Hickey. All rights reserved. Clojure is
covered by the EPL 1.0 license. For the source code of the project, refer to
Expand Down
39 changes: 28 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
[![build](https://github.com/goatshriek/ruby-dragon/actions/workflows/build.yml/badge.svg)](https://github.com/goatshriek/ruby-dragon/actions/workflows/build.yml)
[![Apache 2.0 License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

[Ruby](#ruby-usage), [Kotlin](#kotlin-usage), [JShell](#jshell-usage), and
[Clojure](#clojure-usage) support for Ghidra, both interactive and scripting.
[Ruby](#ruby-usage), [Kotlin](#kotlin-usage), [Groovy](#groovy-usage),
[Clojure](#clojure-usage), and [JShell](#jshell-usage) support for Ghidra.


## Installation
Expand Down Expand Up @@ -134,10 +134,10 @@ Kotlin scripts use a `kts` extension as they are interpreted as scripts rather
than being compiled to java first.


## JShell Usage
The JShell plugin provides an interactive Java interpreter by JShell, a Java
REPL included in Java. It provides the same built in variables that are
available in Java scripts:
## Groovy Usage
Groovy follows the same patterns as the other languages, being provided in the
`GroovyDragon` plugin and reachable from the `Window->Groovy` menu option. It
has the same built-in variables that the others provide:

```
currentAddress
Expand All @@ -150,14 +150,10 @@ currentSelection
`currentAPI` is also provided as with the Kotlin interpreter, again holding an
instance of `FlatProgramAPI` created with `currentProgram`.

This interpreter is especially handy when writing Java scripts, as it allows you
to iteratively test snippets of code from the script without needing to do any
sort of conversion to other languages like Python or Kotlin.


## Clojure Usage
Clojure follows the same patterns as the other languages, being provided in the
`ClojureDragon` plugin and reachable from the `Window->Clojure` menu option.
`ClojureDragon` plugin and the menu item `Window->Clojure`.

The Clojure interpreter and scripts also have bindings that make the state
information available to them, within the `ghidra` namespace. They are:
Expand All @@ -183,6 +179,27 @@ example of this type of access. Those familiar with the Python scripting
interface may recognize this paradigm, as it is the same there.


## JShell Usage
The JShell plugin provides an interactive Java interpreter by JShell, a Java
REPL included in Java. It provides the same built in variables that are
available in Java scripts:

```
currentAddress
currentHighlight
currentLocation
currentProgram
currentSelection
```

`currentAPI` is also provided as with the Kotlin interpreter, again holding an
instance of `FlatProgramAPI` created with `currentProgram`.

This interpreter is especially handy when writing Java scripts, as it allows you
to iteratively test snippets of code from the script without needing to do any
sort of conversion to other languages like Python or Kotlin.


## Contributing
Right now, the easiest way to contribute is to post any suggestions or try it
out and open an issue if you have any problems. Head over to the
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ plugins {
dependencies {
implementation('org.jruby:jruby-complete:9.3.9.0')
implementation('org.clojure:clojure:1.11.1')
implementation('org.apache.groovy:groovy:4.0.6')
implementation('org.apache.groovy:groovy-groovysh:4.0.6')
testImplementation('junit:junit:4.13')
runtimeOnly('org.jetbrains.kotlin:kotlin-scripting-jsr223:1.7.20')
}
Expand Down
7 changes: 0 additions & 7 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ or want to make a suggestion, please submit an issue on the project's
[Github page](https://github.com/goatshriek/ruby-dragon).


## 2.1.0
* [ADD] **Groovy Language Bindings**
While initially aimed at Ruby, this project is ultimately aimed at making a
variety of JVM-based languages available to Ghidra users. Groovy is an easy
target, being the most Java-friendly interpreted language.


## Unallocated to a release
* [ADD] **Complete Example Set**
A full suite of example scripts is needed for users to quickly understand how
Expand Down
2 changes: 1 addition & 1 deletion extension.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=RubyDragon
description=Ruby, Kotlin, JShell, and Clojure interpreters.
description=Ruby, Kotlin, Groovy, Clojure, and JShell interpreters.
author=goatshriek
createdOn=
version=@extversion@
82 changes: 82 additions & 0 deletions ghidra_scripts/GhidraBasicsScriptGroovy.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//Examples of basic Ghidra scripting in Groovy.
//@category: Examples.Groovy

import ghidra.program.model.listing.CodeUnit
import ghidra.app.util.datatype.DataTypeSelectionDialog
import ghidra.util.data.DataTypeParser

// of course, standard variable assignments work as expected
// in normal Groovy fashion, you can use getters without the 'get' prefix
programName = currentProgram.name
creationDate = currentProgram.creationDate
languageId = currentProgram.languageID
compilerSpecId = currentProgram.compilerSpec.compilerSpecID

// printing out some basic program information
// you'll need to use the script.print family of functions to see the output
script.println('Program Info:')
script.println("$programName $languageId ($compilerSpecId)")
script.println()

// get info about the current program's memory layout
script.println('Memory Layout:')
script.println(String.format('Imagebase: 0x%x', currentProgram.imageBase.offset))
currentProgram.memory.blocks.each {
script.println("${it.name} [start: 0x${it.start}, end: 0x${it.end}]")
}
script.println()

// get the current program's function names
script.println('Function List:')
function = script.firstFunction
while (function) {
script.println(function.name)
function = script.getFunctionAfter(function)
}
script.println()

// get the current location in the program
script.println(String.format('Current Location: 0x%x', currentAddress.offset))
script.println()

// get some user input
userInput = script.askString('Hello', 'Please enter a value')
script.println("You entered '$userInput'")

// output a popup window with the entered value
script.popup(userInput)

// add a comment to the current program
minAddress = currentProgram.minAddress
codeUnit = currentProgram.listing.getCodeUnitAt(minAddress)
codeUnit.setComment(CodeUnit.PLATE_COMMENT, 'This is an added comment from Groovy!')

// only valid in interactive scripts
if (!script.isRunningHeadless()) {
// prompting the user for a data type
script.println()
script.println('prompting for a data type...')
tool = script.state.tool
dtm = currentProgram.dataTypeManager
types = DataTypeParser.AllowedDataTypes.FIXED_LENGTH
selectionDialog = new DataTypeSelectionDialog(tool, dtm, -1, types)
tool.showDialog(selectionDialog)
dataType = selectionDialog.getUserChosenDataType()
if (dataType) {
script.println("Chosen data type: $dataType")
}
script.println()

// report progress to the user interface
// do this anywhere things take a while
script.monitor.initialize(10)
10.times {
script.monitor.checkCanceled()
Thread.sleep(1000)
script.monitor.incrementProgress(1)
script.monitor.message = "working on step $it"
}
}

// script output against example executable located in this repository at
// src/test/resources/bin/HelloGhidra.exe
30 changes: 30 additions & 0 deletions ghidra_scripts/SaveStringsScriptGroovy.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Save all strings of five characters or more in the current program to a file
// with the given name, or `saved_strings.txt` if no filename was given as a
// command line argument. This script is based on the CountAndSaveStrings script
// included with Ghidra.

// @category: Examples.Groovy

import java.io.File

// read in the filename, or default to `saved_strings.txt` if none was passed
filename = args.length > 0 ? args[0] : 'saved_strings.txt'

// initialize the string counter
stringCount = 0

// go through the data in the program
new File(filename).withPrintWriter { outFile ->
currentProgram.listing.getDefinedData(true).each {
typeName = it.dataType.name
valueRep = it.defaultValueRepresentation
if ((typeName.equals('unicode') || typeName.equals('string')) && valueRep.length() > 4) {
outFile.println(valueRep)
stringCount += 1
}
}
}


// print out the final string count
script.println("total number of strings: $stringCount")
9 changes: 5 additions & 4 deletions src/main/help/help/TOC_Source.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@
<tocroot>
<tocref id="Ghidra Functionality">
<tocref id="Scripting">
<tocdef id="Clojure Interpreter" sortgroup="z" text="Clojure Interpreter" target="help/topics/rubydragon/clojure.html" />
<tocdef id="JShell Interpreter" sortgroup="z" text="JShell Interpreter" target="help/topics/rubydragon/jshell.html" />
<tocdef id="Kotlin Interpreter" sortgroup="z" text="Kotlin Interpreter" target="help/topics/rubydragon/kotlin.html" />
<tocdef id="Ruby Interpreter" sortgroup="z" text="Ruby Interpreter" target="help/topics/rubydragon/ruby.html" />
<tocdef id="Clojure_interpreter" sortgroup="z" text="Clojure Interpreter" target="help/topics/Clojure/interpreter.html" />
<tocdef id="Groovy_interpreter" sortgroup="z" text="Groovy Interpreter" target="help/topics/Groovy/interpreter.html" />
<tocdef id="JShell_interpreter" sortgroup="z" text="JShell Interpreter" target="help/topics/JShell/interpreter.html" />
<tocdef id="Kotlin_interpreter" sortgroup="z" text="Kotlin Interpreter" target="help/topics/Kotlin/interpreter.html" />
<tocdef id="Ruby_interpreter" sortgroup="z" text="Ruby Interpreter" target="help/topics/Ruby/interpreter.html" />
</tocref>
</tocref>
</tocroot>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/help/help/topics/Groovy/images/reload3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 6f43810

Please sign in to comment.
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy