binexport icon indicating copy to clipboard operation
binexport copied to clipboard

Java error running ghidra export

Open BonusPlay opened this issue 1 year ago • 14 comments

Running latest commit, JDK 21, ghidra 11.2.1.

Could not initialize class com.google.security.zynamics.BinExport$BinExport2
java.lang.NoClassDefFoundError: Could not initialize class com.google.security.zynamics.BinExport$BinExport2
	at com.google.security.binexport.BinExport2Builder.<init>(BinExport2Builder.java:81)
	at com.google.security.binexport.BinExportExporter.export(BinExportExporter.java:92)
	at ghidra.app.plugin.core.exporter.ExporterDialog$ExportTask.run(ExporterDialog.java:578)
	at ghidra.util.task.Task.monitoredRun(Task.java:134)
	at ghidra.util.task.TaskRunner.lambda$startTaskThread$0(TaskRunner.java:106)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: class com.google.security.zynamics.BinExport$BinExport2 tried to access method 'com.google.protobuf.LazyStringArrayList com.google.protobuf.LazyStringArrayList.emptyList()' (com.google.security.zynamics.BinExport$BinExport2 and com.google.protobuf.LazyStringArrayList are in unnamed module of loader ghidra.GhidraClassLoader @483bf400) [in thread "Task - Export visualboyadvance-m---.exe"]
	at com.google.security.zynamics.BinExport$BinExport2.<init>(BinExport.java:19352)
	at com.google.security.zynamics.BinExport$BinExport2.<clinit>(BinExport.java:25089)
	... 8 more

---------------------------------------------------
Build Date: 2024-Nov-05
Ghidra Version: 11.2.1
Java Home: /nix/store/f042x32jfm94d3cgaga8d6xl8vy6sg46-openjdk-21.0.5+11/lib/openjdk
JVM Version: N/A 21.0.5
OS: Linux 6.12.6 amd64

BonusPlay avatar Dec 29 '24 13:12 BonusPlay

Did you build the extension yourself or did you use the release binary?

How did you launch Ghidra? Is this using it headless from the command-line?

cblichmann avatar Jan 06 '25 09:01 cblichmann

Built myself (latest commit is newer than release binary), ghidra ran with UI.

BonusPlay avatar Jan 06 '25 11:01 BonusPlay

This is odd, it looks like the Gradle build did not add the Protobuf dependency correctly.

cblichmann avatar Jan 06 '25 12:01 cblichmann

I'll try to debug this issue a bit, as this might be caused by nix-related build stuff. I can see following classes in the ghidra-binexport.jar, but have no clue why it isn't working...

1980-02-01 00:00:00 .....         2112          905  com/google/protobuf/LazyStringArrayList$ByteArrayListView.class
1980-02-01 00:00:00 .....         2419          921  com/google/protobuf/LazyStringArrayList$ByteStringListView.class
1980-02-01 00:00:00 .....        11117         3951  com/google/protobuf/LazyStringArrayList.class

BonusPlay avatar Jan 06 '25 12:01 BonusPlay

I use Ghidra in headless mode, so I built extension and unzipped it in Ghidra/Extensions folder. I'm facing the same bug with fresh Ghidra 11.3 (JDK 21.0.6) in headless mode

ERROR Abort due to Headless analyzer error: class com.google.security.zynamics.BinExport$BinExport2 tried
 to access method 'com.google.protobuf.LazyStringArrayList com.google.protobuf.LazyStringArrayList.emptyL
ist()' (com.google.security.zynamics.BinExport$BinExport2 and com.google.protobuf.LazyStringArrayList are
 in unnamed module of loader ghidra.GhidraClassLoader @483bf400) (HeadlessAnalyzer) java.lang.IllegalAcce
