NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
51.78k stars 5.89k forks source link

Windows Debugger fails to launch with no terminal output, GetLastError 193 #6999

Closed CarePackage17 closed 3 weeks ago

CarePackage17 commented 1 month ago

Trying to launch a debugging session with dbgeng and it immediately fails with no output whatsoever on the terminal. Python 3.9.13 is installed via MS store and on PATH. Error 193 is ERROR_BAD_EXE_FORMAT, which doesn't make sense at first, unless...

My username has a space inside and whoever is handling paths for launching stuff doesn't like that, as after copying ghidra to another location without spaces and trying again I get at least a python stacktrace (might have missing dependencies).

To Reproduce Steps to reproduce the behavior:

  1. Copy your Ghidra installation to a path with a space
  2. Open an imported executable in the debugger tool
  3. Launch using dbgeng
  4. Get error 193 without any output

Expected behavior The debugger launching (or at least getting meaningful debug output)

Environment (please complete the following information):

d-millar commented 1 month ago

@CarePackage17 Trying to recreate your issue, but having no real success. I launched git-bash.exe from dbgeng (traceRMI/python interface, not IN-VM) successfully - path includes "Program Files" and I left the path as loaded from the file browser, i.e. nothing escaped, no extra quotes. Any chance you could provide more details? Also, maybe, see if you have the same issue running something mundane.

CarePackage17 commented 1 month ago

Maybe it's not any space in the path, but the username specifically (in my case).

I can repro this again, is there any useful logs you need and where do I find them?

d-millar commented 1 month ago

Re logs, anything that shows up in the Debug Console might help. If you run in debug mode (i.e. start with support/ghidraDebug vs.ghidraRun, anything that looks like an error in the console might help. And there is a log file for the debugger that’s generated (called something like debug.log?) but I’ll have check to see where that gets dropped.

nsadeveloper789 commented 1 month ago

There's no longer a debugger-specific log file. (There used to be one that showed the GDB/MI conversation, but that was for gdb only.) Instead, the Terminal window may have important warning/error messages. Sounds like it didn't even get that far, though. I'd say, in the launch options, where it asks for your Python command/path, double-check that it's actually an executable file (PE, and not, say, a shell script.) IINM, Ghidra will also implicitly run cmd.exe to invoke the launcher batch script. I wouldn't think that's the problem, but you might check that the cmd on your PATH is in fact the usual Windows command prompt. Last is perhaps the .bat file is somehow corrupt. It should be at Ghidra/Debug/Debugger-agent-dbgeng/data/debugger-launchers/local-dbgeng.bat (my memory may be fuzzy). Maybe check that it has CRLF and not just LF line endings? (Some of these ideas are real flimsy, I know, just trying to brainstorm a bit.)

CarePackage17 commented 1 month ago

I checked the line endings, they're CRLF as expected.

My python command works fine when used in cmd or wherever, but I think it's a sort of redirect to the proper thing (command execution alias, because MS store installed python does that and you can have multiple versions installed).

That OPT_PYTHON env var the batch script uses, where is it set?

d-millar commented 1 month ago

Re OPT_PYTHON: when you use any of the launchers from the toolbar, e.g. dbgeng, the launcher with that title get selected, e.g. local-dbgeng.bat. The @env items in that launcher are used to populate the dialog that comes up. In the case of OPT_PYTHON_EXE, the value from the dialog is then executed immediately by the .bat.

CarePackage17 commented 1 month ago

I got a stack trace via the Inspect Error window:

GetLastError() returned 193
com.sun.jna.LastErrorException: GetLastError() returned 193
    at ghidra.pty.windows.ConPtyChild.session(ConPtyChild.java:108)
    at ghidra.pty.windows.ConPtyChild.session(ConPtyChild.java:36)
    at ghidra.pty.PtyChild.session(PtyChild.java:68)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.runInTerminal(AbstractTraceRmiLaunchOffer.java:485)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractScriptTraceRmiLaunchOffer.launchBackEnd(AbstractScriptTraceRmiLaunchOffer.java:123)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.launchProgram(AbstractTraceRmiLaunchOffer.java:649)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin$ConfigureAndLaunchTask.run(TraceRmiLauncherServicePlugin.java:123)
    at ghidra.app.services.ProgressService.lambda$execute$0(ProgressService.java:123)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

---------------------------------------------------
Build Date: 2024-Sep-26 1444 EDT
Ghidra Version: 11.2
Java Home: C:\Program Files\Microsoft\jdk-21.0.4.7-hotspot
JVM Version: Microsoft 21.0.4
OS: Windows 10 10.0 amd64
Workstation: DESKTOP-58OMEIQ

Looks like the terminal setup code does something weird. Here's the line for reference.

I did make a procmon trace of the failing case and it starts conhost.exe from System32, no errors there at first sight, it just closes immediately. Not sure how we end up with error 193 of all things.

d-millar commented 1 month ago

OK, going to suggest one more test - apologies if I've already suggested this or you've already tried it:

(1) As before, use "Configure and Launch..." -> dbgeng to bring up the "Launch with dbgeng (in a Python Interpreter)" dialog (2) For "Image", use "C:\Windows\notepad.exe". Unselect "dbgmodel". Make sure "Arguments" and "Path to dbgeng.dll directory" are empty. Tell us what you have in "Python command". (I am using "py", which uses the default $PATH variable to find "C:\Windows\py.exe".

Does this fail with 193? My reason for suggesting this test: the place where you are failing basically uses none of the information in the dialog. This is an attempt to launch "local-dbgeng.bat", albeit with a bunch of other args and parameters, but putting junk in these fields will not cause the process to fail at that location. The only things, as far as I can see, that would cause a failure at that location are (1) local-dbgeng.bat has been corrupted in some way, (2) your system path is pointing to a missing or corrupt version of Kernel32.dll, or (3) the executable being used for "Python Command" is something odd. I feel like (1) and (2) are unlikely and/or would be obvious in other ways.

I have tested with various forms of garbage for the python executable, but haven't managed to come up with a 193 yet. For instance, pointing at, say, desktop.ini launches it as a .ini, or renaming desktop.ini to python.exe returns GetLastError=5.

CarePackage17 commented 1 month ago

It fails exactly the same way with your repro steps. I'm using python as the command, which works fine in cmd and PowerShell (located in %LOCALAPPDATA%\Microsoft\WindowsApps\python.exe, which redirects to version 3.12 in my case).

The error disappears when I move the Ghidra installation folder from my Desktop to C:\tools or something similar.

I don't have any java devtools on my machine right now, but I do have WinDbg and can break on CreateProcessWStub to inspect function arguments, maybe that'll give me a clue what's going wrong.

CarePackage17 commented 1 month ago

So, looking at the docs for CreateProcessW:

The lpApplicationName parameter can be NULL. In that case, the module name must be the first white space–delimited token in the lpCommandLine string. If you are using a long file name that contains a space, use quoted strings to indicate where the file name ends and the arguments begin; (...)

When breaking at that function in WinDbg, lpApplicationName is null and lpCommandLine is the absolute path to local-dbgeng.bat, but it is not wrapped in quotes (like the docs suggest we should do). My username has a space, so Windows treats the part before the space as the exe name and the rest as its arguments.

This still doesn't quite explain the bad exe format error. I looked into C:\Users and...there is a file that's the first part of my user name without an extension because Visual Studio installer also breaks on my user name having spaces when it creates a bunch of log files there.

So then Windows tries to execute that log file as a program and fails. Let's see if I get meaningful errors when I delete that file.

CarePackage17 commented 1 month ago

Alright, the launch actually happens!

I do get another error though:

Cannot invoke "ghidra.program.model.address.Address.getAddressSpace()" because the return value of "ghidra.trace.model.modules.TraceModule.getBase()" is null
java.lang.NullPointerException: Cannot invoke "ghidra.program.model.address.Address.getAddressSpace()" because the return value of "ghidra.trace.model.modules.TraceModule.getBase()" is null
    at ghidra.app.plugin.core.debug.service.modules.ProgramModuleIndexer.getBestMatch(ProgramModuleIndexer.java:386)
    at ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingProposals$ModuleMapProposalGenerator.proposeBestMap(DebuggerStaticMappingProposals.java:144)
    at ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingProposals$ModuleMapProposalGenerator.proposeBestMaps(DebuggerStaticMappingProposals.java:158)
    at ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingServicePlugin.proposeModuleMaps(DebuggerStaticMappingServicePlugin.java:582)
    at ghidra.app.plugin.core.debug.gui.action.ByModuleAutoMapSpec.performMapping(ByModuleAutoMapSpec.java:104)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.invokeMapper(AbstractTraceRmiLaunchOffer.java:195)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.waitForModuleMapping(AbstractTraceRmiLaunchOffer.java:594)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.AbstractTraceRmiLaunchOffer.launchProgram(AbstractTraceRmiLaunchOffer.java:665)
    at ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin$ConfigureAndLaunchTask.run(TraceRmiLauncherServicePlugin.java:123)
    at ghidra.app.services.ProgressService.lambda$execute$0(ProgressService.java:123)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1768)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1760)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:387)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1312)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1843)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1808)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:188)

---------------------------------------------------
Build Date: 2024-Sep-26 1444 EDT
Ghidra Version: 11.2
Java Home: C:\Program Files\Microsoft\jdk-21.0.4.7-hotspot
JVM Version: Microsoft 21.0.4
OS: Windows 10 10.0 amd64
Workstation: DESKTOP-58OMEIQ
d-millar commented 1 month ago

@CarePackage17 Nice catch on the spaces in the path. I thought this would be an easy fix, but turns out not so much. Will have to discuss tomorrow with some folks on the team. WRT the null value for getBase, still working on that one....more when I know more.

reticulatedpines commented 4 days ago

Minor nitpick: the fix commit typos "generate" as "genreate" in "genreateArgument()"

d-millar commented 3 days ago

@reticulatedpines I think this might have been fixed in our source (at least, search isn't finding it). Thanks, though!