CTS infected virus restore algorithm to decrypt files

Preface

This is an infectious virus recently encountered. It infects removable devices and exe files in the previous user's directory. The infected files and the virus matrix will first be written into the files, and then the original files will be encrypted and the infection marks and encrypted secrets will be encrypted. The key is stored together on the additional data. In this regard, I decided to analyze the algorithm to restore the file.

Sample information

名称:CTS.exe
SHA1:cb54a305a566c00742fb972c4ee62266e880ea78

Brief analysis of the sample

The main function of the sample is very short

Insert picture description here
Insert picture description here

Release the CTS.exe file to the windows directory and the temp directory, and set self-starting

Insert picture description here
Open thread to infect files on removable devices

Insert picture description here
Locally only infect exe files in the current user's directory

Insert picture description here

Determine whether it is an exe file

Obtain a 0x10 bit key to encrypt the file read into the buffer. The virus matrix will first be written into the file, and then the original file will be encrypted and stored together with the infection mark and encryption key on the additional data.

Insert picture description here

Use 010editor to compare the two infected files and find that the first 0x6800 of the two files are the same, and they have the same mark at the end

Insert picture description here

After analysis, the last 0x18 bytes at the end of the file are the logo, file size and key.

Insert picture description here

Encryption algorithm analysis

There are not many encryption algorithms, only less than 100 lines of assembly code

.text:00405060 encrypt_file_buffer proc near           ; CODE XREF: relase_file+55↓p
.text:00405060                                         ; infect_file+74↓p
.text:00405060
.text:00405060 var_109         = byte ptr -109h
.text:00405060 byte_100        = byte ptr -108h
.text:00405060 pe_start_addr   = dword ptr -8
.text:00405060 pe_file_size    = dword ptr -4
.text:00405060 crypt_key       = dword ptr  8
.text:00405060
.text:00405060                 push    ebp
.text:00405061                 mov     ebp, esp
.text:00405063                 sub     esp, 108h
.text:00405069                 mov     [ebp+pe_file_size], edx
.text:0040506C                 mov     [ebp+pe_start_addr], ecx
.text:0040506F                 xor     eax, eax
.text:00405071
.text:00405071 loc_405071:                             ; CODE XREF: encrypt_file_buffer+1E↓j
.text:00405071                 mov     [ebp+eax+byte_100], al
.text:00405078                 inc     eax
.text:00405079                 cmp     eax, 100h
.text:0040507E                 jb      short loc_405071
.text:00405080                 push    ebx
.text:00405081                 mov     ebx, [ebp+crypt_key]
.text:00405084                 push    esi
.text:00405085                 push    edi
.text:00405086                 xor     edi, edi
.text:00405088                 xor     esi, esi
.text:0040508A                 lea     ebx, [ebx+0]
.text:00405090
.text:00405090 loc_405090:                             ; CODE XREF: encrypt_file_buffer+69↓j
.text:00405090                 mov     dl, [ebp+esi+byte_100]
.text:00405097                 mov     eax, esi
.text:00405099                 and     eax, 0Fh       
.text:0040509C                 movzx   ecx, dl
.text:0040509F                 movzx   eax, byte ptr [eax+ebx]
.text:004050A3                 add     edi, eax
.text:004050A5                 add     edi, ecx
.text:004050A7                 and     edi, 0FFh      
.text:004050AD                 inc     esi
.text:004050AE                 mov     al, [ebp+edi+byte_100]
.text:004050B5                 mov     [ebp+esi+var_109], al
.text:004050BC                 mov     [ebp+edi+byte_100], dl
.text:004050C3                 cmp     esi, 100h
.text:004050C9                 jb      short loc_405090
.text:004050CB                 xor     ebx, ebx
.text:004050CD                 xor     esi, esi
.text:004050CF                 xor     edi, edi
.text:004050D1                 cmp     [ebp+pe_file_size], ebx
.text:004050D4                 jbe     short loc_40512D
.text:004050D6
.text:004050D6 loc_4050D6:                             ; CODE XREF: encrypt_file_buffer+CB↓j
.text:004050D6                 inc     esi
.text:004050D7                 and     esi, 0FFh
.text:004050DD                 inc     edi
.text:004050DE                 mov     dl, [ebp+esi+byte_100]
.text:004050E5                 movzx   eax, dl
.text:004050E8                 add     ebx, eax
.text:004050EA                 and     ebx, 0FFh
.text:004050F0                 movzx   eax, [ebp+ebx+byte_100]
.text:004050F8                 mov     [ebp+esi+byte_100], al
.text:004050FF                 mov     [ebp+ebx+byte_100], dl
.text:00405106                 movzx   ecx, [ebp+esi+byte_100]
.text:0040510E                 movzx   eax, dl
.text:00405111                 add     ecx, eax
.text:00405113                 and     ecx, 0FFh
.text:00405119                 movzx   eax, [ebp+ecx+byte_100]
.text:00405121                 mov     ecx, [ebp+pe_start_addr]
.text:00405124                 xor     [edi+ecx-1], al
.text:00405128                 cmp     edi, [ebp+pe_file_size]
.text:0040512B                 jb      short loc_4050D6
.text:0040512D
.text:0040512D loc_40512D:                             ; CODE XREF: encrypt_file_buffer+74↑j
.text:0040512D                 pop     edi
.text:0040512E                 pop     esi
.text:0040512F                 pop     ebx
.text:00405130                 mov     esp, ebp
.text:00405132                 pop     ebp
.text:00405133                 retn    4
.text:00405133 encrypt_file_buffer endp

