trailofbits / maat

Open-source symbolic execution framework: https://maat.re
Other
612 stars 43 forks source link

PPC-32 bit error after unit testing branch #171

Closed Katastropic2431 closed 1 year ago

Katastropic2431 commented 1 year ago

Currently, I'm working on adding PowerPC 32-bit support to Maat by following the contributing.md guide. While testing the branch conditional branch greater or equal to, I encountered an error with the message "terminate called after throwing an instance of 'LowlevelError' on the code block provided. All other assembly instructions are working, but when the Maat engine reads the next assembly line after a conditional branch, it throws a low level error.

    unsigned int disass_bge()
    {
        unsigned int ret_value = 0;
        MaatEngine sym = MaatEngine(Arch::Type::PPC32);
        sym.mem->map(0x1000,0x2000);
        sym.mem->map(0x0,0x1000);
        string code;

        code = string("\x40\x80\x00\x20", 4); // bge 18 or bge 0x12
        sym.mem->write_buffer(0x1000, (uint8_t*)code.c_str(), code.size());
        sym.mem->write_buffer(0x1020, (uint8_t*)string("\x38\x40\x10\x00", 4).c_str(), 4); // load immediate 
        sym.mem->write_buffer(0x1004, (uint8_t*)string("\x38\x40\x10\x00", 4).c_str(), 4);

        // Taken
        sym.cpu.ctx().set(PPC32::CR0, exprcst(8,6));
        sym.run_from(0x1000, 1); // this is where it will fail if i change the 1 to 2
        ret_value += _assert( sym.cpu.ctx().get(PPC32::PC).as_uint() == 0x1020, "ArchPPC32: failed to disassembly and/or execute BGE");

        sym.cpu.ctx().set(PPC32::CR0, exprcst(8,4));
        sym.run_from(0x1000, 1);
        ret_value += _assert( sym.cpu.ctx().get(PPC32::PC).as_uint() == 0x1020, "ArchPPC32: failed to disassembly and/or execute BGE");

        sym.cpu.ctx().set(PPC32::CR0, exprcst(8,2));
        sym.run_from(0x1000, 1);
        ret_value += _assert( sym.cpu.ctx().get(PPC32::PC).as_uint() == 0x1020, "ArchPPC32: failed to disassembly and/or execute BGE");

        // Not Taken
        sym.cpu.ctx().set(PPC32::CR0, exprcst(8,9));
        sym.run_from(0x1000, 1);
        ret_value += _assert( sym.cpu.ctx().get(PPC32::PC).as_uint() == 0x1004, "ArchPPC32: failed to disassembly and/or execute BGE");

        sym.cpu.ctx().set(PPC32::CR0, exprcst(8,8));
        sym.run_from(0x1000, 2); // this is where it is failing if i change the 2 to 1 it will work again.
        ret_value += _assert( sym.cpu.ctx().get(PPC32::PC).as_uint() == 0x1004, "ArchPPC32: failed to disassembly and/or execute BGE");

        return ret_value;
    }

This is the error:

[+] Testing arch PPC32 support...    
terminate called after throwing an instance of 'LowlevelError'
Aborted (core dumped)

Looking at the ghidra source code it the error occurs in /build/_deps/ghidrasource-src/Ghidra/Features/Decompiler/src/cpp/globalcontext.cc The low level error is this: throw LowlevelError("Cannot register new context variables after database is initialized");

Like I previous stated, all the other instructions seem to be working including the branch conditional 'BGT' and 'BLT'. However when the maat engine reads the next line assembly line it will throw a 'LowLevelError' if its after a branch conditional regardless if the branch was taken or not.

This error occurs whenever the Global Context is changed, specifically the linkreg.

If anyone can someone provide some input on why this error is occurring.

Edit 1: I am using Ghidra version 10.2.3 Edit 2: After examining Ghidra's issues page, I came across this: https://github.com/NationalSecurityAgency/ghidra/issues/5218, which I think might be relevant to the issue I'm experiencing.

Katastropic2431 commented 1 year ago

I am still working on this issue, any helpful input will be greatly appreciated.

Katastropic2431 commented 1 year ago

I found a fix! I noticed that Sleigh was changing the context register so I just added this line of code to sleigh_interface.cpp to not allow that and it works.

if (arch == Arch::Type::PPC32)
{
    m_sleigh->allowContextSet(false);
}