1 /*
2  *  Copyright (C) 2013-2022 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3  *  Copyright (C) 2007-2013 Sourcefire, Inc.
4  *
5  *  Authors: Ivan Zlatev
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA 02110-1301, USA.
20  */
21 
22 /* Decrypts files, protected by Y0da Cryptor 1.3 */
23 
24 /* aCaB:
25  * 13/01/2006 - merged standalone unpacker into libclamav
26  * 14/01/2006 - major rewrite and bugfix
27  */
28 
29 #include <string.h>
30 
31 #if HAVE_CONFIG_H
32 #include "clamav-config.h"
33 #endif
34 
35 #include "clamav.h"
36 #include "pe.h"
37 #include "others.h"
38 #include "yc.h"
39 
40 #define EC16(x) le16_to_host(x) /* Convert little endian to host */
41 
42 #define DO_HEURISTIC 1
43 
yc_bounds_check(cli_ctx * ctx,char * base,unsigned int filesize,char * offset,unsigned int bound)44 static int yc_bounds_check(cli_ctx *ctx, char *base, unsigned int filesize, char *offset, unsigned int bound)
45 {
46     if ((unsigned int)((offset + bound) - base) > filesize) {
47         cli_dbgmsg("yC: Bounds check assertion.\n");
48 #if DO_HEURISTIC
49         cli_append_virus(ctx, "Heuristics.BoundsCheck");
50 #endif
51         return 1;
52     }
53 
54     return 0;
55 }
56 
57 /* ========================================================================== */
58 /* "Emulates" the poly decryptors */
59 
yc_poly_emulator(cli_ctx * ctx,char * base,unsigned int filesize,char * decryptor_offset,char * code,unsigned int ecx,uint32_t max_emu)60 static int yc_poly_emulator(cli_ctx *ctx, char *base, unsigned int filesize, char *decryptor_offset, char *code, unsigned int ecx, uint32_t max_emu)
61 {
62 
63     /*
64      This is the instruction set of the poly code.
65      Numbers stand for example only.
66 
67      2C 05            SUB AL,5
68      2AC1             SUB AL,CL
69      34 10            XOR AL,10
70      32C1             XOR AL,CL
71      FEC8             DEC AL
72      04 10            ADD AL,10
73      02C1             ADD AL,CL
74      C0C0 06          ROL AL,6
75      C0C8 05          ROR AL,5
76      D2C8             ROR AL,CL
77      D2C0             ROL AL,CL
78 
79   */
80     unsigned char al;
81     unsigned char cl = ecx & 0xff;
82     unsigned int j, i;
83     unsigned int max_jmp_loop = 100000000;
84 
85     for (i = 0; i < ecx && i < max_emu; i++) /* Byte looper - Decrypts every byte and write it back */
86     {
87         if (yc_bounds_check(ctx, base, filesize, code, i)) {
88             return 2;
89         }
90         al = code[i];
91 
92         for (j = 0; j < 0x30; j++) /* Poly Decryptor "Emulator" */
93         {
94             if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
95                 return 2;
96             }
97 
98             switch (decryptor_offset[j]) {
99 
100                 case '\xEB': /* JMP short */
101                     j++;
102                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
103                         return 2;
104                     }
105                     if (!max_jmp_loop)
106                         return 2;
107                     max_jmp_loop--;
108                     j = j + decryptor_offset[j];
109                     break;
110 
111                 case '\xFE': /* DEC  AL */
112                     al--;
113                     j++;
114                     break;
115 
116                 case '\x2A': /* SUB AL,CL */
117                     al = al - cl;
118                     j++;
119                     break;
120 
121                 case '\x02': /* ADD AL,CL */
122                     al = al + cl;
123                     j++;
124                     break;
125                 case '\x32': /* XOR AL,CL */
126                     al = al ^ cl;
127                     j++;
128                     break;
129                     ;
130                 case '\x04': /* ADD AL,num */
131                     j++;
132                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
133                         return 2;
134                     }
135                     al = al + decryptor_offset[j];
136                     break;
137                     ;
138                 case '\x34': /* XOR AL,num */
139                     j++;
140                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
141                         return 2;
142                     }
143                     al = al ^ decryptor_offset[j];
144                     break;
145 
146                 case '\x2C': /* SUB AL,num */
147                     j++;
148                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
149                         return 2;
150                     }
151                     al = al - decryptor_offset[j];
152                     break;
153 
154                 case '\xC0':
155                     j++;
156                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
157                         return 2;
158                     }
159                     if (decryptor_offset[j] == '\xC0') /* ROL AL,num */
160                     {
161                         j++;
162                         if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
163                             return 2;
164                         }
165                         CLI_ROL(al, decryptor_offset[j]);
166                     } else /* ROR AL,num */
167                     {
168                         j++;
169                         if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
170                             return 2;
171                         }
172                         CLI_ROR(al, decryptor_offset[j]);
173                     }
174                     break;
175 
176                 case '\xD2':
177                     j++;
178                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
179                         return 2;
180                     }
181                     if (decryptor_offset[j] == '\xC8') /* ROR AL,CL */
182                     {
183                         j++;
184                         CLI_ROR(al, cl);
185                     } else /* ROL AL,CL */
186                     {
187                         j++;
188                         CLI_ROL(al, cl);
189                     }
190                     break;
191 
192                 case '\x90':
193                 case '\xf8':
194                 case '\xf9':
195                     break;
196 
197                 default:
198                     if (yc_bounds_check(ctx, base, filesize, decryptor_offset, j)) {
199                         return 2;
200                     }
201                     cli_dbgmsg("yC: Unhandled opcode %x\n", (unsigned char)decryptor_offset[j]);
202                     return 1;
203             }
204         }
205         cl--;
206         if (yc_bounds_check(ctx, base, filesize, code, i))
207             return 2;
208         code[i] = al;
209     }
210     return 0;
211 }
212 
213 /* ========================================================================== */
214 /* Main routine which calls all others */
215 
yc_decrypt(cli_ctx * ctx,char * fbuf,unsigned int filesize,struct cli_exe_section * sections,unsigned int sectcount,uint32_t peoffset,int desc,uint32_t ecx,int16_t offset)216 int yc_decrypt(cli_ctx *ctx, char *fbuf, unsigned int filesize, struct cli_exe_section *sections, unsigned int sectcount, uint32_t peoffset, int desc, uint32_t ecx, int16_t offset)
217 {
218     uint32_t ycsect = sections[sectcount].raw + offset;
219     unsigned int i;
220     struct pe_image_file_hdr *pe = (struct pe_image_file_hdr *)(fbuf + peoffset);
221     char *sname                  = (char *)pe + EC16(pe->SizeOfOptionalHeader) + 0x18;
222     uint32_t max_emu;
223     unsigned int ofilesize = filesize;
224     /*
225 
226   First layer (decryptor of the section decryptor) in last section
227 
228   Start offset for analyze: Start of yC Section + 0x93
229   End offset for analyze: Start of yC Section + 0xC3
230   Length to decrypt - ECX = 0xB97
231 
232   */
233     cli_dbgmsg("yC: offset: %x, length: %x\n", offset, ecx);
234     cli_dbgmsg("yC: decrypting decryptor on sect %d\n", sectcount);
235     switch (yc_poly_emulator(ctx, fbuf, filesize, fbuf + ycsect + 0x93, fbuf + ycsect + 0xc6, ecx, ecx)) {
236         case 2:
237             return CL_VIRUS;
238         case 1:
239             return CL_EUNPACK;
240     }
241     filesize -= sections[sectcount].ursz;
242 
243     /*
244 
245   Second layer (decryptor of the sections) in last section
246 
247   Start offset for analyze: Start of yC Section + 0x457
248   End offset for analyze: Start of yC Section + 0x487
249   Length to decrypt - ECX = Raw Size of Section
250 
251   */
252 
253     /* Loop through all sections and decrypt them... */
254     for (i = 0; i < sectcount; i++) {
255         uint32_t name = (uint32_t)cli_readint32(sname + i * 0x28);
256         if (!sections[i].raw ||
257             !sections[i].rsz ||
258             name == 0x63727372 ||     /* rsrc */
259             name == 0x7273722E ||     /* .rsr */
260             name == 0x6F6C6572 ||     /* relo */
261             name == 0x6C65722E ||     /* .rel */
262             name == 0x6164652E ||     /* .eda */
263             name == 0x6164722E ||     /* .rda */
264             name == 0x6164692E ||     /* .ida */
265             name == 0x736C742E ||     /* .tls */
266             (name & 0xffff) == 0x4379 /* yC */
267             ) continue;
268         cli_dbgmsg("yC: decrypting sect%d\n", i);
269         max_emu = filesize - sections[i].raw;
270         if (max_emu > filesize) {
271             cli_dbgmsg("yC: bad emulation length limit %u\n", max_emu);
272             return 1;
273         }
274         switch (yc_poly_emulator(ctx, fbuf, ofilesize, fbuf + ycsect + (offset == -0x18 ? 0x3ea : 0x457),
275                                  fbuf + sections[i].raw,
276                                  sections[i].ursz,
277                                  max_emu)) {
278             case 2:
279                 return CL_VIRUS;
280             case 1:
281                 return CL_EUNPACK;
282         }
283     }
284 
285     /* Remove yC section */
286     pe->NumberOfSections = EC16(sectcount);
287 
288     /* Remove IMPORT_DIRECTORY information */
289     memset((char *)pe + sizeof(struct pe_image_file_hdr) + 0x68, 0, 8);
290 
291     /* OEP resolving */
292     /* OEP = DWORD PTR [ Start of yC section+ A0F] */
293     cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 16, cli_readint32(fbuf + ycsect + 0xa0f));
294 
295     /* Fix SizeOfImage */
296     cli_writeint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38, cli_readint32((char *)pe + sizeof(struct pe_image_file_hdr) + 0x38) - sections[sectcount].vsz);
297 
298     if (cli_writen(desc, fbuf, filesize) == (size_t)-1) {
299         cli_dbgmsg("yC: Cannot write unpacked file\n");
300         return CL_EUNPACK;
301     }
302     return CL_SUCCESS;
303 }
304