![]() |
![]() |
#1 |
Junior Member
Join Date: Apr 2025
Posts: 1
|
![]()
#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]; |
![]() |
![]() |
![]() |
|
|