hugsy / gef

GEF (GDB Enhanced Features) - a modern experience for GDB with advanced debugging capabilities for exploit devs & reverse engineers on Linux
https://hugsy.github.io/gef
MIT License
6.85k stars 724 forks source link

Error in `context` command: `max() arg is an empty sequence` #753

Closed zhouguoqionghai closed 2 years ago

zhouguoqionghai commented 2 years ago

Step 1: Describe your environment

gef➤ version GEF: (Standalone) SHA1(/root/.gef-915ff9114127a6c02301fb3faddb0976737269db.py): d7c49b4c073a097e9a9e93c4ea1091b0644bb935 GDB: Red Hat Enterprise Linux 8.2-15.el8 GDB-Python: 3.6

Step 2: Describe your problem

[!] Command 'context' failed to execute properly, reason: max() arg is an empty sequence Traceback (most recent call last):

Steps to reproduce

1.

Minimalist test case

In function print_guessed_arguments, nb_argument = max(function_parameters.index(p)+1 for p in parameter_set) happened to be the problem.

// compile with gcc -fPIE -pic -o my_issue.out my_issue.c
int main(){ return 0; }

Observed Results

Expected results

Traces

theguy147 commented 2 years ago

@zhouguoqionghai Thank you for the issue. Unfortunately I could not reproduce it locally.

Could you explain further what steps you're taking prior to the error? What GDB/GEF commands are you running? Also let us know what architecture you're using?

Also please fix the compilation instructions (-pic -> -fpic) and update your GEF version to use the latest dev branch as you're currently using an older version.

zhouguoqionghai commented 2 years ago

I am just a newbie to gef. Thanks for your talented work. It's easy to reproduce on my X64 computer,through some experiments, I found each time when I use si command, In this scenario, when it reach call instruction, gef will give the error above.

→ 0x7ffff7bce658 <myprintf+31> callq 0x7ffff7bce550 printf@plt ↳ 0x7ffff7bce550 printf@plt+0 jmpq 0x200ac2(%rip) # 0x7ffff7dcf018 printf@got.plt 0x7ffff7bce556 printf@plt+6 pushq $0x0 0x7ffff7bce55b printf@plt+11 jmpq 0x7ffff7bce540 0x7ffff7bce560 dlsym@plt+0 jmpq 0x200aba(%rip) # 0x7ffff7dcf020 dlsym@got.plt 0x7ffff7bce566 dlsym@plt+6 pushq $0x1 0x7ffff7bce56b dlsym@plt+11 jmpq 0x7ffff7bce540 [!] Command 'context' failed to execute properly, reason: max() arg is an empty sequence Traceback (most recent call last):

My architecture is:

Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 4 On-line CPU(s) list: 0-3 Thread(s) per core: 1 Core(s) per socket: 2 Socket(s): 2 NUMA node(s): 1 Vendor ID: GenuineIntel BIOS Vendor ID: GenuineIntel CPU family: 6 Model: 60 Model name: Intel(R) Core(TM) i5-4460S CPU @ 2.90GHz

zhouguoqionghai commented 2 years ago

I haven't read the gef code now. At the moment, I change line 8048 from nb_argument = max(function_parameters.index(p)+1 for p in parameter_set) to nb_argument = max((function_parameters.index(p)+1 for p in parameter_set), default = 0) to avoid the problem. I have no idea whether it is right.

hugsy commented 2 years ago

@zhouguoqionghai

Thanks for your input. Please fill out correctly all the steps of issue form, otherwise we probably won't be able to reproduce. Give us a proper way to reproduce, including the stack trace and detailed information about the error by enabling the debug mode (gef config gef.debug 1).

hugsy commented 2 years ago

I also tried to reproduce but couldn't, although your error message makes sense (from https://github.com/hugsy/gef/blob/dev/gef.py#L8697). Your error message max() arg is an empty sequence comes from a case which should not have been executed because parameter_set is checked here. However, a clean patch could simply be

        if not nb_argument:
            if is_x86_32():
                nb_argument = len(parameter_set)
            else:
                nb_argument = max([function_parameters.index(p)+1 for p in parameter_set], default=0)

@zhouguoqionghai It would be appreciated if you could us the complete reproduction steps, along with the output from GEF in debug mode.

Thanks

zhouguoqionghai commented 2 years ago

Just an easy helloworld code.

#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("hello world\n");
    return 0;
}

This is my steps

> GEF for linux ready, type `gef' to start, `gef config' to configure
96 commands loaded for GDB Red Hat Enterprise Linux 8.2-15.el8 using Python engine 3.6
Reading symbols from helloworld.out...(no debugging symbols found)...done.
gef➤  gef config gef.debug 1
gef➤  b *main
Breakpoint 1 at 0x400586
gef➤  r

