Full Hancitor malware analysis

12 minute read

As-salamu Alaykum


Hancitor is a famous malware loader that has been in use for years since first being observed in 2015. A malware loader drops the actual malicious content on the system then executes the first stage of the attack. Hancitor has been the attacker’s loader of choice to deliver malwares like: FickerStealer, Sendsafe, and Cobalt Strike if the victim characteristics are met. In recent months, more threat intelligence has been gathered to confirm the selection of Hancitor by Cuba Ransomware gangs as well. The popularity of Hancitor among threat actors is considered to last for a while. ref

Figure: How Hancitor infection happens. *paloaltonetworks photo

Unpacking process

We tried in a later article to unpack Hancitor malware. see it from Here. But we will try another way to unpack it in this sample. Open the sample in the x32dbg and set two BPs on VirtualAlloc and VirtualProtect then run F9. We hit VirtualAlloc and then Execute till return then Follow in Dump of EAX. Keep doing that to hit the VirtualProtect BP we will see M8Z an indicator of Aplib compression.


Then if we scroll down to the offset xx4380 we will get the MZ string which is the start of our unpacked file used in the analysis. Then save it to a file to start the analysis.

Abnormal Entry point

In Hancitor, there are 3 exports BNJAFSRSQIX, SDTECHWMHHONG, DllEntryPoint. And the first two functions have the same address. For the first thought the entry point will be DllEntryPoint, but if we check this function it only returns 1. From the malicious document which we extract the maliciuos Hancitor malware. Launched the rundll32.exe command to execute the BNJAFSRSQIX function, so it must be the real entry point for this DLL.


Gathering victim information

We enter BNJAFSRSQIX we see a call to a function which i renamed it to Hancitor_Main. Then enter sub_10001AA0 renamed info_gathering. First the malware gathers information about the host contains: OS version, Computer name, Domains names, Victim IP address, whether the machine is x64 or x86 OS.


Figure(3): pseudocode of figure 2

Then we enter getVictimID then enter sub_10001C70 which is the function that generates a unique ID for the victim. First, calling GetAdaptersAddresses to get the addresses associated with the network adapters on the victim machine then XOR-ing each (MAC) adapter with its address together. And calling GetVolumeInformationA to retrieve the volume serial number of the machine then XORs it with the result to create the victim’s unique ID.

Figure(4): pseudocode of sub_10001C70 function

How to get the IP of the victim? By sending a GET request to hxxp://api[.]ipify[.]org. If the malware is unable to contact the website, it uses as the victim’s IP address.


Then the final gathering step is to concatinate the gathered victim’s information in two ways to be sent to C2 server:

GUID=<Victim's GUID>&BUILD=<Build ID>&INFO=<Machine Information>&EXT=<Network domain names>&IP=<Victim's IP address>&TYPE=1&WIN=<Windows major version>.<Windows minor version>(x64)

GUID=<Victim's GUID>&BUILD=<Build ID>&INFO=<Machine Information>&EXT=<Network domain names>&IP=<Victim's IP address>&TYPE=1&WIN=<Windows major version>.<Windows minor version>(x32)


Configuration Extraction

Manually Extraction

Malware authors use tricks to obfuscate thier C2 IoCs. One of them is to encrypt it into a big chunk of data as in Hancitor Malware. So we need to search for big chunk of data which later will be decrypted during the runtime. We will find our encrypted configuration in the begining of .data section and if we select the hex values then press D we see it has refernces which means that it’s used somewhere.


There are two chunks of data Pbdata and byte_10005018. If we press x over one of them it takes us to a function which will be called mw_Decrypt_Data which is the function decrypts the configuration of the malware. And these two chuncks of data are parameters in this function.


Now enter this mw_Decrypt_Data function. We see there are 5 API calls:

CryptCreateHash: initiates the hashing of a stream of data.CryptCreateHash the 2nd parameter is Algid which identifies the hash algorithm to use. Its value is 0x8004u which used SHA1 see the decumentation of Algid

CryptDeriveKey: generates cryptographic session keys derived from a base data value CryptDeriveKey the 2nd parameter is Algid Its value is 0x6801u which used RC4

The 4th parameter is dwflags which determinte the size of the key which the key is a set with the upper 16 bits of 0x280011u which is 0x28 divided by 8. Then the key size is 5 bytes.


We get the SHA1 key from pbdata. And we get the RC4 data from byte_10005018 and decrypte the RC4-encrypted data using the first 5 bytes of the SHA1 key.

*How we select hex values only? Do as in the figure 9. then choose hex string (unspaced). then copy what is in the preview.


