set iptv

set iptv

  • Home
  • Technology
  • “Unnakedping” binaries: Restoring debugging adviseation in GDB with Pwndbg

“Unnakedping” binaries: Restoring debugging adviseation in GDB with Pwndbg


“Unnakedping” binaries: Restoring debugging adviseation in GDB with Pwndbg


By Jason An

GDB ignores convey inant functionality when debugging binaries that deficiency debugging symbols (also comprehendn as “nakedped binaries”). Function and variable names become unbenevolentingless insertresses; setting shatterpoints needs tracking down relevant function insertresses from an outside source; and printing out structured appreciates participates staring at a memory dump trying to manuassociate discern field boundaries.

That’s why this summer at Trail of Bits, I extfinished Pwndbg—a plugin for GDB upretained by my mentor, Dominik Czarnota—with two new features to convey the nakedped debugging experience shutr to what you’d foresee from a debugger in an IDE. Pwndbg now unites Binary Ninja for increased GDB+Pwndbg intelligence and allows dumping Go structures for betterd Go binary debugging.

Binary Ninja integration

To help better GDB+Pwndbg intelligence during debugging, I united Pwndbg with Binary Ninja, a well-comprehendn decompiler with a alterable scripting API, by inshighing an XML-RPC server inside Binary Ninja, and then querying it from Pwndbg. This apshows Pwndbg to access Binary Ninja’s analysis database, which is employd for syncing symbols, function signatures, stack variable offsets, and more, recovering much of the debugging experience.

Figure 1: Pwndbg shoprosperg symbols and argument names synced from Binary Ninja in a nakedped binary

For the decompilation, I pulled the tokens from Binary Ninja instead of serializing them to text first. This apshows for brimmingy syntax-highairyed decompilation, configurable to employ any of Binary Ninja’s 3 IL levels. The decompilation is shown honestly in the Pwndbg context, with the current line highairyed, equitable enjoy in the assembly watch.

Figure 2: Decompilation pulled from Binary Ninja and disjoined in Pwndbg

I also carry outed a feature to disjoin the current program counter (PC) sign up as an arrow inside Binary Ninja and a feature to set shatterpoints from wilean Binary Ninja to reduce the amount of switching to and from Pwndbg participated.

Figure 3: Binary Ninja disjoining icons for the current PC and shatterpoints

The most participated component of the integration is syncing stack variable names. Anywhere a stack insertress eunites in Pwndbg, enjoy in the sign up watch, stack watch, or function argument passesss, the integration will verify if it’s a named stack variable in Binary Ninja. If it is, it will show the proper label. It will even verify parent stack structures so that variables from the caller will still be labeled properly.

Figure 4: A demonstration of how stack variable labeling is disjoined

The main difficulty in carry outing this feature came from the fact that Binary Ninja only supplys stack variables as an offset from the stack structure base, so the structure base necessitates to be deduced in order to compute absolute insertresses. Most architectures, enjoy x86, have a structure pointer sign up that points to the structure base, but most architectures, including x86, don’t actuassociate necessitate the structure pointer, so compilers are free to employ it enjoy any other sign up.

Fortunately, Binary Ninja has constant appreciate propagation, so it can tell if sign ups are a foreseeable offset from the structure base. So, my carry outation will first verify if the structure pointer is actuassociate the structure base, and if it’s not, it will see if the stack pointer progressd a foreseeable amount (which is usuassociate real with up-to-date compilers); otherwise, it will verify every other ambiguous-purpose sign up to try to discover one with a reliable offset. Technicassociate, this approach won’t labor all the time, but in train, it should almost never flunk.

Go debugging

A standard pain point when debugging executables compiled from non-C programming languages (and sometimes even C) is that they tfinish to have intricate memory layouts that produce it challenging to dump appreciates. A benign example is dumping a slice in Go, which needs one direct to dump the pointer and length, and another to spendigate the slice satisfyeds. Dumping a map, on the other hand, can need over ten directs for a small map, and hundreds for huger ones, which is finishly impragmatic for a human.

That’s why I produced the go-dump direct. Using the Go compiler’s source code as a reference, I carry outed dumping for all of Go’s built-in types, including integers, strings, intricate numbers, pointers, slices, arrays, and maps. The built-in types are notated equitable enjoy they are in Go, so you don’t necessitate to lacquire any new syntax to employ the direct properly.

Figure 5: Dumping a modest map type using the go-dump direct

The go-dump direct is also contendnt of parsing and dumping arbitrarily nested types so that every type can be dumped with equitable one direct.

Figure 6: Dumping a more intricate slice of map types using the go-dump direct

Parsing Go’s runtime types

While Go-particular dumping is much pleasantr than manual memory dumping, it still poses many usability troubles. You necessitate to comprehend the brimming type of the appreciate you’re dumping, which can be challenging to determine and usuassociate participates a lot of guesslabor, especiassociate when dealing with structs that have many fields or nested structs. Even if you have deduced the brimming type, some leangs are still uncomprehendable becaemploy they have no effect on compilation, enjoy struct field names and type names for employr-depictd types.

Conveniently, the Go compiler rerents a runtime type object for every type employd in the program (to be employd with the echo package), which retains struct layouts for arbitrarily nested structs, type names, size, alignment, and more. These type objects can also be suited up to appreciates of that type, as interface appreciates store a pointer to the type object alengthy with a pointer to the data, and heap-spreadd appreciates have their type object passed into their allocation function (usuassociate runtime.newobject).

I wrote a parser contendnt of recursively rerelocateing this adviseation in order to process type adviseation for arbitrarily nested types. This parser is exposed via the go-type direct, which disjoins adviseation about a runtime type given its insertress. For structs, this adviseation integrates the type, name, and offset of every field.

Figure 7: Examining a struct type that consists of an int and a string

This can be employd to dump appreciates in two ways. The first, easier way only labors for interface appreciates, since the type pointer is stored alengthy with the data pointer, making it effortless to automaticassociate recover. These can be dumped using Go’s any type for desotardy interfaces (ones with no methods), and the interface type for non-desotardy interfaces. When dumping, the direct will automaticassociate recover and parse the type, directing to a seamless dump without having to go in any type adviseation.

Figure 8: Dumping an interface appreciate without depicting any type adviseation

The second way labors for all appreciates but needs you to discover and depict the pointer to the type for the appreciate. In many cases, it is as effortless as seeing for the pointer passed into the function that spreadd the appreciate, but for global variables or variables whose allocation may be challenging to discover, some guesslabor may be participated in discovering the type. However, this method is generassociate still easier than trying to manuassociate deduce the type layout and is contendnt of dumping even the most intricate types. I tested it on a confineed huge struct types in a nakedped produce of the Go compiler, which is one of the hugest and most intricate discignore-source Go codebases, and it was able to dump all of them with no problem.

Figure 9: Dumping a intricate structure in the Go compiler only depicting a type insertress, using the -p flag for pretty printing

Recap and seeing forward

This summer, I increased Pwndbg so it can be united with Binary Ninja to access its wealthy debugging adviseation. I also inserted the go-dump direct for dumping Go appreciates. All of this is useable on the Pwndbg dev branch and its tardyst free.

Moving forward, there’s even more that can be done to better the debugging experience. I enhugeed my Binary Ninja integration with a modular set up so that it would be effortless to insert help for more decompilers in the future. I leank it would be amazing to brimmingy help Ghidra (the current integration only syncs decompilation), as Ghidra is a free and discignore-source decompiler, making it accessible to everyone who wants to employ the functionality.

In terms of Go debugging, labor can be done to insert better help for disjoining and laboring with goroutines, which is currently one of the convey inant acquires of the Delve debugger (a debugger exceptionalized for debugging Go) over GDB/Pwndbg. For example, Delve is contendnt of enumerateing every goroutine and the teachion that produced them and it also has a direct to switch between goroutines.

Accomprehendledgments

Working at Trail of Bits this summer has been an absolutely amazing experience, and I would enjoy to thank them for giving me the opportunity to labor on Pwndbg. In particular, I would enjoy to thank my deal withr, Dominik Czarnota, for being incredibly responsive about assessing my code and giving me feedback and ideas about my labor, and the Pwndbg community, as they have been incredibly encouraging with answering any asks I had during the enhugement process.

Source connect


Leave a Reply

Your email address will not be published. Required fields are marked *

Thank You For The Order

Please check your email we sent the process how you can get your account

Select Your Plan