Today's Golang reversing adventure: Trying to tackle a problem where Hex-Rays wouldn't decompile any Go functions in my binary.
I noticed that in other Go binaries the decompiler would at least produce output, but it was hard to read. (1/11)
In my problem sample, Hex-Rays would decompile the binary, but after I ran IDAGoLanghelper, every function would throw a "call analysis failed" error. Typically, that's indicative of an incorrectly labeled calling convention, arguments, or bad SP values in the function. (2/11)
I start playing with the types for function calls, and still I'm getting the same error. As far as I can tell, IDA is def getting the number of arguments right for these functions, including the "extra arguments" that aren't explicitly passed, but modified to store retvals.(3/11)
While stack return values are weird, that situation shouldn't cause the whole decompilation to fail. I start scratching my head and staring at the error message: (4/11)
And then it hits me, "You dum dum, READ the error". I was completely ignoring the address in the error and instead, inexplicably decided that the problem was that the calling convention was borked *everywhere* instead of a specific address. (5/11)
I look at that address and find this. Then I realize the source of the problem. runtime_morestack_noctxt or runtime_morestack are called at the beginning of every Golang function. If Hex-Rays runs into a problem there, it's going to bork decompilation everywhere! (6/11)
I examine runtime_morestack_noctxt and its call chain. There was one bad stack value: a rogue "esp + 0" highlighted in red. I hit "K" to fix it. Then set the return type of the function to "void" so that the decompiler knows to ignore eax. Hit "Tab" and cross my fingers. (7/11)
Success! Those orange vars mean that the var may be uninitialized. While it seems like a problem, it's actually very helpful. Return values in Go are basically "uninitialized arguments". (8/11)
The space for return values are never explicitly passed, but the callee knows to set the space after the last real argument to the return value. So the decompiler is correctly telling me those values are uninitialized, and as a byproduct, the size of the return values. (9/11)
That information is quite helpful when relating Go types to their underlying representation.

I still don't know why IDAGolangHelper caused the auto-analysis to spit out a bad stack value there though. I need to investigate further how it works its magic. (10/11)
So anyway, today I was reminded of two helpful and humbling things.
1. Pay attention to the ENTIRE error message
2. Everyone, despite their experience, can make really silly mistakes. Like I'm legit embarassed at how long it took me to figure this out 😅 (11/11)
You can follow @mayahustle.
Tip: mention @twtextapp on a Twitter thread with the keyword “unroll” to get a link to it.

Latest Threads Unrolled:

By continuing to use the site, you are consenting to the use of cookies as explained in our Cookie Policy to improve your experience.