📜 ⬆️ ⬇️

Trojan-Downloader.Win32.Cabby.cemx - Part One - Unpacking

Hi, Habr!

I will say right away: I am not a virus analyst and do not do this activity professionally. I work as a network engineer in one of the companies in the group of companies of three letters. So please do not strictly judge and treat with understanding.

The purpose of this article is not an express analysis of malware in order to write a report on the high-level logic of its work, but an immersion in reverse engineering with the head to enhance its knowledge and experience. Therefore, we will go through the whole unpacking algorithm in detail.
')
I'll warn you right away that there will be a lot of pictures and listings of the disassembled code.

Ready for constructive criticism and I will be glad to your advice on optimizing my thoughts.

In the recent past, a sensible CTB-Locker penetrated our company, which interested our information security service: why didn’t antivirus and web traffic filtering work? What exactly this malware does is well described on the securelist . With this, everything is clear and it makes no sense to re-analyze what is described as well.

In order to understand the causes of the incident, we consider the vector of the spread of this malware.

How it looks from the user's point of view:
  1. I received a letter with the attached .cab archive;
  2. The user opens the archive and runs from it .scr;
  3. A .rtf file opens with incomprehensible and uninteresting data;
  4. The user quietly closes the file and continues to work;
  5. After some time, a CTB-Locker window pops up on the desktop with sad user information.

Decrypt


So, we get from the .cab archive the evil and biting .scr. We open it in Immunity Debugger and, after pressing F9 a couple of times, we get to Entry Point 0x4021C6, without encountering any anti-debugging techniques on the way - this is already good.



Having looked a little bit at a glance and having looked around the import, I did not find anything intelligible and “useful”. Nothing related to networking activities - suggests that something is hidden deeper. Packer?

What PEiD will tell us about this:



No known packer found. In addition, entropy analysis tells us that the file is most likely not packaged. But let's look further ...

Having traced a bit of code, we run into the first memory manipulation. The variables passed to HeapCreate are not particularly cleverly veiled:



