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: Alberto Wu, Michal 'GiM' Spadlinski
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 #if HAVE_CONFIG_H
23 #include "clamav-config.h"
24 #endif
25 
26 #include "clamav.h"
27 #include "others.h"
28 #include "execs.h"
29 #include "pe.h"
30 #include "packlibs.h"
31 
doubledl(const char ** scur,uint8_t * mydlptr,const char * buffer,uint32_t buffersize)32 static int doubledl(const char **scur, uint8_t *mydlptr, const char *buffer, uint32_t buffersize)
33 {
34     unsigned char mydl  = *mydlptr;
35     unsigned char olddl = mydl;
36 
37     mydl *= 2;
38     if (!(olddl & 0x7f)) {
39         if (*scur < buffer || *scur >= buffer + buffersize - 1)
40             return -1;
41         olddl = **scur;
42         mydl  = olddl * 2 + 1;
43         *scur = *scur + 1;
44     }
45     *mydlptr = mydl;
46     return (olddl >> 7) & 1;
47 }
48 
cli_unfsg(const char * source,char * dest,int ssize,int dsize,const char ** endsrc,char ** enddst)49 int cli_unfsg(const char *source, char *dest, int ssize, int dsize, const char **endsrc, char **enddst)
50 {
51     uint8_t mydl = 0x80;
52     uint32_t backbytes, backsize, oldback = 0;
53     const char *csrc = source;
54     char *cdst       = dest;
55     int oob, lostbit = 1;
56 
57     if (ssize <= 0 || dsize <= 0) return -1;
58     *cdst++ = *csrc++;
59 
60     while (1) {
61         if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
62             if (oob == -1)
63                 return -1;
64             /* 164 */
65             backsize = 0;
66             if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
67                 if (oob == -1)
68                     return -1;
69                 /* 16a */
70                 backbytes = 0;
71                 if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
72                     if (oob == -1)
73                         return -1;
74                     /* 170 */
75                     lostbit = 1;
76                     backsize++;
77                     backbytes = 0x10;
78                     while (backbytes < 0x100) {
79                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
80                             return -1;
81                         backbytes = backbytes * 2 + oob;
82                     }
83                     backbytes &= 0xff;
84                     if (!backbytes) {
85                         if (cdst >= dest + dsize)
86                             return -1;
87                         *cdst++ = 0x00;
88                         continue;
89                     }
90                 } else {
91                     /* 18f */
92                     if (csrc >= source + ssize)
93                         return -1;
94                     backbytes = *(unsigned char *)csrc;
95                     backsize  = backsize * 2 + (backbytes & 1);
96                     backbytes = (backbytes & 0xff) >> 1;
97                     csrc++;
98                     if (!backbytes)
99                         break;
100                     backsize += 2;
101                     oldback = backbytes;
102                     lostbit = 0;
103                 }
104             } else {
105                 /* 180 */
106                 backsize = 1;
107                 do {
108                     if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
109                         return -1;
110                     backsize = backsize * 2 + oob;
111                     if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
112                         return -1;
113                 } while (oob);
114 
115                 backsize = backsize - 1 - lostbit;
116                 if (!backsize) {
117                     /* 18a */
118                     backsize = 1;
119                     do {
120                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
121                             return -1;
122                         backsize = backsize * 2 + oob;
123                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
124                             return -1;
125                     } while (oob);
126 
127                     backbytes = oldback;
128                 } else {
129                     /* 198 */
130                     if (csrc >= source + ssize)
131                         return -1;
132                     backbytes = *(unsigned char *)csrc;
133                     backbytes += (backsize - 1) << 8;
134                     backsize = 1;
135                     csrc++;
136                     do {
137                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
138                             return -1;
139                         backsize = backsize * 2 + oob;
140                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
141                             return -1;
142                     } while (oob);
143 
144                     if (backbytes >= 0x7d00)
145                         backsize++;
146                     if (backbytes >= 0x500)
147                         backsize++;
148                     if (backbytes <= 0x7f)
149                         backsize += 2;
150 
151                     oldback = backbytes;
152                 }
153                 lostbit = 0;
154             }
155             if (!CLI_ISCONTAINED(dest, dsize, cdst, backsize) || !CLI_ISCONTAINED(dest, dsize, cdst - backbytes, backsize))
156                 return -1;
157             while (backsize--) {
158                 *cdst = *(cdst - backbytes);
159                 cdst++;
160             }
161 
162         } else {
163             /* 15d */
164             if (cdst < dest || cdst >= dest + dsize || csrc < source || csrc >= source + ssize)
165                 return -1;
166             *cdst++ = *csrc++;
167             lostbit = 1;
168         }
169     }
170 
171     if (endsrc) *endsrc = csrc;
172     if (enddst) *enddst = cdst;
173     return 0;
174 }
175 
unmew(const char * source,char * dest,int ssize,int dsize,const char ** endsrc,char ** enddst)176 int unmew(const char *source, char *dest, int ssize, int dsize, const char **endsrc, char **enddst)
177 {
178     uint8_t mydl = 0x80;
179     uint32_t myeax_backbytes, myecx_backsize, oldback = 0;
180     const char *csrc = source;
181     char *cdst       = dest;
182     int oob, lostbit = 1;
183 
184     *cdst++ = *csrc++;
185 
186     while (1) {
187         if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
188             if (oob == -1)
189                 return -1;
190             /* 164 */
191             myecx_backsize = 0;
192             if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
193                 if (oob == -1)
194                     return -1;
195                 /* 16a */
196                 myeax_backbytes = 0;
197                 if ((oob = doubledl(&csrc, &mydl, source, ssize))) {
198                     if (oob == -1)
199                         return -1;
200                     /* 170 */
201                     lostbit = 1;
202                     myecx_backsize++;
203                     myeax_backbytes = 0x10;
204                     while (myeax_backbytes < 0x100) {
205                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
206                             return -1;
207                         myeax_backbytes = myeax_backbytes * 2 + oob;
208                     }
209                     myeax_backbytes &= 0xff;
210                     if (!myeax_backbytes) {
211                         if (cdst >= dest + dsize)
212                             return -1;
213                         *cdst++ = 0x00;
214                         /*cli_dbgmsg("X%02x  ", *(cdst-1)&0xff);*/
215                         continue;
216                     }
217                 } else {
218                     /* 18f */
219                     if (csrc >= source + ssize)
220                         return -1;
221                     myeax_backbytes = *(unsigned char *)csrc;
222                     myecx_backsize  = myecx_backsize * 2 + (myeax_backbytes & 1);
223                     myeax_backbytes = (myeax_backbytes & 0xff) >> 1;
224                     csrc++;
225                     if (!myeax_backbytes) {
226                         /* cli_dbgmsg("\nBREAK \n"); */
227                         break;
228                     }
229                     myecx_backsize += 2;
230                     oldback = myeax_backbytes;
231                     lostbit = 0;
232                 }
233             } else {
234                 /* 180 */
235                 myecx_backsize = 1;
236                 do {
237                     if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
238                         return -1;
239                     myecx_backsize = myecx_backsize * 2 + oob;
240                     if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
241                         return -1;
242                 } while (oob);
243 
244                 myecx_backsize = myecx_backsize - 1 - lostbit;
245                 if (!myecx_backsize) {
246                     /* 18a */
247                     myecx_backsize = 1;
248                     do {
249                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
250                             return -1;
251                         myecx_backsize = myecx_backsize * 2 + oob;
252                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
253                             return -1;
254                     } while (oob);
255 
256                     myeax_backbytes = oldback;
257                 } else {
258                     /* 198 */
259                     if (csrc >= source + ssize)
260                         return -1;
261                     myeax_backbytes = *(unsigned char *)csrc;
262                     myeax_backbytes += (myecx_backsize - 1) << 8;
263                     myecx_backsize = 1;
264                     csrc++;
265                     do {
266                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
267                             return -1;
268                         myecx_backsize = myecx_backsize * 2 + oob;
269                         if ((oob = doubledl(&csrc, &mydl, source, ssize)) == -1)
270                             return -1;
271                     } while (oob);
272 
273                     if (myeax_backbytes >= 0x7d00)
274                         myecx_backsize++;
275                     if (myeax_backbytes >= 0x500)
276                         myecx_backsize++;
277                     if (myeax_backbytes <= 0x7f)
278                         myecx_backsize += 2;
279 
280                     oldback = myeax_backbytes;
281                 }
282                 lostbit = 0;
283             }
284             if (!CLI_ISCONTAINED(dest, dsize, cdst, myecx_backsize) || !CLI_ISCONTAINED(dest, dsize, cdst - myeax_backbytes, myecx_backsize)) {
285                 cli_dbgmsg("MEW: rete: %p %d %p %d %d || %p %d %p %d %d\n", dest, dsize, cdst, myecx_backsize,
286                            CLI_ISCONTAINED(dest, dsize, cdst, myecx_backsize),
287                            dest, dsize, cdst - myeax_backbytes, myecx_backsize,
288                            CLI_ISCONTAINED(dest, dsize, cdst - myeax_backbytes, myecx_backsize));
289                 return -1;
290             }
291             while (myecx_backsize--) {
292                 *cdst = *(cdst - myeax_backbytes);
293                 cdst++;
294             }
295 
296         } else {
297             /* 15d */
298             if (cdst < dest || cdst >= dest + dsize || csrc < source || csrc >= source + ssize) {
299                 cli_dbgmsg("MEW: retf %p %p+%08x=%p, %p %p+%08x=%p\n",
300                            cdst, dest, dsize, dest + dsize, csrc, source, ssize, source + ssize);
301                 return -1;
302             }
303             *cdst++ = *csrc++;
304             /* cli_dbgmsg("Z%02x  ", *(cdst-1)&0xff); */
305             lostbit = 1;
306         }
307     }
308 
309     *endsrc = csrc;
310     *enddst = cdst;
311     return 0;
312 }
313