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

How to Debug an Android Emulator with Ghidra in Windows #6386

Open
alpgul opened this issue Apr 6, 2024 · 3 comments
Open

How to Debug an Android Emulator with Ghidra in Windows #6386

alpgul opened this issue Apr 6, 2024 · 3 comments
Assignees
Labels
Feature: Debugger Status: Triage Information is being gathered

Comments

@alpgul
Copy link

alpgul commented Apr 6, 2024

Error Messages:

  • C://msys64//mingw64//bin//gdb.exe

    The following error occurred while trying to debug in Ghidra:
    ghidra.dbg.error.DebuggerModelTerminatingException: Error while starting GDB: Pty implementation does not support null sessions. Try C:\msys64\mingw64\bin\gdb.exe -i mi2.

  • C://msys64//mingw64//bin//gdb.exe -i mi2

    It gets stuck at the connection phase without any error output.

  • GDB over SSH

    The following error occurred while attempting to debug in Ghidra:
    ghidra.dbg.error.DebuggerModelTerminatingException: Error while starting GDB: SSH connection error

    .ssh/config:

Host localhost
  HostName localhost
  Port 8022
  User root
  IdentityFile C://Users//Demo//.ssh//id_ed25519
  • JDWP Execution

    Connectors and virtual machine sections appear blank, and there is no error output.

System Information:

Windows Version: 10
Ghidra Version: 11.0.2
JVM Version: Oracle Corporation 22
gdb Version: 14.2
gdbserver (GDB) Version: 7.11
SSH: OpenSSH via Termux

Debugging an Application on a Targeted Android Emulator

Description:
I want to report the issues I encountered while debugging an application on an Android emulator using Ghidra. When using Ghidra, I encountered the following errors:

  • The first error occurred when Ghidra tried to start GDB. The error message states, "Pty application does not support empty sessions." To resolve the issue, I was advised to try the command "C://msys64//mingw64//bin//gdb.exe -i mi2" but it did not solve the problem.

  • The second error is related to getting stuck during the connection phase when using the "C://msys64//mingw64//bin//gdb.exe -i mi2" command. There is no error output available.

  • The third error occurred when attempting to use GDB over SSH. When I run ssh via cmd ("ssh root@localhost -p 8022 -i C:/Users/Demo/.ssh/id_ed25519"), the connection is successful. However, I couldn't establish a successful connection using the "ssh config" due to the Android emulator not having "passwd" installed. I defined the config file as "C://Users//Demo//.ssh//config."

  • JDWP Execution: After running the command "adb forward tcp:11111 jdwp:1234" via ADB, I can establish a JDWP connection in Ghidra. However, I cannot perform the debugging process because the connectors and virtual machine sections appear blank, and I don't receive any error output. When I tested JDWP via cmd("jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=11111"), it worked correctly.

@alpgul alpgul changed the title How to Debug an Android Emulator with Ghidra How to Debug an Android Emulator with Ghidra in Windows Apr 6, 2024
@nsadeveloper789
Copy link
Contributor

For the GDB connection, this looks related to #6107. In theory, that issue was resolved in 11.0.2, which you're already using, but it still could be similar. What helped me most there was capturing the application log file. I'd like to start with the case where "It gets stuck at the connection phase without any error output." Please also capture the comms between Ghidra and GDB/MI. That can be accomplished by passing the -Dagent.gdb.manager.log=true to ghidraRun. The file should be called GDB.log, somewhere in your C:\Users\Demo\.ghidra directory.

As for JDWP, this connector has probably suffered too much bitrot at this point. We're not likely to fix it ourselves, though we are open to PRs. Most likely, if we pursue JDWP again, it will be to port it to our new "Trace RMI" system.

@alpgul
Copy link
Author

alpgul commented Apr 8, 2024

When I deleted and recreated the project, gdb worked. However, after the gdb connection, the thread list appears empty and debugging cannot be done. It seems that there is a mismatch between gdb and gdbserver. I am getting an architecture mismatch warning even though the Android emulator and Windows are of the same architecture(x64). Can someone who debugs Android emulator suggest the most stable and error-free solution?

GDB.log:

<MI2: =thread-group-added,id="i1"
<MI2: ~"GNU gdb (GDB) 14.2\n"
*CMD: class agent.gdb.manager.impl.cmd.GdbListInferiorsCommand
>MI2: -list-thread-groups
<MI2: ~"Copyright (C) 2023 Free Software Foundation, Inc.\n"
<MI2: ~"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law."
<MI2: ~"\nType \"show copying\" and \"show warranty\" for details.\n"
<MI2: ~"This GDB was configured as \"x86_64-w64-mingw32\".\n"
<MI2: ~"Type \"show configuration\" for configuration details.\n"
<MI2: ~"For bug reporting instructions, please see:\n"
<MI2: ~"<https://www.gnu.org/software/gdb/bugs/>.\n"
<MI2: ~"Find the GDB manual and other documentation resources online at:\n    <"
<MI2: ~"http://www.gnu.org/software/gdb/documentation/>.\n\n"
<MI2: ~"For help, type \"help\".\n"
<MI2: ~"Type \"apropos word\" to search for commands related to \"word\".\n"
<MI2: (gdb)
<MI2: -list-thread-groups
<MI2: ^done,groups=[{id="i1",type="process"}]
*CMD: class agent.gdb.manager.impl.cmd.GdbListBreakpointsCommand
>MI2: -break-list
<MI2: (gdb)
<MI2: -break-list
<MI2: ^done,BreakpointTable={nr_rows="0",nr_cols="6",hdr=[{width="7",alignment="-1",col_name="number",colhdr="Num"},{width="14",alignment="-1",col_name="type",colhdr="Type"},{width="4",alignment="-1",col_name="disp",colhdr="Disp"},{width="3",alignment="-1",col_name="enabled",colhdr="Enb"},{width="10",alignment="-1",col_name="addr",colhdr="Address"},{width="40",alignment="2",col_name="what",colhdr="What"}],body=[]}
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
<MI2: (gdb)
>MI2: -interpreter-exec console "show architecture"
<MI2: -interpreter-exec console "show architecture"
<MI2: ~"The target architecture is set to \"auto\" (currently \"i386\").\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show endian"
<MI2: (gdb)
<MI2: -interpreter-exec console "show endian"
<MI2: ~"The target endianness is set automatically (currently little endian).\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show os"
<MI2: (gdb)
<MI2: -interpreter-exec console "show os"
<MI2: ~"The current OS ABI is \"auto\" (currently \"Windows\").\n"
<MI2: ~"The default OS ABI is \"Windows\".\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "set confirm off"
<MI2: (gdb)
<MI2: -interpreter-exec console "set confirm off"
<MI2: =cmd-param-changed,param="confirm",value="off"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "set new-console on"
<MI2: (gdb)
<MI2: -interpreter-exec console "set new-console on"
<MI2: =cmd-param-changed,param="new-console",value="on"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show version"
<MI2: (gdb)
<MI2: -interpreter-exec console "show version"
<MI2: ~"GNU gdb (GDB) 14.2\n"
<MI2: ~"Copyright (C) 2023 Free Software Foundation, Inc.\n"
<MI2: ~"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law."
<MI2: ~"\nType \"show copying\" and \"show warranty\" for details.\n"
<MI2: ~"This GDB was configured as \"x86_64-w64-mingw32\".\n"
<MI2: ~"Type \"show configuration\" for configuration details.\n"
<MI2: ~"For bug reporting instructions, please see:\n"
<MI2: ~"<https://www.gnu.org/software/gdb/bugs/>.\n"
<MI2: ~"Find the GDB manual and other documentation resources online at:\n    <"
<MI2: ~"http://www.gnu.org/software/gdb/documentation/>.\n\n"
<MI2: ~"For help, type \"help\".\n"
<MI2: ~"Type \"apropos word\" to search for commands related to \"word\".\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbListThreadsCommand
>MI2: -list-thread-groups i1
<MI2: (gdb)
<MI2: -list-thread-groups i1
<MI2: ^done,threads=[]
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "set sysroot"
<MI2: -interpreter-exec console "set sysroot"
<MI2: =cmd-param-changed,param="sysroot",value=""
<MI2: ^done
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "target remote :9999"
<MI2: -interpreter-exec console "target remote :9999"
<MI2: ~"Remote debugging using :9999\n"
<MI2: &"warning: A handler for the OS ABI \"GNU/Linux\" is not built into this configuration\nof GDB.  Attempting to continue with the default "
<MI2: &"i386:x86-64 settings.\n"
<MI2: &"\n"
<MI2: &"warning: Architecture rejected target-supplied description\n"
<MI2: =tsv-created,name="trace_timestamp",initial="0"
<MI2: =thread-group-started,id="i1",pid="5177"
<MI2: &"warning: /system/bin/app_process64: No such file or directory.\n"
INFO: Modules requested
<MI2: =thread-created,id="1",group-id="i1"
<MI2: =thread-created,id="2",group-id="i1"
.
.
.
<MI2: =thread-created,id="78",group-id="i1"
<MI2: =thread-created,id="79",group-id="i1"
<MI2: =thread-exited,id="1",group-id="i1"
<MI2: =thread-exited,id="2",group-id="i1"
.
.
.
<MI2: =thread-exited,id="79",group-id="i1"
<MI2: =thread-group-exited,id="i1"
<MI2: &"Remote register badly formatted: T0006:ffffffff00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\n"
<MI2: &"here: 00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\n"
<MI2: ^error,msg="Remote register badly formatted: T0006:ffffffff00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\nhere: 00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;"
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "info proc mappings"
<MI2: (gdb)
<MI2: -interpreter-exec console "info proc mappings"
<MI2: &"Not supported on this target.\n"
<MI2: ^error,msg="Not supported on this target."
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "maintenance info sections -all-objects"
<MI2: (gdb)
<MI2: -interpreter-exec console "maintenance info sections -all-objects"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbListThreadsCommand
>MI2: -list-thread-groups i1
<MI2: (gdb)
<MI2: -list-thread-groups i1
<MI2: ^done,threads=[]
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show architecture"
<MI2: (gdb)
<MI2: -interpreter-exec console "show architecture"
<MI2: ~"The target architecture is set to \"auto\" (currently \"i386\").\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbListInferiorsCommand
>MI2: -list-thread-groups
<MI2: (gdb)
<MI2: -list-thread-groups
<MI2: ^done,groups=[{id="i1",type="process"}]
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show os"
<MI2: (gdb)
<MI2: -interpreter-exec console "show os"
<MI2: ~"The current OS ABI is \"auto\" (currently \"Windows\").\n"
<MI2: ~"The default OS ABI is \"Windows\".\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "show endian"
<MI2: (gdb)
<MI2: -interpreter-exec console "show endian"
<MI2: ~"The target endianness is set automatically (currently little endian).\n"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbGetThreadInfoCommand
>MI2: -thread-info 1
<MI2: (gdb)
<MI2: -thread-info 1
<MI2: ^done,threads=[]
*CMD: class agent.gdb.manager.impl.cmd.GdbGetThreadInfoCommand
>MI2: -thread-info 2
<MI2: (gdb)
<MI2: -thread-info 2
<MI2: ^done,threads=[]
*CMD: class agent.gdb.manager.impl.cmd.GdbGetThreadInfoCommand
.
.
.
<MI2: (gdb)
<MI2: -thread-info 78
<MI2: ^done,threads=[]
*CMD: class agent.gdb.manager.impl.cmd.GdbGetThreadInfoCommand
>MI2: -thread-info 79
<MI2: (gdb)
<MI2: -thread-info 79
<MI2: ^done,threads=[]
*CMD: class agent.gdb.manager.impl.cmd.GdbEvaluateCommand
>MI2: -data-evaluate-expression "sizeof(int*)"
<MI2: (gdb)
<MI2: -data-evaluate-expression "sizeof(int*)"
<MI2: ^done,value="4"
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "maintenance info sections -all-objects"
<MI2: (gdb)
<MI2: -interpreter-exec console "maintenance info sections -all-objects"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "maintenance info sections ALLOBJ"
<MI2: (gdb)
<MI2: -interpreter-exec console "maintenance info sections ALLOBJ"
<MI2: ^done
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "info proc mappings"
<MI2: (gdb)
<MI2: -interpreter-exec console "info proc mappings"
<MI2: &"Not supported on this target.\n"
<MI2: ^error,msg="Not supported on this target."
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbReadMemoryCommand
>MI2: -data-read-memory-bytes 0x0 4096
<MI2: -data-read-memory-bytes 0x0 4096
<MI2: ^error,msg="Unable to read memory."
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbReadMemoryCommand
>MI2: -data-read-memory-bytes 0x0 4096
<MI2: -data-read-memory-bytes 0x0 4096
<MI2: ^error,msg="Unable to read memory."
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbReadMemoryCommand
>MI2: -data-read-memory-bytes 0x0 4096
<MI2: -data-read-memory-bytes 0x0 4096
<MI2: ^error,msg="Unable to read memory."
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbConsoleExecCommand
>MI2: -interpreter-exec console "c"
<MI2: -interpreter-exec console "c"
<MI2: &"The program is not being run.\n"
<MI2: ^error,msg="The program is not being run."
<MI2: (gdb)
*CMD: class agent.gdb.manager.impl.cmd.GdbContinueCommand
>MI2: -exec-continue
<MI2: -exec-continue
<MI2: ^error,msg="The program is not being run."
<MI2: (gdb)

