Decrypting and Hunting PrivateLoader By André Tavares Published: 2022-06-06 · Archived: 2026-04-10 02:07:58 UTC PrivateLoader is a loader from a pay-per-install malware distribution service that has been utilized to distribute info stealers, banking trojans, loaders, spambots, rats, miners and ransomware on Windows machines. First seen in early 2021, being hosted on websites that claim to provide cracked software, the customers of the service are able to selectively deliver malware to victims based on location, financial activity, environment, and specific software installed. Let’s have a look at the malware and try to find a way to detect and hunt it. Searching for strings Here’s a sample analyzed by Zscaler on April 2022: aa2c0a9e34f9fa4cbf1780d757cc84f32a8bd005142012e91a6888167f80f4d5 Let’s open it on Ghidra. Going into the entry point, following the code, looking for interesting functions, I quickly spot the function at 0x406360 . It’s calling LoadLibraryA but the lpLibFileName parameter is built dynamically at runtime using the stack. Its seems that we found a string encryption technique. Both the string and the xor key are loaded into the stack. Looking a bit more through the function, its seems that this is the way most of the strings are loaded: LEA EAX=>local_50,[ESP + 0x10] MOV dword ptr [ESP + local_50[0]],0x84038676 MOV dword ptr [ESP + local_50[4]],0xeb71eb3c MOV dword ptr [ESP + local_50[8]],0x36fb7b30 MOV dword ptr [ESP + local_50[12]],0xab7d1f0c MOVAPS XMM1,xmmword ptr [ESP + local_50[0]] MOV dword ptr [ESP + local_30[0]],0xea71e31d MOV dword ptr [ESP + local_30[4]],0xd9428759 MOV dword ptr [ESP + local_30[8]],0x5a971f1e MOV dword ptr [ESP + local_30[12]],0xab7d1f0c PXOR XMM1,xmmword ptr [ESP + local_30[0]] ; kernel32.dll PUSH EAX ; LPCSTR lpLibFileName for LoadLibraryA MOVAPS xmmword ptr [ESP + local_50[0]],XMM1 CALL ESI=>KERNEL32.DLL::LoadLibraryA After XOR the encrypted string with the key, we get kernel32.dll . Decrypting the strings https://tavares.re/blog/2022/06/06/hunting-privateloader-pay-per-install-service/ Page 1 of 6 Now, to faster analyze the malware and better understand its behavior, we should build a string decryptor to help us on our reversing efforts and better document the code. With the help of Capstone disassembly framework, and some trial and error, here’s the script: import pefile import struct from capstone import * def extract_var(op): if ']' in op: op = ''.join(op.split(' ')[-1])[:-1].replace('[', '') return op def search(instructions, var): data_chunks = [] for inst in instructions: if inst[2] == 'mov': try: imm = int(inst[3].split(' ')[-1], 16) data_chunks.append(struct.pack(' 100 } After running this rule on VirusTotal retro hunting, I got over 1k samples on a 1 year timeframe. By manually analyzing some of the matches, I couldn’t find any false positives. As a first attempt of hunting and detecting PrivateLoader, this rule seems to yield good results. Source: https://tavares.re/blog/2022/06/06/hunting-privateloader-pay-per-install-service/ https://tavares.re/blog/2022/06/06/hunting-privateloader-pay-per-install-service/ Page 6 of 6