Allocated memory size 0x6D0. flOptions = 0x40000, which means that the memory area will be executable. Ok, we are watching the allocated memory section, setting the Memory BP to it on the record, and we find a cycle for decrypting and copying data from the .data section to the allocated memory (by the way, it is located almost immediately after HeapCreate):
00401F4A. 85DB TEST EBX, EBX
00401F4C. 0F84 67010000 JE g_r_pice.004020B9
00401F52. 01C0 ADD EAX, EAX
00401F54. 811D C8404000> SBB DWORD PTR DS: [4040C8], 0CE
00401F5E. 82C4 40 ADD AH, 40
00401F61. 83C8 4A OR EAX, 4A
00401F64. 31F6 XOR ESI, ESI
00401F66. 0B37 OR ESI, DWORD PTR DS: [EDI] <- Download data to decrypt from the body of the virus
00401F68. 18E4 SBB AH, AH
00401F6A. 8315 28414000> ADC DWORD PTR DS: [404128], 33
00401F71. 8115 E6404000> ADC DWORD PTR DS: [4040E6], 0A3
00401F7B. 8315 95404000> ADC DWORD PTR DS: [404095], 25
00401F82. F8 CLC
00401F83. 83D7 04 ADC EDI, 4
00401F86. 34 F0 XOR AL, 0F0
00401F88. 1305 E9404000 ADC EAX, DWORD PTR DS: [4040E9]
00401F8E. 1905 48414000 SBB DWORD PTR DS: [404148], EAX
00401F94. 8335 A2414000> XOR DWORD PTR DS: [4041A2], 2B
00401F9B. 3105 41414000 XOR DWORD PTR DS: [404141], EAX
00401FA1. F8 CLC
00401FA2. 83DE 07 SBB ESI, 7
00401FA5. 8325 E0404000> AND DWORD PTR DS: [4040E0], 6A
00401FAC. 82CC E9 OR AH, FFFFFFE9
00401FAF. 2105 68404000 AND DWORD PTR DS: [404068], EAX
00401FB5. 83C8 EE OR EAX, FFFFFFEE
00401FB8. 83F0 FF XOR EAX, FFFFFFFF
00401FBB. F7DE NEG ESI
00401FBD. 810D 07414000> OR DWORD PTR DS: [404107], 0C2
00401FC7. C705 0D404000> MOV DWORD PTR DS: [40400D], 0B8
00401FD1. 3105 C0404000 XOR DWORD PTR DS: [4040C0], EAX
00401FD7. 83C0 05 ADD EAX, 5
00401FDA. 29D6 SUB ESI, EDX
00401FDC. 11C0 ADC EAX, EAX
00401FDE. 1305 2D414000 ADC EAX, DWORD PTR DS: [40412D]
00401FE4. 83E8 2B SUB EAX, 2B
00401FE7. 1305 29404000 ADC EAX, DWORD PTR DS: [404029]
00401FED. 83D8 3E SBB EAX, 3E
00401FF0. 822D BA404000> SUB BYTE PTR DS: [4040BA], - 79
00401FF7. F8 CLC
00401FF8. 83D6 01 ADC ESI, 1
00401FFB. 83F0 B7 XOR EAX, FFFFFFB7
00401FFE. 3105 4E414000 XOR DWORD PTR DS: [40414E], EAX
00402004. 810D ED404000> OR DWORD PTR DS: [4040ED], 0A5
0040200E. 31C0 XOR EAX, EAX
00402010. 31C0 XOR EAX, EAX
00402012. 29D2 SUB EDX, EDX
00402014. 29F2 SUB EDX, ESI
00402016. F7DA NEG EDX
00402018. 31C0 XOR EAX, EAX
0040201A. 8335 DE414000> XOR DWORD PTR DS: [4041DE], 64
00402021. 3105 66404000 XOR DWORD PTR DS: [404066], EAX
00402027. 31C0 XOR EAX, EAX
00402029. 83D0 CC ADC EAX, -34
0040202C. 2B05 33414000 SUB EAX, DWORD PTR DS: [404133]
00402032. C1C2 03 ROL EDX, 3
00402035. 1305 4D404000 ADC EAX, DWORD PTR DS: [40404D]
0040203B. 11C0 ADC EAX, EAX
0040203D. 83C8 B4 OR EAX, FFFFFFB4
00402040. 19C0 SBB EAX, EAX
00402042. C1C2 05 ROL EDX, 5
00402045. 0105 4B404000 ADD DWORD PTR DS: [40404B], EAX
0040204B. 2B05 3C404000 SUB EAX, DWORD PTR DS: [40403C]
00402051. 1305 B0404000 ADC EAX, DWORD PTR DS: [4040B0]
00402057. C705 C4404000> MOV DWORD PTR DS: [4040C4], 0B9
00402061. 56 PUSH ESI
00402062. 8F01 POP DWORD PTR DS: [ECX] <- Saving to Allocated Memory
00402064. 83E0 0E AND EAX, 0E
00402067. 1905 F8414000 SBB DWORD PTR DS: [4041F8], EAX
0040206D. 2905 45404000 SUB DWORD PTR DS: [404045], EAX
00402073. A3 8F404000 MOV DWORD PTR DS: [40408F], EAX
00402078. A3 AF404000 MOV DWORD PTR DS: [4040AF], EAX
0040207D. 83C1 04 ADD ECX, 4
00402080. 2905 18414000 SUB DWORD PTR DS: [404118], EAX
00402086. 19C0 SBB EAX, EAX
00402088. 83D0 D9 ADC EAX, -27
0040208B. 0905 3C404000 OR DWORD PTR DS: [40403C], EAX
00402091. 19C0 SBB EAX, EAX
00402093. 8D5B FC LEA EBX, DWORD PTR DS: [EBX-4]
00402096. 83D8 12 SBB EAX, 12
00402099. 2105 15414000 AND DWORD PTR DS: [404115], EAX
0040209F. C705 AE414000> MOV DWORD PTR DS: [4041AE], 33
004020A9. C705 18404000> MOV DWORD PTR DS: [404018], 0DA
004020B3. 68 4A1F4000 PUSH g_r_pice.00401F4A
004020B8. C3 RETN


We tell the debugger to disassemble the target memory area and get the expected result - quite the executable code:



The transition to the decoded code did not take long:



At the very beginning we find an interesting method for passing parameters to procedures. Consider the example of the first such function. As you can see, the LoadLibrary function is called, to which you need to transfer a string variable of the library name for loading.
02120000 8B7424 04 MOV ESI, DWORD PTR SS: [ESP + 4]
02120004 55 PUSH EBP
02120005 E8 DF010000 CALL 021201E9
0212000A 58 POP EAX
0212000B 50 PUSH EAX
0212000C FFD6 CALL ESI; kernel32.LoadLibraryA