@nsadeveloper789
Copy link
Contributor

@alpgul Thanks for the log. There are a few items of interest, but I think it all comes down to a mismatch is OS/ABI. The first item of interest:

<MI2: &"warning: A handler for the OS ABI \"GNU/Linux\" is not built into this configuration\nof GDB.  Attempting to continue with the default "
<MI2: &"i386:x86-64 settings.\n"
<MI2: &"\n"
<MI2: &"warning: Architecture rejected target-supplied description\n"

You should probably try using the multiarch build of gdb. The rest I think are symptoms of this mismatch, but I exhibit them here to demonstrate that Ghidra is displaying what GDB tells it:

<MI2: =thread-group-started,id="i1",pid="5177"
<MI2: &"warning: /system/bin/app_process64: No such file or directory.\n"
INFO: Modules requested
<MI2: =thread-created,id="1",group-id="i1"
<MI2: =thread-created,id="2",group-id="i1"
.
.
.
<MI2: =thread-created,id="78",group-id="i1"
<MI2: =thread-created,id="79",group-id="i1"
<MI2: =thread-exited,id="1",group-id="i1"
<MI2: =thread-exited,id="2",group-id="i1"
.
.
.
<MI2: =thread-exited,id="79",group-id="i1"
<MI2: =thread-group-exited,id="i1"

