{
	"id": "443d5c75-d1db-433d-9370-de28479cac82",
	"created_at": "2026-04-06T00:12:48.287531Z",
	"updated_at": "2026-04-10T13:12:59.985441Z",
	"deleted_at": null,
	"sha1_hash": "631b9a3ff7674039e4cc082252f71141f13e29bc",
	"title": "Keeping an eye on CloudEyE (GuLoader) - Reverse engineering the loader",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2420984,
	"plain_text": "Keeping an eye on CloudEyE (GuLoader) - Reverse engineering\r\nthe loader\r\nArchived: 2026-04-05 23:47:06 UTC\r\nCloudEye (originally GuLoader) is a small malware downloader written in Visual Basic that's used in delivering\r\nall sorts of malicious payloads to victim machines. Its primary function is to download, decrypt and run an\r\nexecutable binary off a server (commonly a legitimate one like Google Drive or Microsoft OneDrive).\r\nAt the time of writing this article, the malicious code can be split into two parts:\r\nThe core of the program that performs VM checks, downloads the code, decrypts and runs it\r\nA small wrapper that hides the core by encrypting it with a simple xor algorithm\r\nWhile the outer layer is pretty tiny and straightforward, mimicking it and manually unpacking the core can be a bit\r\nof a headache. In this article, we'll explain how one can leverage IDA Pro functionalities to simplify this process.\r\nSample analysed:\r\nZAPYTANIE_OFERTOWE_KPM_03-022021.exe -\r\n41b83b01b84f95653e2cc9467a6d509c291ab6e834bdf786e75616d51ad45164 (VirusTotal, MWDB)\r\nThe first thing you want to do while reverse-engineering Visual Basic binaries in IDA is grab a copy of vb.idc. It's\r\na super useful IDA script that parses the embedded VB metadata and provides you with much more information\r\nabout the binary than the original analysis.\r\nCompare the number of detected event entry points before running the script:\r\nAnd after:\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 1 of 10\n\nLocating the malware entry point is still not trivial, though. You can iterate over all discovered entry points and\r\njudge if there's anything suspicious or not, but that can become quite tedious, and you can still miss some better-hidden code.\r\nSometimes, a good method is to search for all add instructions and find the \"odd one\" with a large immediate\r\nvalue sticking out. You can do that in IDA either by selecting Search -\u003e Text or if you're aspiring to be a\r\npower-user: by quickly tapping Alt + t .\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 2 of 10\n\nMake sure you check the Find all occurrences box, this will take IDA a bit longer, but it will allow you to\r\ninspect all matches at once.\r\nNow, navigate to the function in question:\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 3 of 10\n\nAnd press tab to see the matching decompilation (as usual, the decompiler does most of the job for us):\r\nWith the malware entry address 0x4023CE we can now begin analyzing the real loader. Let's jump to the entry\r\naddress by selecting Jump -\u003e Jump to address (shortcut g )\r\nSurprisingly, there's no code there, just a bunch of data.\r\nThat's because IDA didn't know to follow the code reference; to fix that, we'll have to mark the data as code\r\nourselves. Start by undefining the fragment Edit -\u003e Undefine (shortcut u )\r\nThis will split the large chunk of data into single-byte lines:\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 4 of 10\n\nNow we can once again jump to 0x4023CE (the original line contained many bytes, and IDA doesn't know which\r\none to follow and decides to stay on the first byte) and mark the data as code Edit -\u003e Code (shortcut c ).\r\nThis will automatically disassemble all reachable code blocks and functions.\r\nWe can almost immediately notice that this isn't an ordinary function, but something rather weird is going on:\r\nthere are many jumps with random data between them. We can clear it up a bit by grouping the data between code\r\nblocks together and adding a few arrows:\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 5 of 10\n\nSome of our avid readers will surely recognize this pattern from our Dissecting Smoke Loader article. The main\r\ntakeaway was that while manually reconstructing the code flow and creating a new disassembly is possible;\r\nusually, the best method is to let IDA decompiler deal with such obfuscations.\r\nBut if we try to create a new function at the start address ( Edit -\u003e Functions -\u003e Create Function shortcut p ),\r\nall we get is this annoying error message:\r\n.text:00402FEE: The function has undefined instruction/data at the specified address.\r\nYour request has been put in the autoanalysis queue.\r\nThat's because IDA wasn't able to disassemble the code at the given address; let's see what the fuzz is about.\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 6 of 10\n\nWell, yes, it doesn't look too correct. Instructions in the form of jmp short near ptr \u003caddr\u003e+\u003cnumber\u003e should\r\nalmost always raise a red flag for you. It very often means that the jmp (or any other code-flow-altering\r\ninstruction) tries to jump into the middle of already defined code/data. In this case, though, it looks like IDA just\r\nmade an error, and we have to mark the data as code manually, similarly as we had done previously.\r\nGood as new! We may have to repeat this several times before we get all parts correct.\r\nAt some point, though, we'll come across a fragment that no longer looks like correct x86 code:\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 7 of 10\n\nThat's the code that gets decrypted in previous code blocks; naturally, IDA won't decompile invalid instructions.\r\nWe can get around that using (at least) 2 methods:\r\nby selecting the code segments, we want to include in our newly-created function\r\nby patching the last jmp instruction to ret , which will cut off the last invalid block from our function\r\nWe'll go with the first method as it's a bit more elegant and simple; for any adventurous readers the Edit -\r\n\u003e Patch program menu and a good x86 opcode reference (like http://ref.x86asm.net/coder32.html) should be\r\nmore than enough to try out the other method.\r\nSelecting the whole memory range by dragging the mouse is a bit boring and can sometimes deselect the selected\r\ncode on its own. We'll use the Edit -\u003e Begin selection (shortcut Alt + l ) command. Position the cursor just\r\nbefore the final jmp instruction, begin the selection, go to the loaders entry point ( 0x4023CE ) and create a new\r\nfunction.\r\nIf everything goes correctly, the relevant fragment in the sidebar should change its color to blue:\r\n--\u003e\r\nAnd you should be able to tap Tab and view the simple decompilation pseudocode:\r\nThe logic is actually quite simple, but the code can get much more bloated and confusing in other samples.\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 8 of 10\n\nvoid sub_4023CE()\r\n{\r\n int v0; // ecx\r\n char *v1; // eax\r\n void (*v2)(void); // eax\r\n int i; // ecx\r\n v0 = 21564845;\r\n do\r\n {\r\n __asm { finit }\r\n --v0;\r\n }\r\n while ( v0 );\r\n v1 = \u0026rtcCos;\r\n do\r\n --v1;\r\n while ( *v1 != \"\\x90ZM\" );\r\n v2 = (*(v1 + 1075))(0, 40960, 4096, 64);\r\n for ( i = 0; i != 22396; i = i - 40 + 44 )\r\n *(v2 + i) = _mm_cvtsi64_si32(_m_pxor(_mm_cvtsi32_si64(*(\u0026loc_403F3F + i)), _mm_cvtsi32_si64(0x59DA0A67u)));\r\n v2();\r\n JUMPOUT(0x403F34);\r\n}\r\nGoing step by step:\r\nv0 = 21564845;\r\ndo\r\n{\r\n __asm { finit }\r\n --v0;\r\n}\r\nThis is a simple sleep snippet, nothing super interesting there.\r\nv1 = \u0026rtcCos;\r\ndo\r\n --v1;\r\nwhile ( *v1 != \"\\x90ZM\" );\r\nv2 = (*(v1 + 1075))(4300, 0, 0, 40960, 4096, 64);\r\nThis is a bit more interesting, it fetches the pointer to rtcCos from MSVBVM60.DLL and then iterates downrange\r\nto find the images base address. It then uses that address to calculate a function address by adding 1075 to the\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 9 of 10\n\npointer.\r\nIf we load the dll in IDA and navigate to the fetched address ( 0x732A0000 + 1075 * 4 ) we can learn that it's\r\nVirtualAlloc .\r\nSo this is all just a sneaky a way of calling it without clearly indicating it in imports. Let's move on.\r\nfor ( i = 0; i != 22396; i = i - 40 + 44 )\r\n *(v2 + i) = _mm_cvtsi64_si32(_m_pxor(_mm_cvtsi32_si64(*(\u0026loc_403F3F + i)), _mm_cvtsi32_si64(0x59DA0A67u)));\r\nThis part copies 22396 bytes from 0x403F3F into the newly allocated buffer dexoring it with the constant\r\n0x59DA0A67 in the process.\r\nWe can get the decrypted core without debugging the binary using a short Python script:\r\nimport struct\r\nfrom malduck import xor\r\ndata = xor(key=struct.pack(\"\u003cI\", 0x59DA0A67), data=get_bytes(0x403F3F, 22396))\r\nwith open(\"decrypted.bin\", \"wb\") as f:\r\n f.write(data)\r\nAnd finally, the program jumps into the newly copied buffer.\r\nv2();\r\nTune in next time to the second part, where we'll describe some of the CloudEyE's functions and discuss how we\r\ncan extract the download URLs and the encryption key from unpacked samples automatically using Malduck.\r\nReferences\r\nhttps://research.checkpoint.com/2020/guloader-cloudeye/\r\nhttps://research.checkpoint.com/2020/threat-actors-migrating-to-the-cloud/\r\nhttps://malpedia.caad.fkie.fraunhofer.de/details/win.cloudeye\r\nSource: https://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nhttps://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/\r\nPage 10 of 10",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://cert.pl/en/posts/2021/04/keeping-an-eye-on-guloader-reverse-engineering-the-loader/"
	],
	"report_names": [
		"keeping-an-eye-on-guloader-reverse-engineering-the-loader"
	],
	"threat_actors": [],
	"ts_created_at": 1775434368,
	"ts_updated_at": 1775826779,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/631b9a3ff7674039e4cc082252f71141f13e29bc.pdf",
		"text": "https://archive.orkl.eu/631b9a3ff7674039e4cc082252f71141f13e29bc.txt",
		"img": "https://archive.orkl.eu/631b9a3ff7674039e4cc082252f71141f13e29bc.jpg"
	}
}