Before this function, the procedure “CALL 021001E9” is called. This is what it is:
021201E9 58 POP EAX; 0210000A
021201EA FFD0 CALL EAX

What happens at this moment? When “CALL 021001E9” is called, the address of the instruction after this call to return from the procedure is placed on the stack. After the call, the return address is retrieved from the stack and placed in EAX. Next, the call "CALL EAX", which in turn pushes the address of the next instruction to return to the stack. We look in the dump - we see the name of the library:



Further on listing such method is encountered more than once.

The next interesting point is the procedure for finding the necessary functions from the connected library. Among the parameters passed to the procedure is a pointer to an incomprehensible set of bytes obtained by the method described above, then we will understand why and what it is. So, the procedure itself:
0212034B 60 PUSHAD
0212034C EB 07 JMP SHORT 02120355
0212034E AD LODS DWORD PTR DS: [ESI] <- Algorithm for traversing DLL headers to search export table
0212034F ^ E2 FD LOOPD SHORT 0212034E
02120351 8D3403 LEA ESI, DWORD PTR DS: [EBX + EAX]
02120354 C3 RETN
02120355 8BE8 MOV EBP, EAX
02120357 8BF3 MOV ESI, EBX
02120359 B9 10,000,000 MOV ECX, 10
0212035E E8 EBFFFFFF CALL 0212034E
02120363 B9 1F000000 MOV ECX, 1F
02120368 E8 E1FFFFFF CALL 0212034E
0212036D 56 PUSH ESI
0212036E B9 07000000 MOV ECX, 7
02120373 E8 D6FFFFFF CALL 0212034E
02120378 8BD0 MOV EDX, EAX
0212037A 8B3424 MOV ESI, DWORD PTR SS: [ESP]
0212037D B9 09000000 MOV ECX, 9
02120382 E8 C7FFFFFF CALL 0212034E
02120387 8BFE MOV EDI, ESI
02120389 8BCA MOV ECX, EDX
0212038B E8 BEFFFFFF CALL 0212034E
02120390 33C0 XOR EAX, EAX
02120392 50 PUSH EAX
02120393 C1C8 07 ROR EAX, 7 <- Calculation of a hash sum on behalf of a function from the DLL export table
02120396 C10424 0D ROL DWORD PTR SS: [ESP], 0D
0212039A 010424 ADD DWORD PTR SS: [ESP], EAX
0212039D AC LODS BYTE PTR DS: [ESI]
0212039E 84C0 TEST AL, AL
021203A0 ^ 75 F1 JNZ SHORT 02120393
021203A2 58 POP EAX
021203A3 8BF7 MOV ESI, EDI
021203A5 3BC5 CMP EAX, EBP <- Comparing the resulting hash sum with the value in memory
021203A7 74 03 JE SHORT 021203AC
021203A9 4A DEC EDX
021203AA ^ 75 DD JNZ SHORT 02120389
021203AC 8B3424 MOV ESI, DWORD PTR SS: [ESP] <- If the hash matches, then the address of the desired function is searched for and returned.
021203AF B9 0A000000 MOV ECX, 0A
021203B4 E8 95FFFFFF CALL 0212034E
021203B9 0FB70C56 MOVZX ECX, WORD PTR DS: [ESI + EDX * 2]
021203BD 5E POP ESI
021203BE 51 PUSH ECX
021203BF B9 080000 MOV ECX, 8
021203C4 E8 85FFFFFF CALL 0212034E
021203C9 59 POP ECX
021203CA E8 7FFFFFFF CALL 0212034E
021203CF 897424 1C MOV DWORD PTR SS: [ESP + 1C], ESI
021203D3 61 POPAD
021203D4 C3 RETN

Now it is clear that this procedure receives a pointer to a certain hash sum and the address of the DLL in which the function should be searched. Further, the logic in order:
  1. The headers of PE calculate the address of the export table of the target DLL;
  2. The name of each function from the export table is taken and a certain hash sum is calculated;
  3. The coincidence of the calculated hash sum and that obtained in the parameter is checked;
  4. If the hash sums match, the address of the function found is calculated and returned.

As you search for the necessary functions, the original hash sums are rewritten to real addresses:



