VirtualBox

source: vbox/trunk/src/bldprogs/VBoxDef2LazyLoad.cpp@ 46474

Last change on this file since 46474 was 46474, checked in by vboxsync, 11 years ago

VBoxDef2LazyLoad: Added tool for generating lazy loading of VBoxVMM.dll to prevent it being loaded into VBoxSVC and the VM selector.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.9 KB
Line 
1/* $Id: VBoxDef2LazyLoad.cpp 46474 2013-06-10 16:02:12Z vboxsync $ */
2/** @file
3 * VBoxDef2LazyLoad - Lazy Library Loader Generator.
4 */
5
6/*
7 * Copyright (C) 2013 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* Header Files *
20*******************************************************************************/
21#include <ctype.h>
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <iprt/types.h>
26
27
28/*******************************************************************************
29* Structures and Typedefs *
30*******************************************************************************/
31typedef struct MYEXPORT
32{
33 struct MYEXPORT *pNext;
34 bool fNoName;
35 unsigned uOrdinal;
36 char szName[1];
37} MYEXPORT;
38typedef MYEXPORT *PMYEXPORT;
39
40
41
42/*******************************************************************************
43* Global Variables *
44*******************************************************************************/
45/** @name Options
46 * @{ */
47static const char *g_pszOutput = NULL;
48static const char *g_pszInput = NULL;
49static const char *g_pszLibrary = NULL;
50static bool g_fIgnoreData = true;
51/** @} */
52
53/** Pointer to the export name list head. */
54static PMYEXPORT g_pExpHead = NULL;
55/** Pointer to the next pointer for insertion. */
56static PMYEXPORT *g_ppExpNext = &g_pExpHead;
57
58
59
60static const char *leftStrip(const char *psz)
61{
62 while (isspace(*psz))
63 psz++;
64 return psz;
65}
66
67
68static char *leftStrip(char *psz)
69{
70 while (isspace(*psz))
71 psz++;
72 return psz;
73}
74
75
76static unsigned wordLength(const char *pszWord)
77{
78 unsigned off = 0;
79 char ch;
80 while ( (ch = pszWord[off]) != '\0'
81 && ch != '='
82 && ch != ','
83 && ch != ':'
84 && !isspace(ch) )
85 off++;
86 return off;
87}
88
89
90/**
91 * Parses the module definition file, collecting export information.
92 *
93 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
94 * details has been displayed.
95 * @param pInput The input stream.
96 */
97static RTEXITCODE parseInputInner(FILE *pInput)
98{
99 /*
100 * Process the file line-by-line.
101 */
102 bool fInExports = false;
103 unsigned iLine = 0;
104 char szLine[16384];
105 while (fgets(szLine, sizeof(szLine), pInput))
106 {
107 iLine++;
108
109 /*
110 * Strip leading and trailing spaces from the line as well as
111 * trailing comments.
112 */
113 char *psz = leftStrip(szLine);
114 if (*psz == ';')
115 continue; /* comment line. */
116
117 char *pszComment = strchr(psz, ';');
118 if (pszComment)
119 *pszComment = '\0';
120
121 unsigned cch = (unsigned)strlen(psz);
122 while (cch > 0 && (isspace(psz[cch - 1]) || psz[cch - 1] == '\r' || psz[cch - 1] == '\n'))
123 psz[--cch] = '\0';
124
125 if (!cch)
126 continue;
127
128 /*
129 * Check for known directives.
130 */
131 size_t cchWord0 = wordLength(psz);
132#define WORD_CMP(pszWord1, cchWord1, szWord2) \
133 ( (cchWord1) == sizeof(szWord2) - 1 && memcmp(pszWord1, szWord2, sizeof(szWord2) - 1) == 0 )
134fprintf(stderr,"word: %u: cchWord0=%d '%s'\n", iLine, cchWord0, psz);
135 if (WORD_CMP(psz, cchWord0, "EXPORTS"))
136 {
137 fInExports = true;
138
139 /* In case there is an export on the same line. (Really allowed?) */
140 psz = leftStrip(psz + sizeof("EXPORTS") - 1);
141 if (!*psz)
142 continue;
143 }
144 /* Directives that we don't care about, but need to catch in order to
145 terminate the EXPORTS section in a timely manner. */
146 else if ( WORD_CMP(psz, cchWord0, "NAME")
147 || WORD_CMP(psz, cchWord0, "LIBRARY")
148 || WORD_CMP(psz, cchWord0, "DESCRIPTION")
149 || WORD_CMP(psz, cchWord0, "STACKSIZE")
150 || WORD_CMP(psz, cchWord0, "SECTIONS")
151 || WORD_CMP(psz, cchWord0, "SEGMENTS")
152 || WORD_CMP(psz, cchWord0, "VERSION")
153 )
154 {
155 fInExports = false;
156 }
157
158 /*
159 * Process exports:
160 * entryname[=internalname] [@ordinal[ ][NONAME]] [DATA] [PRIVATE]
161 */
162 if (fInExports)
163 {
164 const char *pchName = psz;
165 unsigned cchName = wordLength(psz);
166
167 psz = leftStrip(psz + cchName);
168 if (*psz == '=')
169 {
170 psz = leftStrip(psz + 1);
171 psz = leftStrip(psz + wordLength(psz));
172 }
173
174 bool fNoName = true;
175 unsigned uOrdinal = ~0U;
176 if (*psz == '@')
177 {
178 psz++;
179 if (!isdigit(*psz))
180 {
181 fprintf(stderr, "%s:%u: error: Invalid ordinal spec.\n", g_pszInput, iLine);
182 return RTEXITCODE_FAILURE;
183 }
184 uOrdinal = *psz++ - '0';
185 while (isdigit(*psz))
186 {
187 uOrdinal *= 10;
188 uOrdinal += *psz++ - '0';
189 }
190 psz = leftStrip(psz);
191 cch = wordLength(psz);
192 if (WORD_CMP(psz, cch, "NONAME"))
193 {
194#if 0
195 fNoName = true;
196 psz = leftStrip(psz + cch);
197#else
198 fprintf(stderr, "%s:%u: error: NONAME export not implemented.\n", g_pszInput, iLine);
199 return RTEXITCODE_FAILURE;
200#endif
201 }
202 }
203
204 while (*psz)
205 {
206 cch = wordLength(psz);
207 if (WORD_CMP(psz, cch, "DATA"))
208 {
209 if (!g_fIgnoreData)
210 {
211 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
212 g_pszInput, iLine, cchName, pchName);
213 return RTEXITCODE_SUCCESS;
214 }
215 }
216 else if (!WORD_CMP(psz, cch, "PRIVATE"))
217 {
218 fprintf(stderr, "%s:%u: error: Cannot wrap up DATA export '%.*s'.\n",
219 g_pszInput, iLine, cchName, pchName);
220 return RTEXITCODE_SUCCESS;
221 }
222 psz = leftStrip(psz + cch);
223 }
224
225 /*
226 * Add the export.
227 */
228 PMYEXPORT pExp = (PMYEXPORT)malloc(sizeof(*pExp) + cchName);
229 if (!pExp)
230 {
231 fprintf(stderr, "%s:%u: error: Out of memory.\n", g_pszInput, iLine);
232 return RTEXITCODE_SUCCESS;
233 }
234 memcpy(pExp->szName, pchName, cchName);
235 pExp->szName[cchName] = '\0';
236 pExp->uOrdinal = uOrdinal;
237 pExp->fNoName = fNoName;
238 pExp->pNext = NULL;
239 *g_ppExpNext = pExp;
240 g_ppExpNext = &pExp->pNext;
241 }
242 }
243
244 /*
245 * Why did we quit the loop, EOF or error?
246 */
247 if (feof(pInput))
248 return RTEXITCODE_SUCCESS;
249 fprintf(stderr, "error: Read while reading '%s' (iLine=%u).\n", g_pszInput, iLine);
250 return RTEXITCODE_FAILURE;
251}
252
253
254/**
255 * Parses g_pszInput, populating the list pointed to by g_pExpHead.
256 *
257 * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE, in the latter case full
258 * details has been displayed.
259 */
260static RTEXITCODE parseInput(void)
261{
262 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
263 FILE *pInput = fopen(g_pszInput, "r");
264 if (pInput)
265 {
266 rcExit = parseInputInner(pInput);
267 fclose(pInput);
268 if (rcExit == RTEXITCODE_SUCCESS && !g_pExpHead)
269 {
270 fprintf(stderr, "error: Found no exports in '%s'.\n", g_pszInput);
271 rcExit = RTEXITCODE_FAILURE;
272 }
273 }
274 else
275 fprintf(stderr, "error: Failed to open '%s' for reading.\n", g_pszInput);
276 return rcExit;
277}
278
279
280static RTEXITCODE generateOutputInner(FILE *pOutput)
281{
282 fprintf(pOutput,
283 ";; Autogenerated from '%s'. DO NOT EDIT!\n"
284 "\n"
285 "%%include \"iprt/asmdefs.mac\"\n"
286 "\n"
287 "BEGINCODE\n",
288 g_pszInput);
289
290 for (PMYEXPORT pExp = g_pExpHead; pExp; pExp = pExp->pNext)
291 {
292 fprintf(pOutput,
293 "BEGINDATA\n"
294 "%%ifdef ASM_FORMAT_PE\n"
295 "global __imp_%s\n"
296 "__imp_%s:\n"
297 "%%endif\n"
298 "g_pfn%s RTCCPTR_DEF ___LazyLoad___%s\n"
299 "BEGINCODE\n"
300 "BEGINPROC %s\n"
301 " jmp RTCCPTR_PRE [g_pfn%s xWrtRIP]\n"
302 "ENDPROC %s\n"
303 "___LazyLoad___%s:\n"
304 /* "int3\n" */
305 "%%ifdef RT_ARCH_AMD64\n"
306 " lea rax, [.szName wrt rip]\n"
307 " lea r10, [g_pfn%s wrt rip]\n"
308 "%%elifdef RT_ARCH_X86\n"
309 " push .szName\n"
310 " push g_pfn%s\n"
311 "%%else\n"
312 " %%error \"Unsupported architecture\"\n"
313 "%%endif\n"
314 " call NAME(LazyLoadResolver)\n"
315 "%%ifdef RT_ARCH_X86\n"
316 " add esp, 8h\n"
317 "%%endif\n"
318 " jmp NAME(%s)\n"
319 ".szName db '%s',0\n"
320 "\n"
321 ,
322 pExp->szName,
323 pExp->szName,
324 pExp->szName, pExp->szName,
325 pExp->szName,
326 pExp->szName,
327 pExp->szName,
328 pExp->szName,
329 pExp->szName,
330 pExp->szName,
331 pExp->szName,
332 pExp->szName);
333 }
334
335 /*
336 * The code that does the loading and resolving.
337 */
338 fprintf(pOutput,
339 "BEGINDATA\n"
340 "g_hMod RTCCPTR_DEF 0\n"
341 "\n"
342 "BEGINCODE\n");
343
344 /*
345 * How we load the module needs to be selectable later on.
346 *
347 * The LazyLoading routine returns the module handle in RCX/ECX, caller
348 * saved all necessary registers.
349 */
350 fprintf(pOutput,
351 ";\n"
352 ";SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, \n"
353 "; uint32_t fFlags, PRTERRINFO pErrInfo);\n"
354 ";\n"
355 "extern IMPNAME(SUPR3HardenedLdrLoadAppPriv)\n"
356 "\n"
357 "BEGINPROC LazyLoading\n"
358 " mov xCX, [g_hMod xWrtRIP]\n"
359 " or xCX, xCX\n"
360 " jnz .return\n"
361 "\n"
362 "%%ifdef ASM_CALL64_GCC\n"
363 " xor rcx, rcx ; pErrInfo (local load)\n"
364 " xor rdx, rdx ; fFlags (local load)\n"
365 " lea rsi, [g_hMod wrt rip] ; phLdrMod\n"
366 " lea rdi, [.szLib wrt rip] ; pszFilename\n"
367 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
368 "\n"
369 "%%elifdef ASM_CALL64_MSC\n"
370 " xor r9, r9 ; pErrInfo (local load)\n"
371 " xor r8, r8 ; fFlags (local load)\n"
372 " lea rdx, [g_hMod wrt rip] ; phLdrMod\n"
373 " lea rcx, [.szLib wrt rip] ; pszFilename\n"
374 " sub rsp, 20h\n"
375 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
376 " add rsp, 20h\n"
377 "\n"
378 "%%elifdef RT_ARCH_X86\n"
379 " push 0 ; pErrInfo\n"
380 " push 0 ; fFlags (local load)\n"
381 " push g_hMod ; phLdrMod\n"
382 " push .szLib ; pszFilename\n"
383 " call IMP2(SUPR3HardenedLdrLoadAppPriv)\n"
384 " add esp, 10h\n"
385 "%%else\n"
386 " %%error \"Unsupported architecture\"\n"
387 "%%endif\n"
388 " or eax, eax\n"
389 " jz .loadok\n"
390 ".badload:\n"
391 " int3\n"
392 " jmp .badload\n"
393 ".loadok:\n"
394 " mov xCX, [g_hMod xWrtRIP]\n"
395 ".return:\n"
396 " ret\n"
397 ".szLib db '%s',0\n"
398 "ENDPROC LazyLoading\n"
399 , g_pszLibrary);
400
401
402 fprintf(pOutput,
403 "\n"
404 ";\n"
405 ";RTDECL(int) RTLdrGetSymbol(RTLDRMOD hLdrMod, const char *pszSymbol, void **ppvValue);\n"
406 ";\n"
407 "extern IMPNAME(RTLdrGetSymbol)\n"
408 "BEGINPROC LazyLoadResolver\n"
409 "%%ifdef RT_ARCH_AMD64\n"
410 " push rbp\n"
411 " mov rbp, rsp\n"
412 " push r15\n"
413 " push r14\n"
414 " mov r15, rax ; name\n"
415 " mov r14, r10 ; ppfn\n"
416 " push r9\n"
417 " push r8\n"
418 " push rcx\n"
419 " push rdx\n"
420 " %%ifdef ASM_CALL64_GCC\n"
421 " push rdi\n"
422 " push rsi\n"
423 " %%else\n"
424 " sub rsp, 20h\n"
425 " %%endif\n"
426 "\n"
427 " call NAME(LazyLoading) ; returns handle in rcx\n"
428 " %%ifdef ASM_CALL64_GCC\n"
429 " mov rdi, rcx ; hLdrMod\n"
430 " mov rsi, r15 ; pszSymbol\n"
431 " mov rdx, r14 ; ppvValue\n"
432 " %%else\n"
433 " mov rdx, r15 ; pszSymbol\n"
434 " mov r8, r14 ; ppvValue\n"
435 " %%endif\n"
436 " call IMP2(RTLdrGetSymbol)\n"
437 " or eax, eax\n"
438 ".badsym:\n"
439 " jz .symok\n"
440 " int3\n"
441 " jmp .badsym\n"
442 ".symok:\n"
443 "\n"
444 " %%ifdef ASM_CALL64_GCC\n"
445 " pop rdi\n"
446 " pop rsi\n"
447 " %%else\n"
448 " add rsp, 20h\n"
449 " %%endif\n"
450 " pop rdx\n"
451 " pop rcx\n"
452 " pop r8\n"
453 " pop r9\n"
454 " pop r14\n"
455 " pop r15\n"
456 " leave\n"
457 "\n"
458 "%%elifdef RT_ARCH_X86\n"
459 " push ebp\n"
460 " mov ebp, esp\n"
461 " push eax\n"
462 " push ecx\n"
463 " push edx\n"
464 "\n"
465 ".loaded:\n"
466 " mov eax, [ebp + 4] ; value addr\n"
467 " push eax\n"
468 " mov edx, [ebp + 8] ; symbol name\n"
469 " push edx\n"
470 " call NAME(LazyLoading) ; returns handle in ecx\n"
471 " mov ecx, [g_hMod]\n"
472 " call IMP2(RTLdrGetSymbol)\n"
473 " add esp, 12\n"
474 " or eax, eax\n"
475 ".badsym:\n"
476 " jz .symok\n"
477 " int3\n"
478 " jmp .badsym\n"
479 ".symok:\n"
480 " pop edx\n"
481 " pop ecx\n"
482 " pop eax\n"
483 " leave\n"
484 "%%else\n"
485 " %%error \"Unsupported architecture\"\n"
486 "%%endif\n"
487 " ret\n"
488 "ENDPROC LazyLoadResolver\n"
489 );
490
491 return RTEXITCODE_SUCCESS;
492}
493
494
495static RTEXITCODE generateOutput(void)
496{
497 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
498 FILE *pOutput = fopen(g_pszOutput, "w");
499 if (pOutput)
500 {
501 rcExit = generateOutputInner(pOutput);
502 if (fclose(pOutput))
503 {
504 fprintf(stderr, "error: Error closing '%s'.\n", g_pszOutput);
505 rcExit = RTEXITCODE_FAILURE;
506 }
507 }
508 else
509 fprintf(stderr, "error: Failed to open '%s' for writing.\n", g_pszOutput);
510 return rcExit;
511}
512
513
514static int usage(const char *pszArgv0)
515{
516 printf("usage: %s --libary <loadname> --output <lazyload.asm> <input.def>\n",
517 "\n"
518 "Copyright (C) 2013 Oracle Corporation\n"
519 , pszArgv0);
520
521 return RTEXITCODE_SUCCESS;
522}
523
524
525int main(int argc, char **argv)
526{
527 /*
528 * Parse options.
529 */
530 for (int i = 1; i < argc; i++)
531 {
532 const char *psz = argv[i];
533 if (*psz == '-')
534 {
535 if (!strcmp(psz, "--output") || !strcmp(psz, "-o"))
536 {
537 if (++i >= argc)
538 {
539 fprintf(stderr, "syntax error: File name expected after '%s'.\n", psz);
540 return RTEXITCODE_SYNTAX;
541 }
542 g_pszOutput = argv[i];
543 }
544 else if (!strcmp(psz, "--library") || !strcmp(psz, "-l"))
545 {
546 if (++i >= argc)
547 {
548 fprintf(stderr, "syntax error: Library name expected after '%s'.\n", psz);
549 return RTEXITCODE_SYNTAX;
550 }
551 g_pszLibrary = argv[i];
552 }
553 else if ( !strcmp(psz, "--help")
554 || !strcmp(psz, "-help")
555 || !strcmp(psz, "-h")
556 || !strcmp(psz, "-?") )
557 return usage(argv[0]);
558 else if ( !strcmp(psz, "--version")
559 || !strcmp(psz, "-V"))
560 {
561 printf("$Revision: 46474 $\n");
562 return RTEXITCODE_SUCCESS;
563 }
564 else
565 {
566 fprintf(stderr, "syntax error: Unknown option '%s'.\n", psz);
567 return RTEXITCODE_SYNTAX;
568 }
569
570 }
571 else
572 {
573 if (g_pszInput)
574 {
575 fprintf(stderr, "syntax error: Already specified '%s' as the input file.\n", g_pszInput);
576 return RTEXITCODE_SYNTAX;
577 }
578 g_pszInput = argv[i];
579 }
580 }
581 if (!g_pszInput)
582 {
583 fprintf(stderr, "syntax error: No input file specified.\n");
584 return RTEXITCODE_SYNTAX;
585 }
586 if (!g_pszOutput)
587 {
588 fprintf(stderr, "syntax error: No output file specified.\n");
589 return RTEXITCODE_SYNTAX;
590 }
591 if (!g_pszLibrary)
592 {
593 fprintf(stderr, "syntax error: No library name specified.\n");
594 return RTEXITCODE_SYNTAX;
595 }
596
597 /*
598 * Do the job.
599 */
600 RTEXITCODE rcExit = parseInput();
601 if (rcExit == RTEXITCODE_SUCCESS)
602 rcExit = generateOutput();
603 return rcExit;
604}
605
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