Then after some repeated `ni` command, when it reach `call` instruction, it will give the error output.Hope this helps.

>      0x400595 <main+15>        mov    $0x400648, %edi
 →   0x40059a <main+20>        callq  0x400490 <puts@plt>
   ↳    0x400490 <puts@plt+0>     jmpq   *0x200b82(%rip)        # 0x601018 <puts@got.plt>
        0x400496 <puts@plt+6>     pushq  $0x0
        0x40049b <puts@plt+11>    jmpq   0x400480
        0x4004a0 <_start+0>       endbr64
        0x4004a4 <_start+4>       xor    %ebp, %ebp
        0x4004a6 <_start+6>       mov    %rdx, %r9

─────────────────────────────── Exception raised ───────────────────────────────
ValueError: max() arg is an empty sequence
───────────────────────────── Detailed stacktrace ──────────────────────────────
n↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 8049, in print_guessed_arguments()
    →                     nb_argument = max(function_parameters.index(p)+1 for p in parameter_set)
↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 7958, in context_args()
    →                 self.print_guessed_arguments(target)
↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 7731, in do_invoke()
    →                     self.layout_mapping[section]()
↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 2545, in wrapper()
    →                 return f(*args, **kwargs)
↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 243, in wrapper()
    →                 rv = f(*args, **kwargs)
↳ File "~/.gef-915ff9114127a6c02301fb3faddb0976737269db.py", line 4189, in invoke()
    →                 bufferize(self.do_invoke)(argv)
─────────────────────────────────── Version ────────────────────────────────────
GEF: (Standalone)
SHA1(/root/.gef-915ff9114127a6c02301fb3faddb0976737269db.py): 8bd6ab0049aba19532168193c5b486a631255297
GDB: Red Hat Enterprise Linux 8.2-15.el8
GDB-Python: 3.6
Loaded commands: $, aliases, aliases add, aliases ls, aliases rm, aslr, assemble, canary, capstone-disassemble, checksec, context, dereference, edit-flags, elf-info, entry-break, format-string-helper, functions, gef-remote, got, heap, heap arenas, heap bins, heap bins fast, heap bins large, heap bins small, heap bins tcache, heap bins unsorted, heap chunk, heap chunks, heap set-arena, heap-analysis-helper, hexdump, hexdump byte, hexdump dword, hexdump qword, hexdump word, highlight, highlight add, highlight clear, highlight list, highlight remove, hijack-fd, ida-interact, is-syscall, ksymaddr, memory, memory list, memory reset, memory unwatch, memory watch, name-break, nop, patch, patch byte, patch dword, patch qword, patch string, patch word, pattern, pattern create, pattern search, pcustom, pcustom edit, pcustom list, pcustom show, pie, pie attach, pie breakpoint, pie delete, pie info, pie remote, pie run, print-format, process-search, process-status, registers, reset-cache, ropper, scan, search-pattern, set-permission, shellcode, shellcode get, shellcode search, stub, syscall-args, theme, trace-run, unicorn-emulate, version, vmmap, xfiles, xinfo, xor-memory, xor-memory display, xor-memory patch
───────────────────────────── Last 10 GDB commands ─────────────────────────────
warning: bad breakpoint number at or near '0'
───────────────────────────── Runtime environment ──────────────────────────────
* GDB: Red Hat Enterprise Linux 8.2-15.el8
* Python: 3.6.8 - final
* OS: Linux - 4.18.0-305.19.1.el8_4.x86_64 (x86_64)
lsb_release is missing, cannot collect additional debug information
────────────────────────────────────────────────────────────────────────────────
zhouguoqionghai commented 2 years ago

Well, I find this check line is not in my installed gef. I just use bash -c "$(curl -fsSL http://gef.blah.cat/sh)" to install. That's maybe the problem.

hugsy commented 2 years ago

Well, I find this check line is not in my installed gef. I just use bash -c "$(curl -fsSL http://gef.blah.cat/sh)" to install. That's maybe the problem.

Before reporting bugs we ask to try with gef from the dev branch (1st requirement)

Did you use the latest version of GEF from dev branch?

You can start by re-trying with it.

theguy147 commented 2 years ago

@zhouguoqionghai in case you don't know how to install GEF from the latest dev branch: either just clone the GitHub repo, checkout dev branch and source gef.py in your .gdbinit or follow the instructions from the README:

Note: to fetch the latest of GEF (i.e. from the dev branch), simply replace in the URL to http://gef.blah.cat/dev.