Skip to content
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

Support starting the jupyter without Ghidra GUI. #32

Open
5c4lar opened this issue Jul 14, 2022 · 3 comments
Open

Support starting the jupyter without Ghidra GUI. #32

5c4lar opened this issue Jul 14, 2022 · 3 comments

Comments

@5c4lar
Copy link

5c4lar commented Jul 14, 2022

Is there a way to run a kotlin jupyter notebook without starting the Ghidra GUI? That would be helpful when developing scripts on a server.

@fmagin
Copy link
Contributor

fmagin commented Jul 14, 2022

Mmh, none that I have setup yet, but in theory it should be quite possible. You can simply call IkotlinKt.embedKernel(connectionFile, EmptyResolutionInfoProvider.INSTANCE, null);} in a postScript and it will set up the kernel, so using the jupyter-console is fairly trivial. For the notebook I guess there just needs to be one function that handles the initial setup of the notebook, which requires a bit of trickery so the Jupyter Notebook thinks that it started the server. I assume that the Jupyter Notebook server would be running on the same host as the Ghidra instance, and you would just be connecting to the notebook server from a remote client?

@5c4lar
Copy link
Author

5c4lar commented Jul 14, 2022

Thanks! @fmagin

I assume that the Jupyter Notebook server would be running on the same host as the Ghidra instance, and you would just be connecting to the notebook server from a remote client?

This is exactly what I'm trying to do.

@fmagin
Copy link
Contributor

fmagin commented Jul 14, 2022

Okay, quickly gave this a try: The first issue is that the NotebookThread constructor takes a PluginTool as an argument, which is not available in headless mode.

But when I change the NotebookProxy class to be public, you can run the following script and it will somewhat start the kernel. It's a bit finicky about when you start the kernel in the Jupyter web interface and when to run the script, because most of the times it fails with Could not initialize class org.slf4j.LoggerFactory (HeadlessAnalyzer) java.lang.NoClassDefFoundError: Could not initialize class org.slf4j.LoggerFactory but sometimes it works.

Could not initialize class org.slf4j.LoggerFactory (HeadlessAnalyzer) java.lang.NoClassDefFoundError: Could not initialize class org.slf4j.LoggerFactory
	at org.jetbrains.kotlinx.jupyter.config.LoggingKt.getLogger(logging.kt:9)
	at org.jetbrains.kotlinx.jupyter.config.LoggingKt.getLogger$default(logging.kt:9)
	at org.jetbrains.kotlinx.jupyter.libraries.ResolutionUtilKt.<clinit>(resolutionUtil.kt:9)
	at org.jetbrains.kotlinx.jupyter.KernelConfig$Companion.create(config.kt:167)
	at org.jetbrains.kotlinx.jupyter.IkotlinKt.embedKernel(ikotlin.kt:105)
	at HeadlessNotebook.run(HeadlessNotebook.kt:27)
	at ghidra.app.script.GhidraScript.executeNormal(GhidraScript.java:379)
	at ghidra.app.script.GhidraScript.doExecute(GhidraScript.java:234)
	at ghidra.app.script.GhidraScript.execute(GhidraScript.java:212)
	at ghidra.app.util.headless.HeadlessAnalyzer.runScript(HeadlessAnalyzer.java:576)
	at ghidra.app.util.headless.HeadlessAnalyzer.runScriptsList(HeadlessAnalyzer.java:909)
	at ghidra.app.util.headless.HeadlessAnalyzer.processWithImport(HeadlessAnalyzer.java:1765)
	at ghidra.app.util.headless.HeadlessAnalyzer.processLocal(HeadlessAnalyzer.java:445)
	at ghidra.app.util.headless.AnalyzeHeadless.launch(AnalyzeHeadless.java:121)
	at ghidra.GhidraLauncher.launch(GhidraLauncher.java:59)
	at ghidra.GhidraLauncher.main(GhidraLauncher.java:74)

@tmr232 you built the Notebook proxy, what do you think is the best way to allow this to work both in the GUI and from a script in headless mode? I'm quite confused why this logging class error only happens sometimes, I guess there are some kind of incompatible libraries involved here.

Script:

import GhidraJupyterKotlin.CellContext
import GhidraJupyterKotlin.NotebookProxy
import ghidra.app.script.GhidraScript
import ghidra.util.Msg
import ghidra.util.task.DummyCancellableTaskMonitor
import org.jetbrains.kotlinx.jupyter.embedKernel
import org.jetbrains.kotlinx.jupyter.libraries.EmptyResolutionInfoProvider
import java.nio.file.Path
import java.util.*


class HeadlessNotebook : GhidraScript() {
    override fun run() {
        val proxyPath = Path.of(
            Optional.ofNullable(System.getenv("GHIDRA_JUPYTER_PROXY"))
                .orElse(
                    Path.of(System.getProperty("user.home"))
                        .resolve(".ghidra")
                        .resolve("notebook_proxy")
                        .toString()
                )
        )
        val connectionFile = NotebookProxy(proxyPath).waitForConnection(DummyCancellableTaskMonitor())
        Msg.info(this, connectionFile.toString())

        embedKernel(
            connectionFile,
            EmptyResolutionInfoProvider, listOf<CellContext>(CellContext(this))
        )
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants