Brute Ratel BRC4
Malware analysis
Published on
Introduction
This article will not be a detailed malware analysis report on the features of Brute Ratel (BRC4), but rather a study focusing on several samples of the same version. In this article, we will compare a few samples, study the C2 configuration, and implement a self-extraction script with IDA Python. Then, we will meticulously examine the encryption and decryption of data sent to the control server. The goal here is to understand how the C2 retrieves its configuration and how data is processed from an encryption/decryption perspective.
For this study, we sourced 5 samples of brute ratel from different platforms such as VT and MalwareBazaar. These different samples were retrieved without looking for any particular link, but it turns out that they're all samples of the same version.
Here are the selected samples :
- 1 ➔ d71dc7ba8523947e08c6eec43a726fe75aed248dfd3a7c4f6537224e9ed05f6f
- 2 ➔ dd8652e2dcfe3f1a72631b3a9585736fbe77ffabee4098f6b3c48e1469bf27aa
- 3 ➔ 3ad53495851bafc48caf6d2227a434ca2e0bef9ab3bd40abfe4ea8f318d37bbe
- 4 ➔ 3ed21a4bfcf9838e06ad3058d13d5c28026c17dc996953a22a00f0609b0df3b9
- 5 ➔ e1a9b35cf1378fda12310f0920c5c53ad461858b3cb575697ea125dfee829611
As a reminder, Brute Ratel BRC4 is a remote command and control (C2) tool that allows remote control of one or multiple agents. The agent implanted on the victim's machine is capable of performing various operations. For a detailed analysis of the agent's capabilities, you can refer to the in-depth study conducted by Vlad Pasca here.
Analysis and comparison
All samples exhibit identical behavior upon program launch: a set of data is placed on the stack. In the capture below, it is evident that the majority of the program consists of data stored on the stack, awaiting further execution in memory.
At the end of this repetition, we can observe the values 0x4D and 0x5A, which correspond to M and Z respectively, signifying the byte sequence indicating that it is indeed an executable file.
From this point onwards, we can already begin comparing the different samples, as the first differences are observed immediately after the program is stored in the stack. I divided the 5 samples into two groups, as some of them make use of WinAPI functions, while others use system calls (SYSCALL). All samples employ PEB parsing and API hashing to dynamically resolve functions. Some of them make calls using the CALL [REGISTER] operation, while others use the SYSCALL operation after retrieving the corresponding identifier for the desired system call.
Here is a summary table:
Group 1: samples with API hashing + PEB parsing ➔ CALL [REGISTER]
- 1 ➔ d71dc7ba8523947e08c6eec43a726fe75aed248dfd3a7c4f6537224e9ed05f6f
- 3 ➔ 3ad53495851bafc48caf6d2227a434ca2e0bef9ab3bd40abfe4ea8f318d37bbe
- 5 ➔ e1a9b35cf1378fda12310f0920c5c53ad461858b3cb575697ea125dfee829611
Group 2: samples with API hashing + PEB parsing ➔ SYSCALL
- 2 ➔ dd8652e2dcfe3f1a72631b3a9585736fbe77ffabee4098f6b3c48e1469bf27aa
- 4 ➔ 3ed21a4bfcf9838e06ad3058d13d5c28026c17dc996953a22a00f0609b0df3b9
Address resolution
The techniques of PEB parsing and API hashing are used in these samples (to learn more about these two techniques, here is my previous article based on API hashing and PEB parsing). The group 1 samples retrieve the base address of kernel32:
The group 2 samples retrieve the base address of ntdll:
For group 1 samples, we observe parsing to retrieve the base address of the Kernel32 module, whereas for group 2 samples, we see the loading of the ntdll module. This difference is due to the distinct methods of function calls: group 1 employs WinAPI function calls, while group 2 utilizes system calls.
In the address resolution process, we observe hashes that are placed on the stack before calling a function to process the hash and resolve an address pointing to a WinAPI function. As for the identifier in group 2 samples, it is retrieved in a new function located at the end of the process.
In the capture below, here is a sample of the code used to dynamically resolve functions:
For the right part, we have two different codes depending on the variant we are analyzing.
Here is a sample from a sample of group 1:
Here is a sample from a sample of group 2:
There is a slight difference observed in the samples from Group 2. In this case, a new function appears at the end of the process, which is responsible for retrieving the identifier of a function from the ntdll module. The purpose of using system calls is to bypass the security mechanisms of certain anti-virus or EDR solutions that rely on userland hooking for protection.
The hashing process is relatively simple, involving a ROR operation by 0x0D. It's relatively easy to resolve function names with this uncomplicated hashing method. For instance, we can extract the complete list of function names from the ntdll and kernel32 modules to iterate through each name in the hashing process to match the hashes. Alternatively, we can simply follow the instruction ADD RDI, RBP to identify the function that will be called since it's stored in the RDI register.
Here are the functions called by the samples from group 1:
Here are the functions called by the samples from group 2:
To retrieve the identifier that refers to the desired function, you first need to resolve the address pointing to it. This process aims to obtain the correct identifier, as it can vary depending on the Windows version. An error in this identifier could lead to a program crash, as the wrong function would be called with incorrect arguments. These identifiers are documented in various blogs, such as the one by j00ru here.
To better understand how the identifier is retrieved at the [pointer+4] location, you can observe how the functions are structured.
Here is a sample of the functions NtReadFile and NtAllocateVirtualMemory:
Observation of initial results
The first functions resolved for both groups of samples are VirtualAllocEx and NtAllocateVirtualMemory. These functions indicate that two new memory regions will be created as they are called twice. These two memory regions will contain data, with one of them holding the program to be executed and the other containing the C2 configuration.
Here is a sample from group 1 that shows the creation of the two memory regions:
Here is a sample from group 1 that demonstrates the injection of data into these two memory regions:
Configuration and script
In this section, we will explore how to automate the retrieval of the configuration using IDA and Python. It is essential to note that the configuration is injected into a memory area at address 0x20000, regardless of the variant used.
Here are the steps of our script:
1. We enumerate all instructions of the functions recognized by IDA and add 1 to the value of the address of the last instruction found. All of this is done to reach the first instruction of the last targeted function, which is not listed in IDA's recognized functions:
import idc
import idaapi
import time
print(
"""###############
# START #
###############
"""
)
for func in idautils.Functions():
for instruction in idautils.Heads(func, idc.get_func_attr(func, idc.FUNCATTR_END)):
True
instruction += 1
start_address = instruction
 
2. We add all addresses and their instructions to the "instructions" list in order to traverse this list later to search for all instructions containing the terms call or syscall:
instructions = []
for i, addr in enumerate(idautils.Heads(start_address, ida_ida.cvar.inf.max_ea)):
mnem = idaapi.ua_mnem(addr)
operand = idc.print_operand(addr, 0)
operand2 = idc.print_operand(addr, 1)
if operand2 != "":
instructions.append(hex(addr) + ": " + mnem + " " + operand + ", " + operand2)
elif mnem == "retn":
break
else:
instructions.append(hex(addr) + ": " + mnem + " " + operand)
call_func = []
for i in instructions:
if "call" in i:
if "syscall" in i.split(": ")[1]:
call_func.append(i.split(":")[0])
elif len(i.split(": ")[1]) == 8:
call_func.append(i.split(":")[0])
 
3. We retrieve the address of the last CALL or SYSCALL instruction to add it as a breakpoint before the configuration and debugger launch:
addr_to_break = call_func[-1]
time.sleep(2)
idaapi.add_bpt(int(addr_to_break, base=16), 0, idaapi.BPT_DEFAULT)
idaapi.load_debugger("windbg", 1)
idaapi.start_process(ida_nalt.get_input_file_path(), "", "")
idaapi.continue_process()
 
4. We retrieve the value of the RSP register to enumerate the addresses it contains, in order to search for the address 0x20000 which contains the C2 configuration:
ida_dbg.wait_for_next_event(ida_dbg.WFNE_SUSP, -1)
rsp_value = idaapi.get_reg_val("RSP")
addr = 0
while hex(addr) != "0x20000":
rsp_value += 8
addr = idaapi.get_bytes(rsp_value, 8)
addr = struct.unpack("<Q", addr)[0]
print(hex(addr))
print(idaapi.get_bytes(addr, 256))
idaapi.exit_process()
print(
"""#############
# END #
#############
"""
)
 
Here is the complete code:
import idautils
import idc
import idaapi
import time
print(
"""###############
# START #
###############
"""
)
for func in idautils.Functions():
for instruction in idautils.Heads(func, idc.get_func_attr(func, idc.FUNCATTR_END)):
True
instruction += 1
start_address = instruction
instructions = []
for i, addr in enumerate(idautils.Heads(start_address, ida_ida.cvar.inf.max_ea)):
mnem = idaapi.ua_mnem(addr)
operand = idc.print_operand(addr, 0)
operand2 = idc.print_operand(addr, 1)
if operand2 != "":
instructions.append(hex(addr) + ": " + mnem + " " + operand + ", " + operand2)
elif mnem == "retn":
break
else:
instructions.append(hex(addr) + ": " + mnem + " " + operand)
call_func = []
for i in instructions:
if "call" in i:
if "syscall" in i.split(": ")[1]:
call_func.append(i.split(":")[0])
elif len(i.split(": ")[1]) == 8:
call_func.append(i.split(":")[0])
addr_to_break = call_func[-1]
time.sleep(2)
idaapi.add_bpt(int(addr_to_break, base=16), 0, idaapi.BPT_DEFAULT)
idaapi.load_debugger("windbg", 1)
idaapi.start_process(ida_nalt.get_input_file_path(), "", "")
idaapi.continue_process()
ida_dbg.wait_for_next_event(ida_dbg.WFNE_SUSP, -1)
rsp_value = idaapi.get_reg_val("RSP")
addr = 0
while hex(addr) != "0x20000":
rsp_value += 8
addr = idaapi.get_bytes(rsp_value, 8)
addr = struct.unpack("<Q", addr)[0]
print(hex(addr))
print(idaapi.get_bytes(addr, 256))
idaapi.exit_process()
print(
"""#############
# END #
#############
"""
)
 
