{
	"id": "58d56c6c-52dc-4530-9b1b-acbe1575da8d",
	"created_at": "2026-04-06T00:20:08.965286Z",
	"updated_at": "2026-04-10T03:24:24.156499Z",
	"deleted_at": null,
	"sha1_hash": "dc4b692c4ba13fd1a10f1e04c2cfa8d3ad3be265",
	"title": "BAZARLOADER: Analysing The Main Loader | 0ffset Training Solutions",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 2673984,
	"plain_text": "BAZARLOADER: Analysing The Main Loader | 0ffset Training\r\nSolutions\r\nBy Chuong Dong\r\nPublished: 2022-05-27 · Archived: 2026-04-05 23:09:14 UTC\r\nThis post is a follow up on the last one on BAZARLOADER. If you’re interested in how to unpack the initial\r\nstages of this malware, you can check it out here. \r\nIn this post, we’ll cover the final stage of this loader, which has the capability to download and executes remote\r\npayloads such as Cobalt Strike and Conti ransomware. To follow along, you can grab the sample as well as the\r\nPCAP files for it on Malware-Traffic-Analysis.net.\r\nStep 1: Checking System Languages\r\nSimilar to a lot of malware, BAZARLOADER manually checks the system’s languages to avoid executing on\r\nmachines in Russia and nearby countries.\r\nIt calls GetSystemDefaultLangID to retrieve the system’s default language and GetKeyboardLayoutList to\r\niterate through the system’s keyboard layouts.\r\nFor each of these languages, the malware checks if it’s valid using a bitmask.\r\nIf the language identifier is greater than 0x43 or less than 0x18, it’s treated as valid and BAZARLOADER\r\nproceeds with its execution.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 1 of 26\n\nIf it’s in the range between 0x18 and 0x43, the difference between the language identifier and 0x18 is used as the\r\nindex of the bit to be checked in the bitmask.\r\nThe bitmask that BAZARLOADER uses is 0xD8080190C03, which is\r\n11011000000010000000000110010000110000000011 in binary. The first bit in the bitmask is checked if the\r\nlanguage ID is 0x18. The second bit is checked if the language ID is 0x19, and so on…\r\nBelow is the list of all languages from the bitmask that the malware avoids.\r\nRomanian, Russian, Ukrainian, Belarusian, Tajik, Armenian, Azerbaijani, Georgian, Kazakh, Kyrgyz, Turkmen, Uzbe\r\nStep 2: Run-Once Mutex\r\nTo check for multiple running instances of itself, BAZARLOADER first extracts the subauthority of a SID from\r\nits process. It does this by calling GetTokenInformation to retrieve the process’s token integrity level and calling\r\nGetSidSubAuthorityCount and GetSidSubAuthority to access the subauthority of a SID.\r\nIf the SID’s subauthority is SECURITY_MANDATORY_SYSTEM_RID or\r\nSECURITY_MANDATORY_PROTECTED_PROCESS_RID, BAZARLOADER checks if the mutex\r\n“{b837ef4f-10ee-4821-ac76-2331eb32a23f}” is currently owned by any other process by calling CreateMutexA.\r\nIf it is, the malware terminates itself. However, there is a small bug with the condition to check if the mutex object\r\nexists, which assumes it fails to open the mutex when it actually succeeds.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 2 of 26\n\nAfter this, the malware resolves the string “{0caa6ebb-cf78-4b01-9b0b-51032c9120ce}” and tries to create a\r\nmutex with that name.\r\nIf this mutex object already exists, the malware also terminates itself.\r\nIf the SID’s subauthority is not SECURITY_MANDATORY_SYSTEM_RID or\r\nSECURITY_MANDATORY_PROTECTED_PROCESS_RID, BAZARLOADER still uses these two mutex\r\nnames but adds the string “Global\\” in front of them. This checks for the mutexes in the global namespace instead\r\nof the per-session namespace, which allows the malware to check if it has instances running in other users’\r\nsessions.\r\nStep 4: Generating Random Internet Traffic\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 3 of 26\n\nTo generate Internet activities to hide its communication with C2 servers, BAZARLOADER first calls\r\nInternetOpenA to initialize the use of WinINet functions with the following string as the HTTP user agent.\r\nMozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko\r\nThe malware then spawns a thread to periodically connect to random URLs and generate noises to hide the main\r\nC2 traffic by utilizing the following structure.\r\nstruct random_internet_thread_struct\r\n{\r\n HINTERNET internet_sess_handle;\r\n HANDLE thread_handle;\r\n random_internet_thread_struct *self;\r\n LPCRITICAL_SECTION critical_section;\r\n __int64 padding[4];\r\n int creation_flag;\r\n};\r\nFirst, BAZARLOADER calls InitializeCriticalSection to initialize the structure’s critical section object, which is\r\nlater used to protect accesses to the creation_flag field.\r\nNext, it sets the self field to point to the structure, the creation_flag field to TRUE, and calls CreateThread to\r\nspawn a thread to perform these random Internet operations. If it fails to create a thread, the creation_flag field is\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 4 of 26\n\nset to FALSE.\r\nThe thread first tries to obtain ownership of the critical section object and check if the creation flag is enabled. If it\r\nis, the malware resolves the following URLs as stack strings.\r\nhttps://google.com/api/get\r\nhttps://yahoo.com/api/get\r\nhttps://amazon.com/api/get\r\nhttps://bing.com/api/get\r\nNext, the thread enters an infinite loop to start generating the traffic noises. For random number generation,\r\nBAZARLOADER uses different functions that call the Windows API BCryptGenRandom to generate a set\r\nnumber of random bytes.\r\nIt randomly chooses one of the 4 URLs listed above, randomly generates the URL path segments for that, and\r\ncombines the two to build the full URL.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 5 of 26\n\nTo generate the path segments, the function takes in the minimum and maximum numbers of path segments to\r\ngenerate and the minimum and maximum length for each path segment.\r\nIt generates a count for the path segments randomly in the given range. For each of the segments, the malware\r\nrandomly generates a string with a random length in the given range that contains numbers and\r\nuppercase/lowercase letters.\r\nFinally, the malware calls InternetOpenURLA to establish a connection with the generated URL. It calls\r\nHTTPQueryInfoA with the HTTP_QUERY_CONTENT_LENGTH flag to retrieve the content’s length,\r\nallocates a buffer with that size, and calls InternetReadFile to read data from that URL.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 6 of 26\n\nThis is done repeatedly until C2 communication and payload injection are finished, which generates a lot of noise\r\nto mask the main traffic coming to and from C2 servers.\r\nStep 4: Cryptographic Structure Population\r\nBAZARLOADER mainly uses the following structure for communication with C2 servers. The fields of the\r\nstructure will be explained as we go along analyzing the code.\r\nstruct __declspec(align(8)) BazarLoader_struct\r\n{\r\n C2_connection_struct C2_connection_struct;\r\n HINTERNET C2_request_handle;\r\n HINTERNET C2_temp_request_handle;\r\n crypto_struct crypto_struct;\r\n SYSTEMTIME curr_system_time;\r\n char *datetime_string;\r\n _QWORD datetime_string_hash;\r\n unsigned int *datetime_string_hash_len;\r\n opennic_server_struct opennic_DNS_server_struct;\r\n string_struct_list C2_addr_list;\r\n};\r\nFirst, it populates the crypto_struct field in the main structure. This structure contains cryptographic handles that\r\nare later used to decrypt executables being sent from C2 servers.\r\nThe structure can be reconstructed as below.\r\nstruct crypto_struct\r\n{\r\n BCRYPT_ALG_HANDLE RSA_algo_handle;\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 7 of 26\n\nBCRYPT_ALG_HANDLE SHA384_algo_handle;\r\n BCRYPT_KEY_HANDLE RSA_public_key_handle;\r\n BCRYPT_KEY_HANDLE RSA_private_key_handle;\r\n DWORD RSA_public_block_length;\r\n DWORD RSA_private_block_length;\r\n};\r\nThe malware resolves the strings “RSA” and “SHA384” and calls BCryptOpenAlgorithmProvider to retrieve\r\nhandles for these two algorithms. The handles are stored in the corresponding fields in the crypto_struct\r\nstructure.\r\nNext, it resolves its hard-coded RSA public and private key blobs in memory to import their corresponding key\r\nhandles.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 8 of 26\n\nFor each blob, the malware resolves one of the strings “RSAFULLPRIVATEBLOB” or “RSAPUBLICBLOB”\r\nand uses it to specify the blob’s type when calling BCryptImportKeyPair to import the corresponding key\r\nhandle.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 9 of 26\n\nFinally, it calls BCryptGetProperty to retrieve the length of the RSA public and private cipher blocks. With this\r\nstructure fully populated, BAZARLOADER can now perform RSA encryption/decryption as well as SHA384\r\nhashing.\r\nStep 5: C2 Connection Through Raw IP Addresses\r\nPrior to communicating with C2 servers, BAZARLOADER first resolves a list of raw IP addresses and writes\r\nthem into the C2_addr_list field in the main structure.\r\nThis field is a structure representing a list of string structures, both of which can be reconstructed as below.\r\nstruct string_struct\r\n{\r\n char *buffer;\r\n char *length;\r\n char *max_length;\r\n};\r\nstruct string_struct_list\r\n{\r\n string_struct *list_ptr;\r\n __int64 count;\r\n __int64 max_count;\r\n};\r\nBelow is the list of all IP addresses for the C2 servers used in this sample.\r\nhttps://5[.]182[.]207[.]28:443\r\nhttps://80[.]71[.]158[.]42:443\r\nhttps://198[.]252[.]108[.]16:443\r\nhttps://84[.]32[.]188[.]136:443\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 10 of 26\n\nFor each of these addresses, the malware attempts to communicate with the corresponding server and download\r\nthe next stage executable.\r\nTo establish a connection, it populates the following structure.\r\nstruct C2_connection_struct\r\n{\r\n URL_COMPONENTSA C2_URL_components;\r\n HINTERNET connection_handle;\r\n __int64 connection_last_error;\r\n};\r\nThe malware calls InternetCrackUrlA to retrieve the C2’s URL components and InternetConnectA to connect\r\nto the server.\r\nThis connection structure’s fields are then copied into the main structure’s C2_connection_struct. Here, I’m not\r\nentirely sure why they don’t just populate the main structure directly instead.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 11 of 26\n\nSimilarly, BAZARLOADER populates the structure below to create an HTTP request to C2. The request’s object\r\nname and HTTP verb are resolved to be “/data/service” and “GET”.\r\nstruct C2_request_struct\r\n{\r\n HINTERNET request_handle;\r\n __int64 request_error;\r\n};\r\nThe request’s HTTP version is resolved to be “HTTP/1.1”, and BAZARLOADER calls HttpOpenRequestA to\r\ncreate this request for the C2 server using the connection handle retrieved above.\r\nIt also calls InternetSetOptionA to set the timeout for receiving a response and sending the request to 300\r\nseconds and the timeout for connecting to C2s to 120 seconds.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 12 of 26\n\nBAZARLOADER then generates the HTTP header to be appended to the request. It does this by calling\r\nGetSystemTime to populate the curr_system_time and the datetime_string field of the main structure with the\r\ncurrent date and time.\r\nIt also generates the SHA384 hash of the datetime string to populate the structure’s datetime_string_hash and\r\ndatetime_string_hash_len fields.\r\nNext, BAZARLOADER signs the generated hash with its RSA private by calling BCryptSignHash and uses this\r\nhash signature to randomly generate the HTTP header.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 13 of 26\n\nBelow is the form of the random HTTP header.\r\nBAZARLOADER’s HTTP Header\r\nWith the generated HTTP header and the request handle, BAZARLOADER calls HttpSendRequestA to send the\r\nrequest to the C2 server and calls HttpQueryInfoA to retrieve the status code.\r\nIf the status code is not HTTP_STATUS_OK, the malware moves on to another C2 address.\r\nIf the status code is HTTP_STATUS_OK, BAZARLOADER calls InternetQueryDataAvailable to determine\r\nthe size of data to read, allocates the memory buffer according to the size, and calls InternetReadFile to read the\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 14 of 26\n\nnext-stage payload until everything is written into memory.\r\nFinally, the malware decrypts the payload with its RSA public key by calling BCryptDecrypt and checks to make\r\nsure the payload’s size is greater than 64 bytes and that it contains an MZ header.\r\nStep 6: C2 Connection Through Custom URLs\r\nIf BAZARLOADER fails to download the next stage executable from the IP addresses listed above, it attempts to\r\nresolve custom C2 domains using OpenNIC, a user-owned DNS community service.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 15 of 26\n\nTo begin querying OpenNIC’s API, the malware first resolves the URL “api.opennicproject.org” and calls\r\nInternetConnectA to establish a connection to the site.\r\nNext, it calls HttpOpenRequestA to create a GET request handle with the object name “/geoip/?\r\nbare\u0026ipv=4\u0026wl=all\u0026res=8” and send the request using HttpSendRequestA.\r\nBy examining OpenNIC’s APIs, we can break down this object name to see what BAZARLOADER is requesting.\r\nThe “bare” parameter requests to only list the DNS server IP address, the “ipv” parameter requests to only list\r\nIPv4 servers, the “wl” parameter requests to only list whitelisted servers, and the “res” parameter requests to list 8\r\nservers only.\r\nTo test this, we can simply paste the path below to a browser of our choosing.\r\napi.opennicproject.org/geoip/?bare\u0026ipv=4\u0026wl=all\u0026res=8\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 16 of 26\n\nThe malware then enters a loop to call InternetQueryDataAvailable and InternetReadFile to read the 8\r\nOpenNIC’s DNS servers into memory. \r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 17 of 26\n\nFor each DNS server IP address, BAZARLOADER parses it from string to int and populates the\r\nopennic_server_struct field in the main structure. Below is the structure used to store OpenNIC IP addresses.\r\nstruct opennic_server_struct\r\n{\r\n _QWORD init_server_count;\r\n HINTERNET opennic_internet_handle;\r\n DWORD opennic_server_IP_list[7];\r\n _BYTE gap2C[28];\r\n _QWORD server_count;\r\n};\r\nFinally, the malware decodes the following custom C2 domains, attempts to resolve them using the DNS servers,\r\nand downloads the next-stage executable.\r\nreddew28c[.]bazar\r\nbluehail[.]bazar\r\nwhitestorm9p[.]bazar\r\nFor each of these custom domains, BAZARLOADER calls DnsQuery_A to query a DNS Resource Record from\r\nOpenNIC’s servers to resolve the C2 server’s IP address.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 18 of 26\n\nAfter checking if the IP address is valid, the malware tries connecting to it and requests to download the next stage\r\nexecutable similar to what we have seen in the previous step.\r\nStep 5: Injection Through Process Hollowing\r\nAfter successfully downloading the next stage executable, BAZARLOADER begins the injection functionality to\r\nlaunch it from another process.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 19 of 26\n\nFor this functionality, BAZARLOADER populates the following structure.\r\nstruct injection_struct\r\n{\r\n HANDLE browser_proc_handle;\r\n PVOID full_exec_command;\r\n PVOID thread_curr_directory;\r\n PVOID browser_environment_struct;\r\n STARTUPINFOA thread_startup_info;\r\n LPPROC_THREAD_ATTRIBUTE_LIST proc_thread_attr_list;\r\n};\r\nFirst, it checks if its process is elevated with admin privileges. It calls GetCurrentProcess and\r\nOpenProcessToken to retrieve its own process token handle and GetTokenInformation to get the token’s\r\nelevation information.\r\nIf the process is not elevated, it resolves the following processes’ names and tries to populate the injection\r\nstructure’s fields.\r\nchrome.exe\r\nfirefox.exe\r\nmsedge.exe\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 20 of 26\n\nFor each process name, the malware enumerates the process’s snapshot to retrieve its ID and calls OpenProcess to\r\nget its handle.\r\nTo populate the full_exec_command and thread_curr_directory fields which contain the process’s command\r\nline and full path, BAZARLOADER first extracts the process parameters from the Process Environment Block\r\n(PEB).\r\nTo access the PEB, the malware calls NtQueryInformationProcess to retrieve the PEB’s adress and calls\r\nReadProcessMemory to read the PEB into memory.\r\nNext, it calls ReadProcessMemory to read the process parameters from the process’s memory.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 21 of 26\n\nWith the process parameter RTL_USER_PROCESS_PARAMETERS structure, BAZARLOADER reads the\r\nprocess’s command line and full path to populate the injection structure.\r\nSimilarly, it also uses the process parameter to access the browser’s environment block and writes it to the\r\ninjection structure.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 22 of 26\n\nIf BAZARLOADER has admin privilege, instead of a browser’s process, it tries to populate the injection structure\r\nwith a svchost.exe process from the following command line.\r\n\\\\system32\\\\svchost.exe -k unistackSvcGroup\r\nNext, using the injection struct, the malware calls CreateProcessA to create the target process in the suspended\r\nstate to perform process hollowing.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 23 of 26\n\nWe won’t dive too deep into this process hollowing implementation, since it’s almost the exact same\r\nimplementation as seen here.\r\nWe can quickly spot that process hollowing is taking place through the Windows APIs being called.\r\nNtUnmapViewOfSection is called to unmap and carve out the parent’s memory. VirtualAllocEx and\r\nWriteProcessMemory are then called to allocate virtual memory in the parent’s process and write the malicious\r\npayload into it.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 24 of 26\n\nWe can also see that the malware iterates through the parent’s section header to find the “.reloc” section and\r\nperforms relocation on the injected image in memory.\r\nFinally, BAZARLOADER calls SetThreadContext to set the new entry point for the parent process and calls\r\nResumeThread to resume the parent’s process again, which will execute the injected executable.\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 25 of 26\n\nAnd with that, we have analyzed how BAZARLOADER downloads a remote executable and executes it using\r\nprocess hollowing! If you have any questions regarding the analysis, feel free to reach out to me via Twitter.\r\nSource: https://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nhttps://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/\r\nPage 26 of 26\n\n  https://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/    \nAnd with that, we have analyzed how BAZARLOADER downloads a remote executable and executes it using\nprocess hollowing! If you have any questions regarding the analysis, feel free to reach out to me via Twitter.\nSource: https://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/      \n   Page 26 of 26",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://www.0ffset.net/reverse-engineering/analysing-the-main-bazarloader/"
	],
	"report_names": [
		"analysing-the-main-bazarloader"
	],
	"threat_actors": [
		{
			"id": "610a7295-3139-4f34-8cec-b3da40add480",
			"created_at": "2023-01-06T13:46:38.608142Z",
			"updated_at": "2026-04-10T02:00:03.03764Z",
			"deleted_at": null,
			"main_name": "Cobalt",
			"aliases": [
				"Cobalt Group",
				"Cobalt Gang",
				"GOLD KINGSWOOD",
				"COBALT SPIDER",
				"G0080",
				"Mule Libra"
			],
			"source_name": "MISPGALAXY:Cobalt",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434808,
	"ts_updated_at": 1775791464,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/dc4b692c4ba13fd1a10f1e04c2cfa8d3ad3be265.pdf",
		"text": "https://archive.orkl.eu/dc4b692c4ba13fd1a10f1e04c2cfa8d3ad3be265.txt",
		"img": "https://archive.orkl.eu/dc4b692c4ba13fd1a10f1e04c2cfa8d3ad3be265.jpg"
	}
}