Malware Analyzing Series Blog 01

Blog01 Part 1

Cool.DLL

Note: This is my First time doing this kind of Analyze, If there is any mistake that I made, I’m very sorry, please forgive me, I’m new to this, I will try fixing and trying harder everyday.

image

SHA256: 8ff43b6ddf6243bd5ee073f9987920fa223809f589d151d7e438fd8cc08ce292

image

image

Using Capa, it detected there was a process Injection at the address 0x100400AC, lets open IDA and check it

image

So there was a VirtualProtecEx

image

Let’s dig more into it by debugging with x32dbg since this is 32 bit dll

image

If you don’t know why are we searching for that Windows API, then here the explaination:

VirtualProtectEx is typically used with pages allocated by VirtualAllocEx and for your information there is a technique called, DLL Injection, this technique is used to force a process to load a DLL. Main potentially involved APIs: 
OpenProcess( ), VirtualAllocEx( ), WriteProcessMemory and CreateRemoteThreat | NtCreateThread( ) | RtlCreateUserThread( ).
Also this DLL seem like a packed Executable due to íts IAT and High entropy

image

But first Lets just sync the IDA with the Debugger, it will help us analyze way more easier.

image

Okay, thats definately look better than before! Now its time to step into/over to understand what does this code do. After stepping over hundreds of times of looping I finally found something intersting another WindowsAPI calling, this time its the actual Virtual Alloc, Let’s put a breakpoint here so we can get it faster if we need to to resart the whole process.

image

As you can see below, the EAX register will hold the value of the Virtual Alloc, let’s dump that EAX register.

image

After Debugging around the Virtual Alloc and dumping where the register seem weird, I finally found something interesting

image

image

image

The EIP now locate somewhere it shouldn’t be along with a PE, following the memory map then dumping out the memory, if you look carefully this header is somekind of M8Z

image

Dumping the memory out and checking for the M8Z header we got this result

image

Using this repo to decompressed the Dumped Memory -> Aplib.py

After getting the decompressed DLL, load it back in IDA again, we can see the function clearly now, the function currently showing in the screenshot below is a function where it sending your, ID, Windows version, IP.

image

image

image

UserAgent, Getting the Data back from the C2 server.

image

image

This is the config function I think.

image

There are something cool while digging in these function, I found where it decrypt or connect to the C2 server.

image

image

It take 0x2000 bytes of the Encrypted Data then use 0x8 bytes from the key to decrypt the whole Encrypted Data.

image

We can dump this Data out using Ida python, then write a script to get back the data that it encrypted.

#include <iostream>
#include <windows.h>
#include <wincrypt.h>
#include <string>
#include <fstream>
using namespace std;

DWORD __cdecl crypt(BYTE* pbData, DWORD pdwDataLen, BYTE* pbDataa, DWORD dwDataLen)
{
    DWORD pdwDataLen_1; // esi
    HCRYPTPROV phProv; // [esp+8h] [ebp-Ch] BYREF
    HCRYPTKEY phKey; // [esp+Ch] [ebp-8h] BYREF
    HCRYPTHASH phHash; // [esp+10h] [ebp-4h] BYREF

    phKey = 0;
    pdwDataLen_1 = 0;
    phHash = 0;
    phProv = 0;
	if (CryptAcquireContextA(&phProv, 0, 0, 1u, 0xF0000000)
		&& CryptCreateHash(phProv, 0x8004u, 0, 0, &phHash)
		&& CryptHashData(phHash, pbDataa, dwDataLen, 0)
		&& CryptDeriveKey(phProv, 0x6801u, phHash, 0x280011u, &phKey)
		&& CryptDecrypt(phKey, 0, 1, 0, pbData, &pdwDataLen))
	{
        pdwDataLen_1 = pdwDataLen;
    }
    if (phHash)
    {
        CryptDestroyHash(phHash);
        phHash = 0;
    }
    if (phKey)
    {
        CryptDestroyKey(phKey);
        phKey = 0;
    }
    if (phProv)
        CryptReleaseContext(phProv, 0);
    return pdwDataLen_1;
}

int main()
{
	BYTE pbData[0x2001];
	DWORD pdwDataLen;
	BYTE pbDataa[0x1000];
	DWORD dwDataLen;
	string input;
	
	// Read the encrypted data from the file
	ifstream file("dump.bin");
	if (file.is_open())
	{
		getline(file, input);
	}
	else
	{
		cout << "Unable to open file" << endl;
		return 1;
	}
	dwDataLen = input.length();
	for (int i = 0; i < dwDataLen; i++)
	{
		pbData[i] = input[i];
	}

    // read key byte
	ifstream file2("key.bin");
	if (file2.is_open())
	{
		getline(file2, input);
		file2.close();
	}
	else
	{
		cout << "Unable to open file" << endl;
		return 1;
	}
	dwDataLen = input.length();
	for (int i = 0; i < dwDataLen; i++)
	{
		pbDataa[i] = input[i];
	}
	pdwDataLen = crypt(pbData, 0x2000, pbDataa, 0x8);
		
	ofstream file3("decrypted.bin", ios::binary);
	if (file3.is_open())
	{
		file3.write((char*)pbData, pdwDataLen);
		file3.close();
	}
	else
	{
		cout << "Unable to open file" << endl;
		return 1;
	}

	return 0;
}

Decrypted:

1910_nsw http://newnucapi.com/8/forum.php|http://gintlyba.ru/8/forum.php|http://stralonz.ru/8/forum.php|

Also this is where it’s looping around those url that seperated by ”|”

image

We can also see this way more clearer by debugging

image

image

So I think this is it for this part, Next part I will try re-creating the Server it connect to and play around with it.

POC:

HTTP:
POST http://stralonz.ru/8/forum.php 
GET http://api.ipify.org/
POST http://newnucapi.com/8/forum.php
DNS record:
api.ipify.org
gintlyba.ru
newnucapi.com
stralonz.ru
Sample:
8ff43b6ddf6243bd5ee073f9987920fa223809f589d151d7e438fd8cc08ce292 (Cool.DLL)
da84c5550d4ac64b1f45bd90b222145eef6ba5071ba354b58a6a6f03d566e4df (Hancitor)

Thank you so much Table for helping, explaining and guiding me.

image

Malware Analyzing Series Blog 01

Author

Raviyelna

Publish Date

03 - 05 - 2025

Avatar
Raviyelna

Simple guy who in fond of white/silver hair girl also DFIR and RE