Result obtained on a sample from group 1:
Result obtained on a sample from group 2:
In some samples, we observe a different configuration in which the content is encrypted with RC4 and then encoded in base64. The password required to decrypt the RC4 content is located within the program injected into memory. This password can be identified by examining strings or by continuing dynamic analysis until the moment of configuration decryption.
Here is the result obtained with a sample exhibiting a different configuration:
To identify the key, it is necessary to navigate to the function handling the configuration. For a sample with unencrypted configuration, this function simply serves to retrieve each element of the configuration for later use. However, for a sample with encrypted configuration, we observe two distinct function calls at the beginning of this function.
The first function is used to decode the base64-encoded configuration, while the second function decrypts the result using the key placed on the stack during the call. This function represents an implementation of RC4 for decryption.
Let's consider this capture to support our analysis:
The capture below represents the decrypted configuration of this sample:
Encryption / Decryption
This final section of the article focuses on the processing of data sent and received by the BRC4 agent, with the aim of developing a Python program that allows us to encrypt and decrypt BRC4 requests. This part can be divided into three distinct stages:
- - The key generation for encryption/decryption step
- - The encryption step
- - The decryption step
In the configuration, we find a password, which serves as the key to generate a longer key. Both the key and the long key will be used for data encryption and decryption.
Here is the encryption part:
Here is the decryption part:
A common element in both parts is the function responsible for generating the long key, which is essential for both use cases. This function performs several operations, starting by setting the key size to 16 characters. This means that if the original key is shorter than 16 characters, it will be filled with the value 0x00 to reach a length of 16 characters. Then, this key undergoes an XOR operation with a short key generated from the original key and constant values.
The capture below shows the process:
Here is the python code snippet reproducing this analyzed program section:
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Encrypt or decrypt data of BRC4.")
parser.add_argument("choice", help="d for decrypt or e for encrypt")
parser.add_argument("offset", help="offset for encryption/decryption")
parser.add_argument("mykey", help="key for encryption/decryption")
args = parser.parse_args()
offset = int(args.offset)
mykey = [ord(i) for i in args.mykey]
if len(mykey) < 16:
for i in range(16 - len(mykey)):
mykey.append(0x00)
values1 = [
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
]
values2 = [
0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F, 0x25, 0x4A, 0x94, 0x33, 0x66, 0xCC, 0x83, 0x1D, 0x3A,
0x74, 0xE8, 0xCB, 0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8,
0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF,
0xC5, 0x91, 0x39, 0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F, 0x25, 0x4A, 0x94, 0x33, 0x66, 0xCC,
0x83, 0x1D, 0x3A, 0x74, 0xE8, 0xCB, 0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B,
0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3,
0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, 0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F, 0x25, 0x4A, 0x94,
0x33, 0x66, 0xCC, 0x83, 0x1D, 0x3A, 0x74, 0xE8, 0xCB, 0x8D, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35,
0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, 0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F,
0x25, 0x4A, 0x94, 0x33, 0x66, 0xCC, 0x83, 0x1D, 0x3A, 0x74, 0xE8, 0xCB, 0x8D, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A, 0x2F, 0x5E, 0xBC, 0x63,
0xC6, 0x97, 0x35, 0x6A, 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39, 0x72, 0xE4, 0xD3, 0xBD,
0x61, 0xC2, 0x9F, 0x25, 0x4A, 0x94, 0x33, 0x66, 0xCC, 0x83, 0x1D, 0x3A, 0x74, 0xE8, 0xCB, 0x8D,
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
]
values1 = [(i + offset & 0xFF) for i in values1]
values2 = [(i + offset & 0xFF) for i in values2]
mypass = []
for i in mykey:
mypass.append(i)
edx = 1
keytmp = [i for i in mypass[-4:]]
key = [0, 0, 0, 0]
key[0] = keytmp[1]
key[1] = keytmp[2]
key[2] = keytmp[3]
key[3] = keytmp[0]
newkey = []
newkey.append(values1[key[0]])
newkey.append(values1[key[1]])
newkey.append(values1[key[2]])
newkey.append(values1[key[3]])
newkey[0] = values1[key[0]] ^ values2[edx]
key = newkey
long_pass = []
i = 0
z = 0
zz = 0
while z <= 0xB0:
if z != 0:
if z == 160:
save_mypass = []
for x in range(len(mypass)):
save_mypass.append(mypass[x])
if z == 156:
save_key = []
for x in range(len(key)):
save_key.append(key[x])
for j in range(0x04):
tmp = mypass[i] ^ key[j]
mypass[i] = tmp
key[j] = tmp
if z < 160:
long_pass.append(tmp)
i += 1
z += 1
zz += 1
if i == 0x10:
i = 0
if zz == 16:
zz = 0
edx += 1
keytmp = []
for l in range(4):
keytmp.append(key[l])
key[0] = keytmp[1]
key[1] = keytmp[2]
key[2] = keytmp[3]
key[3] = keytmp[0]
newkey = []
newkey.append(values1[key[0]])
newkey.append(values1[key[1]])
newkey.append(values1[key[2]])
newkey.append(values1[key[3]])
newkey[0] = values1[key[0]] ^ values2[edx]
key = newkey
key = []
for i in mykey:
key.append(i)
long_data_with_pass = key + long_pass
if args.choice in ["e", "encrypt"]:
# insert json in data
data = ""
encryptSring(data, key, values1, long_data_with_pass, long_pass, offset)
elif args.choice in ["d", "decrypt"]:
# insert base64 value in data
data = ""
decryptSring(data, key, long_data_with_pass, long_pass, offset)
 
