{
	"id": "ada9318a-a5e4-442c-9708-f044a3f287b5",
	"created_at": "2026-04-06T00:06:57.77887Z",
	"updated_at": "2026-04-10T13:11:39.073416Z",
	"deleted_at": null,
	"sha1_hash": "80b8ee84d1b0324d0d12fd2934ed33956e2c815c",
	"title": "Extracting type information from Go binaries",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 94793,
	"plain_text": "Extracting type information from Go binaries\r\nBy Ivan Kwiatkowski\r\nPublished: 2021-10-27 · Archived: 2026-04-05 13:19:11 UTC\r\nDuring the 2021 edition of the SAS conference, I had the pleasure of delivering a workshop focused on reverse-engineering Go binaries. The goal of the workshop was to share basic knowledge that would allow analysts to\r\nimmediately start looking into malware written in Go. A YouTube version of the workshop was released around\r\nthe same time. Of course, the drawback of providing entry-level or immediately actionable information is that a\r\nfew subtleties must be omitted. One particular topic I brushed aside was related to the way that Go creates objects.\r\nIn this screenshot taken from IDA Pro, we can see a call to the runtime.newobject function, which receives a\r\nstructure as an argument (here, in the RDX register, two lines above the call). The malware presented in the\r\nworkshop (Sunshuttle, from the DarkHalo APT, MD5 5DB340A70CB5D90601516DB89E629E43) is\r\nstraightforward to the extent that it can be understood without paying too much attention to these objects. In the\r\nvideos, I recommend ignoring these calls and instead focusing on documented Golang API functions. With the\r\nhelp of a debugger, it is easy to obtain the arguments and mentally reconstruct the original source code of the\r\napplication.\r\nHowever, Go malware following different coding practices could be littered with this kind of objects, to a point\r\nwhere the reverse engineer has no choice but to understand their nature to figure out what the code is supposed to\r\ndo. Unfortunately, the contents of the structure passed as an argument to runtime.newobject does not immediately\r\nappear to contain useful information:\r\nhttps://securelist.com/extracting-type-information-from-go-binaries/104715/\r\nPage 1 of 4\n\nTo find out more about this structure, we need to have a look at the Go source code to find the definition for the\r\nrtype structure. At the time of writing, its definition for the latest version of Go is as shown below.\r\ntype rtype struct {\r\n    size       uintptr\r\n    ptrdata    uintptr // number of bytes in the type that can contain pointers\r\n    hash       uint32  // hash of type; avoids computation in hash tables\r\n    tflag      tflag   // extra type information flags\r\n    align      uint8   // alignment of variable with this type\r\n    fieldAlign uint8   // alignment of struct field with this type\r\n    kind       uint8   // enumeration for C\r\n    // function for comparing objects of this type\r\n    // (ptr to object A, ptr to object B) -\u003e ==?\r\nhttps://securelist.com/extracting-type-information-from-go-binaries/104715/\r\nPage 2 of 4\n\nequal     func(unsafe.Pointer, unsafe.Pointer) bool\r\n    gcdata    *byte   // garbage collection data\r\n    str       nameOff // string form\r\n    ptrToThis typeOff // type for pointer to this type, may be zero\r\n}\r\nThere are two fields in this structure that are relevant to us. The first one is “kind”, which is an enum (defined in\r\nthe same file) representing a sort of base type for the object: Boolean, integers of various lengths, but also arrays,\r\nmaps, interfaces, etc. The other is “nameOff”, which is a pointer to a string representation of the described type for\r\nthe purposes of reflection. The latter is extremely useful to reverse engineers, as it immediately tells us what the\r\nobject is. This structure can itself be contained in specialized ones for interfaces, maps, and so on.\r\nAlas, the result of creating these structures in IDA Pro and applying the correct one to the newobject argument is\r\nsomewhat underwhelming:\r\nWhere is our human-readable name? It turns out that the offset provided by nameOff is relative to the .rdata\r\nsection of the PE in the case of Windows programs – this is something you can confirm with a hex editor.\r\nThe offset leads us to another structure, which contains some information about the string, including its size, and\r\nfinally, the string itself. Initially, the size of the string had a fixed length (2 bytes), but that appears to have\r\nchanged in Go 1.17 (now varint-encoded). Nonetheless, the coveted information lies here: the object instantiated\r\nin our original newobject call was an md5.digest, which we can now look up in the documentation if needed.\r\nGo programs may contain hundreds of these calls, and newobject is not the only function that relies on these rtype\r\nstructures (i.e. runtime.makechan, runtime.makemap, etc.), so it is obviously impractical to manually look up each\r\ntype using a hex editor. Enter IDA scripting! It is, in fact, possible to entirely automate this operation by writing a\r\nfew lines of Python.\r\nhttps://securelist.com/extracting-type-information-from-go-binaries/104715/\r\nPage 3 of 4\n\nThe script I use in my daily work has been included in SentinelOne’s recently released AlphaGoLang repository,\r\nas step 5 of the process. It performs the following actions:\r\nInspect all the calls to functions, such as newobject, and look at their arguments to find rtype\r\nApply the structure shown above to those bytes in IDA to make them easier to read.\r\nLook up the corresponding string representation for the type and add it as a comment wherever it is\r\nreferred to.\r\nOne thing the script struggles with a little is figuring out how the string size is encoded, as I was not able to find\r\nan easy way of determining the Go version from a Python script (yet). Should this cause problems, the many\r\ncomments should allow you to update the script to fit your use case. If you are new to IDA scripting, I would also\r\nrecommend that you go have a look at the source code, as it is a great example of the many things you can do with\r\nthe Python API! And if you would like to learn even more on the subject (and more) with detailed video tutorials,\r\nplease consider signing up for our online reverse-engineering course on the Xtraining platform.\r\nI hope you find the script useful! Feel free to report any bugs or submit fixes and updates on GitHub!\r\nSource: https://securelist.com/extracting-type-information-from-go-binaries/104715/\r\nhttps://securelist.com/extracting-type-information-from-go-binaries/104715/\r\nPage 4 of 4",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://securelist.com/extracting-type-information-from-go-binaries/104715/"
	],
	"report_names": [
		"104715"
	],
	"threat_actors": [
		{
			"id": "70872c3a-e788-4b55-a7d6-b2df52001ad0",
			"created_at": "2023-01-06T13:46:39.18401Z",
			"updated_at": "2026-04-10T02:00:03.239111Z",
			"deleted_at": null,
			"main_name": "UNC2452",
			"aliases": [
				"DarkHalo",
				"StellarParticle",
				"NOBELIUM",
				"Solar Phoenix",
				"Midnight Blizzard"
			],
			"source_name": "MISPGALAXY:UNC2452",
			"tools": [
				"SNOWYAMBER",
				"HALFRIG",
				"QUARTERRIG"
			],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434017,
	"ts_updated_at": 1775826699,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/80b8ee84d1b0324d0d12fd2934ed33956e2c815c.pdf",
		"text": "https://archive.orkl.eu/80b8ee84d1b0324d0d12fd2934ed33956e2c815c.txt",
		"img": "https://archive.orkl.eu/80b8ee84d1b0324d0d12fd2934ed33956e2c815c.jpg"
	}
}