Do we have a way to view assembly and c code both using gdb.
disassemble function_name shows only assembly, I was trying to find a way to easliy map c code to assembly.
Thanks
You can run gdb in Text User Interface (TUI) mode:
gdb -tui <your-binary>
(gdb) b main
(gdb) r
(gdb) layout split
The layout split command divides the window into two parts - one of them displaying the source code, the other one the corresponding assembly.
A few others tricks:
set disassembly-flavor intel - if your prefer intel notation
set print asm-demangle - demangles C++ names in assembly view
ni - next instruction
si - step instruction
If you do not want to use the TUI mode (e.g. your terminal does not like it), you can always do:
x /12i $pc
which means print 12 instructions from current program counter address - this also works with the tricks above (demangling, stepping instructions, etc.).
The "x /12i $pc" trick works in both gdb and cgdb, whereas "layout split" only works in gdb.
Enjoy :)
Try disassemble /m.
Refer to http://sourceware.org/gdb/current/onlinedocs/gdb/Machine-Code.html#Machine-Code
The format is similar to that of objdump -S, and intermixes source with disassembly. Sample output excerpt:
10 int i = 0;
=> 0x0000000000400536 <+9>: movl $0x0,-0x14(%rbp)
11 while (1) {
12 i++;
0x000000000040053d <+16>: addl $0x1,-0x14(%rbp)
For your purpose, try
objdump -S <your_object_file>
from man objdump:
-S
--source
Display source code intermixed with disassembly, if possible.
Implies -d.
The fastest way to obtain this is to press the key combination ctrl-x 2 after launching gdb.
This will give you immediately a split window with source code and assembly in Text User Interface Mode (described in accepted answer).
Just another tooltip: keyboard arrows in this mode are used for navigate up and down through the source code, to use them to access commands history you can use ctrl-x o that will refocus on gdb shell window.
Related
Recently I have been working on CTF challenges that require the attacker to stage shellcode in the environment. With ASLR disabled, one can rely on only slight differences between the environment of the shell, for example, and that of the exploitable process (e.g. differences due only to binary name differences). However, GDB (and R2) will make slight changes to the environment that make this very hard to do due to the environment variables shifting around slightly when not being debugged.
For example, GDB seems to at least add the environment variables LINES and COLUMNS. However, these can be removed by invoking GDB as follows:
gdb -ex 'set exec-wrapper env -u LINES -u COLUMNS' -ex 'r < exploit.input' challenge.bin
Note that GDB will implicitly use the fully qualified path when debugging a binary, so the user can further decrease any differences by invoking the binary in a similar manner.
`pwd`/challenge.bin < exploit.input
However, there still appear to be some differences. I have many times been able to get an exploit working while in GDB, but only to have it crash when run without the debugger. I've read mention of some script (sometimes referred to as setenv.sh) that can (allegedly) be used to setup an environment exactly like GDB, but I have not been able to find it.
Looking at the env of the shell:
LANG=en_US.UTF-8
PROFILEHOME=
DISPLAY=:0
OLDPWD=/home/user
SHELL_SESSION_ID=e7a0e681012e480fb044a034a775bb83
INVOCATION_ID=8ef3be94d09f4e47a0322ddf0d6ed787
COLORTERM=truecolor
MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins
XDG_VTNR=1
XDG_SESSION_ID=c1
USER=user
PWD=/test
HOME=/home/user
JOURNAL_STREAM=9:15350
KONSOLE_DBUS_SESSION=/Sessions/1
KONSOLE_DBUS_WINDOW=/Windows/1
GTK_MODULES=canberra-gtk-module
MAIL=/var/spool/mail/user
WINDOWPATH=1
TERM=xterm-256color
SHELL=/bin/bash
KONSOLE_DBUS_SERVICE=:1.7
KONSOLE_PROFILE_NAME=Profile 1
SHELLCODE=����
XDG_SEAT=seat0
SHLVL=4
COLORFGBG=15;0
LANGUAGE=
WINDOWID=16777222
LOGNAME=user
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
XAUTHORITY=/home/user/.Xauthority
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
_=/usr/bin/env
And comparing it to that of GDG (LINES and COLUMNS removed):
/test/challenge.bin
_=/usr/bin/gdb
LANG=en_US.UTF-8
DISPLAY=:0
PROFILEHOME=
OLDPWD=/home/user
SHELL_SESSION_ID=e7a0e681012e480fb044a034a775bb83
INVOCATION_ID=8ef3be94d09f4e47a0322ddf0d6ed787
COLORTERM=truecolor
MOZ_PLUGIN_PATH=/usr/lib/mozilla/plugins
XDG_VTNR=1
XDG_SESSION_ID=c1
USER=user
PWD=/test
HOME=/home/user
JOURNAL_STREAM=9:15350
KONSOLE_DBUS_SESSION=/Sessions/1
KONSOLE_DBUS_WINDOW=/Windows/1
GTK_MODULES=canberra-gtk-module
MAIL=/var/spool/mail/user
WINDOWPATH=1
SHELL=/bin/bash
TERM=xterm-256color
KONSOLE_DBUS_SERVICE=:1.7
KONSOLE_PROFILE_NAME=Profile 1
SHELLCODE=����
COLORFGBG=15;0
SHLVL=4
XDG_SEAT=seat0
LANGUAGE=
WINDOWID=16777222
LOGNAME=user
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
XDG_RUNTIME_DIR=/run/user/1000
XAUTHORITY=/home/user/.Xauthority
PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl
/test/challenge.bin
One can see the environments are not very different on inspection. Notably, the GDB env seems to have a second instance of the debugged binary's name (e.g. challenge.bin, in this case), as well as the fact that it sets _ to GDB rather than the debugged binary. The offsets seem to be way off, even when taking these small changes into account.
TL;DR
How can the GDB environment differences be nulled out for the case when it is necessary to know a priori the locations of things in the environment with and without the debugger running?
In an effort of lazyness, has anyone fully characterized the with/without GDB environment, or the changes GDB makes?
And for those interested, R2 appears to made changes to PATH. There may also be other differences.
How can the GDB environment differences be nulled out
One way is to run the binary outside of GDB (have the binary wait for GDB to attach, as described here), and attach GDB to it from "outside".
Update:
the binary in question is part of a challenge and source is not provided
You can patch _start with a jmp _start (so the binary will never progress past the first instruction). Once attached, replace the jmp with the original instruction, and start debugging.
Update 2:
Are you familiar with a better process?
In order to find offset of a given function in the ELF file, you need two values: offset of the function within section, and offset of section within the file.
For example:
$ readelf -Ws a.out | grep ' _start'
58: 00000000004003b0 43 FUNC GLOBAL DEFAULT 11 _start
This tells you that _start is linked at 0x4003b0 in section 11.
What is that section, what is its starting address, and where in the file does it start?
$ readelf -WS a.out | grep '\[11\]'
[11] .text PROGBITS 00000000004003b0 0003b0 000151 00 AX 0 0 16
We now see that _start is at the very start of .text (this is usually the case), and that .text starts at offset 0x3b0 in the file. QED.
An even better process is to use GDB to perfom the patching (GDB will perform all the finding of offsets). Suppose I want to overwrite the first instruction of _start with 0xCC instruction:
$ gdb --write -q ./a.out
Reading symbols from ./a.out...done.
Let's look at the original instructions first:
(gdb) x/4i _start
0x4003b0 <_start>: xor %ebp,%ebp
0x4003b2 <_start+2>: mov %rdx,%r9
0x4003b5 <_start+5>: pop %rsi
0x4003b6 <_start+6>: mov %rsp,%rdx
Now let's patch the first one:
(gdb) set *(char*)0x4003b0 = 0xCC
(gdb) x/4i _start
0x4003b0 <_start>: int3
0x4003b1 <_start+1>: in (%dx),%eax
0x4003b2 <_start+2>: mov %rdx,%r9
0x4003b5 <_start+5>: pop %rsi
(gdb) quit
Segmentation fault (core dumped) <<-- this is a GDB bug. I should fix it some day.
$ objdump -d a.out
...
Disassembly of section .text:
00000000004003b0 <_start>:
4003b0: cc int3 <<-- success!
4003b1: ed in (%dx),%eax
4003b2: 49 89 d1 mov %rdx,%r9
...
Voila!
I am trying to troubleshoot a bus error with some inline SSE2 assembly. The source code has a macro that uses 5 pointers, and I suspect one of them is not aligned.
I set a breakpoint on the source line. But when I perform a disass, it disassembles from the top of the function, and not where the debugger is stopped. There are hundreds of lines of assembly, so its not really helpful to me. Pressing ENTER 30 to 40 times in response to "Press ENTER to continue" got old very quickly.
I tried a disass $pc, but it dsassembled from the top of the function. I also tried a disass . (with the dot meaning "here"), but that resulted in:
A syntax error in expression, near `.'.
What does GDB use to denote "here"?
You were correct with the use of $pc to represent the current location. The reason that this did not do what you expected when used with the disassemble command is that the disassemble command tries by default to disassemble the function containing the given address which is what you are seeing.
There are alternative forms that can be given to disassemble, for example start,end where start and end are addresses, or start,+length where start is an address and length is a number of bytes.
Try help disassemble at the gdb prompt for more information.
As an alternative you can also use the x (examine) command to display instructions, without the smart find the beginning of the function behaviour, so x/10i $pc will display 10 instructions starting from $pc. This can be helpful if you only want the instructions disassembled, however you don't have access to the /m or /r modifiers that are available on the disassemble command. These modifiers display interleaved source and assembler (for /m) or the raw instruction bytes (for /r).
Also, if the whole press ENTER to continue thing is getting old then you can try set height 0 to turn off the pager, do make sure that you have enough scroll back in your terminal though :)
I'm a Vim user and don't know much about Emacs. I'm interested with Emacs because I find that debugging within Emacs is more pleasant. For example, it provides syntax highlighting and I can set breakpoints with the mouse.
Everything works well except when printf is encountered.
Simple code for illustration:
1 #include <stdio.h>
2
3 int main()
4 {
5 int a = 1;
6 printf("%d\n", a);
7 int b = 2;
8 return 0;
9 }
emacs main.c
left click on the bottom half
M-x gdb[return][return]
(gdb) b 6
(gdb) r
By now, the source codes are showed in the upper half, and gdb prompt in the bottom half. This is exactly what I want.
(gdb) n
Now the source codes disappear, and the upper half is used to show stdout instead. This is really inconvenient. I'd like the stdout to show in the gdb buffer, and the sources stay in the upper buffer, just as the gdb -tui mode.
Instead of manually setting up your splits each time, try telling GDB which windows you want available.
For example:
;; Show main source buffer when using GDB
(setq gdb-show-main t)
Now you can simply use M-x gdb to start GDB, and it should keep your source code buffer displayed in a split window.
Incidentally, Emacs' GDB interface supports a number of other windows that you may want to enable:
If gdb-many-windows is non-nil, then M-x gdb displays the
following frame layout:
+--------------------------------+--------------------------------+
| GUD interaction buffer | Locals/Registers buffer |
|--------------------------------+--------------------------------+
| Primary Source buffer | I/O buffer for debugged pgm |
|--------------------------------+--------------------------------+
| Stack buffer | Breakpoints/Threads buffer |
+--------------------------------+--------------------------------+
If you ever change the window layout, you can restore the "many
windows" layout by typing M-x gdb-restore-windows. To toggle between
the many windows layout and a simple layout with just the GUD
interaction buffer and a source file, type M-x gdb-many-windows.
You may also specify additional GDB-related buffers to display,
either in the same frame or a different one. Select the buffers you
want by typing M-x gdb-display-BUFFERTYPE-buffer or M-x gdb-frame-BUFFERTYPE-buffer, where BUFFERTYPE is the relevant buffer
type, such as breakpoints. You can do the same with the menu bar,
with the GDB-Windows and GDB-Frames sub-menus of the GUD menu.
When you finish debugging, kill the GUD interaction buffer with C-x k,
which will also kill all the buffers associated with the session.
However you need not do this if, after editing and re-compiling your
source code within Emacs, you wish to continue debugging. When you
restart execution, GDB automatically finds the new executable. Keeping
the GUD interaction buffer has the advantage of keeping the shell
history as well as GDB's breakpoints. You do need to check that the
breakpoints in recently edited source files are still in the right
places.
You might also like to try M-x gud-gdb. It's a much more bare-bones UI, but I personally prefer it.
The problem I am trying to solve is that I want to dynamically compute the length of an instruction given its address (from within GDB) and set that length as the value of a variable. The challenge is that I don't want any extraneous output printed to the console (e.g. disassembled instructions, etc.).
My normal approach to this is to do x/2i ADDR, then subtract the two addresses. I would like to achieve the same thing automatically; however, I don't want anything printed to the console. If I could disable console output then I would be able to do this by doing x/2i ADDR, followed by $_ - ADDR.
I have not found a way to disable the output of a command in GDB. If you know such a way then please tell me! However, I have discovered interpreter-exec and GDB/MI. A quick test shows that doing x/2i works on GDB/MI, and the value of $_ computed by the MI interpreter is shared with the console interpreter. Unfortunately, this approach also spits out a lot of output.
Does anyone know a way to either calculate the length of an instruction without displaying anything, or how to disable the output of interpreter-exec, thus allowing me to achieve my goal? Thank you.
I'll give an arguably cleaner and more extensible solution that's not really shorter. It implements $instn_length() as a new GDB convenience function.
Save this to instn-length.py
import gdb
def instn_length(addr_expr):
t = gdb.execute('x/2i ' + addr_expr, to_string=True)
return long(gdb.parse_and_eval('$_')) - long(gdb.parse_and_eval(addr_expr))
class InstnLength(gdb.Function):
def __init__(self):
super(InstnLength, self).__init__('instn_length')
def invoke(self, addr):
return instn_length(str(long(addr)))
InstnLength()
Then run
$ gdb -q -x instn-length.py /bin/true
Reading symbols from /usr/bin/true...Reading symbols from /usr/lib/debug/usr/bin/true.debug...done.
done.
(gdb) start
Temporary breakpoint 1 at 0x4014c0: file true.c, line 59.
Starting program: /usr/bin/true
Temporary breakpoint 1, main (argc=1, argv=0x7fffffffde28) at true.c:59
59 if (argc == 2)
(gdb) p $instn_length($pc)
$1 = 3
(gdb) disassemble /r $pc, $pc + 4
Dump of assembler code from 0x4014c0 to 0x4014c4:
An alternative implementation of instn_length() is to use the gdb.Architecture.disassemble() method in GDB 7.6+:
def instn_length(addr_expr):
addr = long(gdb.parse_and_eval(addr_expr))
arch = gdb.selected_frame().architecture()
return arch.disassemble(addr)[0]['length']
I have found a suitable solution; however, shorter solutions would be preferred. This solution sets a logging file to /dev/null, sets to to be overridden if it exists, and then redirects the console output to the log file temporarily.
define get-in-length
set logging file /dev/null
set logging overwrite on
set logging redirect on
set logging on
x/2i $arg0
set logging off
set logging redirect off
set logging overwrite off
set $_in_length = ((unsigned long) $_) - ((unsigned long) $arg0)
end
This solution was heavily inspired by another question's answer: How to get my program name in GDB when writting a "define" script?.
I'd like to go through a binary file my teacher gave me line by line to check addresses on the stack and the contents of different registers, but I'm not extremely familiar with using gdb. Although I have the C code, we're supposed to work entirely from a binary file. Here are the commands I've used so far:
(gdb) file SomeCode
Which gives me this message:
Reading symbols from ../overflow/SomeCode ...(no debugging symbols found)...done.
Then I use :
(gdb) disas main
which gives me all of the assembly. I wanted to set up a break point and use the "next" command, but none of the commands I tried work. Does anyone know the syntax I would use?
try using ni which is nexti. equivalent is si which is step instruction
nexti if you want to jump over function calls.
stepi if you want to enter a function call.
The following documentation is very helpful; it has a list of all the important commands you could use on gdb.
X86-64: http://csapp.cs.cmu.edu/public/docs/gdbnotes-x86-64.pdf
IA32: http://csapp.cs.cmu.edu/public/docs/gdbnotes-ia32.pdf