Here is the python code snippet reproducing the data encryption:
import base64
import argparse
import sys
def encryptSring(data, key, values1, long_data_with_pass, long_pass, offset):
data = [i for i in data]
encryptString = []
for i in range(16):
if ((len(data) + i) % 16) == 0:
len_max = len(data) + i
break
for j in range(i):
if j == 0:
data.append(0x0D)
elif j == 1:
data.append(0x0A)
else:
data.append(0)
T = 0
while T < (len_max / 16):
newpass = []
for i in range(16):
try:
tmp = ord(data[(16 * T) + i]) ^ key[i]
except TypeError:
tmp = data[(16 * T) + i] ^ key[i]
newpass.append(tmp)
tempo_pass = []
for i in range(0xA0, len(long_data_with_pass)):
tempo_pass.append(long_data_with_pass[i])
##############
# START LOOP #
##############
count = 0
while count < 9:
for i in range(16):
tmp = newpass[i]
tmp = values1[tmp]
newpass[i] = tmp
tmppass = []
for i in [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11]:
tmppass.append(newpass[i])
valueEngine1 = [
0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,
0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9A, 0x9C, 0x9E,
0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0xBE,
0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6, 0xD8, 0xDA, 0xDC, 0xDE,
0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6, 0xF8, 0xFA, 0xFC, 0xFE,
0x1B, 0x19, 0x1F, 0x1D, 0x13, 0x11, 0x17, 0x15, 0x0B, 0x09, 0x0F, 0x0D, 0x03, 0x01, 0x07, 0x05,
0x3B, 0x39, 0x3F, 0x3D, 0x33, 0x31, 0x37, 0x35, 0x2B, 0x29, 0x2F, 0x2D, 0x23, 0x21, 0x27, 0x25,
0x5B, 0x59, 0x5F, 0x5D, 0x53, 0x51, 0x57, 0x55, 0x4B, 0x49, 0x4F, 0x4D, 0x43, 0x41, 0x47, 0x45,
0x7B, 0x79, 0x7F, 0x7D, 0x73, 0x71, 0x77, 0x75, 0x6B, 0x69, 0x6F, 0x6D, 0x63, 0x61, 0x67, 0x65,
0x9B, 0x99, 0x9F, 0x9D, 0x93, 0x91, 0x97, 0x95, 0x8B, 0x89, 0x8F, 0x8D, 0x83, 0x81, 0x87, 0x85,
0xBB, 0xB9, 0xBF, 0xBD, 0xB3, 0xB1, 0xB7, 0xB5, 0xAB, 0xA9, 0xAF, 0xAD, 0xA3, 0xA1, 0xA7, 0xA5,
0xDB, 0xD9, 0xDF, 0xDD, 0xD3, 0xD1, 0xD7, 0xD5, 0xCB, 0xC9, 0xCF, 0xCD, 0xC3, 0xC1, 0xC7, 0xC5,
0xFB, 0xF9, 0xFF, 0xFD, 0xF3, 0xF1, 0xF7, 0xF5, 0xEB, 0xE9, 0xEF, 0xED, 0xE3, 0xE1, 0xE7, 0xE5
]
valueEngine2 = [
0x00, 0x03, 0x06, 0x05, 0x0C, 0x0F, 0x0A, 0x09, 0x18, 0x1B, 0x1E, 0x1D, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39, 0x28, 0x2B, 0x2E, 0x2D, 0x24, 0x27, 0x22, 0x21,
0x60, 0x63, 0x66, 0x65, 0x6C, 0x6F, 0x6A, 0x69, 0x78, 0x7B, 0x7E, 0x7D, 0x74, 0x77, 0x72, 0x71,
0x50, 0x53, 0x56, 0x55, 0x5C, 0x5F, 0x5A, 0x59, 0x48, 0x4B, 0x4E, 0x4D, 0x44, 0x47, 0x42, 0x41,
0xC0, 0xC3, 0xC6, 0xC5, 0xCC, 0xCF, 0xCA, 0xC9, 0xD8, 0xDB, 0xDE, 0xDD, 0xD4, 0xD7, 0xD2, 0xD1,
0xF0, 0xF3, 0xF6, 0xF5, 0xFC, 0xFF, 0xFA, 0xF9, 0xE8, 0xEB, 0xEE, 0xED, 0xE4, 0xE7, 0xE2, 0xE1,
0xA0, 0xA3, 0xA6, 0xA5, 0xAC, 0xAF, 0xAA, 0xA9, 0xB8, 0xBB, 0xBE, 0xBD, 0xB4, 0xB7, 0xB2, 0xB1,
0x90, 0x93, 0x96, 0x95, 0x9C, 0x9F, 0x9A, 0x99, 0x88, 0x8B, 0x8E, 0x8D, 0x84, 0x87, 0x82, 0x81,
0x9B, 0x98, 0x9D, 0x9E, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8F, 0x8C, 0x89, 0x8A,
0xAB, 0xA8, 0xAD, 0xAE, 0xA7, 0xA4, 0xA1, 0xA2, 0xB3, 0xB0, 0xB5, 0xB6, 0xBF, 0xBC, 0xB9, 0xBA,
0xFB, 0xF8, 0xFD, 0xFE, 0xF7, 0xF4, 0xF1, 0xF2, 0xE3, 0xE0, 0xE5, 0xE6, 0xEF, 0xEC, 0xE9, 0xEA,
0xCB, 0xC8, 0xCD, 0xCE, 0xC7, 0xC4, 0xC1, 0xC2, 0xD3, 0xD0, 0xD5, 0xD6, 0xDF, 0xDC, 0xD9, 0xDA,
0x5B, 0x58, 0x5D, 0x5E, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4F, 0x4C, 0x49, 0x4A,
0x6B, 0x68, 0x6D, 0x6E, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7F, 0x7C, 0x79, 0x7A,
0x3B, 0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2F, 0x2C, 0x29, 0x2A,
0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1F, 0x1C, 0x19, 0x1A
]
valueEngine1 = [(i + offset & 0xFF) for i in valueEngine1]
valueEngine2 = [(i + offset & 0xFF) for i in valueEngine2]
v42 = [0] * 16
v42[0] = (
valueEngine2[tmppass[1]]
^ valueEngine1[tmppass[0]]
^ tmppass[3]
^ tmppass[2]
)
v42[1] = valueEngine2[tmppass[2]] ^ (
valueEngine1[tmppass[1]] ^ tmppass[3] ^ tmppass[0]
)
v42[2] = valueEngine2[tmppass[3]] ^ (
valueEngine1[tmppass[2]] ^ (tmppass[1] ^ tmppass[0])
)
v42[3] = valueEngine1[tmppass[3]] ^ (
valueEngine2[tmppass[0]] ^ (tmppass[2] ^ tmppass[1])
)
v42[4] = (
valueEngine2[tmppass[5]]
^ valueEngine1[tmppass[4]]
^ tmppass[7]
^ tmppass[6]
)
v42[5] = (
valueEngine2[tmppass[6]]
^ valueEngine1[tmppass[5]]
^ tmppass[7]
^ tmppass[4]
)
v42[6] = valueEngine2[tmppass[7]] ^ (
valueEngine1[tmppass[6]] ^ tmppass[5] ^ tmppass[4]
)
v42[7] = (
valueEngine1[tmppass[7]]
^ valueEngine2[tmppass[4]]
^ tmppass[6]
^ tmppass[5]
)
v42[8] = (
valueEngine2[tmppass[9]]
^ valueEngine1[tmppass[8]]
^ tmppass[11]
^ tmppass[10]
)
v42[9] = (
valueEngine2[tmppass[10]]
^ valueEngine1[tmppass[9]]
^ tmppass[11]
^ tmppass[8]
)
v42[10] = (
valueEngine2[tmppass[11]]
^ valueEngine1[tmppass[10]]
^ tmppass[9]
^ tmppass[8]
)
v42[11] = valueEngine1[tmppass[11]] ^ (
valueEngine2[tmppass[8]] ^ (tmppass[10] ^ tmppass[9])
)
v42[12] = (
valueEngine2[tmppass[13]]
^ valueEngine1[tmppass[12]]
^ tmppass[15]
^ tmppass[14]
)
v42[13] = (
valueEngine2[tmppass[14]]
^ valueEngine1[tmppass[13]]
^ tmppass[15]
^ tmppass[12]
)
v42[14] = valueEngine2[tmppass[15]] ^ (
valueEngine1[tmppass[14]] ^ tmppass[13] ^ tmppass[12]
)
v42[15] = (
valueEngine1[tmppass[15]]
^ valueEngine2[tmppass[12]]
^ tmppass[14]
^ tmppass[13]
)
for i in range(16):
tmppass[i] = v42[i]
tmp_long_pass = []
for i in range(count * 16, (count + 1) * 16):
tmp_long_pass.append(long_pass[i])
for i in range(16):
tmp = tmppass[i] ^ tmp_long_pass[i]
tmppass[i] = tmp
for i in range(16):
newpass[i] = tmppass[i]
count += 1
##############
# END LOOP #
##############
for i in range(16):
tmp = tmppass[i]
tmp = values1[tmp]
newpass[i] = tmp
tmppass = []
for i in [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11]:
tmppass.append(newpass[i])
for i in range(16):
tmp = tmppass[i] ^ tempo_pass[i]
tmppass[i] = tmp
for i in range(16):
encryptString.append(tmppass[i])
T += 1
hex_bytes = []
for hex_str in encryptString:
hex_byte = hex_str.to_bytes(1, "big")
hex_bytes.append(hex_byte)
b64encryptredString = base64.b64encode(b"".join(hex_bytes)).decode()
print("\n\nEncrypted data : \n", b64encryptredString)
 
