NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
48.51k stars 5.61k forks source link

Golang receiver methods analysis #6220

Open oxeye-shawn opened 3 months ago

oxeye-shawn commented 3 months ago

Describe the bug While attempting to analyze Ghidra analysis for Golang binaries, a discrepancy was encountered regarding the getDef() function for receiver methods. The following code snippet was analyzed:

func RunCommandHandler(w http.ResponseWriter, r *http.Request) {
    cmd := r.URL.Query().Get("cmd")
    timeout := r.URL.Query().Get("timeout")

    bashRunner := &BashRunner{
        Cmd:     cmd,
        Timeout: 10, // Default timeout of 10 seconds if not provided
    }

    if timeout != "" {
        bashRunner.Timeout = convertToInt(timeout)
    }

    output, err := bashRunner.Run()
    if err != nil {
        http.Error(w, fmt.Sprintf("Failed to execute command: %s\nError: %s\n", cmd, err), http.StatusInternalServerError)
        return
    }

    fmt.Fprintf(w, "Command output:\n%s", string(output))
}

After analysis, the decompiled output of Ghidra was examined up to the bashRunner.Run() call:

void main::main.RunCommandHandler(net/http.ResponseWriter w,net/http.Request *r)
{
    []interface_{} a;
    net/url.Values phVar1;
    int iVar2;
    void *pvVar3;
    runtime.itab *prVar4;
    undefined auVar5 [16];
    string sVar6;
    string format;
    io.Writer w_00;
    main.(*BashRunner).Run_multivalue_return_type mVar7;
    string sVar8;
    string format_00;
    []interface_{} a_00;
    net/http.ResponseWriter w-spill;
    net/http.Request *r-spill;
    main.BashRunner *bashRunner;
    runtime._type *local_198;
    net/url.URL *local_178;
    net/url.URL *local_170;
    string timeout;
    error err;
    string cmd;
    interface_{} local_e8;
    string local_d8;
    error local_c8;
    []uint8 output;
    undefined local_58 [16];
    int iStack_48;
    uint8 *local_40;
    undefined local_38 [16];
    interface_{} local_28;
    undefined local_18 [16];

    w_00.data = w.data;
    auVar5 = (undefined  [16])0x0;
    while (&local_178 <= CURRENT_G.stackguard0) {
      runtime::runtime.morestack_noctxt();
    }
    local_170 = r->URL;
    phVar1 = net/url::net/url.(*URL).Query(local_170);
    sVar6.len = 3;
    sVar6.str = (uint8 *)"cmd";
    sVar6 = net/url::net/url.Values.Get((net/url.Values)phVar1,sVar6);
    local_178 = r->URL;
    phVar1 = net/url::net/url.(*URL).Query(local_178);
    sVar8.len = 7;
    sVar8.str = (uint8 *)"timeout";
    timeout = net/url::net/url.Values.Get((net/url.Values)phVar1,sVar8);
    cmd.str = sVar6.str;
    cmd.len = sVar6.len;
    local_58._0_8_ = cmd.str;
    iStack_48 = 10;
    local_58._8_8_ = cmd.len;
    if (timeout.len != 0) {
      iVar2 = main.convertToInt(timeout);
                      /* WARNING: Ignoring partial resolution of indirect */
      iStack_48 = iVar2;
    }
    local_40 = (uint8 *)0x0;
    local_c8 = (error)auVar5;
    local_38 = auVar5;
    mVar7 = main.(*BashRunner).Run((main.BashRunner *)local_58);
}

Issue with Analysis:

Upon using the API call to trace the function call, the obtained Pcode was:

(VARIABLE, 0x40, 40) CALL (ram, 0x62c7c0, 8) , (unique, 0x3c80, 8)

Subsequently, performing getDef() on the unique identifier led to:

(unique, 0x3c80, 8) CAST (unique, 0x100003a0, 8)

Continuing to trace the definition, the next Pcode encountered was:

(unique, 0x100003a0, 8) PTRSUB (register, 0x20, 8) , (const, 0xffffffffffffffa8, 8)

This up tracing sequence led to a dead end due to the need for a definition for the register 0x20. Furthermore, its descendants did not lead to the desired variable local_58, hindering the analysis process. Consequently, understanding the program flow and security risks related to using local_58 within the function call context became challenging.

Expected behavior When tracing up the definition of the receiver method, the expectation is to arrive at the point of local_58 creation. By examining its descendants, the aim is to reach the line where local_58._08 = cmd.str; is defined.

Environment (please complete the following information):

dev747368 commented 2 months ago

What arch is the go binary compiled for? Could you show the storage that was assigned to the return value of the main.(*BashRunner).Run() function?

Also, does changing the type of local_58 to main.BashRunner help?