From the code point of view, there are three loops

First look at the first loop. It is obvious by looking directly at the assembly instructions that you are creating an array with a size of 0x100 bytes and assigning a value from 0x00 to 0xFF.

Insert picture description here

Can be converted into C code

char key_table[256] = {
    
     0 };
for (int i = 0; i < 256; i++)
{
    
    
	key_table[i] = i;
}

The second loop, update the array data

Insert picture description here

The main concern here is who assigns values ​​to the array, just assign values ​​to that part of the array

.text:004050B5                 mov     [ebp+esi+var_109], al
.text:004050BC                 mov     [ebp+edi+byte_100], dl

First of all [ebp+esi+var_109], esi starts from 1, and only increments by 1 each time the loop, so it is key_table[i]

al from key_table[edi]([ebp+edi+byte_100])the withdrawn, edi = (edi + key [ i] + key_table [i]) & 0xFF

dl是key_table[i+1]

Can be converted into C code

int esi = 0;
int edi = 0;
int edx = 0;
int eax = 0;
int ecx = 0;
int ebx = 0;
for (int i = 0; i < 256; i++)
{
    
    
	edx = key_table[esi];
	eax = esi;
	eax = eax & 0xF;
	ecx = edx;
	eax = key[eax];
	edi = (edi + eax + ecx) & 0xFF;
	esi += 1;
	eax = key_table[edi];
	key_table[esi - 1] = eax;
	key_table[edi] = edx;
}

The last loop, XOR encrypted data

Insert picture description here

Again, just focus on the key points

xor     [edi+ecx-1], al

Then get the C code

ebx = 0;
esi = 0;
edi = 0;
for (int i = 0; i < ecrypt_file_size; i++)
{
    
    
	esi += 1;
	esi = esi & 0xFF;
	edi += 1;
	edx = key_table[esi];
	eax = edx;
	ebx = (ebx + eax) & 0xFF;
	eax = key_table[ebx];
	key_table[esi] = eax;
	key_table[ebx] = edx;
	ecx = key_table[esi];
	eax = edx;
	ecx = (ecx + eax) & 0xFF;
	eax = key_table[ecx];
	buffer[0x6800 + edi - 1] = buffer[0x6800 + edi - 1] ^ eax;
}

Therefore, the complete encryption and decryption code is as follows:

void encrypt_file_buffer()
{
    
    
	int esi = 0;
	int edi = 0;
	int edx = 0;
	int eax = 0;
	int ecx = 0;
	int ebx = 0;
	char key_table[256] = {
    
     0 };

	for (int i = 0; i < 256; i++)
	{
    
    
		key_table[i] = i;
	}
	for (int i = 0; i < 256; i++)
	{
    
    
		edx = key_table[esi];
		eax = esi;
		eax = eax & 0xF;
		ecx = edx;
		eax = key[eax];
		edi = (edi + eax + ecx) & 0xFF;
		esi += 1;
		eax = key_table[edi];
		key_table[esi - 1] = eax;
		key_table[edi] = edx;
	}
	ebx = 0;
	esi = 0;
	edi = 0;
	for (int i = 0; i < ecrypt_file_size; i++)
	{
    
    
		esi += 1;
		esi = esi & 0xFF;
		edi += 1;
		edx = key_table[esi];
		eax = edx;
		ebx = (ebx + eax) & 0xFF;
		eax = key_table[ebx];
		key_table[esi] = eax;
		key_table[ebx] = edx;
		ecx = key_table[esi];
		eax = edx;
		ecx = (ecx + eax) & 0xFF;
		eax = key_table[ecx];
		buffer[0x6800 + edi - 1] = buffer[0x6800 + edi - 1] ^ eax;
	}
}

to sum up

Although the written reduction looks a bit convoluted, the algorithm is not difficult. When I first restored the algorithm, I defined the name of the variable in a proper way, and then I mixed the value with the corresponding value. I stumbled and took a long time to write it. Later, I felt that it was really stupid to do so. I directly flattened the previous restoration code. Variables directly correspond to registers, and brainless correspond to assembly. I quickly got it done. Be regarded as a small pit that I stepped on, share it with everyone.

Source code acquisition:
https://github.com/Iam0x17

Guess you like

Origin blog.csdn.net/weixin_44001905/article/details/104325103