Then open cyberchef using from hex and SHA1 we get the SHA1 key ad818c687f8dc7f281135753e567eababa03d0ba. Then select the whole chunck of data of byte_10005018 and copy hex as we did in SHA1 and use RC4 and using the first 5 bytes of SHA1.


Here are 3 C2 servers which the malware communicate with for further commands based on the collected victim host information. Build ID 2909_xplw.




Automated Extraction


import pefile  #Parse data into a PE format
import re      #Use a regular expression to locate our config data
import struct  # Convert binary data into numeric values.
import hashlib #Generate a SHA1 hash

file_path = r'file path' #file path
data = open(file_path,'rb').read() # read it in binary 
pe = pefile.PE(data=data) # to parse data as PE file to acess sections and offsets

# Use Regular Expression to Locate The Decryption Code
key = rb'\x6a(.)\x68(....)\x68\x00\x20\x00\x00' #opcode as in the figure(6).
m = re.search(key, data) #  extract the data that was matched by the wildcard.
if m != None:
  print("key length: %r" % m.group(1))
  print("key address: %r" % m.group(2)) 

# Convert The Extracted Key Information
struct.unpack('b', m.group(1))[0] #converte into bytes
hex(struct.unpack('<I', m.group(2))[0]) # converting an unsigned integer (DWORD) stored in little-endian format in hex

# Use The Key Information To Extract The Key Data
key_len = struct.unpack('b', m.group(1))[0]
key_address = struct.unpack('<I', m.group(2))[0]
key_rva = key_address - pe.OPTIONAL_HEADER.ImageBase
key_offset = pe.get_offset_from_rva(key_rva)
key_data = data[key_offset:key_offset+key_len]
config_data = data[key_offset+key_len:key_offset+key_len+0x2000]

# Hash The Key Data To Create The Key
m = hashlib.sha1()
key = m.digest()[:5]

# RC4 Decryption
def rc4crypt(data, key):
    #If the input is a string convert to byte arrays
    if type(data) == str:
        data = data.encode('utf-8')
    if type(key) == str:
        key = key.encode('utf-8')
    x = 0
    box = list(range(256))
    for i in range(256):
        x = (x + box[i] + key[i % len(key)]) % 256
        box[i], box[x] = box[x], box[i]
    x = 0
    y = 0
    out = []
    for c in data:
        x = (x + 1) % 256
        y = (y + box[x]) % 256
        box[x], box[y] = box[y], box[x]
        out.append(c ^ box[(box[x] + box[y]) % 256])
    return bytes(out)

# Parsing The Config
config = rc4crypt(config_data, key)
build_id = config.split(b'\x00')[0]
c2_string = b''
for s in config.split(b'\x00')[1:]:
    if s != b'':
        c2_string = s
c2_list = c2_string.split(b'|')
print("BUILD: %s" % build_id)
for c2 in c2_list:
    if c2 != b'':
        print("C2: %s" % c2)

For better understanding visit OALabs github

C2 server Communication

After collecting all victim information and put into one fourm as we mentioned above. the malware tries to get the C2 URL from the configuration and sends the data to C2 the servers. If we enter the function getNext_URL. It tries to get the next URL address from the list using the location of | between the C2 servers.


Then we enter send_Data_To_C2 function, we see 3 API calls which are an indication of sending data to C2 server:

HttpOpenRequestA: Creates an HTTP POST request handle.

HttpSendRequestA: Sends the specified request or data to the HTTP server.

InternetReadFile: Reads data or commands from a handle opened by the HttpOpenRequest function.