It seems GDB was not able to get any initial break in the application. The target is created and exited before Ghidra has a chance to interrogate GDB about the target. The "thread-group-exited" event is the application terminating.

<MI2: &"Remote register badly formatted: T0006:ffffffff00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\n"
<MI2: &"here: 00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\n"
<MI2: ^error,msg="Remote register badly formatted: T0006:ffffffff00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;\nhere: 00000000;07:7811b4ceff7f0000;10:6a0cc457c87a0000;thread:p1439.1439;core:1;"

Here gdb and gdbserver do not agree in how to exchange registers. I suspect this is due to OS/ABI, but I'm not sure. During negotation of the connection, the gdbserver may send a small XML snippet describing the target. This description also includes the order and types/sizes of registers, which is important for decoding the long hex string GDB is complaining about above. GDB rejected that description because it doesn't understand the GNU/Linux ABI in that description. That's my guess, anyway.

<MI2: -thread-info 1
<MI2: ^done,threads=[]

This is just further demonstrating why the Threads list is empty. The target application has exited by now, because GDB did not get an initial break. When Ghidra asks for the threads list, it is indeed empty.

My recommendation is to try gdb-multiarch. Get it working from just a plain terminal, without Ghidra, to verify all the other pieces are working correctly. Then, once that's working, try again from Ghidra.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Debugger Status: Triage Information is being gathered
Projects
None yet
Development

No branches or pull requests

3 participants