Closed k7sjhl closed 2 years ago
@k7sjhl Not being familiar with the hackaday exercises, I may need a little more to go on. Am assuming this is a Windows executable. Do you have the Windows debuggers installed (either as part of Visual Studio or the Windows Kits)? Can you debug the executable with windbg or Visual Studio successfully, i.e. is this just a Ghidra problem?
@d-millar The exercises: https://github.com/wrongbaud/hackaday-u/tree/master/session-one/exercises
Try executing c1.
I am not sure if I have windows debuggers installed, what else do I need to run the ghidra debugger?
@k7sjhl Will give it a shot, but, if you don't have the windows debuggers installed, well, nothing good is going to happen.
@d-millar hi again, I installed windbg and the whole kit. Still got the same problem
@k7sjhl So I donwloaded c1 and brought it up in Ghidra - this is an ELF executable, no? It's not going to run on Windows.
@d-millar It works with the analyzer but not with the debugger. How can I debug it?
@k7sjhl You'll need to run it on Linux or under WSL (and install gdb or lldb) or, if you're feeling brave, you can run it in the emulator.
@d-millar hey thanks, it worked on Linux. Is there any way to do it on Windows though? Could you tell me how can I pass a parameter using the gdb in ghidra?
@k7sjhl Yes re Windows, and several approaches here depending on what you want. If you really want the executable running on your Windows box and you're running a current version of Windows, you'll need to install the Windows Linux subsystem (https://docs.microsoft.com/en-us/windows/wsl/install) and then debug via "GDB over SSH". There are a number of discussions in our Github Discussions forum related to this - just drop WSL in the Search bar in Discussions.
If you want to run Ghidra on Windows but have a box somewhere else (say, in a VM) running LInux, you can also run the debugger agent on the Linux machine and connect via "GDB over GADP", or, as in the WSL case, connect via "GDB over SSH" directly.
To pass a parameter, the easiest way (I think) is to use the pull-down from the toolbar, Debugger->GDB IN-VM, and then add the parameters on the command line prompt. You can also use the Targets window to start gdb, and then use the Launch button (little gear next to the bug) to pass in the parameters. There a bug right now with how these parameters get saved, so maybe copy&paste your command line if it's long and complicated.
@d-millar hey, thank you for the answer. The ghidra debugging feature works on Linux with GDB. Could you describe me step by step how I can use it on windows? Do I need to setup it somehow (how to connect over SSH?). I have never done it before, I assume the debugger window is then in the Linux VM I use, and the other parts remain in Windows?
Another problem would be, is there any way to get to certain part of the code without knowing the right parameters? For the task c1 for example, you need to guess the right password in order for the debugger to jump to the other parts of the instructions. Is there some way to force the debugger to move where I want, without knowing the right password?
What I wanted to also achieve is that I could see register entries at the instruction I wanted, but if the program never runs to that point, since a correct parameter is missing (password), thats not possible, in my understanding. Maybe is there some kind of function that allows me to see the register entries at the certain instruction I select?
@k7sjhl Re step-by-step, I could, but I feel there are better explanations out there for some parts. For example, I am not the best guy to explain how to install WSL - did you try the link above? Once you have WSL installed, you may need to install gdb/gdbserver. How to do that will depend on which version of Linux you installed in the WSL. At this point, I would make sure you can ssh into the WSL environment. Assuming that works, the credential info for "GDB over SSH" will be the same as those you used to ssh in directly.
When you connect using "GDB over SSH", you are basically using SSH to start gdb in the WSL environment, i.e. ssh is executing gdb on your behalf. Assuming that works, you can then start up your c1 executable using the Objects window with whatever parameters you desire. The one tricky bit is you have to make sure the path is correct and use Launch vs QuickLaunch. QuickLaunch will attempt to use the path stored in the program database, which, if you imported it on Windows, will be incorrect.
If all of that is working (!), the Registers view show update every time you break or step the process, so you should be able to track things like password values if they are passed by register or to see them in the Dynamic memory if they are stored there unencrypted. You might want to verify both are working by issuing the raw gdb commands in the Interpreter window, e.g. "info registers".
If you are at the branches that decide behavior based on whether or not the password is correct, you can also modify the registers under test (or memory) and force the program down whatever path you chose.
@d-millar hey thanks. Could you tell me more detailed on how to modify the registers to force the program to go the desired way? Is there a way for ghidra or other tool to do this for me? For example, I would like to land at certain instruction to see the contents of registers at that place, I mark it and the debugger modifies all needed jumps etc. to make it possible to get to that place? Is that even real?
If not, how do I modify, lets say a JMP instruction to do the jump, instead of moving further? I have a CMP instruction before and JZ after, so if the CMP result is 0, the flag should be set and I should perform the jump. What and how do I modify that in order to get what I want?
Also is there a view in the debugger that allows me to see the flags set? I tried to look into registers and there are some registers marked as flags, although the Z flag or so doesnt seem to trigger when CMP result is 0, but the JZ still jumps to desired place.
Sorry we are a bit out of topic right now but this information would help me a lot.
@k7sjhl Most debuggers give you r/w capability for both the registers and memory. For example, in gdb for an x86_64 target, set $RIP = 0xDEADBEEF will change the program counter's value to 0xDEADBBEF, and the next single-step will take there. The Interpreter window essentially exposes the entire functionality of the underlying debugger, so raw gdb commands should always be available to you. That said, I believe you can also use the Registers view to modify registers by hitting the "Enable editing" button in the top right. For memory, right now the Dynamic version of the Byte Viewer lacks an edit capability, so you'll have to use the Interpreter interface.
For most gdb commands, a quick Google of "gdb commands" will get you what you need. There are a lot of nice cheatsheets out there, and you can always type "help" in the Interpreter.
As you noted correctly, modifying a jump is usually done one of three ways: (1) you can modify the actual memory for the instruction, eg. change JZ to JMP, (2) you can modify the values going into the comparison before the comparison, or (3) you can modify the flags after the comparison. For x86_64, the flags register is EFL/EFLAGS/RFL/RFLAGS depending on who's referring to it. Generally, speaking you modify the entire register rather than the individual flag. (Honestly, I can't remember whether gdb allows you to modify individual flags - it might.)
I did notice, testing on Windows with dbgeng, that the flag registers appear to be unchanged. Might be a bug here. The values in the Objects tree and the Interpreter should always be good as they directly reflect the state of the debugger. (Registers reflects the state of the Ghidra trace.)
@k7sjhl Just to follow-up, for gdb it appears the rflags register in Registers is correct and editable if you decide to go that route. The individual flags in the Register window do not appear to be split out. The names are there, but the values are greyed out indicating they're stale or inaccessible. (A known issue and probably too complicated to explain right now.) The Windows version was actually broken, so super-glad you brought up the topic. Would have gone unnoticed, no doubt. Any luck with WSL?
@d-millar hello again. To be honest I dont know how to configure the windows to run through SSH to run GDB, although I may fail because my laptop might be blocking some connections. How can I change a JZ to JMP? I learned to just change the RIP register to address what I want, but I wonder if I could just change all jump conditions to "JMP" in a few steps, permanently or at least as long as the session is working. I Didnt try WSL further since you mentioned it cannot run .elf files.
I see that the flags register is changing whenever a flag is set, although how do I know which part of the register is which flag? Is there some scheme for this? Does any of the debuggers allow me to change a flag manually?
@k7sjhl Apologies - I think I gave you the wrong impression on some things....
So, first point, WSL IS one way to run .elf files on Windows. The loader for Windows handles a few different file formats, but typically PE files and not ELF. By installing the Windows Linux subsystem, you are, in essence, creating a new operating environment in which you CAN run ELF files. It's similar to setting up a virtual machine a la VMware or VirtualBox (although the underlying technology is substantially different.) So, if you have Windows 10 (Build 19041 or higher) or 11 and are unhappy with the Linux setup you're using right now, I would suggest installing WSL. It's a little tricky to use, but I've done it - and, if I can do it, you can do it.
One nice thing about using WSL is that it's unlikely Windows will default to blocking SSH connections between the Windows environment and a local WSL environment on the sam machine. With regard to your laptop blocking connections, can you SSH into it (or from it) directly? I would test that first. If that works, am sure we can walk you through the "GDB over SSH" setup.
So, to change JZ to JMP: JZ is either 74 plus a 1-byte offset or 0F 84 plus an 4-byte offset for near and far jumps; JMP is EB plus a 1-byte offset or E9 plus a 4-byte offset. (There are other variations, but for simplicity lets just consider those.) So, if you want to modify a near JZ to a near JMP, you have to overwrite the 74 with EB. In gdb (and hence the Ghidra Interpreter window), the command to do this is at say address 0x12345678 would be "set ((char ) 0x12345678) = 0xEB". For a far jump, you have to overwrite both the 0F with E9 and 84 plus the first 3 bytes of the offset with the full 4-byte offset. That is to say, the instruction for JMP 0xDEADBEEF is (luckily) a byte shorter than the instruction for JZ 0xDEADBEEF, so (yay) it fits but (boo) it involves shifting the offset.
After you've set the new instruction, I would recommend either refreshing the Objects tree and scrolling the Dynamic view up and down a ways to force the Dynamic view to update. If not, you'll still be looking at old code. You could also type "x 0xDEADBEEF" in the Interpreter to e(x)amine the memory and verify your change.
Regarding the flags, for x86/x64, the flags are contained in a separate register called EFL or RFL (or EFLAGS or RFLAGS, depending on whose talking about it) - not a portion of the other registers. Which bits are which is described in the Intel Processor Manual, which I would recommend downloading a copy of (). You can change this the same way you changed RIP, so you should be good to go on that front.
Hope that helps - yell if you have more questions!
@d-millar hey, thank you for the answers, they helped me a lot. I know I am a bit out of topic, but is there a way to run the debugger with ARM 32bit elf files?
@k7sjhl As long as you have a machine/OS to run the files on, the answer is likely to be yes. For instance, I can debug AARCH elf files in Ghidra by running (or connectign remotely) to my macbook which has an M1 processor. If you don't have an OS that supports ARM, you probably have to go the emulation route.
@d-millar which OS can support ARM? Could I run it on Macbook with M1 processor? Which emulator do you mean and how could I set it up?
@k7sjhl For any program to run, it has to be matched (more or less exactly) to the processor and the operating system. It has to be compiled to the correct instruction set to match the processor which executes the instructions. It has to have the correct file format so that the OS's loader can start it up, and it has to be linked against the correct set of libraries, so that it can make use of things like the OS's syscalls.
VMs are on way of solving the OS mismatch problem. A VM running Linux for example has the loader and libraries to match ELF executables. They do not solve the processor problem, so, if, for example, the host is Windows annd the VM is Linux, both need to be, say, x86. To solve the processor problem, you need a translation layer. For example, Rosetta on M1 macs translates x86 instructions into AARCH, which is a flavor of ARM. Similarly, there are emulators for things like Xbox or GameBoy, that allow you to run non-x86 games on Windows or Linux.
Wikipedia is a good resource here. The emulator entry is very complete, and certainly is a more comprehensive explanation than I can supply.
I am trying to use the ghidra debugger on one of the hackadayu exercises but I get the following error messages:
Launch failed for {args=/C:/Users/abc/Desktop/ghidra/hackaday-u-master/session-one/exercises/c1} ghidra.dbg.error.DebuggerUserException: Launch failed for {args=/C:/Users/abc/Desktop/ghidra/hackaday-u-master/session-one/exercises/c1} at ghidra.dbg.gadp.client.GadpClient.checkError(GadpClient.java:163) at ghidra.dbg.gadp.client.GadpClient.lambda$sendChecked$2(GadpClient.java:358) at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:642) at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506) at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2073) at ghidra.async.AsyncPairingCache.fulfill(AsyncPairingCache.java:166) at ghidra.dbg.gadp.client.GadpClient.lambda$receiveLoop$4(GadpClient.java:378) at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1736) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829)
I try to debug it using dbgeng locally via GADP. None of other options work either. I tried running it on different environments windows/linux and using admin rights etc. nothing helped.
How can I run the debugger in ghidra?