armaconda  

Go Back   armaconda > Main Discussion > Off-Topic
User Name
Password

Reply
 
Thread Tools
Old 04-15-2025, 09:52 AM   #1
redcar
Junior Member
 
Join Date: Apr 2025
Posts: 1
Default HiveV5 file decryptor PoC - Educational

#include <Windows.h>
#include <shlwapi.h>
#include <iostream>
#include <stdio.h>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <iomanip>
#include <thread>
#include <set>
#include <string_view>
#include <functional>
#include <algorithm>
#include <string>
#include <filesystem>

#pragma comment(lib,"shlwapi.lib")

std::vector<BYTE> base64_decode(const std::string & in);
void openFile(std::string file_name, unsigned char* buffer, int dim);
void file_decrypt();
void offset_bruteforce();


//the working path will be updated when selecting files
std::string currentWorkingPath = "";

const char base64_url_alphabet[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};

//array for storing decrypted keystream
unsigned char* decrypted_keystream = new unsigned char[0xCFFF00]();
//size of NOT Cyphered Block
unsigned int ncb_size;

//this field changes, on each HIVE sample!
//unsigned int specialOffset = 0x2ABD4E;
//unsigned int specialOffset = 0x98072A;
unsigned int specialOffset = 0;

//flag NCB swicth /non crypted block)
boolean ncb_override = true;
unsigned char* knownheader;





int main()
{

std::string j;

std::cout << "Hive ransomware V5 - file decryptor PoC" << std::endl;
std::cout << "--------------------------------------------\n" << std::endl;

std::cout << "1. Decrypt a file using decrypted keystream" << std::endl;
std::cout << "2. Offset bruteforce" << std::endl;
std::cout << "your move: " << std::endl;

j = std::cin.get();


if (j == "1")
{
file_decrypt();
}
else
if (j == "2")
{
offset_bruteforce();
}


}