Then, using GetProcAddress, the addresses of three more functions are found: HeapAlloc, HeapFree, and GetTickCount.
02120039 5F POP EDI
0212003A 83C7 0D ADD EDI, 0D
0212003D 57 PUSH EDI
0212003E 53 PUSH EBX
0212003F FF55 08 Call DWORD PTR SS: [EBP + 8]
02120042 8906 MOV DWORD PTR DS: [ESI], EAX
02120044 83C7 0A ADD EDI, 0A
02120047 57 PUSH EDI
02120048 53 PUSH EBX
02120049 FF55 08 CALL DWORD PTR SS: [EBP + 8]
0212004C 8946 04 MOV DWORD PTR DS: [ESI + 4], EAX
0212004F 83C7 09 ADD EDI, 9
02120052 57 PUSH EDI
02120053 53 PUSH EBX
02120054 FF55 08 CALL DWORD PTR SS: [EBP + 8]; kernel32.GetProcAddress
02120057 8946 08 MOV DWORD PTR DS: [ESI + 8], EAX

Found addresses are added to the end of the already formed array of addresses used by API:



The array of functions used is formed, after which its use begins immediately with the allocation of a new memory area of ​​the same size as last time - 0x6D0:



flProtect = 0x40, which again indicates the possibility of executing code in the allocated memory.
After “VirtualAlloc” we immediately meet the cycle of copying the current memory location to a new one, while saving the return address for the “RETN” to the 0x81 offset:



"RETN" transfers the execution of the code to a new memory area, which looks like this:
00220081 E8 CB050000 CALL 00220651
00220086 5D POP EBP
00220087 5E POP ESI
00220088 873424 XCHG DWORD PTR SS: [ESP], ESI
0022008B 56 PUSH ESI
0022008C E8 2E050000 CALL 002205BF
00220091 E8 6C050000 CALL 00220602

“CALL 00220651” is a procedure already known to us, which in an artful manner returns us the address of an array with the addresses of the restored functions.
"CALL 002205BF" - checks the validity of the process loaded into memory by the signatures "MZ" and "PE".
002205BF 66: 33F6 XOR SI, SI
002205C2 66: BA 4D5A MOV DX, 5A4D
002205C6 66: AD LODS WORD PTR DS: [ESI]
002205C8 66: 33D0 XOR DX, AX
002205CB 74 08 JE SHORT 002205D5
002205CD 81EE 02100000 SUB ESI, 1002
002205D3 ^ EB ED JMP SHORT 002205C2
002205D5 8D5E FE LEA EBX, DWORD PTR DS: [ESI-2]
002205D8 84FF TEST BH, BH
002205DA ^ 75 F1 JNZ SHORT 002205CD
002205DC 8B76 3A MOV ESI, DWORD PTR DS: [ESI + 3A]
002205DF 66: BA 5045 MOV DX, 4550
002205E3 8D341E LEA ESI, DWORD PTR DS: [ESI + EBX]
002205E6 66: AD LODS WORD PTR DS: [ESI]
002205E8 66: 33D0 XOR DX, AX
002205EB ^ 75 E0 JNZ SHORT 002205CD
002205ED C3 RETN

"CALL 00220602" - allocates a new chunk of memory in size 0x2C00 (now read-write only), finds the full name of the file that started the current process and opens the file for reading
00220602 8B7D 70 MOV EDI, DWORD PTR SS: [EBP + 70]; SS: [002206C4] = 00002C00
00220605 6A 04 PUSH 4
00220607 68 00100000 PUSH 1000
0022060C 57 PUSH EDI
0022060D 6A 00 PUSH 0
0022060F FF55 10 CALL DWORD PTR SS: [EBP + 10]; kernel32.VirtualAlloc
00220612 8BF0 MOV ESI, EAX
00220614 81EC 04010000 SUB ESP, 104
0022061A 8BFC MOV EDI, ESP
0022061C 68 04010000 PUSH 104
00220621 57 PUSH EDI
00220622 53 PUSH EBX; 00400000
00220623 FF55 20 CALL DWORD PTR SS: [EBP + 20]; kernel32.GetModuleFileNameA
00220626 6A 00 PUSH 0
00220628 68 80000000 PUSH 80
0022062D 6A 03 PUSH 3
0022062F 6A 00 PUSH 0
00220631 6A 01 PUSH 1
00220633 68 00000080 PUSH 80000000
00220638 57 PUSH EDI
00220639 FF55 24 CALL DWORD PTR SS: [EBP + 24]; kernel32.CreateFileA
0022063C 81C4 04010000 ADD ESP, 104
00220642 C3 RETN


