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

LLDB stepsyscall crash debugger #2544

Closed
patryk4815 opened this issue Nov 18, 2024 · 3 comments
Closed

LLDB stepsyscall crash debugger #2544

patryk4815 opened this issue Nov 18, 2024 · 3 comments
Labels

Comments

@patryk4815
Copy link
Member

patryk4815 commented Nov 18, 2024

$ ./pwndbg/bin/pwndbg-lldb /bin/sh
pwndbg-lldb> run -s
pwndbg-lldb> stepsyscall
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/dbg/lldb/repl/__init__.py:387 in run         │
│                                                                                                  │
│   384 │   │   │   assert driver.process.GetUniqueID() == process.process.GetUniqueID()           │
│   385 │   │   │                                                                                  │
│   386 │   │   │   try:                                                                           │
│ ❱ 387 │   │   │   │   driver.run_coroutine(coroutine)                                            │
│   388 │   │   │   except Exception:                                                              │
│   389 │   │   │   │   # We treat exceptions coming from the execution controllers the            │390 │   │   │   │   # same way we treat exceptions coming from commands.                       │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/dbg/lldb/repl/proc.py:268 in run_coroutine   │
│                                                                                                  │
│   265 │   │   while True:                                                                        │
│   266 │   │   │   try:                                                                           │
│   267 │   │   │   │   if exception is None:                                                      │
│ ❱ 268 │   │   │   │   │   step = coroutine.send(None)                                            │
│   269 │   │   │   │   else:                                                                      │
│   270 │   │   │   │   │   step = coroutine.throw(exception)                                      │
│   271 │   │   │   │   │   # The coroutine has caught the exception. Continue running             │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/commands/next.py:164 in _stepsyscall         │
│                                                                                                  │
│   161 │                                                                                          │
│   162while (                                                                                │
│   163 │   │   pwndbg.aglib.proc.alive                                                            │
│ ❱ 164 │   │   and not (await pwndbg.aglib.next.break_next_interrupt(ec))                         │
│   165 │   │   and (await pwndbg.aglib.next.break_next_branch(ec))                                │
│   166 │   ):                                                                                     │
│   167 │   │   # Here we are e.g. on a CALL instruction (temporarily breakpointed by `break_nex   │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/next.py:116 in break_next_interrupt    │
│                                                                                                  │
│   113                                                                                            │
│   114                                                                                            │
│   115 async def break_next_interrupt(ec: pwndbg.dbg_mod.ExecutionController, address=None):      │
│ ❱ 116ins = next_int(address)                                                                │
│   117 │                                                                                          │
│   118proc = pwndbg.dbg.selected_inferior()                                                  │
│   119if ins:                                                                                │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/next.py:30 in next_int                 │
│                                                                                                  │
│    27Otherwise, return None.                                                                │
│    28 │   ...                                                                                    │
│    29if address is None:                                                                    │
│ ❱  30 │   │   ins = pwndbg.aglib.disasm.one(pwndbg.aglib.regs.pc)                                │
│    31 │   │   if not ins:                                                                        │
│    32 │   │   │   return None                                                                    │
│    33 │   │   address = ins.next                                                                 │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/__init__.py:251 in one          │
│                                                                                                  │
│   248 │   │   return None                                                                        │
│   249 │                                                                                          │
│   250# A for loop in case this returns an empty list                                        │
│ ❱ 251for insn in get(address, 1, emu, enhance=enhance, from_cache=from_cache, put_cache=p   │
│   252 │   │   if put_backward_cache:                                                             │
│   253 │   │   │   backward_cache[insn.next] = insn.address                                       │
│   254 │   │   return insn                                                                        │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/__init__.py:286 in get          │
│                                                                                                  │
│   283 │                                                                                          │
│   284retval: List[PwndbgInstruction] = []                                                   │
│   285for _ in range(instructions):                                                          │
│ ❱ 286 │   │   i = get_one_instruction(                                                           │
│   287 │   │   │   address, emu, enhance=enhance, from_cache=from_cache, put_cache=put_cache      │
│   288 │   │   )                                                                                  │
│   289 │   │   if i is None:                                                                      │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/__init__.py:224 in              │
│ get_one_instruction                                                                              │
│                                                                                                  │
│   221 │   │   pwn_ins = PwndbgInstruction(ins)                                                   │
│   222 │   │                                                                                      │
│   223 │   │   if enhance:                                                                        │
│ ❱ 224 │   │   │   pwndbg.aglib.disasm.arch.DisassemblyAssistant.enhance(pwn_ins, emu)            │
│   225 │   │                                                                                      │
│   226 │   │   if put_cache:                                                                      │
│   227 │   │   │   computed_instruction_cache[address] = pwn_ins                                  │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/arch.py:253 in enhance          │
│                                                                                                  │
│    250 │   │   enhancer._enhance_next(instruction, emu, jump_emu)                                │
│    251 │   │                                                                                     │
│    252 │   │   if bool(pwndbg.config.disasm_annotations):                                        │
│ ❱  253 │   │   │   enhancer._set_annotation_string(instruction, emu)                             │
│    254 │   │                                                                                     │
│    255 │   │   # Disable emulation after CALL instructions. We do it after enhancement, as we c  │256 │   │   # to determine the call's target address.                                         │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/x86.py:98 in                    │
│ _set_annotation_string                                                                           │
│                                                                                                  │
│    95 │   │   │   │   instruction.operands[0].type == CS_OP_MEM,                                 │
│    96 │   │   │   )                                                                              │
│    97 │   │   else:                                                                              │
│ ❱  98 │   │   │   self.annotation_handlers.get(instruction.id, lambda *a: None)(instruction, e   │
│    99 │                                                                                          │
│   100def handle_mov(self, instruction: PwndbgInstruction, emu: Emulator) -> None:           │
│   101 │   │   left, right = instruction.operands                                                 │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/x86.py:127 in handle_mov        │
│                                                                                                  │
│   124 │   │   │   )                                                                              │
│   125 │   │   elif left.type == CS_OP_REG and right.before_value is not None:                    │
│   126 │   │   │   # MOV REG, REG|IMM                                                             │
│ ❱ 127 │   │   │   self._common_move_annotator(instruction, emu)                                  │
│   128 │                                                                                          │
│   129def handle_vmovaps(self, instruction: PwndbgInstruction, emu: Emulator) -> None:       │
│   130 │   │   # If the source or destination is in memory, it must be aligned to:                │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/arch.py:1008 in                 │
│ _common_move_annotator                                                                           │
│                                                                                                  │
│   1005 │   │   │   if result is not None:                                                        │
│   1006 │   │   │   │   TELESCOPE_DEPTH = max(0, int(pwndbg.config.disasm_telescope_depth))       │
│   1007 │   │   │   │                                                                             │
│ ❱ 1008 │   │   │   │   telescope_addresses = self._telescope(                                    │
│   1009 │   │   │   │   │   result,                                                               │
│   1010 │   │   │   │   │   TELESCOPE_DEPTH + 1,                                                  │
│   1011 │   │   │   │   │   instruction,                                                          │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/disasm/arch.py:503 in _telescope       │
│                                                                                                  │
│    500 │   │   │   │   return result                                                             │
│    501 │   │   │                                                                                 │
│    502 │   │   │   else:                                                                         │
│ ❱  503 │   │   │   │   return pwndbg.chain.get(address, limit=limit)                             │
│    504 │   │   else:                                                                             │
│    505 │   │   │   # If the target address is in a non-writeable map, we can pretty safely tele  │506 │   │   │   # This is best-effort to give a better experience                             │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/chain.py:81 in get                           │
│                                                                                                  │
│    78 │   │   │   │   break                                                                      │
│    79 │   │   │                                                                                  │
│    80 │   │   │   next_address = int(                                                            │
│ ❱  81 │   │   │   │   pwndbg.aglib.memory.get_typed_pointer_value(pwndbg.aglib.typeinfo.ppvoid   │
│    82 │   │   │   )                                                                              │
│    83 │   │   │   address = next_address ^ ((address >> 12) if safe_linking else 0)              │
│    84 │   │   │   address &= pwndbg.aglib.arch.ptrmask                                           │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/memory.py:289 in                       │
│ get_typed_pointer_value                                                                          │
│                                                                                                  │
│   286type_name: str | pwndbg.dbg_mod.Type, addr: int | pwndbg.dbg_mod.Value                 │
│   287 ) -> pwndbg.dbg_mod.Value:                                                                 │
│   288"""Read the pointer value of addr cast to type specified by type_name"""               │
│ ❱ 289return get_typed_pointer(type_name, addr).dereference()                                │
│   290                                                                                            │
│   291                                                                                            │
│   292 @pwndbg.lib.cache.cache_until("stop")                                                      │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/memory.py:282 in get_typed_pointer     │
│                                                                                                  │
│   279 │   │   real_type = type                                                                   │
│   280else:                                                                                  │
│   281 │   │   raise ValueError(f"Invalid type: {type}")                                          │
│ ❱ 282return cast_pointer(real_type, addr)                                                   │
│   283                                                                                            │
│   284                                                                                            │
│   285 def get_typed_pointer_value(                                                               │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/aglib/memory.py:266 in cast_pointer          │
│                                                                                                  │
│   263 ) -> pwndbg.dbg_mod.Value:                                                                 │
│   264 │   ...Create a Value containing given address and cast it to the pointer of specified t   │
│   265if isinstance(addr, int):                                                              │
│ ❱ 266 │   │   addr = pwndbg.dbg.selected_inferior().create_value(addr)                           │
│   267return addr.cast(type.pointer())                                                       │
│   268                                                                                            │
│   269                                                                                            │
│                                                                                                  │
│ /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/dbg/lldb/__init__.py:1088 in create_value    │
│                                                                                                  │
│   1085 │   ) -> pwndbg.dbg_mod.Value:                                                            │
│   1086 │   │   import struct                                                                     │
│   1087 │   │                                                                                     │
│ ❱ 1088 │   │   b = struct.pack("<Q", value)                                                      │
│   1089 │   │                                                                                     │
│   1090 │   │   e = lldb.SBError()                                                                │
│   1091 │   │   data = lldb.SBData()                                                              │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
error: 'Q' format requires 0 <= number <= 18446744073709551615
If that is an issue, you can report it on https://github.com/pwndbg/pwndbg/issues
(Please don't forget to search if it hasn't been reported before)
To generate the report and open a browser, you may run `bugreport --run-browser`
PS: Pull requests are welcome
> /opt/tmp/pwndbg/lib/python3.12/site-packages/pwndbg/dbg/lldb/__init__.py(1088)create_value()
-> b = struct.pack("<Q", value)
(Pdb) value
-88
(Pdb)
@patryk4815 patryk4815 added the bug label Nov 18, 2024
@patryk4815 patryk4815 changed the title stepsyscall crash debugger LLDB stepsyscall crash debugger Nov 18, 2024
@patryk4815
Copy link
Member Author