ssError: class com.google.security.zynamics.BinExport$BinExport2 tried to access method 'com.google.proto
buf.LazyStringArrayList com.google.protobuf.LazyStringArrayList.emptyList()' (com.google.security.zynamic
s.BinExport$BinExport2 and com.google.protobuf.LazyStringArrayList are in unnamed module of loader ghidra
.GhidraClassLoader @483bf400)                                                                            
        at com.google.security.zynamics.BinExport$BinExport2.<init>(BinExport.java:19352)                
        at com.google.security.zynamics.BinExport$BinExport2.<clinit>(BinExport.java:25089)              
        at com.google.security.binexport.BinExport2Builder.<init>(BinExport2Builder.java:81)             
        at BinExport.export(BinExport.java:99)                                                           
        at BinExport.run(BinExport.java:81)                                                              
        at ghidra.app.script.GhidraScript.executeNormal(GhidraScript.java:405)                           
        at ghidra.app.script.GhidraScript.doExecute(GhidraScript.java:260)                               
        at ghidra.app.script.GhidraScript.execute(GhidraScript.java:238)                                 
        at ghidra.app.util.headless.HeadlessAnalyzer.runScript(HeadlessAnalyzer.java:588)                
        at ghidra.app.util.headless.HeadlessAnalyzer.runScriptsList(HeadlessAnalyzer.java:926)           
        at ghidra.app.util.headless.HeadlessAnalyzer.analyzeProgram(HeadlessAnalyzer.java:1074)          
        at ghidra.app.util.headless.HeadlessAnalyzer.processFileWithImport(HeadlessAnalyzer.java:1563)   
        at ghidra.app.util.headless.HeadlessAnalyzer.processWithLoader(HeadlessAnalyzer.java:1745)       
        at ghidra.app.util.headless.HeadlessAnalyzer.processWithImport(HeadlessAnalyzer.java:1686)       
        at ghidra.app.util.headless.HeadlessAnalyzer.processWithImport(HeadlessAnalyzer.java:1770)       
        at ghidra.app.util.headless.HeadlessAnalyzer$1.processResult(HeadlessAnalyzer.java:335)          
        at ghidra.framework.protocol.ghidra.GhidraURLQuery.doQueryUrl(GhidraURLQuery.java:141)           
        at ghidra.framework.protocol.ghidra.GhidraURLQuery.queryRepositoryUrl(GhidraURLQuery.java:67)    
        at ghidra.app.util.headless.HeadlessAnalyzer.processURL(HeadlessAnalyzer.java:317)               
        at ghidra.app.util.headless.AnalyzeHeadless.launch(AnalyzeHeadless.java:195)                     
        at ghidra.GhidraLauncher.launch(GhidraLauncher.java:81)                                          
        at ghidra.Ghidra.main(Ghidra.java:54)                                                            

I tried to add extension in GUI mode and then use it in headless, it works. It may be related with this issue ?

tonybounty avatar Feb 07 '25 14:02 tonybounty

Do you manipulate these settings in launch.properties?

VMARGS=-Dapplication.settingsdir=
VMARGS=-Dapplication.cachedir=

bukowa avatar Feb 12 '25 23:02 bukowa

Ghidra uses protobuf 4.31 in its Gradle file:

# Set Ghidra protobuf version
ghidra.protobuf.java.version=4.31.0

While we're at 3.25.1 BinExport Gradle:

dependencies {
    extraLibs 'com.google.protobuf:protobuf-java:3.25.1'
    configurations.implementation.extendsFrom(configurations.extraLibs)
}

I'll check whether simply upgrading to a later version works.

cblichmann avatar Sep 04 '25 13:09 cblichmann

1189dc6 updates to Java protobuf 4.31 (same as Ghidra's), but this still does not seem to change anything:

Could not initialize class com.google.security.zynamics.BinExport$BinExport2
java.lang.NoClassDefFoundError: Could not initialize class com.google.security.zynamics.BinExport$BinExport2
	at com.google.security.binexport.BinExport2Builder.<init>(BinExport2Builder.java:81)
	at com.google.security.binexport.BinExportExporter.export(BinExportExporter.java:92)
	at ghidra.app.plugin.core.exporter.ExporterDialog$ExportTask.run(ExporterDialog.java:578)
	at ghidra.util.task.Task.monitoredRun(Task.java:134)
	at ghidra.util.task.TaskRunner.lambda$startTaskThread$0(TaskRunner.java:106)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalAccessError: class com.google.security.zynamics.BinExport$BinExport2 tried to access method 'com.google.protobuf.LazyStringArrayList com.google.protobuf.LazyStringArrayList.emptyList()' (com.google.security.zynamics.BinExport$BinExport2 and com.google.protobuf.LazyStringArrayList are in unnamed module of loader ghidra.GhidraClassLoader @483bf400) [in thread "Task - Export switch"]
	at com.google.security.zynamics.BinExport$BinExport2.<init>(BinExport.java:19467)
	at com.google.security.zynamics.BinExport$BinExport2.<clinit>(BinExport.java:25736)
	... 8 more

---------------------------------------------------
Build Date: 2025-Aug-26 1351 EDT
Ghidra Version: 11.4.2
Java Home: /usr/lib/jvm/java-21-openjdk-amd64
JVM Version: Debian 21.0.8
OS: Linux 6.XX.XX-1yyyy1-amd64 amd64

cblichmann avatar Sep 04 '25 14:09 cblichmann

If I have following error, how it could be resolved? (Running Ghidra v11.4 on Linux, using "BinExport 12 (Updated for Ghidra 11.0.3")

2025-09-06 03:24:50 ERROR (ExportTask) Task Error: Export MainV6.bin - Uncaught Exception: java.lang.IllegalAccessError: class 
com.google.security.zynamics.BinExport$BinExport2 tried to access method 'com.google.protobuf.LazyStringArrayList 
com.google.protobuf.LazyStringArrayList.emptyList()' (com.google.security.zynamics.BinExport$BinExport2 and 
com.google.protobuf.LazyStringArrayList are in unnamed module of loader ghidra.GhidraClassLoader @483bf400) java.lang.IllegalAccessError: class com.google.security.zynamics.BinExport$BinExport2 tried to access method 'com.google.protobuf.LazyStringArrayList com.google.protobuf.LazyStringArrayList.emptyList()' (com.google.security.zynamics.BinExport$BinExport2 and com.google.protobuf.LazyStringArrayList are in unnamed module of loader ghidra.GhidraClassLoader @483bf400)
	at com.google.security.zynamics.BinExport$BinExport2.<init>(BinExport.java:19352)
	at com.google.security.zynamics.BinExport$BinExport2.<clinit>(BinExport.java:25089)
	at com.google.security.binexport.BinExport2Builder.<init>(BinExport2Builder.java:68)
	at com.google.security.binexport.BinExportExporter.export(BinExportExporter.java:92)
	at ghidra.app.plugin.core.exporter.ExporterDialog$ExportTask.run(ExporterDialog.java:578)
	at ghidra.util.task.Task.monitoredRun(Task.java:134)
	at ghidra.util.task.TaskRunner.lambda$startTaskThread$0(TaskRunner.java:106)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.lang.Thread.run(Thread.java:1583)