Here is the python code snippet reproducing the data decryption:
def decryptSring(data, key, long_data_with_pass, long_pass, offset):
decryptSrings = ""
data = base64.b64decode(data)
len_max = len(data)
for i in range(16):
if (len_max + i) % 16 == 0:
break
else:
data += b"\x00"
tempo_pass = []
for i in range(0xA0, len(long_data_with_pass)):
tempo_pass.append(long_data_with_pass[i])
T = 0
while T < (len_max / 16):
newpass = []
for i in range(16):
tmp = data[(16 * T) + i] ^ tempo_pass[i]
newpass.append(tmp)
tmppass = []
for i in [0, 0x0D, 0xA, 7, 4, 1, 0x0E, 0x0B, 8, 5, 2, 0x0F, 0x0C, 9, 6, 3]:
tmppass.append(newpass[i])
values3 = [
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
]
values3 = [(i + offset & 0xFF) for i in values3]
for i in range(16):
tmp = tmppass[i]
tmp = values3[tmp]
newpass[i] = tmp
##############
# START LOOP #
##############
count = 9
while count > 0:
tmp_long_pass = []
for i in range((count - 1) * 16, count * 16):
tmp_long_pass.append(long_pass[i])
for i in range(16):
tmp = newpass[i] ^ tmp_long_pass[i]
newpass[i] = tmp
valueEngine1 = [
0x00, 0x0E, 0x1C, 0x12, 0x38, 0x36, 0x24, 0x2A, 0x70, 0x7E, 0x6C, 0x62, 0x48, 0x46, 0x54, 0x5A,
0xE0, 0xEE, 0xFC, 0xF2, 0xD8, 0xD6, 0xC4, 0xCA, 0x90, 0x9E, 0x8C, 0x82, 0xA8, 0xA6, 0xB4, 0xBA,
0xDB, 0xD5, 0xC7, 0xC9, 0xE3, 0xED, 0xFF, 0xF1, 0xAB, 0xA5, 0xB7, 0xB9, 0x93, 0x9D, 0x8F, 0x81,
0x3B, 0x35, 0x27, 0x29, 0x03, 0x0D, 0x1F, 0x11, 0x4B, 0x45, 0x57, 0x59, 0x73, 0x7D, 0x6F, 0x61,
0xAD, 0xA3, 0xB1, 0xBF, 0x95, 0x9B, 0x89, 0x87, 0xDD, 0xD3, 0xC1, 0xCF, 0xE5, 0xEB, 0xF9, 0xF7,
0x4D, 0x43, 0x51, 0x5F, 0x75, 0x7B, 0x69, 0x67, 0x3D, 0x33, 0x21, 0x2F, 0x05, 0x0B, 0x19, 0x17,
0x76, 0x78, 0x6A, 0x64, 0x4E, 0x40, 0x52, 0x5C, 0x06, 0x08, 0x1A, 0x14, 0x3E, 0x30, 0x22, 0x2C,
0x96, 0x98, 0x8A, 0x84, 0xAE, 0xA0, 0xB2, 0xBC, 0xE6, 0xE8, 0xFA, 0xF4, 0xDE, 0xD0, 0xC2, 0xCC,
0x41, 0x4F, 0x5D, 0x53, 0x79, 0x77, 0x65, 0x6B, 0x31, 0x3F, 0x2D, 0x23, 0x09, 0x07, 0x15, 0x1B,
0xA1, 0xAF, 0xBD, 0xB3, 0x99, 0x97, 0x85, 0x8B, 0xD1, 0xDF, 0xCD, 0xC3, 0xE9, 0xE7, 0xF5, 0xFB,
0x9A, 0x94, 0x86, 0x88, 0xA2, 0xAC, 0xBE, 0xB0, 0xEA, 0xE4, 0xF6, 0xF8, 0xD2, 0xDC, 0xCE, 0xC0,
0x7A, 0x74, 0x66, 0x68, 0x42, 0x4C, 0x5E, 0x50, 0x0A, 0x04, 0x16, 0x18, 0x32, 0x3C, 0x2E, 0x20,
0xEC, 0xE2, 0xF0, 0xFE, 0xD4, 0xDA, 0xC8, 0xC6, 0x9C, 0x92, 0x80, 0x8E, 0xA4, 0xAA, 0xB8, 0xB6,
0x0C, 0x02, 0x10, 0x1E, 0x34, 0x3A, 0x28, 0x26, 0x7C, 0x72, 0x60, 0x6E, 0x44, 0x4A, 0x58, 0x56,
0x37, 0x39, 0x2B, 0x25, 0x0F, 0x01, 0x13, 0x1D, 0x47, 0x49, 0x5B, 0x55, 0x7F, 0x71, 0x63, 0x6D,
0xD7, 0xD9, 0xCB, 0xC5, 0xEF, 0xE1, 0xF3, 0xFD, 0xA7, 0xA9, 0xBB, 0xB5, 0x9F, 0x91, 0x83, 0x8D
]
valueEngine2 = [
0x00, 0x0D, 0x1A, 0x17, 0x34, 0x39, 0x2E, 0x23, 0x68, 0x65, 0x72, 0x7F, 0x5C, 0x51, 0x46, 0x4B,
0xD0, 0xDD, 0xCA, 0xC7, 0xE4, 0xE9, 0xFE, 0xF3, 0xB8, 0xB5, 0xA2, 0xAF, 0x8C, 0x81, 0x96, 0x9B,
0xBB, 0xB6, 0xA1, 0xAC, 0x8F, 0x82, 0x95, 0x98, 0xD3, 0xDE, 0xC9, 0xC4, 0xE7, 0xEA, 0xFD, 0xF0,
0x6B, 0x66, 0x71, 0x7C, 0x5F, 0x52, 0x45, 0x48, 0x03, 0x0E, 0x19, 0x14, 0x37, 0x3A, 0x2D, 0x20,
0x6D, 0x60, 0x77, 0x7A, 0x59, 0x54, 0x43, 0x4E, 0x05, 0x08, 0x1F, 0x12, 0x31, 0x3C, 0x2B, 0x26,
0xBD, 0xB0, 0xA7, 0xAA, 0x89, 0x84, 0x93, 0x9E, 0xD5, 0xD8, 0xCF, 0xC2, 0xE1, 0xEC, 0xFB, 0xF6,
0xD6, 0xDB, 0xCC, 0xC1, 0xE2, 0xEF, 0xF8, 0xF5, 0xBE, 0xB3, 0xA4, 0xA9, 0x8A, 0x87, 0x90, 0x9D,
0x06, 0x0B, 0x1C, 0x11, 0x32, 0x3F, 0x28, 0x25, 0x6E, 0x63, 0x74, 0x79, 0x5A, 0x57, 0x40, 0x4D,
0xDA, 0xD7, 0xC0, 0xCD, 0xEE, 0xE3, 0xF4, 0xF9, 0xB2, 0xBF, 0xA8, 0xA5, 0x86, 0x8B, 0x9C, 0x91,
0x0A, 0x07, 0x10, 0x1D, 0x3E, 0x33, 0x24, 0x29, 0x62, 0x6F, 0x78, 0x75, 0x56, 0x5B, 0x4C, 0x41,
0x61, 0x6C, 0x7B, 0x76, 0x55, 0x58, 0x4F, 0x42, 0x09, 0x04, 0x13, 0x1E, 0x3D, 0x30, 0x27, 0x2A,
0xB1, 0xBC, 0xAB, 0xA6, 0x85, 0x88, 0x9F, 0x92, 0xD9, 0xD4, 0xC3, 0xCE, 0xED, 0xE0, 0xF7, 0xFA,
0xB7, 0xBA, 0xAD, 0xA0, 0x83, 0x8E, 0x99, 0x94, 0xDF, 0xD2, 0xC5, 0xC8, 0xEB, 0xE6, 0xF1, 0xFC,
0x67, 0x6A, 0x7D, 0x70, 0x53, 0x5E, 0x49, 0x44, 0x0F, 0x02, 0x15, 0x18, 0x3B, 0x36, 0x21, 0x2C,
0x0C, 0x01, 0x16, 0x1B, 0x38, 0x35, 0x22, 0x2F, 0x64, 0x69, 0x7E, 0x73, 0x50, 0x5D, 0x4A, 0x47,
0xDC, 0xD1, 0xC6, 0xCB, 0xE8, 0xE5, 0xF2, 0xFF, 0xB4, 0xB9, 0xAE, 0xA3, 0x80, 0x8D, 0x9A, 0x97
]
valueEngine3 = [
0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77,
0x90, 0x99, 0x82, 0x8B, 0xB4, 0xBD, 0xA6, 0xAF, 0xD8, 0xD1, 0xCA, 0xC3, 0xFC, 0xF5, 0xEE, 0xE7,
0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, 0x73, 0x7A, 0x61, 0x68, 0x57, 0x5E, 0x45, 0x4C,
0xAB, 0xA2, 0xB9, 0xB0, 0x8F, 0x86, 0x9D, 0x94, 0xE3, 0xEA, 0xF1, 0xF8, 0xC7, 0xCE, 0xD5, 0xDC,
0x76, 0x7F, 0x64, 0x6D, 0x52, 0x5B, 0x40, 0x49, 0x3E, 0x37, 0x2C, 0x25, 0x1A, 0x13, 0x08, 0x01,
0xE6, 0xEF, 0xF4, 0xFD, 0xC2, 0xCB, 0xD0, 0xD9, 0xAE, 0xA7, 0xBC, 0xB5, 0x8A, 0x83, 0x98, 0x91,
0x4D, 0x44, 0x5F, 0x56, 0x69, 0x60, 0x7B, 0x72, 0x05, 0x0C, 0x17, 0x1E, 0x21, 0x28, 0x33, 0x3A,
0xDD, 0xD4, 0xCF, 0xC6, 0xF9, 0xF0, 0xEB, 0xE2, 0x95, 0x9C, 0x87, 0x8E, 0xB1, 0xB8, 0xA3, 0xAA,
0xEC, 0xE5, 0xFE, 0xF7, 0xC8, 0xC1, 0xDA, 0xD3, 0xA4, 0xAD, 0xB6, 0xBF, 0x80, 0x89, 0x92, 0x9B,
0x7C, 0x75, 0x6E, 0x67, 0x58, 0x51, 0x4A, 0x43, 0x34, 0x3D, 0x26, 0x2F, 0x10, 0x19, 0x02, 0x0B,
0xD7, 0xDE, 0xC5, 0xCC, 0xF3, 0xFA, 0xE1, 0xE8, 0x9F, 0x96, 0x8D, 0x84, 0xBB, 0xB2, 0xA9, 0xA0,
0x47, 0x4E, 0x55, 0x5C, 0x63, 0x6A, 0x71, 0x78, 0x0F, 0x06, 0x1D, 0x14, 0x2B, 0x22, 0x39, 0x30,
0x9A, 0x93, 0x88, 0x81, 0xBE, 0xB7, 0xAC, 0xA5, 0xD2, 0xDB, 0xC0, 0xC9, 0xF6, 0xFF, 0xE4, 0xED,
0x0A, 0x03, 0x18, 0x11, 0x2E, 0x27, 0x3C, 0x35, 0x42, 0x4B, 0x50, 0x59, 0x66, 0x6F, 0x74, 0x7D,
0xA1, 0xA8, 0xB3, 0xBA, 0x85, 0x8C, 0x97, 0x9E, 0xE9, 0xE0, 0xFB, 0xF2, 0xCD, 0xC4, 0xDF, 0xD6,
0x31, 0x38, 0x23, 0x2A, 0x15, 0x1C, 0x07, 0x0E, 0x79, 0x70, 0x6B, 0x62, 0x5D, 0x54, 0x4F, 0x46
]
valueEngine4 = [
0x00, 0x0B, 0x16, 0x1D, 0x2C, 0x27, 0x3A, 0x31, 0x58, 0x53, 0x4E, 0x45, 0x74, 0x7F, 0x62, 0x69,
0xB0, 0xBB, 0xA6, 0xAD, 0x9C, 0x97, 0x8A, 0x81, 0xE8, 0xE3, 0xFE, 0xF5, 0xC4, 0xCF, 0xD2, 0xD9,
0x7B, 0x70, 0x6D, 0x66, 0x57, 0x5C, 0x41, 0x4A, 0x23, 0x28, 0x35, 0x3E, 0x0F, 0x04, 0x19, 0x12,
0xCB, 0xC0, 0xDD, 0xD6, 0xE7, 0xEC, 0xF1, 0xFA, 0x93, 0x98, 0x85, 0x8E, 0xBF, 0xB4, 0xA9, 0xA2,
0xF6, 0xFD, 0xE0, 0xEB, 0xDA, 0xD1, 0xCC, 0xC7, 0xAE, 0xA5, 0xB8, 0xB3, 0x82, 0x89, 0x94, 0x9F,
0x46, 0x4D, 0x50, 0x5B, 0x6A, 0x61, 0x7C, 0x77, 0x1E, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2F,
0x8D, 0x86, 0x9B, 0x90, 0xA1, 0xAA, 0xB7, 0xBC, 0xD5, 0xDE, 0xC3, 0xC8, 0xF9, 0xF2, 0xEF, 0xE4,
0x3D, 0x36, 0x2B, 0x20, 0x11, 0x1A, 0x07, 0x0C, 0x65, 0x6E, 0x73, 0x78, 0x49, 0x42, 0x5F, 0x54,
0xF7, 0xFC, 0xE1, 0xEA, 0xDB, 0xD0, 0xCD, 0xC6, 0xAF, 0xA4, 0xB9, 0xB2, 0x83, 0x88, 0x95, 0x9E,
0x47, 0x4C, 0x51, 0x5A, 0x6B, 0x60, 0x7D, 0x76, 0x1F, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2E,
0x8C, 0x87, 0x9A, 0x91, 0xA0, 0xAB, 0xB6, 0xBD, 0xD4, 0xDF, 0xC2, 0xC9, 0xF8, 0xF3, 0xEE, 0xE5,
0x3C, 0x37, 0x2A, 0x21, 0x10, 0x1B, 0x06, 0x0D, 0x64, 0x6F, 0x72, 0x79, 0x48, 0x43, 0x5E, 0x55,
0x01, 0x0A, 0x17, 0x1C, 0x2D, 0x26, 0x3B, 0x30, 0x59, 0x52, 0x4F, 0x44, 0x75, 0x7E, 0x63, 0x68,
0xB1, 0xBA, 0xA7, 0xAC, 0x9D, 0x96, 0x8B, 0x80, 0xE9, 0xE2, 0xFF, 0xF4, 0xC5, 0xCE, 0xD3, 0xD8,
0x7A, 0x71, 0x6C, 0x67, 0x56, 0x5D, 0x40, 0x4B, 0x22, 0x29, 0x34, 0x3F, 0x0E, 0x05, 0x18, 0x13,
0xCA, 0xC1, 0xDC, 0xD7, 0xE6, 0xED, 0xF0, 0xFB, 0x92, 0x99, 0x84, 0x8F, 0xBE, 0xB5, 0xA8, 0xA3
]
valueEngine1 = [(i + offset & 0xFF) for i in valueEngine1]
valueEngine2 = [(i + offset & 0xFF) for i in valueEngine2]
valueEngine3 = [(i + offset & 0xFF) for i in valueEngine3]
valueEngine4 = [(i + offset & 0xFF) for i in valueEngine4]
result = [0] * 16
result[0] = (
valueEngine3[newpass[3]]
^ valueEngine2[newpass[2]]
^ valueEngine4[newpass[1]]
^ valueEngine1[newpass[0]]
)
result[1] = (
valueEngine2[newpass[3]]
^ valueEngine4[newpass[2]]
^ valueEngine1[newpass[1]]
^ valueEngine3[newpass[0]]
)
result[2] = (
valueEngine4[newpass[3]]
^ valueEngine1[newpass[2]]
^ valueEngine3[newpass[1]]
^ valueEngine2[newpass[0]]
)
result[3] = valueEngine1[newpass[3]] ^ (
valueEngine3[newpass[2]]
^ (valueEngine2[newpass[1]] ^ valueEngine4[newpass[0]])
)
result[4] = (
valueEngine3[newpass[7]]
^ valueEngine2[newpass[6]]
^ valueEngine4[newpass[5]]
^ valueEngine1[newpass[4]]
)
result[5] = (
valueEngine2[newpass[7]]
^ valueEngine4[newpass[6]]
^ valueEngine1[newpass[5]]
^ valueEngine3[newpass[4]]
)
result[6] = (
valueEngine4[newpass[7]]
^ valueEngine1[newpass[6]]
^ valueEngine3[newpass[5]]
^ valueEngine2[newpass[4]]
)
result[7] = valueEngine1[newpass[7]] ^ (
valueEngine3[newpass[6]]
^ (valueEngine2[newpass[5]] ^ valueEngine4[newpass[4]])
)
result[8] = (
valueEngine3[newpass[11]]
^ valueEngine2[newpass[10]]
^ valueEngine4[newpass[9]]
^ valueEngine1[newpass[8]]
)
result[9] = (
valueEngine2[newpass[11]]
^ valueEngine4[newpass[10]]
^ valueEngine1[newpass[9]]
^ valueEngine3[newpass[8]]
)
result[10] = (
valueEngine4[newpass[11]]
^ valueEngine1[newpass[10]]
^ valueEngine3[newpass[9]]
^ valueEngine2[newpass[8]]
)
result[11] = valueEngine1[newpass[11]] ^ (
valueEngine3[newpass[10]]
^ (valueEngine2[newpass[9]] ^ valueEngine4[newpass[8]])
)
result[12] = (
valueEngine3[newpass[15]]
^ valueEngine2[newpass[14]]
^ valueEngine4[newpass[13]]
^ valueEngine1[newpass[12]]
)
result[13] = (
valueEngine2[newpass[15]]
^ valueEngine4[newpass[14]]
^ valueEngine1[newpass[13]]
^ valueEngine3[newpass[12]]
)
result[14] = (
valueEngine4[newpass[15]]
^ valueEngine1[newpass[14]]
^ valueEngine3[newpass[13]]
^ valueEngine2[newpass[12]]
)
result[15] = (
(valueEngine2[newpass[13]] ^ valueEngine4[newpass[12]])
^ (valueEngine3[newpass[14]])
^ valueEngine1[newpass[15]]
)
for i in range(16):
tmppass[i] = result[i]
tmppass = []
for i in [0, 0x0D, 0xA, 7, 4, 1, 0x0E, 0x0B, 8, 5, 2, 0x0F, 0x0C, 9, 6, 3]:
tmppass.append(result[i])
for i in range(16):
tmp = tmppass[i]
tmp = values3[tmp]
newpass[i] = tmp
count -= 1
##############
# END LOOP #
##############
for i in range(16):
tmp = newpass[i] ^ key[i]
newpass[i] = tmp
decryptSrings += "".join([chr(k) for k in newpass])
T += 1
print("\n\nDecrypted data : \n", decryptSrings)
 
Scripts are available here.
Conclusion
This analysis allowed us to delve into the intricacies of configuration, as well as the processes of data encryption and decryption. Overall, this study highlights the importance of reverse engineering in the context of malware analysis, specifically focusing on a C2 agent. It enables us to dissect queries to the control server and gain a better understanding of the tactics employed by attackers. However, it is crucial that the samples are recovered without damage, and network traffic is adequately monitored to accurately reproduce attack scenarios.
Although this version of Brute Ratel may not be the latest, it's worth noting that some samples of this version are still in circulation, underscoring the relevance of this in-depth analysis.