From PCAP of Malware-Traffic-Analysis.net. We ping the 1st C2 server ( hxxp://forkineler(.)com/8/forum.php) to get the IP which will help us to get the C2 response. Open the PCAP file and search with ip.addr == then follow then TCP stream. As we see POST and GET request and base64 encoded response. base64 encoded C2 response: VZAEARZAEg4OCkBVVU4XGw8IChUUDlQID1VOSwlUGBMUBwEWQBIODgpAVVVOFxsPCAoVFA5UCA9VTktUGBMUBw==. Then enter check_C2_response function: first it checks the 1st 4 chars IsUpperCase? if Not in upper case the check fails and return 0.


If the check is valid then it decodes the base64 C2 response and XORs the result with the letter z using CyberChef.


As we see in the last figure the response command contains:

 A specific action from  `{'b','e','l','n','r'}`

 A colon (:) char

 A URL is used to download malicious content


Download content and inject

Explaining the set of actions the malware will do from {'b','e','l','n','r'}.


b action

The downloaded content will be injected into a new svchost.exe process using the APIs: VirtualAllocEx and WriteProcessMemory. First the malware downloads content, as in the download_content function, from the malicious URL in the C2 response then inject it into a new svchost process.

Figure(19): action: download_inject_into_New_svchost function

Entering download_content then entering decrypt_decompress_downloadedContent. We will see that it’s trying to decrypt the downlaoded content by XOR-ing with its first 8 bytes then using RtlDecompressBuffer function to decompress. See doc then continue

Figure(20): decrypt_decompress_downloadedContent function

Figure(21): using CreateProcessA to create a suspended svchost process

using VirtualAllocEx to allocate a buffer in the memory, then w_HeapAlloc to allocate a heap buffer, and then WriteProcessMemory to write the payload from the heap to svchost allocated memory.

Figure(22): using CreateProcessA to create a suspended svchost process

Figure(23): the entryPoint of svchost is the entryPoint of injected malicious content

b action in brief:

  1. Download the malicious content from the URL.
  2. Decrypting and decompress the content.
  3. create svchost in a suspended state.
  4. Allocate a buffer in the memory for the malicous content.
  5. Load the malicious content into the allocated buffer.
  6. Make the entryPoint of the injected malicous content is the entryPoint of svchost.exe process
  7. Then resume the process

e action

The downloaded content will be injected into the current running process. Download then inject.

Figure(24): Download then inject into the currently running process

Figure(25): Loading the import table

e action in brief:

  1. Download the malicious content from the URL.
  2. Decrypting and decompress the content.
  3. Allocate memory for the content in the current running process.
  4. Load import table
  5. Load the malicious content into the allocated buffer.
  6. launch the thread using two methods:
    • using CreateThread which resolves the entryPoint Or
    • using the returned entryPoint after writing the content in memory.

i action

Downloads shellcode and inject it into the current process or into svchost.exe.

Figure(26): How injecting and executing the shellcode using i action

i action in brief:

  1. Download the shellcode from the URL.
  2. Decrypting and decompress the content which is shellcode.
  3. inject the shellcode by one methode:
    • Creating svchost.exe process then inject the process then resumes the process. Or
    • Inject into the current running process.

n action

Does nothing, or it’s used to ping the victim.

r action

Drop an EXE or DLL in the Temp folder then inject into svchost.exe.

Figure(27): How injecting and executing the content using r action

r action in brief:

  1. Download the the content from the URL.
  2. Decrypting and decompress the content.
  3. Gets the path of TEMP folder and create a file and its random name begins with BN in the path of TEMP folder.
  4. Execute the downloaded content which depends on if it’s an EXE or DLL:
    • An EXE it will be executed normally.
    • a DLL executed by using rundll32.exe.


Abnormal Entry point: DllEntryPoint is not the real entryPoint, but BNJAFSRSQIX is the EnryPoint.

Gathering victim information: Gatheing info about the victim which gives choice for the malware to generate unique ID and downlaod which content.

Configuration Extraction: The key is encrypted in SHA1 and the embedded configuration encrypted in RC4. The malware uses CryptoAPI to do the decryption using the first 5 bytes of the SHA1 key.

C2 server Communication: The victim information will be sended to the C2 server. After decoding the base64 encoded with additional layer of single-byte XOR C2 response. The decoded C2 response has Build ID and URLs from which the malicous content is downloaded.

Download content and inject: From the decoded C2 response, the malware will decide which content will be downlaoded then injected then executed. If it’s a malicious EXE, DLL, or shellcodes.


No. Description Hash and URLs
1 The packed DLL (MD5 ) 32799A01C72148AB003AF600F8EB40DC
2 The unpacked DLL (MD5) B7679D55FC9B5F3447FF743EEAAB7493
3 C2 response server hxxp://4maurpont.ru/41s.bin (
4 C2 Server 1 hxxp://forkineler(.)com/8/forum.php
5 C2 Server 2 hxxp://yemodene(.)ru/8/forum.php
6 C2 Server 3 hxxp://fordecits(.)ru/8/forum.php

Article quote

سبحانك! ما أضيق الطريق عليّ ما لم تكن دليله! وما أوحشه عليّ مَن لم تكن أنيسه


  1. https://cyber-anubis.github.io/malware%20analysis/hancitor/#the-b-command

  2. https://www.0ffset.net/reverse-engineering/malware-analysis/hancitor-analysing-the-main-loader/

  3. https://www.youtube.com/watch?v=OQuRwpUTBpQ&list=PLGf_j68jNtWG_6ZwFN4kx7jfKTQXoG_BN&index=9&t=2s&ab_channel=OALabs

  4. https://www.binarydefense.com/analysis-of-hancitor-when-boring-begets-beacon/

  5. https://elis531989.medium.com/dissecting-and-automating-hancitors-config-extraction-1a6ed85d99b8