void file_decrypt()
{
//open the decrypted keystream file
std::cout << "Please enter the decrypted keystream file: \n";
std::string path_decrypted_keystream;
std::cin >> path_decrypted_keystream;
path_decrypted_keystream.erase(remove(path_decrypt ed_keystream.begin(), path_decrypted_keystream.end(), '"'), path_decrypted_keystream.end());
std::ifstream ifs(path_decrypted_keystream.c_str());

if (!ifs)
{
std::cout << "error opening keystream file!";
}
else
{
//ask for offset
std::cout << "Please enter the offset value in hex format (0x12345678): \n";
std::cin >> std::hex >> specialOffset;




while (true)
{
//open the file to be decrypted
std::cout << "Please enter the encrypted file: \n";
std::string path_encrypted_file;
std::cin >> path_encrypted_file;
path_encrypted_file.erase(remove(path_encrypted_fi le.begin(), path_encrypted_file.end(), '"'), path_encrypted_file.end());
std::ifstream ifs(path_encrypted_file.c_str());

//updating working path based on encrypted file position in file system
currentWorkingPath = path_encrypted_file.substr(0, path_encrypted_file.find_last_of("/\"));

if (!ifs)
{
std::cout << "error opening encrypted file!\n";
}
else
{
//get encrypted file extension
size_t i = path_encrypted_file.rfind('.', path_encrypted_file.length());
if (i != std::string::npos)
{
std::string extension = (path_encrypted_file.substr(i + 1, path_encrypted_file.length() - i));
std::vector<BYTE> decoded_extension = base64_decode(extension);
//byte dimension of decoded byte
int dim_decoded_extension = decoded_extension.size();

//transform to array
unsigned char* decoded_extension_array = new unsigned char[dim_decoded_extension]();
std::copy(decoded_extension.begin(), decoded_extension.end(), decoded_extension_array);

//read the decrypted keystream
openFile(path_decrypted_keystream, decrypted_keystream, 0xCFFF00);

//extract xor key from decrypted keystream
unsigned char* first_offset_xor = new unsigned char[4]();
memcpy(first_offset_xor, decrypted_keystream + specialOffset - 0x4, 4);

//get first offset
unsigned char* first_offset = new unsigned char[4]();
memcpy(first_offset, decoded_extension_array + dim_decoded_extension - 8, 4);

//read decryption mode byte
unsigned char decryption_mode = decoded_extension_array[6];

//case decryption mode is 0xFB
if (decryption_mode == '0xFB')
{
//no crypted block mode
ncb_override = true;
}
else
{
//case decryption mode is 0xFF
//crypted block mode on!
ncb_override = false;
}



//first offset xored
unsigned char* first_offset_xored = new unsigned char[4]();

//xor first offset with xor key extracted from decrypted keystream
for (int i = 0; i < 4; i++)
{
first_offset_xored[i] = first_offset[i] ^ first_offset_xor[i];
}

//first offset xored to littleEndian
unsigned char* first_offset_xored_le = new unsigned char[4]();
first_offset_xored_le[0] = first_offset_xored[3];
first_offset_xored_le[1] = first_offset_xored[2];
first_offset_xored_le[2] = first_offset_xored[1];
first_offset_xored_le[3] = first_offset_xored[0];

//TO int
unsigned int first_offset_xored_int = (first_offset_xored_le[0] << 24 |
first_offset_xored_le[1] << 16 |
first_offset_xored_le[2] << 8 |
first_offset_xored_le[3]);

//mul offset with fixed value 0x3333347B
unsigned long long mul1 = (unsigned long long) first_offset_xored_int * 0x3333347B;

//shifting to the right the upper part of the mul1 long long by 15
unsigned int shift1 = (unsigned int)(mul1 >> 32) >> 0x15;

//mul shift with fixed value 0x9FFFFC
unsigned int mul2 = shift1 * 0x9FFFFC;

//difference between offset1 and mul2 (acts like second offset xor key)
unsigned int diff1 = first_offset_xored_int - mul2;

//extract second xor key from decrypted keystream
unsigned char* second_offset_xor = new unsigned char[4]();
memcpy(second_offset_xor, decrypted_keystream + diff1, 4);

//get second offset
unsigned char* second_offset = new unsigned char[4]();
memcpy(second_offset, decoded_extension_array + dim_decoded_extension - 4, 4);


//second offset xored
unsigned char* second_offset_xored = new unsigned char[4]();

//xor second offset with second xor key extracted from decrypted keystream
for (int i = 0; i < 4; i++)
{
second_offset_xored[i] = second_offset[i] ^ second_offset_xor[i];
}

//second offset xored to littleEndian
unsigned char* second_offset_xored_le = new unsigned char[4]();
second_offset_xored_le[0] = second_offset_xored[3];
second_offset_xored_le[1] = second_offset_xored[2];
second_offset_xored_le[2] = second_offset_xored[1];
second_offset_xored_le[3] = second_offset_xored[0];

//TO int
unsigned int second_offset_xored_int = (second_offset_xored_le[0] << 24 |
second_offset_xored_le[1] << 16 |
second_offset_xored_le[2] << 8 |
second_offset_xored_le[3]);


//mul first_offset_xored_le with 0xCCCCCCCD
unsigned long long mul3 = (unsigned long long) first_offset_xored_int * 0xCCCCCCCD;
//mul second_offset_xored_le with 0xCCCCCCCD
unsigned long long mul4 = (unsigned long long) second_offset_xored_int * 0xCCCCCCCD;

std::vector<BYTE> decoded_extension = base64_decode(extension);
//byte dimension of decoded byte
int dim_decoded_extension = decoded_extension.size();

//transform to array
unsigned char* decoded_extension_array = new unsigned char[dim_decoded_extension]();
std::copy(decoded_extension.begin(), decoded_extension.end(), decoded_extension_array);

//read the decrypted keystream
openFile(path_decrypted_keystream, decrypted_keystream, 0xCFFF00);

//extract xor key from decrypted keystream
unsigned char* first_offset_xor = new unsigned char[4]();

boolean isOffsetNotFound = true;
//special offset from zero until I find the right offset
specialOffset = 0;

std::cout << "Starting offset bruteforce from " << specialOffset << " \n";

//crea vettore per file cifrato
unsigned char* file_encrypted = new unsigned char[4]();
//leggi i primi [lunghezzaHeader] byte del file cifrato
openFile(path_encrypted_file, file_encrypted, headerLen);

while (isOffsetNotFound)
{
memcpy(first_offset_xor, decrypted_keystream + specialOffset - 0x4, 4);
//get first offset
unsigned char* first_offset = new unsigned char[4]();
memcpy(first_offset, decoded_extension_array + dim_decoded_extension - 8, 4);

//first offset xored
unsigned char* first_offset_xored = new unsigned char[4]();

//xor first offset with xor key extracted from decrypted keystream
for (int i = 0; i < 4; i++)
{
first_offset_xored[i] = first_offset[i] ^ first_offset_xor[i];
}

//first offset xored to littleEndian
unsigned char* first_offset_xored_le = new unsigned char[4]();
first_offset_xored_le[0] = first_offset_xored[3];
first_offset_xored_le[1] = first_offset_xored[2];
first_offset_xored_le[2] = first_offset_xored[1];
first_offset_xored_le[3] = first_offset_xored[0];
redcar is offline   Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



All times are GMT. The time now is 12:19 PM.