@OBarronCS Hi! Maybe this is relevant with your PR? #2533

@patryk4815
Copy link
Member Author

patryk4815 commented Nov 28, 2024

Should we skip before_value when emu is null?
image
He is crashing because right_operand has negative value:

 Operands: [
   ['RAX': Symbol: None, Before: 0x178bfbff, After: None, type=CS_OP_REG, size=8, access=CS_AC_WRITE]]
   ['-0x58': Symbol: None, Before: -0x58, After: None, type=CS_OP_IMM, size=8, access=CS_AC_INVALID]]
]

mov rax, 0xffffffffffffffa8 at 0x7ffff7fdc8e3 (size=7) (arch: x86)
        ID: 460, mov
        Raw asm: mov    rax, 0xffffffffffffffa8
        New asm: mov    rax, 0xffffffffffffffa8
        Next: 0x7ffff7fdc8ea
        Target: 0x7ffff7fdc8ea, Target string=, const=None
        Condition: UNDETERMINED
        Groups: []
        Annotation: None
        Conditional jump: False. Taken: False
        Unconditional jump: False
        Declare unconditional: None
        Declare unconditional jump: False
        Force jump target: False
        Can change PC: False
        Syscall:  N/A
        Causes Delay slot: False
        Split: NO_SPLIT
        Call-like: False

