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