ghidra
ghidra copied to clipboard
Golang receiver methods analysis
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.0_8 = cmd.str; is defined.
Environment (please complete the following information):
- OS: macOS 13.0
- Java Version: 17.0.4.1
- Ghidra Version: 11.0.1
- Ghidra Origin: Locally built
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?