zalexua avatar Sep 06 '25 00:09 zalexua

Same error here, i downloaded from the latest build action

PwccaCode avatar Sep 09 '25 21:09 PwccaCode

Yes, this is a bit tricky to figure out. I still think this somehow might be due to us building with a different protobuf version than the one that ships with Ghidra.
Note to self: Try building with the officual Ghidra build container and see if that changes anything.

cblichmann avatar Sep 11 '25 12:09 cblichmann

Same error here ...

brdsutte avatar Oct 11 '25 11:10 brdsutte

How is this error still happening? 🤦‍♀️

lucashandsen avatar Oct 20 '25 10:10 lucashandsen

Two common ways this mismatch happens as I see it:

  1. Source-built Ghidra includes protobuf 4.31.0

    If you built Ghidra from source at/after the commit f1607b5c that changed the protobuf version in ‎gradle.properties, your runtime is protobuf 4.31.0. Using a BinExport extension compiled against protobuf 3.x (or bundling a 3.x jar inside the extension) will fail at runtime.

  2. Official Ghidra 11.4.2 release uses protobuf 3.21.8

    If you use the official 11.4.2 release (which still ships protobuf-java-3.21.8), but build BinExport with protoc/protobuf 4.x or bundle a 4.x jar (as is now the default) in the extension, you will also encounter errors.

Important packaging detail

Ghidra's support/buildExtension.gradle packages the module's local lib/ directory into the extension ZIP under BinExport/lib/. Any jar placed at binexport/java/lib/, e.g.: ~/binexport/java/lib/protobuf-java-4.31.0.jar will be included in the *.zip and override Ghidra’s classpath at runtime, causing the mismatch even if your Gradle dependencies are correct and even if you would do something like this:

gradle -PGHIDRA_INSTALL_DIR=$GHIDRA_INSTALL_DIR clean cleanGenerateProto --refresh-dependencies
gradle -PGHIDRA_INSTALL_DIR=$GHIDRA_INSTALL_DIR generateProto buildExtension

Quick and dirty fix in binexport/java/build.gradle:

def detectGhidraProtoVersion = { ->
    def defaultVer = '3.21.8'
    def ghidraDir = project.hasProperty('GHIDRA_INSTALL_DIR') ? file(project.property('GHIDRA_INSTALL_DIR')) : null
    if (ghidraDir?.exists()) {
        // Source builds: ghidra.protobuf.java.version in gradle.properties
        def gp = new File(ghidraDir, 'gradle.properties')
        if (gp.exists()) {
            def props = new Properties()
            gp.withInputStream { props.load(it) }
            def v = props.getProperty('ghidra.protobuf.java.version')
            if (v) return v.trim()
        }
        // Release installs: scan for protobuf-java-*.jar
        def jars = fileTree(ghidraDir).matching { include '**/protobuf-java-*.jar' }.files
        if (!jars.isEmpty()) {
            def m = jars.first().name =~ /protobuf-java-(\d+\.\d+\.\d+)/
            if (m.find()) return m.group(1)
        }
    }
    return defaultVer
}

def protobufVersion = detectGhidraProtoVersion()

dependencies { compileOnly "com.google.protobuf:protobuf-java:${protobufVersion}" }
protobuf { protoc { artifact = "com.google.protobuf:protoc:${protobufVersion}" } }
configurations { runtimeClasspath { exclude group: 'com.google.protobuf', module: 'protobuf-java' } }

cQQkie-dev avatar Oct 29 '25 19:10 cQQkie-dev