After returning the handle to the open file, the pointer is set at offset 0x6263:
00220096 8BF8 MOV EDI, EAX
00220098 6A 00 PUSH 0
0022009A 6A 00 PUSH 0
0022009C FF75 6C PUSH DWORD PTR SS: [EBP + 6C]; SS: [002206C0] = 00006263
0022009F 57 PUSH EDI
002200A0 FF55 28 CALL DWORD PTR SS: [EBP + 28]; kernel32.SetFilePointer

In the HEX editor, you can see that some data is actually stored on this offset, most likely encrypted:


Reading data from a file of 0x2C00 size at the specified offset into the previously created memory segment:
002200A3 8B4D 70 MOV ECX, DWORD PTR SS: [EBP + 70]; SS: [002206C4] = 00002C00
002200A6 6A 00 PUSH 0
002200A8 54 PUSH ESP
002200A9 58 POP EAX
002200AA FF3424 PUSH DWORD PTR SS: [ESP]; Stack SS: [0018FF28] = 0000005C
002200AD 50 PUSH EAX
002200AE 51 PUSH ECX
002200AF 56 PUSH ESI; 00230000
002200B0 57 PUSH EDI
002200B1 FF55 2C CALL DWORD PTR SS: [EBP + 2C]; kernel32.ReadFile


Next, the decryption procedure for the copied data is called:



I will not show the whole listing of the procedure, here is the decryption cycle:
00220505 3B75 60 CMP ESI, DWORD PTR SS: [EBP + 60]
00220508 75 0D JNZ SHORT 00220517
0022050A 0375 64 ADD ESI, DWORD PTR SS: [EBP + 64]
0022050D 037D 64 ADD EDI, DWORD PTR SS: [EBP + 64]
00220510 2B4D 64 SUB ECX, DWORD PTR SS: [EBP + 64]
00220513 85C9 TEST ECX, ECX
00220515 74 12 JE SHORT 00220529
00220517 AD LODS DWORD PTR DS: [ESI] <- read, decrypt, write
00220518 50 PUSH EAX
00220519 05 224AFE8D ADD EAX, 8DFE4A22
0022051E 0FC8 BSWAP EAX
00220520 33C2 XOR EAX, EDX
00220522 5A POP EDX
00220523 AB STOS DWORD PTR ES: [EDI]
00220524 83E9 03 SUB ECX, 3
00220527 ^ E2 DC LOOPD SHORT 00220505


After decoding in the dump you can see the following picture:



The signatures "MZ" and "PE" suggest that we are close to the goal.

Formation of new headers and sections of the current process.
After decryption, 512 bytes in the ImageBase of the current process are overwritten with the decrypted data (of course, after changing the rights to the target memory area to RW):



The result is that the old headings and section table are rewritten by new ones. As can be seen from the new section table - there will be two sections ".text" and ".rsrc":



