rizinorg / rz-ghidra

Deep ghidra decompiler and sleigh disassembler integration for rizin
GNU Lesser General Public License v3.0
829 stars 88 forks source link

AnnotateVariable() method doesn't find the correct reference offset for global variables #323

Open sakiodre opened 1 year ago

sakiodre commented 1 year ago

I'm implementing my own ghidra decompiler and researching your source as a reference, while trying to make the xml parser I noticed that some global variable token has a varnode that is in the "register" or "unique" space.

I've checked on my end and it doesn't look like i parsed the xml incorrectly. Since your source doesn't handle this case, isn't this a bug?


void AnnotateGlobalVariable(Varnode *varnode, std::vector<RzCodeAnnotation> *out)
{
    RzCodeAnnotation annotation = {};
    annotation.type = RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE;
    annotation.reference.offset = varnode->getOffset();
    out->push_back(annotation);
}

void AnnotateVariable(ANNOTATOR_PARAMS){
        ....
    if (high->isPersist() && high->isAddrTied())
        AnnotateGlobalVariable(varnode, out);
}
ITAYC0HEN commented 1 year ago

@thestr4ng3r what do you think? is it intentional?

thestr4ng3r commented 1 year ago

Might indeed be a bug that there are false positives in the "global variable" recognition. But it should be checked with a concrete test case.

sakiodre commented 1 year ago

I've tested this repeatedly over the past few days, and it looks like the check for high->isPersist() && high->isAddrTied() is indeed false positive. This is how I fix this issue:

AddrSpace* space = varnode->getSpace();
AddrSpace* codeSpace = space->getTrans()->getDefaultCodeSpace();
annotation.reference.offset = (space != codeSpace) ? varnode->getTiedVarnode()->getOffset() : varnode->getOffset();

Note that I use the latest fork of ghidra, but that doesn't seem to be the issue.

sakiodre commented 1 year ago

I've come to a conclusion that this happens when a global variable get assign a value, something like this:

uRam_deadbeef = *(uint64_t*)(iVar8 + 0x123);

In this case, uRam_deadbeef varnode's address is in the unique (IPTR_INTERNAL) space, with the def pcodeop is CPUI_LOAD and its input1 is CPUI_CAST -> CPUI_INT_ADD (iVar8, 123).

And the fix varnode->getTiedVarnode() I mentioned above has been working fine for me till now. I'll make a PR in the next few days when I have free time and also bump ghidra to the latest version, it put everything in the ghidra namespace now so it's a bit complicated.

XVilka commented 1 year ago

And the fix varnode->getTiedVarnode() I mentioned above has been working fine for me till now. I'll make a PR in the next few days when I have free time and also bump ghidra to the latest version, it put everything in the ghidra namespace now so it's a bit complicated.

Hi, have you had a chance to do that? Also, is there any test case? Minified example would work best.