{
	"id": "e788f6b5-8885-4a23-a6e4-c8aa8afd051b",
	"created_at": "2026-04-10T03:22:12.020025Z",
	"updated_at": "2026-04-10T13:11:32.307798Z",
	"deleted_at": null,
	"sha1_hash": "f87052b1c00454e96e267630963418ee3b83a2bd",
	"title": "Aurora Stealer",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2613579,
	"plain_text": "Aurora Stealer\r\nBy Mohamed Adel\r\nPublished: 2023-04-12 · Archived: 2026-04-10 03:07:05 UTC\r\nAurora Stealer is an information stealer Written in GO. It is a commercial stealer that costs around 250$ per month. The\r\nmalware can steal Browser password and saved cookies, crypto information (Desktop and Web), Telegram, Steam and\r\nSpecific files from the victim machine and can take a screenshot from it.\r\nThe icon of the executable gives us a hit about how this is spreading. It has Photoshop icon, most probably it was spreading\r\nusing Malvertising.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 1 of 19\n\nFirst we want to know some basic information about the file so I will use DiE to do so.\r\nIt was identified as GO binary. .symtab is a legacy section in GO binaries. In GO binaries prior to Version 1.3 .symtab\r\nsection hold the symbol table but it is no longer filed with anything useful. Without Symbols, the reversing will be so hard as\r\na simple Hello world program in GO has about 2000 function this is a result of that GO compiler statically linking all the\r\nneeded libraries. Later, I will try to tackle this problem using existed Tools.\r\nAn important aspect of the basic Triaging of a Malware is to check the readable Strings of the file. But GO is different in\r\neverything. The strings has a part of that too.\r\nIn GO, the strings are stored in Unicode format without null terminating character so many tools will handle that wrong.\r\nAlso, the existence of this large number of library functions will make it worse. The resulting number of lines using strings\r\nutility in Die is 7371 line. We can reduce this number by matching for the library functions like the following Regex\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 2 of 19\n\n1 .*(runtime|\\/usr|\\/root).*\\n?\r\nthis matches the lines that contains runtime, usr and root. this filters around 2500 line but still around 5000 line. these lines\r\ncontains the function imported in program, you can check them but it will be so exhausting to get information from it. Let’s\r\nContinue our analysis using the disassembler.\r\nI will upload the sample to IDA to explore it. In the old versions of IDA, Library functions will not be recognized and\r\nrenamed. Also the types will be mostly wrong.\r\nTo handle this there is some tools you can use to fix the types and names. I’ve used GoReSym.\r\nThis is a standalone executable you can run with following parameters\r\n1 GoReSym_win.exe -t -d -p \u003cPATH_TO_FILE\u003e \u003e fix.json\r\nfor more info about the available parameters, Check the repo of the tool.\r\ncontent of the output is in JSON format so I saved it to use it in this IDA Script to rename the functions and correct the types\r\nin IDA database.\r\nNOTE: -t parameter fix the types information but if you the decompiler will fail to decompile it.\r\nIf you want to know how this tool is working, Check this article. Basically it search for pclntab structure by searching for\r\na magic header and follow the pointer to symbols table.\r\n 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n// pcHeader holds data used by the pclntab lookups.\r\ntype pcHeader struct {\r\nmagic uint32\r\n/*\r\ngo12magic =\r\ngo116magic =\r\ngo118magic =\r\ngo120magic =\r\n*/\r\npad1, pad2 uint8 // 0,0\r\nminLC uint8 // min instruction size\r\nptrSize uint8 // size of a ptr in bytes\r\nnfunc int // number of functions in the module\r\nnfiles uint // number of entries in the file tab\r\ntextStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text\r\nfuncnameOffset uintptr // offset to the funcnametab variable from pcHeader\r\ncuOffset uintptr // offset to the cutab variable from pcHeader\r\nfiletabOffset uintptr // offset to the filetab variable from pcHeader\r\npctabOffset uintptr // offset to the pctab variable from pcHeader\r\npclnOffset uintptr // offset to the pclntab variable from pcHeader\r\n}\r\nThis is also used by the go parser itself in order to locate the function, For more info here\r\nAnother set of scripts available we can use it doing the same thing is Alphagolang\r\nI will use Alphagolang here but both will provide similar result.\r\nFirst I used recreate_pclntab.py script to recreate pclntab structure.\r\nSecond, I used function_discovery_and_renaming.py script to rename the functions.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 3 of 19\n\nThird, I used categorize_go_folders.py to categorize the functions and pack them in folders, This will be very helpful to\r\nfocus on user-code.\r\nFourth, I used string_cast.py to fix string references.\r\nFifth, I used extract_types.py to correct the types information by applying C like types to the used structures.\r\nThe result\r\nNow, We have a better environment so we can start exploring the code efficiently.\r\nIn function calls, GO has a different calling convention.\r\nAll the argument are passed using the stack from the left to right. The following assembly code is in Go assembler format\r\n1 func testConv(x,y int) int {return x+y}\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\ntestConv:\r\nMOVQ 0x8(SP), AX ; get arg x\r\nMOVQ 0x10(SP), CX ; get arg y\r\nADDQ CX, AX ; %ax \u003c- x + y\r\nMOVQ AX, 0x20(SP) ; return x+y-z\r\nRET\r\nthe compiler have to make sure that there is enough space on the stack to accommodate all the arguments and return values.\r\nGo stores strings in a Unicode -UTF-8- format without null terminating characters in a section contain all the strings but.\r\nStrings in go stored in structure of value and length pair called StringHeader . So, in all the function where a string\r\nargument is passed, you will see an extra argument contain the length of the string.\r\n1\r\n2\r\n3\r\n4\r\ntype StringHeader struct {\r\nData uintptr\r\nLen int\r\n}\r\nFirst we start with main_init function ( sub_595590 ). In GO, init() is a predefined function that takes no argument,\r\nReturn no values. And Runs before any code in the package.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 4 of 19\n\nThe block number 1 shows that it loads some DLLs and functions.\r\nDLL Function\r\nuser32.dll GetDesktopWindow\r\nuser32.dll EnumDisplayMonitors\r\nuser32.dll GetMonitorInfoW\r\nuser32.dll EnumDisplaySettingsW\r\nkernel32.dll LocalFree\r\nCrypt32.dll CryptUnprotectData\r\nIn Block number 2, It Reads the the environment Variable USERPROFILE and concatenate \\\\APPDATA\\\\LOCAL\\ and\r\n\\\\APPDATA\\\\ROAMING\\ and save the new string to the memory.\r\nIn block 3, It did the same thing to get the Paths C:\\\\Users\\\\{user}\\\\APPDATA\\\\ROAMING,\u003cLocal\u003e\\\\ but it replaces the\r\nstring C:\\\\Users with C:\\\\windows.old\\Users with Replace function from strings package\r\n1\r\n2\r\nfunc Replace(original string, old string, new string, n int) string\r\n//where n is the number of times replacing occures. -1 for replace all\r\nthis location is created when the user update from one version to another and it contains all the old information from the\r\nprevious installation.\r\nmoving to main_main ( sub_595470 ). It creates a new procedure by making a call to newproc function from runtime\r\npackage.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 5 of 19\n\nfollowing the code to main_ConnectToServer ( sub_58ABE0 ). This function has some interesting functionality we will\r\nexplore next.\r\nIn block 1, the malware sleeps for 1000000000 nanoseconds -I tried a simple program with the same call to sleep and it was\r\nequivalent to time.Nanosecond -\r\nThen it establishes a TCP connection to 82.115.223.249:8081 IP address using function Dial from net package. Then\r\nit Reads the Received packet. the Dial function in GO returns 2 values, Conn interface and Error, which IDA cannot\r\nrecognize so, I will follow my intuition. If the connection returned error, it will try to reconnect again.\r\nIn Block 2, The connection was established but it first checks the response from the remote IP. If it was blocked due to the\r\ngeo location, as the IP is Russian, it will try to reconnect.\r\nIf the response was WORK string, the connection is established successfully and the malware can continue with its\r\nfunctionality as shown in block 3 and 4\r\nMoving to main_GetInfoUser() ( sub_58B880 ). The first Lines in this subroutine takes us to another function,\r\nmain_MachineID ( sub_5897A0 )\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 6 of 19\n\nThe malware Runs the command cmd.exe /c wmic csproduct get uuid to get UUID of the device. Returning to\r\nmain_GetInfoUser .\r\nIt retrieves the screen width and height using win32 API GetSystemMetrics , GO allow using third-party packages directly\r\nfrom GitHub and the the cause of the function naming. The screen resolution is represented in the format\r\n\u003cwidth\u003ex\u003cheight\u003e .\r\nThe next call is to main_GetOS ( sub_58A530 ).\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 7 of 19\n\nThis function retrieves the OS version using wmic command wmic os get Caption . and filter the output based on the\r\nform it is printed to format is in a space separated string.\r\nReturning back to main_GetInfoUser a call to main_getGPU ( sub_58A200 ) is made.\r\nThe GPU information retrieved by executing the command cmd /C wmic path win32_VideoController get name\r\nUsing the same method in main_getCPU ( sub_589F10 ). It gets CPU information with command cmd /c wmic cpu get\r\nname\r\nin main_sysTotalMemory ( sub_58B550 )It gets the memory status by executing GlobalMemoryStatusEx function.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 8 of 19\n\nmain_CMD_SHELL is called to execute cmd /c systeminfo that gets all the specs of the device.\r\nThat was the last thing the function main_GetInfoUser do.\r\nBack in main_main , the function main_grab ( sub_593E80 ) is called. This function responsible for doing the main goal\r\nof the malware, Stealing.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 9 of 19\n\npanic function is used to check for unexpected errors. common use of panic is to abort if a function returns an error\r\nvalue that we don’t want to handle.\r\nGoing to the first function main_file_grabber ( sub_594110 )\r\nthis function search for a specific file taken from the C2 server and it is base64 encoded and in JSON format.\r\nThen, It search for the file in some predefined directories and location.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 10 of 19\n\nthe function io_ioutil_ReadDir reads the content of the directory and stores the output in a fs.fileinfo structure ,\r\nsorted by the filename\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\ntype FileInfo interface {\r\nName() string // base name of the file\r\nSize() int64 // length in bytes for regular files; system-dependent for others\r\nMode() FileMode // file mode bits\r\nModTime() time.Time // modification time\r\nIsDir() bool // abbreviation for Mode().IsDir()\r\nSys() any // underlying data source (can return nil)\r\n}\r\nThen it walks through the returned structure and reads the file of interest\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 11 of 19\n\nthen it encode the file content in Base64 and adds the tags used in the JSON formatted packet content to be sent to the\r\nremote system\r\nWe will visit SendToServer latter. Now, lets go back to the caller function and explore the next function,\r\nmain_Grab_func3 ( sub_58F0B0 ).\r\nThis function goes through the %APPDATA%Roaming directory and calls another function. the function\r\npath_filepath_Walk walks the directory from the Root passed in the second parameter calling a function fn.WinDirFunc\r\nat each file and directory in it including the Root.\r\n1 func Walk(root string, fn WalkFunc) error\r\n1 type WalkFunc func(path string, info fs.FileInfo, err error) error\r\nSo, Next one to visit is WalkFunc used main_Grab_func3_2 ( sub_58DED0 ).\r\nThis function steals the Browser information stored\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 12 of 19\n\nFor Chromium based browsers it gets the Local State file and calls main_getMasterKey that as the name suggest, Gets the\r\nmaster key and decode it .then, decrypts it by calling CryptUnprotectData which is called from main_xDecrypt\r\nIt handles the case of using Opera and Firefox browsers\r\nBack to the caller function, The malware steals the password and cookies from the browser data and adds the tags of the\r\nJSON file to be sent to the C2 server.\r\nThen, It goes through the %USERPROFILE% searching for any Crypto wallets information\r\nIt Looks for PC applications and Web based wallets and add its associated type and name to the JSON data to be sent\r\nfunction main_Grab_func_7 ( sub_591D50 ) is used to take a screenshot from the victim system\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 13 of 19\n\nThe PNG file is then base64 encoded and add the value to the tag screenshot to be sent.\r\nThe next targeted information is Telegram, It did the same procedure discussed before with telegram data folder at\r\nmain_Grab_func_6 ( sub_591980 )\r\nWalkFunc → main_Grab_func_6_2 ( sub_591120 )\r\nfunction main_Grab_func9 ( sub_593B30 ) steals steam data in the same way\r\nmain_SendToServer_NEW ( sub_594DD0 ) is used to send the collected data to the server.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 14 of 19\n\nThe collected information stored in JSON format. the Data then compressed using gzip compression algorithm and\r\nencoded with Base64 encoding to be sent to the server using the previously established TCP connection.\r\nwe can look at the network communication using PCAP file provided by Any Run sandbox.\r\nBy opening the file in Wireshark and filter using the IP 82.115.223.249\r\nFollowing the TCP stream\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 15 of 19\n\nThe first packet received is WORK indicates that the connection is successful and the malware then begin to collect the\r\nrequired data and compress it and send it to the server. At the last packet received from the the C2 server is Thanks .\r\nwe can use Cyberchef to decode and decompress the data.\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 16 of 19\n\nthe Error list include the files that the malware cannot read or access. On of the packets has a very large size, as the\r\nscreenshot field has a very large Base64 encoded data\r\nthe screenshot:\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 17 of 19\n\nSample JSON file can be found here https://pastebin.com/YpTwAC94\r\nAurora stealer is a new commercial infostealer. Most of it’s capabilities are typical things that can be found in most of the\r\nstealers. it can grab Browser saved password/cookies and Cryptocurrency wallets information from Desktop applications\r\nand Web based wallets. Also, it can grab a files from the victim machine and take a screenshot. The communication with C2\r\nserver is done over TCP protocol. Most of these things can be found in most of the stealer But being written in GO makes it\r\nspecial, even it has a plaintext strings, The reversing process is quite annoying as most of the tools cannot handle GO\r\nbinaries in a right way.\r\n29339458f4a33ee922f25d36b83f19797a15a279634e9c44ebd3816866a541cb\r\n82.115.223[.]249:8081\r\n 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\nrule aurora_stealer{\r\n meta:\r\n malware = \"Aurora stealer\"\r\n hash = \"29339458f4a33ee922f25d36b83f19797a15a279634e9c44ebd3816866a541cb\"\r\n reference = \"https://d01a.github.io/\"\r\n Author = \"d01a\"\r\n description = \"detect Aurora stealer\"\r\n strings:\r\n $is_go = \"Go build\" ascii\r\n $a1 = \"C:\\\\Windows.old\\\\Users\\\\\" ascii\r\n $a2 = \"\\\\AppData\\\\Roaming\\\\\" ascii\r\n $a3 = \"wmic csproduct get uuid\" ascii\r\n $a4 = \"wmic cpu get name\" ascii\r\n $a5 = \"systeminfo\" ascii\r\n $a6 = \"coNNNECTIONGWQFGQW\" ascii\r\n $fun1 = \"main.Grab\" ascii\r\n $fun2 = \"main.getMasterKey\" ascii\r\n $fun3 = \"main.SendToServer_NEW\" ascii\r\n $fun4 = \"main.ConnectToServer\" ascii\r\n $fun5 = \"main.xDecrypt\" ascii\r\n $fun6 = \"main.GetDisplayBounds\" ascii\r\n condition:\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 18 of 19\n\n28\r\n29\r\n uint16(0) == 0x5a4d and ( $is_go and (4 of ($a*)) and (4 of ($fun*)) )\r\n}\r\nhttps://gist.github.com/alexander-hanel/59af86b0154df44a2c9cebfba4996073\r\nThe Go Programming Language\r\nhttps://pkg.go.dev/\r\nPCAP file\r\nhttps://dr-knz.net/go-calling-convention-x86-64.html\r\nhttps://dr-knz.net/go-calling-convention-x86-64-2020.html\r\nAurora: a rising stealer flying under the radar - SEKOIA.IO Blog\r\nSource: https://d01a.github.io/aurora-stealer/\r\nhttps://d01a.github.io/aurora-stealer/\r\nPage 19 of 19",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://d01a.github.io/aurora-stealer/"
	],
	"report_names": [
		"aurora-stealer"
	],
	"threat_actors": [],
	"ts_created_at": 1775791332,
	"ts_updated_at": 1775826692,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/f87052b1c00454e96e267630963418ee3b83a2bd.pdf",
		"text": "https://archive.orkl.eu/f87052b1c00454e96e267630963418ee3b83a2bd.txt",
		"img": "https://archive.orkl.eu/f87052b1c00454e96e267630963418ee3b83a2bd.jpg"
	}
}