llef icon indicating copy to clipboard operation
llef copied to clipboard

Fix x86-ELF debugging support from x86_64 FreeBSD

Open therealdreg opened this issue 1 year ago • 7 comments

image

image

its not working well for a 32 bit process :\

  1. registers should be: eax, ebx...
  2. stack should be 4 byte align
  3. disasm is wrong (64 bit), sould be i386

Also worth mentioning that for a program in pure assembly, disassembly is not ideal. It would be ideal to be able to configure the number of instructions and whether I want to see the opcodes...

Something like:

image


btw, @stephen-f0 Thanks for doing this project... LLDB has always been a pain in the *ss...

therealdreg avatar May 01 '24 12:05 therealdreg

Hi @therealdreg,

Thanks for raising the issue. That's an interesting edge case and great to hear you are (attempting) to use LLEF!

I have just clarified that debugging i386 targets on x86_64 Linux hosts works as expected (all the LLEF context is in i386) So I believe this issue is specific to *BSD hosts. In slower time I'll setup a FreeBSD host for myself and give it a good poke. I'm fairly confident however this is likely to be an actual LLDB issue as we rely entirely on their API for architecture selection and register retrieval.

What happens is you run the native LLDB command register read on that same binary do you get back i386 registers or x64?

As for customising the disassembly output I've just completed a feature currently in PR #29 which adds in support for settings - this forms some of the ground work towards a longer term goal of having a much more user-customisable experience.

stephen-f0 avatar May 01 '24 13:05 stephen-f0

lldb) register read
General Purpose Registers:
       rax = 0x0000000000000000
       rbx = 0x00000000ffffdff0
       rcx = 0x0000000000000000
       rdx = 0x0000000000000000
       rdi = 0x0000000000000000
       rsi = 0x0000000000000000
       rbp = 0x0000000000000000
       rsp = 0x00000000ffffd674
        r8 = 0x0000000000000000
        r9 = 0x0000000000000000
       r10 = 0x0000000000000000
       r11 = 0x0000000000000000
       r12 = 0x0000000000000000
       r13 = 0x0000000000000000
       r14 = 0x0000000000000000
       r15 = 0x0000000000000000
       rip = 0x0000000008048089
    rflags = 0x0000000000000202
        cs = 0x0000000000000033
        fs = 0x0013
        gs = 0x001b
        ss = 0x000000000000003b
        ds = 0x003b
        es = 0x003b

therealdreg avatar May 01 '24 14:05 therealdreg

here my dirty tricks for lldb:

image

https://github.com/therealdreg/lldb_reversing

therealdreg avatar May 01 '24 14:05 therealdreg

Awesome thanks - Looks like LLDB is doing it wrong hence why LLEF is doing it wrong :)

I expect we'll be able to support a "force architecture" mode or something. Come to think of it I believe I've seen some poor architecture selection for certain MIPS targets as well that this might resolve.

stephen-f0 avatar May 01 '24 14:05 stephen-f0

Awesome, thx for your support. I linked this project in my repo :D

therealdreg avatar May 01 '24 14:05 therealdreg

I got setup with a FreeBSD instance and could replicate your exact issue. Ideally this should be fixed in LLDB but it seems like LLDB on FreeBSD is still quite fragile anyway. I've put up a quick WIP PoC which allows forcing architectures on this branch:

https://github.com/foundryzero/llef/tree/feature/force-arch

Once you've launched you can use the new force_arch setting to force it to i386:

llefsettings set force_arch i386

In the current implementation I've only fixed up the register output - the stack etc are still using whatever LLDB is providing (i.e. x86_64). If you get a moment please give it a try and let us know your thoughts.

stephen-f0 avatar May 02 '24 09:05 stephen-f0

The register is wrong, you should show "rip / pc"

The stack and disas is wrong

image

we need force the 32 bit code, something like:

di -b -c 10 -A i386 -s $pc
  • Keep in mind that if we don't force the number of lines in a pure ASM program, we will only be able to see one instruction and this is not usable... (-c 10)
  • Additionally, showing the opcodes in the instructions is essential for me.

And for stack something like:

memory read -s 4 -c 10 -l 1 -f x $sp

helloworld.asm

section .data
    msg     db      'Hello Dreg from 32 bit code FreeBSD!!', 0Ah
    hbytes	equ	$-msg

section .text
    global _start

_start:
    ; sys_write
    push dword hbytes
    push dword msg
    push dword 1
    mov eax, 4
    push eax ; garbage... freebsd call convention...
    int 0x80

    ; sys_exit
    push 0
    mov eax, 1
    push eax ; garbage...
    int 0x80

build.sh

#!/usr/bin/env bash
rm -rf helloworld hellworld.o && nasm -f elf helloworld.asm && ld -m elf_i386_fbsd -o helloworld -s helloworld.o

@stephen-f0 comment updated! take a look :D

therealdreg avatar May 02 '24 11:05 therealdreg

I've merged in the force_arch setting today and cut release v1.1.0.

For the time being it's still not going to do anything more than adjust the top register output. All other areas like the stack and disassembly view would require too much hackery to get working correctly. (especially given this appears to be an LLDB bug rather than LLEF). What you can do though now in v1.1.0 is disable the problematic areas e.g. llefsettings set show_code False then run your own LLDB commands if you want to view those sections.

Maybe in the future we could have a feature to allow users to run custom LLDB commands on the LLEF breakpoint to solve issues like the disassembly output.

stephen-f0 avatar Jul 19 '24 15:07 stephen-f0