@OBarronCS He is crashing on this instruction:
image

why emu is null?

 (Pdb) up
> /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/x86.py(127)handle_mov()
-> self._common_move_annotator(instruction, emu)
(Pdb) type(emu)
<class 'NoneType'>
Done enhancing
Start enhancing instruction at 0x7ffff7fdc8e3 - mov rax, 0xffffffffffffffa8
Read value from process register: 395049983

(Pdb) where
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/dbg/lldb/repl/__init__.py(387)run()
-> driver.run_coroutine(coroutine)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/dbg/lldb/repl/proc.py(268)run_coroutine()
-> step = coroutine.send(None)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/commands/next.py(164)_stepsyscall()
-> and not (await pwndbg.aglib.next.break_next_interrupt(ec))
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/next.py(116)break_next_interrupt()
-> ins = next_int(address)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/next.py(30)next_int()
-> ins = pwndbg.aglib.disasm.one(pwndbg.aglib.regs.pc)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/__init__.py(245)one()
-> for insn in get(address, 1, emu, enhance=enhance, from_cache=from_cache, put_cache=put_cache):
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/__init__.py(280)get()
-> i = get_one_instruction(
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/__init__.py(218)get_one_instruction()
-> pwndbg.aglib.disasm.arch.DisassemblyAssistant.enhance(pwn_ins, emu)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/arch.py(253)enhance()
-> enhancer._set_annotation_string(instruction, emu)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/x86.py(98)_set_annotation_string()
-> self.annotation_handlers.get(instruction.id, lambda *a: None)(instruction, emu)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/x86.py(127)handle_mov()
-> self._common_move_annotator(instruction, emu)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/arch.py(1010)_common_move_annotator()
-> telescope_addresses = self._telescope(
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/disasm/arch.py(505)_telescope()
-> return pwndbg.chain.get(address, limit=limit)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/chain.py(81)get()
-> pwndbg.aglib.memory.get_typed_pointer_value(pwndbg.aglib.typeinfo.ppvoid, address)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/memory.py(289)get_typed_pointer_value()
-> return get_typed_pointer(type_name, addr).dereference()
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/memory.py(282)get_typed_pointer()
-> return cast_pointer(real_type, addr)
  /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/aglib/memory.py(266)cast_pointer()
-> addr = pwndbg.dbg.selected_inferior().create_value(addr)
> /nix/store/dwcqxpa0ajh9cbckmdxcm69f931vdhq8-pwndbg-lldb/share/pwndbg/pwndbg/dbg/lldb/__init__.py(1093)create_value()
-> b = struct.pack("<Q", value)

(Pdb) instruction
mov rax, 0xffffffffffffffa8 at 0x7ffff7fdc8e3 (size=7) (arch: x86)
        ID: 460, mov
        Raw asm: mov    rax, 0xffffffffffffffa8
        New asm: mov    rax, 0xffffffffffffffa8
        Next: 0x7ffff7fdc8ea
        Target: 0x7ffff7fdc8ea, Target string=, const=None
        Condition: UNDETERMINED
        Groups: []
        Annotation: None
        Operands: [['RAX': Symbol: None, Before: 0x178bfbff, After: None, type=CS_OP_REG, size=8, access=CS_AC_WRITE]] ['-0x58': Symbol: None, Before: -0x58, After: None, type=CS_OP_IMM, size=8, access=CS_AC_INVALID]]]
        Conditional jump: False. Taken: False
        Unconditional jump: False
        Declare unconditional: None
        Declare unconditional jump: False
        Force jump target: False
        Can change PC: False
        Syscall:  N/A
        Causes Delay slot: False
        Split: NO_SPLIT
        Call-like: False

@patryk4815
Copy link
Member Author

fixed in #2645

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

1 participant