Next, go to the following code:
00220101 0349 3C ADD ECX, DWORD PTR DS: [ECX + 3C]
00220104 8D79 18 LEA EDI, DWORD PTR DS: [ECX + 18]
00220107 8B57 20 MOV EDX, DWORD PTR DS: [EDI + 20]
0022010A 0FB741 14 MOVZX EAX, WORD PTR DS: [ECX + 14]
0022010E 03F8 ADD EDI, EAX
00220110 0FB749 06 MOVZX ECX, WORD PTR DS: [ECX + 6]
00220114 60 PUSHAD <- the beginning of the cycle of formation of new sections
00220115 8B47 08 MOV EAX, DWORD PTR DS: [EDI + 8]
00220118 85C0 TEST EAX, EAX
0022011A 74 42 JE SHORT 0022015E
0022011C E8 CD040000 CALL 002205EE
00220121 8BC8 MOV ECX, EAX
00220123 8B47 24 MOV EAX, DWORD PTR DS: [EDI + 24]
00220126 E8 AA020000 CALL 002203D5
0022012B 0377 14 ADD ESI, DWORD PTR DS: [EDI + 14]
0022012E FF77 10 PUSH DWORD PTR DS: [EDI + 10]
00220131 8B7F 0C MOV EDI, DWORD PTR DS: [EDI + C]
00220134 03FB ADD EDI, EBX
00220136 5B POP EBX
00220137 50 PUSH EAX
00220138 8BD4 MOV EDX, ESP
0022013A 52 PUSH EDX
0022013B 50 PUSH EAX
0022013C 51 PUSH ECX
0022013D 57 PUSH EDI
0022013E 51 PUSH ECX
0022013F 52 PUSH EDX
00220140 6A 04 PUSH 4
00220142 51 PUSH ECX
00220143 57 PUSH EDI
00220144 FF55 0C CALL DWORD PTR SS: [EBP + C]
00220147 59 POP ECX
00220148 33C0 XOR EAX, EAX
0022014A 57 PUSH EDI
0022014B F3: AA REP STOS BYTE PTR ES: [EDI] <- reset the main memory area of ​​the process
0022014D 5F POP EDI
0022014E 85F6 TEST ESI, ESI
00220150 74 08 JE SHORT 0022015A
00220152 85DB TEST EBX, EBX
00220154 74 04 JE SHORT 0022015A
00220156 8BCB MOV ECX, EBX
00220158 F3: A4 REP MOVS BYTE PTR ES: [EDI], BYTE PTR DS: [ESI] <- Record New Section
0022015A FF55 0C CALL DWORD PTR SS: [EBP + C]
0022015D 58 POP EAX
0022015E 61 POPAD
0022015F 83C7 28 ADD EDI, 28
00220162 ^ E2 B0 LOOPD SHORT 00220114

At the very beginning, a section table is searched. Next on the cycle is RawData and VirtualSize each section, resetting the main memory sections and writing new sections. Thus, a new “body” of the current process is formed.

Further we meet the procedure call:
00220169 E8 AE000000 CALL 0022021C

It performs IAT (Import Address Table) recovery at the beginning of the ".text" section. The result of the procedure:


Then, the memory is freed in which the data were previously stored to form a new process environment (0x00230000):
002201BD FF55 14 CALL DWORD PTR SS: [EBP + 14]; kernel32.VirtualFree


Come to the epilogue - extract OEP:



And the transition to OEP:



We tell the debugger to analyze the code and get a beautiful and readable listing of the already unpacked downloader, in which the lines used to load the main function module are already distinguishable:



General decryptor logic




  1. Memory allocation with RWE rights, size 0x6D0 (1744 bytes) using HeapCreate. Decryption and copying data from the .data section (0x00408E63 - 0x00409532) to the allocated memory;
  2. Transfer of code execution to zero offset of allocated memory;
  3. Search for necessary API functions and create an array with their addresses at offset 0x654 in the current memory area;
  4. Creating a new section of memory with RWE rights, of the same size 0x6D0 (1744 bytes) using VirtualAlloc. Copying the contents of the current memory to a new one;
  5. Transfer of code execution to a new memory location at offset 0x81 using the “PUSH - RETN” method;
  6. Allocation of a new memory area of ​​0x2C00 (11 264 bytes) with RW rights;
  7. Open source file for reading. Copying data (with file offset 0x6263 - 0x8E62) from a file to a new memory location;
  8. Decryption of copied data;
  9. Formation of a new process environment;
  10. Transition to OEP (0x004019BA).


Process dump


It remains to make a process dump to get the executable unpacked virus file. In order not to do manual fix after a dump, I used the OllyDumpEx plugin for Immunity Debugger:



The resulting executable file at startup has the following structure:



Conclusion


In the course of the work done, they got the unpacked Downloader executable file. Yes, it would be possible to shorten the description, going over the key points of copying and decrypting data and moving to OEP. In combat conditions, when analyzing malware, they rarely understand the decryptor's logic in detail. But let me remind you, the purpose of the article is to immerse in reversing and, as a bonus, understand how malware protectors work.

The goal that I could not achieve in this article is the localization of the main points of the tread, which are responsible for the “deception” of the antivirus emulator. These constructs are certainly present in the decryptor. If someone tells you how to identify them, I will be grateful.

In the second part of the article, we will look at the functional load of the Downloader and how the CTB-Locker cryptographer itself is launched. I do not promise that it will appear the other day, because I am limited in time, and I don’t deny my little experience in this field - I figure out with some points in the course of writing articles, which also takes time.

Source: https://habr.com/ru/post/257413/


All Articles