Article Directory
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
Release the CTS.exe file to the windows directory and the temp directory, and set self-starting
Open thread to infect files on removable devices
Locally only infect exe files in the current user's directory
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.
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
After analysis, the last 0x18 bytes at the end of the file are the logo, file size and key.
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.
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
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
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