VirtualBox

source: vbox/trunk/src/bldprogs/VBoxCheckImports.cpp@ 59961

Last change on this file since 59961 was 59404, checked in by vboxsync, 9 years ago

Forward-ported r104938, r104943, r104950, r104952, r104953, r104987, r104988, r104990 from 5.0:

  • VBoxStub: Lazy import DLLs not in the KnownDlls list (and then some) and check that we don't accidentally add new imports as time goes by.
  • VBoxStub: the dlls have export names, so use them instead of the ordinals.
  • VBoxDef2LazyLoad fixes and error reporting, fixed missing VBoxCheckImports dependency during use in VBoxStub.
  • iprt/initterm.h,vbox-img,VBoxStub: Introduced RTR3INIT_FLAGS_STANDALONE_APP for statically linked applications that are expected to run outside the normal VirtualBox installation directory and need to be on their toes wrt dynamic library search paths. (Only windows, really.) Also, _always_ initialize IPRT first, don't ever do anything before that unless it 104% must be done there.
  • RTR3INIT_FLAGS_STANDALONE_APP trumps concerns about Vista GUI
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: VBoxCheckImports.cpp 59404 2016-01-19 10:10:39Z vboxsync $ */
2/** @file
3 * IPRT - Checks that a windows image only imports from a given set of DLLs.
4 */
5
6/*
7 * Copyright (C) 2012-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/formats/mz.h>
23#include <iprt/formats/pecoff.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28
29/*********************************************************************************************************************************
30* Structures and Typedefs *
31*********************************************************************************************************************************/
32typedef struct
33{
34 const char *pszImage;
35 FILE *pFile;
36 bool f32Bit;
37 union
38 {
39 IMAGE_NT_HEADERS32 Nt32;
40 IMAGE_NT_HEADERS64 Nt64;
41 } Hdrs;
42
43 uint32_t cSections;
44 PIMAGE_SECTION_HEADER paSections;
45} MYIMAGE;
46
47
48static bool Failed(MYIMAGE *pThis, const char *pszFmt, ...)
49{
50 va_list va;
51 fprintf(stderr, "error '%s': ", pThis->pszImage);
52 va_start(va, pszFmt);
53 vfprintf(stderr, pszFmt, va);
54 va_end(va);
55 fprintf(stderr, "\n");
56 return false;
57}
58
59
60static bool ReadPeHeaders(MYIMAGE *pThis)
61{
62 /*
63 * MZ header.
64 */
65 IMAGE_DOS_HEADER MzHdr;
66 if (fread(&MzHdr, sizeof(MzHdr), 1, pThis->pFile) != 1)
67 return Failed(pThis, "Reading DOS header");
68
69 if (MzHdr.e_magic != IMAGE_DOS_SIGNATURE)
70 return Failed(pThis, "No MZ magic (found %#x)", MzHdr.e_magic);
71
72 if (fseek(pThis->pFile, MzHdr.e_lfanew, SEEK_SET) != 0)
73 return Failed(pThis, "Seeking to %#lx", (unsigned long)MzHdr.e_lfanew);
74
75 /*
76 * NT signature + file header.
77 */
78 if (fread(&pThis->Hdrs.Nt32, offsetof(IMAGE_NT_HEADERS32, OptionalHeader), 1, pThis->pFile) != 1)
79 return Failed(pThis, "Reading NT file header");
80
81 if (pThis->Hdrs.Nt32.Signature != IMAGE_NT_SIGNATURE)
82 return Failed(pThis, "No PE magic (found %#x)", pThis->Hdrs.Nt32.Signature);
83
84 if (pThis->Hdrs.Nt32.FileHeader.SizeOfOptionalHeader == sizeof(pThis->Hdrs.Nt32.OptionalHeader))
85 pThis->f32Bit = true;
86 else if (pThis->Hdrs.Nt32.FileHeader.SizeOfOptionalHeader == sizeof(pThis->Hdrs.Nt64.OptionalHeader))
87 pThis->f32Bit = false;
88 else
89 return Failed(pThis, "Unsupported SizeOfOptionalHeaders value: %#x",
90 pThis->Hdrs.Nt32.FileHeader.SizeOfOptionalHeader);
91
92 /*
93 * NT optional header.
94 */
95 if (fread(&pThis->Hdrs.Nt32.OptionalHeader, pThis->Hdrs.Nt32.FileHeader.SizeOfOptionalHeader, 1, pThis->pFile) != 1)
96 return Failed(pThis, "Reading NT optional header");
97
98 if ( pThis->Hdrs.Nt32.OptionalHeader.Magic
99 != (pThis->f32Bit ? IMAGE_NT_OPTIONAL_HDR32_MAGIC : IMAGE_NT_OPTIONAL_HDR64_MAGIC) )
100 return Failed(pThis, "Bad optional header magic: %#x", pThis->Hdrs.Nt32.OptionalHeader.Magic);
101
102 uint32_t NumberOfRvaAndSizes = pThis->f32Bit
103 ? pThis->Hdrs.Nt32.OptionalHeader.NumberOfRvaAndSizes
104 : pThis->Hdrs.Nt64.OptionalHeader.NumberOfRvaAndSizes;
105 if (NumberOfRvaAndSizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
106 return Failed(pThis, "Unsupported NumberOfRvaAndSizes value: %#x", NumberOfRvaAndSizes);
107
108 /*
109 * Read the section table.
110 */
111 pThis->cSections = pThis->Hdrs.Nt32.FileHeader.NumberOfSections;
112 if (!pThis->cSections)
113 return Failed(pThis, "No sections in image!");
114 pThis->paSections = (PIMAGE_SECTION_HEADER)calloc(sizeof(pThis->paSections[0]), pThis->cSections);
115 if (!pThis->paSections)
116 return Failed(pThis, "Out of memory!");
117 if (fread(pThis->paSections, sizeof(pThis->paSections[0]), pThis->cSections, pThis->pFile) != pThis->cSections)
118 return Failed(pThis, "Reading NT section headers");
119
120
121 return true;
122}
123
124
125static bool ReadAtRva(MYIMAGE *pThis, uint32_t uRva, void *pvBuf, size_t cbToRead)
126{
127 unsigned const uRvaOrg = uRva;
128 size_t const cbToReadOrg = cbToRead;
129
130 /*
131 * Header section.
132 */
133 int iSh = -1;
134 uint32_t uSectRva = 0;
135 uint32_t offSectRaw = 0;
136 uint32_t cbSectRaw = pThis->f32Bit
137 ? pThis->Hdrs.Nt32.OptionalHeader.SizeOfHeaders
138 : pThis->Hdrs.Nt64.OptionalHeader.SizeOfHeaders;
139 uint32_t cbSectMax = pThis->paSections[0].VirtualAddress;
140
141 for (;;)
142 {
143 /* Read if we've got a match. */
144 uint32_t off = uRva - uSectRva;
145 if (off < cbSectMax)
146 {
147 uint32_t cbThis = cbSectMax - off;
148 if (cbThis > cbToRead)
149 cbThis = (uint32_t)cbToRead;
150
151 memset(pvBuf, 0, cbThis);
152
153 if (off < cbSectRaw)
154 {
155 if (fseek(pThis->pFile, offSectRaw + off, SEEK_SET) != 0)
156 return Failed(pThis, "Seeking to %#x", offSectRaw + off);
157 if (fread(pvBuf, RT_MIN(cbThis, cbSectRaw - off), 1, pThis->pFile) != 1)
158 return Failed(pThis, "Reading %u bytes at %#x", RT_MIN(cbThis, cbSectRaw - off), offSectRaw + off);
159 }
160
161 cbToRead -= cbThis;
162 if (!cbToRead)
163 return true;
164 pvBuf = (uint8_t *)pvBuf + cbThis;
165 }
166
167 /* next section */
168 iSh++;
169 if ((unsigned)iSh >= pThis->cSections)
170 return Failed(pThis, "RVA %#x LB %u is outside the image", uRvaOrg, cbToReadOrg);
171 uSectRva = pThis->paSections[iSh].VirtualAddress;
172 offSectRaw = pThis->paSections[iSh].PointerToRawData;
173 cbSectRaw = pThis->paSections[iSh].SizeOfRawData;
174 if ((unsigned)iSh + 1 < pThis->cSections)
175 cbSectMax = pThis->paSections[iSh + 1].VirtualAddress - uSectRva;
176 else
177 cbSectMax = pThis->paSections[iSh].Misc.VirtualSize;
178 }
179}
180
181
182static bool ReadStringAtRva(MYIMAGE *pThis, uint32_t uRva, char *pszBuf, size_t cbMax)
183{
184 uint32_t const uRvaOrg = uRva;
185
186 /*
187 * Try read the whole string at once.
188 */
189 uint32_t cbImage = pThis->f32Bit
190 ? pThis->Hdrs.Nt32.OptionalHeader.SizeOfImage
191 : pThis->Hdrs.Nt64.OptionalHeader.SizeOfImage;
192 uint32_t cbThis = uRva < cbImage ? cbImage - uRva : 1;
193 if (cbThis > cbMax)
194 cbThis = (uint32_t)cbMax;
195 if (!ReadAtRva(pThis, uRva, pszBuf, cbThis))
196 return false;
197 if (memchr(pszBuf, 0, cbThis) != NULL)
198 return true;
199
200 /*
201 * Read more, byte-by-byte.
202 */
203 for (;;)
204 {
205 cbMax -= cbThis;
206 if (!cbMax)
207 return Failed(pThis, "String to long at %#x", uRvaOrg);
208 pszBuf += cbThis;
209 uRva += cbThis;
210
211 cbThis = 1;
212 if (!ReadAtRva(pThis, uRva, pszBuf, cbThis))
213 return false;
214 if (!*pszBuf)
215 return true;
216 }
217}
218
219
220static void *ReadAtRvaAlloc(MYIMAGE *pThis, uint32_t uRva, size_t cbToRead)
221{
222 void *pvBuf = malloc(cbToRead);
223 if (pvBuf)
224 {
225 if (ReadAtRva(pThis, uRva, pvBuf, cbToRead))
226 return pvBuf;
227 free(pvBuf);
228 }
229 else
230 Failed(pThis, "Out of memory!");
231 return NULL;
232}
233
234
235static bool ParseAndCheckImports(MYIMAGE *pThis, const char **papszAllowed, unsigned cAllowed)
236{
237 /*
238 * Do we have an import directory? If so, read it.
239 */
240 IMAGE_DATA_DIRECTORY ImpDir = pThis->f32Bit
241 ? pThis->Hdrs.Nt32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
242 : pThis->Hdrs.Nt64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
243 if (ImpDir.Size == 0)
244 return true;
245
246 uint32_t cImps = ImpDir.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
247 if (cImps * sizeof(IMAGE_IMPORT_DESCRIPTOR) != ImpDir.Size)
248 return Failed(pThis, "Import directory size is not a multiple of IMAGE_IMPORT_DESCRIPTOR: %#x", ImpDir.Size);
249
250 PIMAGE_IMPORT_DESCRIPTOR paImps = (PIMAGE_IMPORT_DESCRIPTOR)ReadAtRvaAlloc(pThis, ImpDir.VirtualAddress, ImpDir.Size);
251 if (!paImps)
252 return false;
253
254 /* There is usually an empty entry at the end. */
255 if ( paImps[cImps - 1].Name == 0
256 || paImps[cImps - 1].FirstThunk == 0)
257 cImps--;
258
259 /*
260 * Do the processing.
261 */
262 bool fRc = true;
263 for (uint32_t i = 0; i < cImps; i++)
264 {
265 /* Read the import name string. */
266 char szName[128];
267 if (!ReadStringAtRva(pThis, paImps[i].Name, szName, sizeof(szName)))
268 {
269 fRc = false;
270 break;
271 }
272
273 /* Check it against the list of allowed DLLs. */
274 bool fFound = false;
275 unsigned j = cAllowed;
276 while (j-- > 0)
277 if (stricmp(papszAllowed[j], szName) == 0)
278 {
279 fFound = true;
280 break;
281 }
282 if (!fFound)
283 fRc = Failed(pThis, "Illegal import: '%s'", szName);
284 }
285
286 free(paImps);
287 return fRc;
288}
289
290
291static int usage(const char *argv0)
292{
293 printf("usage: %s --image <image> [allowed-dll [..]]\n");
294 return RTEXITCODE_SUCCESS;
295}
296
297
298int main(int argc, char **argv)
299{
300 /*
301 * Parse arguments.
302 */
303 const char *pszImage = NULL;
304 const char **papszAllowed = (const char **)calloc(argc, sizeof(const char *));
305 unsigned cAllowed = 0;
306
307 for (int i = 1; i < argc; i++)
308 {
309 const char *psz = argv[i];
310 if (*psz == '-')
311 {
312 if (!strcmp(psz, "--image") || !strcmp(psz, "-i"))
313 {
314 if (++i >= argc)
315 {
316 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
317 return RTEXITCODE_SYNTAX;
318 }
319 pszImage = argv[i];
320 }
321 else if ( !strcmp(psz, "--help")
322 || !strcmp(psz, "-help")
323 || !strcmp(psz, "-h")
324 || !strcmp(psz, "-?") )
325 return usage(argv[0]);
326 else if ( !strcmp(psz, "--version")
327 || !strcmp(psz, "-V"))
328 {
329 printf("$Revision: 59404 $\n");
330 return RTEXITCODE_SUCCESS;
331 }
332 else
333 {
334 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
335 return RTEXITCODE_SYNTAX;
336 }
337 }
338 else
339 papszAllowed[cAllowed++] = argv[i];
340 }
341
342 if (!pszImage)
343 {
344 fprintf(stderr, "syntax error: No input file specified.\n");
345 return RTEXITCODE_SYNTAX;
346 }
347
348 /*
349 * Open the image and process headers.
350 */
351 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
352 MYIMAGE MyImage;
353 memset(&MyImage, 0, sizeof(MyImage));
354 MyImage.pszImage = pszImage;
355 MyImage.pFile = fopen(pszImage, "rb");
356 if (MyImage.pFile)
357 {
358 if ( ReadPeHeaders(&MyImage)
359 && ParseAndCheckImports(&MyImage, papszAllowed, cAllowed))
360 rcExit = RTEXITCODE_SUCCESS;
361
362 fclose(MyImage.pFile);
363 free(MyImage.paSections);
364 }
365 else
366 Failed(&MyImage, "Failed to open image for binary reading.");
367
368 return rcExit;
369}
370
371
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette