VirtualBox

source: kBuild/trunk/src/kWorker/kWorker.c@ 2832

Last change on this file since 2832 was 2832, checked in by bird, 8 years ago

kWorker: Got cl.exe (2010) going. ~20 faster on a medium 220 lined C++ file.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 72.1 KB
Line 
1/* $Id: kWorker.c 2832 2016-08-19 21:15:32Z bird $ */
2/** @file
3 * kWorker - experimental process reuse worker for Windows.
4 */
5
6/*
7 * Copyright (c) 2016 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26
27/*********************************************************************************************************************************
28* Header Files *
29*********************************************************************************************************************************/
30#include <k/kHlp.h>
31#include <k/kLdr.h>
32
33#include <stdio.h>
34#include <intrin.h>
35#include <setjmp.h>
36
37#include <nt/ntstat.h>
38/* lib/nt_fullpath.c */
39extern void nt_fullpath(const char *pszPath, char *pszFull, size_t cchFull);
40#include <Windows.h>
41#include <winternl.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47typedef enum KWLOCATION
48{
49 KWLOCATION_INVALID = 0,
50 KWLOCATION_EXE_DIR,
51 KWLOCATION_IMPORTER_DIR,
52 KWLOCATION_SYSTEM32,
53 KWLOCATION_UNKNOWN_NATIVE,
54 KWLOCATION_UNKNOWN,
55} KWLOCATION;
56
57typedef enum KWMODSTATE
58{
59 KWMODSTATE_INVALID = 0,
60 KWMODSTATE_NEEDS_BITS,
61 KWMODSTATE_NEEDS_INIT,
62 KWMODSTATE_BEING_INITED,
63 KWMODSTATE_INIT_FAILED,
64 KWMODSTATE_READY,
65} KWMODSTATE;
66
67typedef struct KWMODULE *PKWMODULE;
68typedef struct KWMODULE
69{
70 /** Pointer to the next image. */
71 PKWMODULE pNext;
72 /** The normalized path to the image. */
73 const char *pszPath;
74 /** The hash of the program path. */
75 KU32 uHashPath;
76 /** Number of references. */
77 KU32 cRefs;
78 /** UTF-16 version of pszPath. */
79 const wchar_t *pwszPath;
80 /** The offset of the filename in pszPath. */
81 KU16 offFilename;
82 /** Set if executable. */
83 KBOOL fExe;
84 /** Set if native module entry. */
85 KBOOL fNative;
86 /** Loader module handle. */
87 PKLDRMOD pLdrMod;
88 /** The windows module handle. */
89 HMODULE hOurMod;
90
91 union
92 {
93 /** Data for a manually loaded image. */
94 struct
95 {
96 /** The of the loaded image bits. */
97 size_t cbImage;
98 /** Where we load the image. */
99 void *pvLoad;
100 /** Virgin copy of the image. */
101 void *pvCopy;
102 /** Ldr pvBits argument. This is NULL till we've successfully resolved
103 * the imports. */
104 void *pvBits;
105 /** The state. */
106 KWMODSTATE enmState;
107 /** Number of imported modules. */
108 size_t cImpMods;
109 /** Import array (variable size). */
110 PKWMODULE apImpMods[1];
111 } Manual;
112 } u;
113} KWMODULE;
114
115
116typedef struct KWDYNLOAD *PKWDYNLOAD;
117typedef struct KWDYNLOAD
118{
119 /** Pointer to the next in the list. */
120 PKWDYNLOAD pNext;
121
122 /** The normalized path to the image. */
123 const char *pszPath;
124 /** The module name (within pszPath). */
125 const char *pszModName;
126 /** UTF-16 version of pszPath. */
127 const wchar_t *pwszPath;
128 /** The hash of the path. */
129 KU32 uHashPath;
130
131 /** The module handle we present to the application.
132 * This is the LoadLibraryEx return value for special modules and the
133 * KWMODULE.hOurMod value for the others. */
134 HMODULE hmod;
135
136 /** The module for non-special resource stuff, NULL if special. */
137 PKWMODULE pMod;
138} KWDYNLOAD;
139
140
141typedef enum KWTOOLTYPE
142{
143 KWTOOLTYPE_INVALID = 0,
144 KWTOOLTYPE_SANDBOXED,
145 KWTOOLTYPE_WATCOM,
146 KWTOOLTYPE_EXEC,
147 KWTOOLTYPE_END
148} KWTOOLTYPE;
149
150typedef struct KWTOOL *PKWTOOL;
151typedef struct KWTOOL
152{
153 /** Pointer to the next in the hash collision chain. */
154 PKWTOOL pNext;
155 /** The normalized path to the program. */
156 const char *pszPath;
157 /** The hash of the program path. */
158 KU32 uHashPath;
159 /** The kind of tool. */
160 KWTOOLTYPE enmType;
161 /** UTF-16 version of pszPath. */
162 wchar_t const *pwszPath;
163
164 union
165 {
166 struct
167 {
168 /** The executable. */
169 PKWMODULE pExe;
170 /** List of dynamically loaded modules.
171 * These will be kept loaded till the tool is destroyed (if we ever do that). */
172 PKWDYNLOAD pDynLoadHead;
173 } Sandboxed;
174 } u;
175} KWTOOL;
176
177
178typedef struct KWSANDBOX *PKWSANDBOX;
179typedef struct KWSANDBOX
180{
181 /** The tool currently running in the sandbox. */
182 PKWTOOL pTool;
183 /** Jump buffer. */
184 jmp_buf JmpBuf;
185 /** The thread ID of the main thread (owner of JmpBuf). */
186 DWORD idMainThread;
187 /** Copy of the NT TIB of the main thread. */
188 NT_TIB TibMainThread;
189 /** The exit code in case of longjmp. */
190 int rcExitCode;
191
192 /** The command line. */
193 const char *pszCmdLine;
194 /** The UTF-16 command line. */
195 wchar_t *pwszCmdLine;
196 /** Number of arguments in papszArgs. */
197 int cArgs;
198 /** The argument vector. */
199 char **papszArgs;
200 /** The argument vector. */
201 wchar_t **papwszArgs;
202
203 /** The _pgmptr msvcrt variable. */
204 char *pgmptr;
205 /** The _wpgmptr msvcrt variable. */
206 wchar_t *wpgmptr;
207
208 /** The _initenv msvcrt variable. */
209 char **initenv;
210 /** The _winitenv msvcrt variable. */
211 wchar_t **winitenv;
212
213 /** The _environ msvcrt variable. */
214 char **environ;
215 /** The _wenviron msvcrt variable. */
216 wchar_t **wenviron;
217
218
219 UNICODE_STRING SavedCommandLine;
220} KWSANDBOX;
221
222/** Replacement function entry. */
223typedef struct KWREPLACEMENTFUNCTION
224{
225 /** The function name. */
226 const char *pszFunction;
227 /** The length of the function name. */
228 KSIZE cchFunction;
229 /** The module name (optional). */
230 const char *pszModule;
231 /** The replacement function or data address. */
232 KUPTR pfnReplacement;
233} KWREPLACEMENTFUNCTION;
234typedef KWREPLACEMENTFUNCTION const *PCKWREPLACEMENTFUNCTION;
235
236#if 0
237/** Replacement function entry. */
238typedef struct KWREPLACEMENTDATA
239{
240 /** The function name. */
241 const char *pszFunction;
242 /** The length of the function name. */
243 KSIZE cchFunction;
244 /** The module name (optional). */
245 const char *pszModule;
246 /** Function providing the replacement. */
247 KUPTR (*pfnMakeReplacement)(PKWMODULE pMod, const char *pchSymbol, KSIZE cchSymbol);
248} KWREPLACEMENTDATA;
249typedef KWREPLACEMENTDATA const *PCKWREPLACEMENTDATA;
250#endif
251
252
253/*********************************************************************************************************************************
254* Global Variables *
255*********************************************************************************************************************************/
256/** The sandbox data. */
257static KWSANDBOX g_Sandbox;
258
259/** Module hash table. */
260static PKWMODULE g_apModules[127];
261
262/** Tool hash table. */
263static PKWTOOL g_apTools[63];
264
265static int g_cVerbose = 2;
266
267/* Further down. */
268extern KWREPLACEMENTFUNCTION const g_aSandboxReplacements[];
269extern KU32 const g_cSandboxReplacements;
270
271/** Create a larget BSS blob that with help of /IMAGEBASE:0x10000 should
272 * cover the default executable link address of 0x400000. */
273#pragma section("DefLdBuf", write, execute, read)
274__declspec(allocate("DefLdBuf"))
275static KU8 g_abDefLdBuf[16*1024*1024];
276
277
278
279/*********************************************************************************************************************************
280* Internal Functions *
281*********************************************************************************************************************************/
282static FNKLDRMODGETIMPORT kwLdrModuleGetImportCallback;
283static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod);
284
285
286
287/**
288 * Debug printing.
289 * @param pszFormat Debug format string.
290 * @param ... Format argument.
291 */
292static void kwDbgPrintfV(const char *pszFormat, va_list va)
293{
294 if (g_cVerbose >= 2)
295 {
296 fprintf(stderr, "debug: ");
297 vfprintf(stderr, pszFormat, va);
298 }
299}
300
301
302/**
303 * Debug printing.
304 * @param pszFormat Debug format string.
305 * @param ... Format argument.
306 */
307static void kwDbgPrintf(const char *pszFormat, ...)
308{
309 if (g_cVerbose >= 2)
310 {
311 va_list va;
312 va_start(va, pszFormat);
313 kwDbgPrintfV(pszFormat, va);
314 va_end(va);
315 }
316}
317
318
319/**
320 * Debugger printing.
321 * @param pszFormat Debug format string.
322 * @param ... Format argument.
323 */
324static void kwDebuggerPrintfV(const char *pszFormat, va_list va)
325{
326 if (IsDebuggerPresent())
327 {
328 char szTmp[2048];
329 _vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
330 OutputDebugStringA(szTmp);
331 }
332}
333
334
335/**
336 * Debugger printing.
337 * @param pszFormat Debug format string.
338 * @param ... Format argument.
339 */
340static void kwDebuggerPrintf(const char *pszFormat, ...)
341{
342 va_list va;
343 va_start(va, pszFormat);
344 kwDebuggerPrintfV(pszFormat, va);
345 va_end(va);
346}
347
348
349
350/**
351 * Error printing.
352 * @param pszFormat Message format string.
353 * @param ... Format argument.
354 */
355static void kwErrPrintfV(const char *pszFormat, va_list va)
356{
357 fprintf(stderr, "error: ");
358 vfprintf(stderr, pszFormat, va);
359}
360
361
362/**
363 * Error printing.
364 * @param pszFormat Message format string.
365 * @param ... Format argument.
366 */
367static void kwErrPrintf(const char *pszFormat, ...)
368{
369 va_list va;
370 va_start(va, pszFormat);
371 kwErrPrintfV(pszFormat, va);
372 va_end(va);
373}
374
375
376/**
377 * Normalizes the path so we get a consistent hash.
378 *
379 * @returns status code.
380 * @param pszPath The path.
381 * @param pszNormPath The output buffer.
382 * @param cbNormPath The size of the output buffer.
383 */
384static int kwPathNormalize(const char *pszPath, char *pszNormPath, size_t cbNormPath)
385{
386 char *pchSlash;
387 nt_fullpath(pszPath, pszNormPath, cbNormPath);
388
389 pchSlash = kHlpStrChr(pszNormPath, '/');
390 while (pchSlash)
391 {
392 *pchSlash = '\\';
393 pchSlash = kHlpStrChr(pchSlash + 1, '/');
394 }
395
396 return 0;
397}
398
399
400/**
401 * Hashes a string.
402 *
403 * @returns 32-bit string hash.
404 * @param pszString String to hash.
405 */
406static KU32 kwStrHash(const char *pszString)
407{
408 /* This algorithm was created for sdbm (a public-domain reimplementation of
409 ndbm) database library. it was found to do well in scrambling bits,
410 causing better distribution of the keys and fewer splits. it also happens
411 to be a good general hashing function with good distribution. the actual
412 function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below
413 is the faster version used in gawk. [there is even a faster, duff-device
414 version] the magic constant 65599 was picked out of thin air while
415 experimenting with different constants, and turns out to be a prime.
416 this is one of the algorithms used in berkeley db (see sleepycat) and
417 elsewhere. */
418 KU32 uHash = 0;
419 KU32 uChar;
420 while ((uChar = (unsigned char)*pszString++) != 0)
421 uHash = uChar + (uHash << 6) + (uHash << 16) - uHash;
422 return uHash;
423}
424
425
426
427/**
428 * Converts the given string to unicode.
429 *
430 * @returns Length of the resulting string in wchar_t's.
431 * @param pszSrc The source string.
432 * @param pwszDst The destination buffer.
433 * @param cwcDst The size of the destination buffer in wchar_t's.
434 */
435static size_t kwStrToUtf16(const char *pszSrc, wchar_t *pwszDst, size_t cwcDst)
436{
437 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */
438 size_t offDst = 0;
439 while (offDst < cwcDst)
440 {
441 char ch = *pszSrc++;
442 pwszDst[offDst++] = ch;
443 if (!ch)
444 return offDst - 1;
445 kHlpAssert((unsigned)ch < 127);
446 }
447
448 pwszDst[offDst - 1] = '\0';
449 return offDst;
450}
451
452
453/**
454 * Converts the given UTF-16 to a normal string.
455 *
456 * @returns Length of the resulting string.
457 * @param pwszSrc The source UTF-16 string.
458 * @param pszDst The destination buffer.
459 * @param cbDst The size of the destination buffer in bytes.
460 */
461static size_t kwUtf16ToStr(const wchar_t *pwszSrc, char *pszDst, size_t cbDst)
462{
463 /* Just to the quick ASCII stuff for now. correct ansi code page stuff later some time. */
464 size_t offDst = 0;
465 while (offDst < cbDst)
466 {
467 wchar_t wc = *pwszSrc++;
468 pszDst[offDst++] = (char)wc;
469 if (!wc)
470 return offDst - 1;
471 kHlpAssert((unsigned)wc < 127);
472 }
473
474 pszDst[offDst - 1] = '\0';
475 return offDst;
476}
477
478
479
480/** UTF-16 string length. */
481static KSIZE kwUtf16Len(wchar_t const *pwsz)
482{
483 KSIZE cwc = 0;
484 while (*pwsz != '\0')
485 cwc++, pwsz++;
486 return cwc;
487}
488
489/**
490 * Copy out the UTF-16 string following the convension of GetModuleFileName
491 */
492static DWORD kwUtf16CopyStyle1(wchar_t const *pwszSrc, wchar_t *pwszDst, KSIZE cwcDst)
493{
494 KSIZE cwcSrc = kwUtf16Len(pwszSrc);
495 if (cwcSrc + 1 <= cwcDst)
496 {
497 kHlpMemCopy(pwszDst, pwszSrc, (cwcSrc + 1) * sizeof(wchar_t));
498 return (DWORD)cwcSrc;
499 }
500 if (cwcDst > 0)
501 {
502 size_t cwcDstTmp = cwcDst - 1;
503 pwszDst[cwcDstTmp] = '\0';
504 if (cwcDstTmp > 0)
505 kHlpMemCopy(pwszDst, pwszSrc, cwcDstTmp);
506 }
507 SetLastError(ERROR_INSUFFICIENT_BUFFER);
508 return (DWORD)cwcDst;
509}
510
511
512/**
513 * Copy out the ANSI string following the convension of GetModuleFileName
514 */
515static DWORD kwStrCopyStyle1(char const *pszSrc, char *pszDst, KSIZE cbDst)
516{
517 KSIZE cchSrc = kHlpStrLen(pszSrc);
518 if (cchSrc + 1 <= cbDst)
519 {
520 kHlpMemCopy(pszDst, pszSrc, cchSrc + 1);
521 return (DWORD)cchSrc;
522 }
523 if (cbDst > 0)
524 {
525 size_t cbDstTmp = cbDst - 1;
526 pszDst[cbDstTmp] = '\0';
527 if (cbDstTmp > 0)
528 kHlpMemCopy(pszDst, pszSrc, cbDstTmp);
529 }
530 SetLastError(ERROR_INSUFFICIENT_BUFFER);
531 return (DWORD)cbDst;
532}
533
534
535
536/**
537 * Retains a new reference to the given module
538 * @returns pMod
539 * @param pMod The module to retain.
540 */
541static PKWMODULE kwLdrModuleRetain(PKWMODULE pMod)
542{
543 kHlpAssert(pMod->cRefs > 0);
544 kHlpAssert(pMod->cRefs < 64);
545 pMod->cRefs++;
546 return pMod;
547}
548
549
550/**
551 * Releases a module reference.
552 *
553 * @param pMod The module to release.
554 */
555static void kwLdrModuleRelease(PKWMODULE pMod)
556{
557 if (--pMod->cRefs == 0)
558 {
559 /* Unlink it. */
560 if (!pMod->fExe)
561 {
562 PKWMODULE pPrev = NULL;
563 unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
564 if (g_apModules[idx] == pMod)
565 g_apModules[idx] = pMod->pNext;
566 else
567 {
568 PKWMODULE pPrev = g_apModules[idx];
569 kHlpAssert(pPrev != NULL);
570 while (pPrev->pNext != pMod)
571 {
572 pPrev = pPrev->pNext;
573 kHlpAssert(pPrev != NULL);
574 }
575 pPrev->pNext = pMod->pNext;
576 }
577 }
578
579 /* Release import modules. */
580 if (!pMod->fNative)
581 {
582 KSIZE idx = pMod->u.Manual.cImpMods;
583 while (idx-- > 0)
584 {
585 kwLdrModuleRelease(pMod->u.Manual.apImpMods[idx]);
586 pMod->u.Manual.apImpMods[idx] = NULL;
587 }
588 }
589
590 /* Free our resources. */
591 kLdrModClose(pMod->pLdrMod);
592 pMod->pLdrMod = NULL;
593
594 if (!pMod->fNative)
595 {
596 kHlpPageFree(pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
597 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
598 }
599
600 kHlpFree(pMod);
601 }
602 else
603 kHlpAssert(pMod->cRefs < 64);
604}
605
606
607/**
608 * Links the module into the module hash table.
609 *
610 * @returns pMod
611 * @param pMod The module to link.
612 */
613static PKWMODULE kwLdrModuleLink(PKWMODULE pMod)
614{
615 unsigned idx = pMod->uHashPath % K_ELEMENTS(g_apModules);
616 pMod->pNext = g_apModules[idx];
617 g_apModules[idx] = pMod;
618 return pMod;
619}
620
621
622/**
623 * Creates a module using the native loader.
624 *
625 * @returns Module w/ 1 reference on success, NULL on failure.
626 * @param pszPath The normalized path to the module.
627 * @param uHashPath The module path hash.
628 */
629static PKWMODULE kwLdrModuleCreateNative(const char *pszPath, KU32 uHashPath)
630{
631 /*
632 * Open the module and check the type.
633 */
634 PKLDRMOD pLdrMod;
635 int rc = kLdrModOpenNative(pszPath, &pLdrMod);
636 if (rc == 0)
637 {
638 /*
639 * Create the entry.
640 */
641 KSIZE cbPath = kHlpStrLen(pszPath) + 1;
642 PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod) + cbPath + 1 + cbPath * 2 * sizeof(wchar_t));
643 if (pMod)
644 {
645 pMod->pszPath = (char *)kHlpMemCopy(pMod + 1, pszPath, cbPath);
646 pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
647 kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
648 pMod->uHashPath = uHashPath;
649 pMod->cRefs = 1;
650 pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath);
651 pMod->fExe = K_FALSE;
652 pMod->fNative = K_TRUE;
653 pMod->pLdrMod = pLdrMod;
654 pMod->hOurMod = (HMODULE)(KUPTR)pLdrMod->aSegments[0].MapAddress;
655 kwDbgPrintf("New module: %p LB %#010x %s (native)\n",
656 (KUPTR)pMod->pLdrMod->aSegments[0].MapAddress, kLdrModSize(pMod->pLdrMod), pMod->pszPath);
657 return kwLdrModuleLink(pMod);
658 }
659 //kLdrModClose(pLdrMod);
660 }
661 return NULL;
662}
663
664
665/**
666 * Creates a module using the our own loader.
667 *
668 * @returns Module w/ 1 reference on success, NULL on failure.
669 * @param pszPath The normalized path to the module.
670 * @param uHashPath The module path hash.
671 * @param fExe K_TRUE if this is an executable image, K_FALSE
672 * if not. Executable images does not get entered
673 * into the global module table.
674 * @param pExeMod The executable module of the process (for
675 * resolving imports). NULL if fExe is set.
676 */
677static PKWMODULE kwLdrModuleCreateNonNative(const char *pszPath, KU32 uHashPath, KBOOL fExe, PKWMODULE pExeMod)
678{
679 /*
680 * Open the module and check the type.
681 */
682 PKLDRMOD pLdrMod;
683 int rc = kLdrModOpen(pszPath, 0 /*fFlags*/, (KCPUARCH)K_ARCH, &pLdrMod);
684 if (rc == 0)
685 {
686 switch (pLdrMod->enmType)
687 {
688 case KLDRTYPE_EXECUTABLE_FIXED:
689 case KLDRTYPE_EXECUTABLE_RELOCATABLE:
690 case KLDRTYPE_EXECUTABLE_PIC:
691 if (!fExe)
692 rc = KERR_GENERAL_FAILURE;
693 break;
694
695 case KLDRTYPE_SHARED_LIBRARY_RELOCATABLE:
696 case KLDRTYPE_SHARED_LIBRARY_PIC:
697 case KLDRTYPE_SHARED_LIBRARY_FIXED:
698 if (fExe)
699 rc = KERR_GENERAL_FAILURE;
700 break;
701
702 default:
703 rc = KERR_GENERAL_FAILURE;
704 break;
705 }
706 if (rc == 0)
707 {
708 KI32 cImports = kLdrModNumberOfImports(pLdrMod, NULL /*pvBits*/);
709 if (cImports >= 0)
710 {
711 /*
712 * Create the entry.
713 */
714 KSIZE cbPath = kHlpStrLen(pszPath) + 1;
715 PKWMODULE pMod = (PKWMODULE)kHlpAllocZ(sizeof(*pMod)
716 + sizeof(pMod) * cImports
717 + cbPath
718 + cbPath * 2 * sizeof(wchar_t));
719 if (pMod)
720 {
721 KBOOL fFixed;
722
723 pMod->cRefs = 1;
724 pMod->offFilename = (KU16)(kHlpGetFilename(pszPath) - pszPath);
725 pMod->uHashPath = uHashPath;
726 pMod->fExe = fExe;
727 pMod->fNative = K_FALSE;
728 pMod->pLdrMod = pLdrMod;
729 pMod->u.Manual.cImpMods = (KU32)cImports;
730 pMod->pszPath = (char *)kHlpMemCopy(&pMod->u.Manual.apImpMods[cImports + 1], pszPath, cbPath);
731 pMod->pwszPath = (wchar_t *)(pMod->pszPath + cbPath + (cbPath & 1));
732 kwStrToUtf16(pMod->pszPath, (wchar_t *)pMod->pwszPath, cbPath * 2);
733
734 /*
735 * Figure out where to load it and get memory there.
736 */
737 fFixed = pLdrMod->enmType == KLDRTYPE_EXECUTABLE_FIXED
738 || pLdrMod->enmType == KLDRTYPE_SHARED_LIBRARY_FIXED;
739 pMod->u.Manual.pvLoad = fFixed ? (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress : NULL;
740 pMod->u.Manual.cbImage = kLdrModSize(pLdrMod);
741 if ( !fFixed
742 || (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf >= sizeof(g_abDefLdBuf)
743 || sizeof(g_abDefLdBuf) - (KUPTR)pMod->u.Manual.pvLoad - (KUPTR)g_abDefLdBuf < pMod->u.Manual.cbImage)
744 rc = kHlpPageAlloc(&pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, KPROT_EXECUTE_READWRITE, fFixed);
745 if (rc == 0)
746 {
747 rc = kHlpPageAlloc(&pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage, KPROT_READWRITE, K_FALSE);
748 if (rc == 0)
749 {
750
751 KI32 iImp;
752
753 /*
754 * Link the module (unless it's an executable image) and process the imports.
755 */
756 pMod->hOurMod = (HMODULE)pMod->u.Manual.pvLoad;
757 if (!fExe)
758 kwLdrModuleLink(pMod);
759 kwDbgPrintf("New module: %p LB %#010x %s (kLdr)\n",
760 pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage, pMod->pszPath);
761 kwDebuggerPrintf("TODO: .reload /f %s=%p\n", pMod->pszPath, pMod->u.Manual.pvLoad);
762
763 for (iImp = 0; iImp < cImports; iImp++)
764 {
765 char szName[1024];
766 rc = kLdrModGetImport(pMod->pLdrMod, NULL /*pvBits*/, iImp, szName, sizeof(szName));
767 if (rc == 0)
768 {
769 rc = kwLdrModuleResolveAndLookup(szName, pExeMod, pMod, &pMod->u.Manual.apImpMods[iImp]);
770 if (rc == 0)
771 continue;
772 }
773 break;
774 }
775
776 if (rc == 0)
777 {
778 rc = kLdrModGetBits(pLdrMod, pMod->u.Manual.pvCopy, (KUPTR)pMod->u.Manual.pvLoad,
779 kwLdrModuleGetImportCallback, pMod);
780 if (rc == 0)
781 {
782 pMod->u.Manual.pvBits = pMod->u.Manual.pvCopy;
783 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
784 return pMod;
785 }
786 }
787
788 kwLdrModuleRelease(pMod);
789 return NULL;
790 }
791
792 kHlpPageFree(pMod->u.Manual.pvLoad, pMod->u.Manual.cbImage);
793 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
794 }
795 else if (fFixed)
796 kwErrPrintf("Failed to allocate %#x bytes at %p\n",
797 pMod->u.Manual.cbImage, (void *)(KUPTR)pLdrMod->aSegments[0].LinkAddress);
798 else
799 kwErrPrintf("Failed to allocate %#x bytes\n", pMod->u.Manual.cbImage);
800 }
801 }
802 }
803 kLdrModClose(pLdrMod);
804 }
805 else
806 kwErrPrintf("kLdrOpen failed with %#x (%d) for %s\n", rc, rc, pszPath);
807 return NULL;
808}
809
810
811/** Implements FNKLDRMODGETIMPORT, used by kwLdrModuleCreate. */
812static int kwLdrModuleGetImportCallback(PKLDRMOD pMod, KU32 iImport, KU32 iSymbol, const char *pchSymbol, KSIZE cchSymbol,
813 const char *pszVersion, PKLDRADDR puValue, KU32 *pfKind, void *pvUser)
814{
815 PKWMODULE pCurMod = (PKWMODULE)pvUser;
816 PKWMODULE pImpMod = pCurMod->u.Manual.apImpMods[iImport];
817 int rc;
818 K_NOREF(pMod);
819
820 if (pImpMod->fNative)
821 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, NULL /*pvBits*/, KLDRMOD_BASEADDRESS_MAP,
822 iSymbol, pchSymbol, cchSymbol, pszVersion,
823 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
824 puValue, pfKind);
825 else
826 rc = kLdrModQuerySymbol(pImpMod->pLdrMod, pImpMod->u.Manual.pvBits, (KUPTR)pImpMod->u.Manual.pvLoad,
827 iSymbol, pchSymbol, cchSymbol, pszVersion,
828 NULL /*pfnGetForwarder*/, NULL /*pvUSer*/,
829 puValue, pfKind);
830 if (rc == 0)
831 {
832 KU32 i = g_cSandboxReplacements;
833 while (i-- > 0)
834 if ( g_aSandboxReplacements[i].cchFunction == cchSymbol
835 && kHlpMemComp(g_aSandboxReplacements[i].pszFunction, pchSymbol, cchSymbol) == 0)
836 {
837 if ( !g_aSandboxReplacements[i].pszModule
838 || kHlpStrICompAscii(g_aSandboxReplacements[i].pszModule, &pImpMod->pszPath[pImpMod->offFilename]) == 0)
839 {
840 kwDbgPrintf("replacing %s!%s\n", &pImpMod->pszPath[pImpMod->offFilename], g_aSandboxReplacements[i].pszFunction);
841 *puValue = g_aSandboxReplacements[i].pfnReplacement;
842 }
843 }
844 }
845
846 //printf("iImport=%u (%s) %*.*s rc=%d\n", iImport, &pImpMod->pszPath[pImpMod->offFilename], cchSymbol, cchSymbol, pchSymbol, rc);
847 return rc;
848
849}
850
851
852/**
853 * Gets the main entrypoint for a module.
854 *
855 * @returns 0 on success, KERR on failure
856 * @param pMod The module.
857 * @param puAddrMain Where to return the address.
858 */
859static int kwLdrModuleQueryMainEntrypoint(PKWMODULE pMod, KUPTR *puAddrMain)
860{
861 KLDRADDR uLdrAddrMain;
862 int rc = kLdrModQueryMainEntrypoint(pMod->pLdrMod, pMod->u.Manual.pvBits, (KUPTR)pMod->u.Manual.pvLoad, &uLdrAddrMain);
863 if (rc == 0)
864 {
865 *puAddrMain = (KUPTR)uLdrAddrMain;
866 return 0;
867 }
868 return rc;
869}
870
871
872static KBOOL kwLdrModuleCanLoadNatively(const char *pszFilename, KWLOCATION enmLocation)
873{
874 if (enmLocation == KWLOCATION_SYSTEM32)
875 return K_TRUE;
876 if (enmLocation == KWLOCATION_UNKNOWN_NATIVE)
877 return K_TRUE;
878 return kHlpStrICompAscii(pszFilename, "msvcrt.dll") == 0
879 || kHlpStrNICompAscii(pszFilename, "msvc", 4) == 0
880 || kHlpStrNICompAscii(pszFilename, "msdis", 5) == 0
881 || kHlpStrNICompAscii(pszFilename, "mspdb", 5) == 0;
882}
883
884
885/**
886 * Worker for kwLdrModuleResolveAndLookup that checks out one possibility.
887 *
888 * If the file exists, we consult the module hash table before trying to load it
889 * off the disk.
890 *
891 * @returns Pointer to module on success, NULL if not found, ~(KUPTR)0 on
892 * failure.
893 * @param pszPath The name of the import module.
894 * @param enmLocation The location we're searching. This is used in
895 * the heuristics for determining if we can use the
896 * native loader or need to sandbox the DLL.
897 * @param pExe The executable (optional).
898 */
899static PKWMODULE kwLdrModuleTryLoadDll(const char *pszPath, KWLOCATION enmLocation, PKWMODULE pExeMod)
900{
901 /*
902 * Does the file exists and is it a regular file?
903 */
904 BirdStat_T Stat;
905 int rc = birdStatFollowLink(pszPath, &Stat);
906 if (rc == 0)
907 {
908 if (S_ISREG(Stat.st_mode))
909 {
910 /*
911 * Yes! Normalize it and look it up in the hash table.
912 */
913 char szNormPath[1024];
914 rc = kwPathNormalize(pszPath, szNormPath, sizeof(szNormPath));
915 if (rc == 0)
916 {
917 KU32 const uHashPath = kwStrHash(szNormPath);
918 unsigned idxHash = uHashPath % K_ELEMENTS(g_apModules);
919 PKWMODULE pMod = g_apModules[idxHash];
920 if (pMod)
921 {
922 do
923 {
924 if ( pMod->uHashPath == uHashPath
925 && kHlpStrComp(pMod->pszPath, szNormPath) == 0)
926 return kwLdrModuleRetain(pMod);
927 pMod = pMod->pNext;
928 } while (pMod);
929 }
930
931 /*
932 * Not in the hash table, so we have to load it from scratch.
933 */
934 if (kwLdrModuleCanLoadNatively(kHlpGetFilename(szNormPath), enmLocation))
935 pMod = kwLdrModuleCreateNative(szNormPath, uHashPath);
936 else
937 pMod = kwLdrModuleCreateNonNative(szNormPath, uHashPath, K_FALSE /*fExe*/, pExeMod);
938 if (pMod)
939 return pMod;
940 return (PKWMODULE)~(KUPTR)0;
941 }
942 }
943 }
944 return NULL;
945}
946
947
948/**
949 * Gets a reference to the module by the given name.
950 *
951 * We must do the search path thing, as our hash table may multiple DLLs with
952 * the same base name due to different tools version and similar. We'll use a
953 * modified search sequence, though. No point in searching the current
954 * directory for instance.
955 *
956 * @returns 0 on success, KERR on failure.
957 * @param pszName The name of the import module.
958 * @param pExe The executable (optional).
959 * @param pImporter The module doing the importing (optional).
960 * @param ppMod Where to return the module pointer w/ reference.
961 */
962static int kwLdrModuleResolveAndLookup(const char *pszName, PKWMODULE pExe, PKWMODULE pImporter, PKWMODULE *ppMod)
963{
964 KSIZE const cchName = kHlpStrLen(pszName);
965 char szPath[1024];
966 PKWMODULE pMod = NULL;
967
968
969 /* The import path. */
970 if (pMod == NULL && pImporter != NULL)
971 {
972 if (pImporter->offFilename + cchName >= sizeof(szPath))
973 return KERR_BUFFER_OVERFLOW;
974 kHlpMemCopy(kHlpMemPCopy(szPath, pImporter->pszPath, pImporter->offFilename), pszName, cchName + 1);
975 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_IMPORTER_DIR, pExe);
976 }
977
978 /* Application directory first. */
979 if (pMod == NULL && pExe != NULL && pExe != pImporter)
980 {
981 if (pExe->offFilename + cchName >= sizeof(szPath))
982 return KERR_BUFFER_OVERFLOW;
983 kHlpMemCopy(kHlpMemPCopy(szPath, pExe->pszPath, pExe->offFilename), pszName, cchName + 1);
984 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_EXE_DIR, pExe);
985 }
986
987 /* The windows directory. */
988 if (pMod == NULL)
989 {
990 UINT cchDir = GetSystemDirectoryA(szPath, sizeof(szPath));
991 if ( cchDir <= 2
992 || cchDir + 1 + cchName >= sizeof(szPath))
993 return KERR_BUFFER_OVERFLOW;
994 szPath[cchDir++] = '\\';
995 kHlpMemCopy(&szPath[cchDir], pszName, cchName + 1);
996 pMod = kwLdrModuleTryLoadDll(szPath, KWLOCATION_SYSTEM32, pExe);
997 }
998
999 /* Return. */
1000 if (pMod != NULL && pMod != (PKWMODULE)~(KUPTR)0)
1001 {
1002 *ppMod = pMod;
1003 return 0;
1004 }
1005 *ppMod = NULL;
1006 return KERR_GENERAL_FAILURE;
1007}
1008
1009
1010/**
1011 * Does module initialization starting at @a pMod.
1012 *
1013 * This is initially used on the executable. Later it is used by the
1014 * LoadLibrary interceptor.
1015 *
1016 * @returns 0 on success, error on failure.
1017 * @param pMod The module to initialize.
1018 */
1019static int kwLdrModuleInitTree(PKWMODULE pMod)
1020{
1021 int rc = 0;
1022 if (!pMod->fNative)
1023 {
1024 /* Need to copy bits? */
1025 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_BITS)
1026 {
1027 kHlpMemCopy(pMod->u.Manual.pvLoad, pMod->u.Manual.pvCopy, pMod->u.Manual.cbImage);
1028 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_INIT;
1029 }
1030
1031 if (pMod->u.Manual.enmState == KWMODSTATE_NEEDS_INIT)
1032 {
1033 /* Must do imports first, but mark our module as being initialized to avoid
1034 endless recursion should there be a dependency loop. */
1035 KSIZE iImp;
1036 pMod->u.Manual.enmState = KWMODSTATE_BEING_INITED;
1037
1038 for (iImp = 0; iImp < pMod->u.Manual.cImpMods; iImp++)
1039 {
1040 rc = kwLdrModuleInitTree(pMod->u.Manual.apImpMods[iImp]);
1041 if (rc != 0)
1042 return rc;
1043 }
1044
1045 rc = kLdrModCallInit(pMod->pLdrMod, pMod->u.Manual.pvLoad, (KUPTR)pMod->u.Manual.pvLoad);
1046 if (rc == 0)
1047 pMod->u.Manual.enmState = KWMODSTATE_READY;
1048 else
1049 pMod->u.Manual.enmState = KWMODSTATE_INIT_FAILED;
1050 }
1051 }
1052 return rc;
1053}
1054
1055
1056
1057
1058/**
1059 * Creates a tool entry and inserts it.
1060 *
1061 * @returns Pointer to the tool entry. NULL on failure.
1062 * @param pszTool The normalized path to the tool.
1063 * @param uHashPath The hash of the tool path.
1064 * @param idxHashTab The hash table index of the tool.
1065 */
1066static PKWTOOL kwToolEntryCreate(const char *pszTool, KU32 uHashPath, unsigned idxHashTab)
1067{
1068 KSIZE cbTool = kHlpStrLen(pszTool) + 1;
1069 PKWTOOL pTool = (PKWTOOL)kHlpAllocZ(sizeof(*pTool) + cbTool + 1 + cbTool * 2 * sizeof(wchar_t));
1070 if (pTool)
1071 {
1072 pTool->pszPath = (char *)kHlpMemCopy(pTool + 1, pszTool, cbTool);
1073 pTool->pwszPath = (wchar_t *)(pTool->pszPath + cbTool + (cbTool & 1));
1074 kwStrToUtf16(pTool->pszPath, (wchar_t *)pTool->pwszPath, cbTool * 2);
1075 pTool->uHashPath = uHashPath;
1076 pTool->enmType = KWTOOLTYPE_SANDBOXED;
1077
1078 pTool->u.Sandboxed.pExe = kwLdrModuleCreateNonNative(pszTool, uHashPath, K_TRUE /*fExe*/, NULL);
1079 if (!pTool->u.Sandboxed.pExe)
1080 pTool->enmType = KWTOOLTYPE_EXEC;
1081
1082 /* Link the tool. */
1083 pTool->pNext = g_apTools[idxHashTab];
1084 g_apTools[idxHashTab] = pTool;
1085 return pTool;
1086 }
1087 return NULL;
1088}
1089
1090
1091/**
1092 * Looks up the given tool, creating a new tool table entry if necessary.
1093 *
1094 * @returns Pointer to the tool entry. NULL on failure.
1095 * @param pszExe The executable for the tool (not normalized).
1096 */
1097static PKWTOOL kwToolLookup(const char *pszExe)
1098{
1099 /*
1100 * Normalize the path and look up the tool in the g_apTools hash table.
1101 */
1102 char szNormPath[4096];
1103 int rc = kwPathNormalize(pszExe, szNormPath, sizeof(szNormPath));
1104 if (rc == 0)
1105 {
1106 KU32 uHashPath = kwStrHash(szNormPath);
1107 unsigned idxHash = uHashPath % K_ELEMENTS(g_apTools);
1108 PKWTOOL pTool = g_apTools[idxHash];
1109 if (pTool)
1110 {
1111 do
1112 {
1113 if ( pTool->uHashPath == uHashPath
1114 && kHlpStrComp(pTool->pszPath, szNormPath) == 0)
1115 return pTool;
1116 pTool = pTool->pNext;
1117 } while (pTool);
1118 }
1119
1120 /*
1121 * Not found, create new entry.
1122 */
1123 return kwToolEntryCreate(szNormPath, uHashPath, idxHash);
1124 }
1125 return NULL;
1126}
1127
1128
1129
1130/**
1131 * Parses the argument string passed in as pszSrc.
1132 *
1133 * @returns size of the processed arguments.
1134 * @param pszSrc Pointer to the commandline that's to be parsed.
1135 * @param pcArgs Where to return the number of arguments.
1136 * @param argv Pointer to argument vector to put argument pointers in. NULL allowed.
1137 * @param pchPool Pointer to memory pchPool to put the arguments into. NULL allowed.
1138 *
1139 * @remarks Lifted from startuphacks-win.c
1140 */
1141static int parse_args(const char *pszSrc, int *pcArgs, char **argv, char *pchPool)
1142{
1143 int bs;
1144 char chQuote;
1145 char *pfFlags;
1146 int cbArgs;
1147 int cArgs;
1148
1149#define PUTC(c) do { ++cbArgs; if (pchPool != NULL) *pchPool++ = (c); } while (0)
1150#define PUTV do { ++cArgs; if (argv != NULL) *argv++ = pchPool; } while (0)
1151#define WHITE(c) ((c) == ' ' || (c) == '\t')
1152
1153#define _ARG_DQUOTE 0x01 /* Argument quoted (") */
1154#define _ARG_RESPONSE 0x02 /* Argument read from response file */
1155#define _ARG_WILDCARD 0x04 /* Argument expanded from wildcard */
1156#define _ARG_ENV 0x08 /* Argument from environment */
1157#define _ARG_NONZERO 0x80 /* Always set, to avoid end of string */
1158
1159 cArgs = 0;
1160 cbArgs = 0;
1161
1162#if 0
1163 /* argv[0] */
1164 PUTC((char)_ARG_NONZERO);
1165 PUTV;
1166 for (;;)
1167 {
1168 PUTC(*pszSrc);
1169 if (*pszSrc == 0)
1170 break;
1171 ++pszSrc;
1172 }
1173 ++pszSrc;
1174#endif
1175
1176 for (;;)
1177 {
1178 while (WHITE(*pszSrc))
1179 ++pszSrc;
1180 if (*pszSrc == 0)
1181 break;
1182 pfFlags = pchPool;
1183 PUTC((char)_ARG_NONZERO);
1184 PUTV;
1185 bs = 0; chQuote = 0;
1186 for (;;)
1187 {
1188 if (!chQuote ? (*pszSrc == '"' /*|| *pszSrc == '\''*/) : *pszSrc == chQuote)
1189 {
1190 while (bs >= 2)
1191 {
1192 PUTC('\\');
1193 bs -= 2;
1194 }
1195 if (bs & 1)
1196 PUTC(*pszSrc);
1197 else
1198 {
1199 chQuote = chQuote ? 0 : *pszSrc;
1200 if (pfFlags != NULL)
1201 *pfFlags |= _ARG_DQUOTE;
1202 }
1203 bs = 0;
1204 }
1205 else if (*pszSrc == '\\')
1206 ++bs;
1207 else
1208 {
1209 while (bs != 0)
1210 {
1211 PUTC('\\');
1212 --bs;
1213 }
1214 if (*pszSrc == 0 || (WHITE(*pszSrc) && !chQuote))
1215 break;
1216 PUTC(*pszSrc);
1217 }
1218 ++pszSrc;
1219 }
1220 PUTC(0);
1221 }
1222
1223 *pcArgs = cArgs;
1224 return cbArgs;
1225}
1226
1227
1228
1229
1230/*
1231 *
1232 * Process and thread related APIs.
1233 * Process and thread related APIs.
1234 * Process and thread related APIs.
1235 *
1236 */
1237
1238/** ExitProcess replacement. */
1239static void WINAPI kwSandbox_Kernel32_ExitProcess(UINT uExitCode)
1240{
1241 if (g_Sandbox.idMainThread == GetCurrentThreadId())
1242 {
1243 PNT_TIB pTib = (PNT_TIB)NtCurrentTeb();
1244
1245 g_Sandbox.rcExitCode = (int)uExitCode;
1246
1247 /* Before we jump, restore the TIB as we're not interested in any
1248 exception chain stuff installed by the sandboxed executable. */
1249 *pTib = g_Sandbox.TibMainThread;
1250
1251 longjmp(g_Sandbox.JmpBuf, 1);
1252 }
1253 __debugbreak();
1254}
1255
1256
1257/** ExitProcess replacement. */
1258static BOOL WINAPI kwSandbox_Kernel32_TerminateProcess(HANDLE hProcess, UINT uExitCode)
1259{
1260 if (hProcess == GetCurrentProcess())
1261 kwSandbox_Kernel32_ExitProcess(uExitCode);
1262 __debugbreak();
1263 return TerminateProcess(hProcess, uExitCode);
1264}
1265
1266
1267/** Normal CRT exit(). */
1268static void __cdecl kwSandbox_msvcrt_exit(int rcExitCode)
1269{
1270 kwDbgPrintf("kwSandbox_msvcrt_exit: %d\n", rcExitCode);
1271 kwSandbox_Kernel32_ExitProcess(rcExitCode);
1272}
1273
1274
1275/** Quick CRT _exit(). */
1276static void __cdecl kwSandbox_msvcrt__exit(int rcExitCode)
1277{
1278 /* Quick. */
1279 kwDbgPrintf("kwSandbox_msvcrt__exit %d\n", rcExitCode);
1280 kwSandbox_Kernel32_ExitProcess(rcExitCode);
1281}
1282
1283
1284/** Return to caller CRT _cexit(). */
1285static void __cdecl kwSandbox_msvcrt__cexit(int rcExitCode)
1286{
1287 kwDbgPrintf("kwSandbox_msvcrt__cexit: %d\n", rcExitCode);
1288 kwSandbox_Kernel32_ExitProcess(rcExitCode);
1289}
1290
1291
1292/** Quick return to caller CRT _c_exit(). */
1293static void __cdecl kwSandbox_msvcrt__c_exit(int rcExitCode)
1294{
1295 kwDbgPrintf("kwSandbox_msvcrt__c_exit: %d\n", rcExitCode);
1296 kwSandbox_Kernel32_ExitProcess(rcExitCode);
1297}
1298
1299
1300/** Runtime error and exit _amsg_exit(). */
1301static void __cdecl kwSandbox_msvcrt__amsg_exit(int iMsgNo)
1302{
1303 kwDbgPrintf("\nRuntime error #%u!\n", iMsgNo);
1304 kwSandbox_Kernel32_ExitProcess(255);
1305}
1306
1307
1308/** The CRT internal __getmainargs() API. */
1309static int __cdecl kwSandbox_msvcrt___getmainargs(int *pargc, char ***pargv, char ***penvp,
1310 int dowildcard, int const *piNewMode)
1311{
1312 *pargc = g_Sandbox.cArgs;
1313 *pargv = g_Sandbox.papszArgs;
1314 *penvp = g_Sandbox.environ;
1315
1316 /** @todo startinfo points at a newmode (setmode) value. */
1317 return 0;
1318}
1319
1320
1321/** The CRT internal __wgetmainargs() API. */
1322static int __cdecl kwSandbox_msvcrt___wgetmainargs(int *pargc, wchar_t ***pargv, wchar_t ***penvp,
1323 int dowildcard, int const *piNewMode)
1324{
1325 *pargc = g_Sandbox.cArgs;
1326 *pargv = g_Sandbox.papwszArgs;
1327 *penvp = g_Sandbox.wenviron;
1328
1329 /** @todo startinfo points at a newmode (setmode) value. */
1330 return 0;
1331}
1332
1333
1334
1335/** Kernel32 - GetCommandLineA() */
1336static LPCSTR /*LPSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineA(VOID)
1337{
1338 return g_Sandbox.pszCmdLine;
1339}
1340
1341
1342/** Kernel32 - GetCommandLineW() */
1343static LPCWSTR /*LPWSTR*/ WINAPI kwSandbox_Kernel32_GetCommandLineW(VOID)
1344{
1345 return g_Sandbox.pwszCmdLine;
1346}
1347
1348
1349/** Kernel32 - GetStartupInfoA() */
1350static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoA(LPSTARTUPINFOA pStartupInfo)
1351{
1352 __debugbreak();
1353}
1354
1355
1356/** Kernel32 - GetStartupInfoW() */
1357static VOID WINAPI kwSandbox_Kernel32_GetStartupInfoW(LPSTARTUPINFOW lpStartupInfo)
1358{
1359 __debugbreak();
1360}
1361
1362
1363/** CRT - __p___argc(). */
1364static int * __cdecl kwSandbox_msvcrt___p___argc(void)
1365{
1366 return &g_Sandbox.cArgs;
1367}
1368
1369
1370/** CRT - __p___argv(). */
1371static char *** __cdecl kwSandbox_msvcrt___p___argv(void)
1372{
1373 return &g_Sandbox.papszArgs;
1374}
1375
1376
1377/** CRT - __p___sargv(). */
1378static wchar_t *** __cdecl kwSandbox_msvcrt___p___wargv(void)
1379{
1380 return &g_Sandbox.papwszArgs;
1381}
1382
1383
1384/** CRT - __p__acmdln(). */
1385static char ** __cdecl kwSandbox_msvcrt___p__acmdln(void)
1386{
1387 return (char **)&g_Sandbox.pszCmdLine;
1388}
1389
1390
1391/** CRT - __p__acmdln(). */
1392static wchar_t ** __cdecl kwSandbox_msvcrt___p__wcmdln(void)
1393{
1394 return &g_Sandbox.pwszCmdLine;
1395}
1396
1397
1398/** CRT - __p__pgmptr(). */
1399static char ** __cdecl kwSandbox_msvcrt___p__pgmptr(void)
1400{
1401 return &g_Sandbox.pgmptr;
1402}
1403
1404
1405/** CRT - __p__wpgmptr(). */
1406static wchar_t ** __cdecl kwSandbox_msvcrt___p__wpgmptr(void)
1407{
1408 return &g_Sandbox.wpgmptr;
1409}
1410
1411
1412/** CRT - _get_pgmptr(). */
1413static errno_t __cdecl kwSandbox_msvcrt__get_pgmptr(char **ppszValue)
1414{
1415 *ppszValue = g_Sandbox.pgmptr;
1416 return 0;
1417}
1418
1419
1420/** CRT - _get_wpgmptr(). */
1421static errno_t __cdecl kwSandbox_msvcrt__get_wpgmptr(wchar_t **ppwszValue)
1422{
1423 *ppwszValue = g_Sandbox.wpgmptr;
1424 return 0;
1425}
1426
1427/** Just in case. */
1428static void kwSandbox_msvcrt__wincmdln(void)
1429{
1430 __debugbreak();
1431}
1432
1433
1434/** Just in case. */
1435static void kwSandbox_msvcrt__wwincmdln(void)
1436{
1437 __debugbreak();
1438}
1439
1440/** CreateThread interceptor. */
1441static HANDLE WINAPI kwSandbox_Kernel32_CreateThread(LPSECURITY_ATTRIBUTES pSecAttr, SIZE_T cbStack,
1442 PTHREAD_START_ROUTINE pfnThreadProc, PVOID pvUser,
1443 DWORD fFlags, PDWORD pidThread)
1444{
1445 __debugbreak();
1446 return NULL;
1447}
1448
1449
1450/** _beginthread - create a new thread. */
1451static uintptr_t __cdecl kwSandbox_msvcrt__beginthread(void (__cdecl *pfnThreadProc)(void *), unsigned cbStack, void *pvUser)
1452{
1453 __debugbreak();
1454 return 0;
1455}
1456
1457
1458/** _beginthreadex - create a new thread. */
1459static uintptr_t __cdecl kwSandbox_msvcrt__beginthreadex(void *pvSecAttr, unsigned cbStack,
1460 unsigned (__stdcall *pfnThreadProc)(void *), void *pvUser,
1461 unsigned fCreate, unsigned *pidThread)
1462{
1463 __debugbreak();
1464 return 0;
1465}
1466
1467
1468/*
1469 *
1470 * Environment related APIs.
1471 * Environment related APIs.
1472 * Environment related APIs.
1473 *
1474 */
1475
1476/** Kernel32 - GetEnvironmentVariableA() */
1477static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableA(LPCSTR pwszVar, LPSTR pszValue, DWORD cbValue)
1478{
1479 __debugbreak();
1480 return 0;
1481}
1482
1483
1484/** Kernel32 - GetEnvironmentVariableW() */
1485static DWORD WINAPI kwSandbox_Kernel32_GetEnvironmentVariableW(LPCWSTR pwszVar, LPWSTR pwszValue, DWORD cbValue)
1486{
1487 kwDbgPrintf("GetEnvironmentVariableW: '%ls'\n", pwszVar);
1488 //__debugbreak();
1489 //SetLastError(ERROR_ENVVAR_NOT_FOUND);
1490 //return 0;
1491 return GetEnvironmentVariableW(pwszVar, pwszValue, cbValue);
1492}
1493
1494
1495/** Kernel32 - SetEnvironmentVariableA() */
1496static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableA(LPCSTR pszVar, LPCSTR pszValue)
1497{
1498 __debugbreak();
1499 return FALSE;
1500}
1501
1502
1503/** Kernel32 - SetEnvironmentVariableW() */
1504static BOOL WINAPI kwSandbox_Kernel32_SetEnvironmentVariableW(LPCWSTR pwszVar, LPCWSTR pwszValue)
1505{
1506 kwDbgPrintf("SetEnvironmentVariableW: '%ls' = '%ls'\n", pwszVar, pwszValue);
1507 return SetEnvironmentVariableW(pwszVar, pwszValue);
1508 //__debugbreak();
1509 //return FALSE;
1510}
1511
1512
1513/** Kernel32 - ExpandEnvironmentStringsA() */
1514static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsA(LPCSTR pszSrc, LPSTR pwszDst, DWORD cbDst)
1515{
1516 __debugbreak();
1517 return 0;
1518}
1519
1520
1521/** Kernel32 - ExpandEnvironmentStringsW() */
1522static DWORD WINAPI kwSandbox_Kernel32_ExpandEnvironmentStringsW(LPCWSTR pwszSrc, LPWSTR pwszDst, DWORD cbDst)
1523{
1524 __debugbreak();
1525 return 0;
1526}
1527
1528
1529/** CRT - _putenv(). */
1530static int __cdecl kwSandbox_msvcrt__putenv(const char *pszVarEqualValue)
1531{
1532 __debugbreak();
1533 return 0;
1534}
1535
1536
1537/** CRT - _wputenv(). */
1538static int __cdecl kwSandbox_msvcrt__wputenv(const wchar_t *pwszVarEqualValue)
1539{
1540 __debugbreak();
1541 return 0;
1542}
1543
1544
1545/** CRT - _putenv_s(). */
1546static errno_t __cdecl kwSandbox_msvcrt__putenv_s(const char *pszVar, const char *pszValue)
1547{
1548 __debugbreak();
1549 return 0;
1550}
1551
1552
1553/** CRT - _wputenv_s(). */
1554static errno_t __cdecl kwSandbox_msvcrt__wputenv_s(const wchar_t *pwszVar, const wchar_t *pwszValue)
1555{
1556 kwDbgPrintf("_wputenv_s: '%ls' = '%ls'\n", pwszVar, pwszValue);
1557 //__debugbreak();
1558 return SetEnvironmentVariableW(pwszVar, pwszValue) ? 0 : -1;
1559}
1560
1561
1562/** CRT - get pointer to the __initenv variable (initial environment). */
1563static char *** __cdecl kwSandbox_msvcrt___p___initenv(void)
1564{
1565 return &g_Sandbox.initenv;
1566}
1567
1568
1569/** CRT - get pointer to the __winitenv variable (initial environment). */
1570static wchar_t *** __cdecl kwSandbox_msvcrt___p___winitenv(void)
1571{
1572 return &g_Sandbox.winitenv;
1573}
1574
1575
1576/** CRT - get pointer to the _environ variable (current environment). */
1577static char *** __cdecl kwSandbox_msvcrt___p__environ(void)
1578{
1579 return &g_Sandbox.environ;
1580}
1581
1582
1583/** CRT - get pointer to the _wenviron variable (current environment). */
1584static wchar_t *** __cdecl kwSandbox_msvcrt___p__wenviron(void)
1585{
1586 return &g_Sandbox.wenviron;
1587}
1588
1589
1590/** CRT - get the _environ variable (current environment).
1591 * @remarks Not documented or prototyped? */
1592static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_environ(char ***ppapszEnviron)
1593{
1594 __debugbreak(); /** @todo check the callers expecations! */
1595 *ppapszEnviron = g_Sandbox.environ;
1596 return 0;
1597}
1598
1599
1600/** CRT - get the _wenviron variable (current environment).
1601 * @remarks Not documented or prototyped? */
1602static KUPTR /*void*/ __cdecl kwSandbox_msvcrt__get_wenviron(wchar_t ***ppapwszEnviron)
1603{
1604 __debugbreak(); /** @todo check the callers expecations! */
1605 *ppapwszEnviron = g_Sandbox.wenviron;
1606 return 0;
1607}
1608
1609
1610
1611/*
1612 *
1613 * Loader related APIs
1614 * Loader related APIs
1615 * Loader related APIs
1616 *
1617 */
1618
1619
1620/** Kernel32 - LoadLibraryExA() */
1621static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExA(LPCSTR pszFilename, HANDLE hFile, DWORD fFlags)
1622{
1623 PKWDYNLOAD pDynLoad;
1624 PKWMODULE pMod;
1625 int rc;
1626
1627 if ( (fFlags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)
1628 || (hFile != NULL && hFile != INVALID_HANDLE_VALUE) )
1629 {
1630 __debugbreak();
1631 return LoadLibraryExA(pszFilename, hFile, fFlags);
1632 }
1633
1634 /*
1635 * Deal with resource / data DLLs.
1636 */
1637 if (fFlags & ( DONT_RESOLVE_DLL_REFERENCES
1638 | LOAD_LIBRARY_AS_DATAFILE
1639 | LOAD_LIBRARY_AS_IMAGE_RESOURCE) )
1640 {
1641 HMODULE hmod;
1642 char szNormPath[4096];
1643 KU32 uHashPath;
1644
1645 /* currently, only deal with those that has a path. */
1646 if (kHlpIsFilenameOnly(pszFilename))
1647 {
1648 __debugbreak();
1649 return LoadLibraryExA(pszFilename, hFile, fFlags);
1650 }
1651
1652 /* Normalize the path. */
1653 rc = kwPathNormalize(pszFilename, szNormPath, sizeof(szNormPath));
1654 if (rc != 0)
1655 {
1656 __debugbreak();
1657 return LoadLibraryExA(pszFilename, hFile, fFlags);
1658 }
1659
1660 /* Try look it up. */
1661 uHashPath = kwStrHash(szNormPath);
1662 for (pDynLoad = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
1663 if ( pDynLoad->uHashPath == uHashPath
1664 && kHlpStrComp(pDynLoad->pszPath, szNormPath) == 0)
1665 {
1666 if (pDynLoad->pMod == NULL)
1667 return pDynLoad->hmod;
1668 __debugbreak();
1669 }
1670
1671 /* Then try load it. */
1672 hmod = LoadLibraryExA(szNormPath, hFile, fFlags);
1673 if (hmod)
1674 {
1675 KSIZE cbNormPath = kHlpStrLen(szNormPath) + 1;
1676 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad) + cbNormPath + cbNormPath * 2 * sizeof(wchar_t));
1677 if (pDynLoad)
1678 {
1679 pDynLoad->pszPath = (char *)kHlpMemCopy(pDynLoad + 1, szNormPath, cbNormPath);
1680 pDynLoad->pwszPath = (wchar_t *)(pDynLoad->pszPath + cbNormPath + (cbNormPath & 1));
1681 kwStrToUtf16(pDynLoad->pszPath, (wchar_t *)pDynLoad->pwszPath, cbNormPath * 2);
1682 pDynLoad->pszModName = kHlpGetFilename(pDynLoad->pszPath);
1683 pDynLoad->uHashPath = uHashPath;
1684 pDynLoad->pMod = NULL; /* indicates special */
1685 pDynLoad->hmod = hmod;
1686
1687 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
1688 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
1689 }
1690 else
1691 __debugbreak();
1692 }
1693 return hmod;
1694 }
1695
1696 /*
1697 * Normal library loading.
1698 * We start by being very lazy and reusing the code for resolving imports.
1699 */
1700 if (!kHlpIsFilenameOnly(pszFilename))
1701 pMod = kwLdrModuleTryLoadDll(pszFilename, KWLOCATION_UNKNOWN, g_Sandbox.pTool->u.Sandboxed.pExe);
1702 else
1703 {
1704__debugbreak();
1705 rc = kwLdrModuleResolveAndLookup(pszFilename, g_Sandbox.pTool->u.Sandboxed.pExe, NULL /*pImporter*/, &pMod);
1706 if (rc != 0)
1707 pMod = NULL;
1708 }
1709 if (!pMod)
1710 {
1711 __debugbreak();
1712 SetLastError(ERROR_MOD_NOT_FOUND);
1713 return NULL;
1714 }
1715
1716 /*
1717 * Make sure it's initialized.
1718 */
1719 rc = kwLdrModuleInitTree(pMod);
1720 if (rc == 0)
1721 {
1722 /*
1723 * Create an dynamic loading entry for it.
1724 */
1725 pDynLoad = (PKWDYNLOAD)kHlpAlloc(sizeof(*pDynLoad));
1726 if (pDynLoad)
1727 {
1728 pDynLoad->pszPath = pMod->pszPath;
1729 pDynLoad->pwszPath = pMod->pwszPath;
1730 pDynLoad->pszModName = kHlpGetFilename(pDynLoad->pszPath);
1731 pDynLoad->uHashPath = pMod->uHashPath;
1732 pDynLoad->pMod = pMod;
1733 pDynLoad->hmod = pMod->hOurMod;
1734
1735 pDynLoad->pNext = g_Sandbox.pTool->u.Sandboxed.pDynLoadHead;
1736 g_Sandbox.pTool->u.Sandboxed.pDynLoadHead = pDynLoad;
1737
1738 return pDynLoad->hmod;
1739 }
1740 }
1741
1742 __debugbreak();
1743 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1744 kwLdrModuleRelease(pMod);
1745 return NULL;
1746}
1747
1748
1749/** Kernel32 - LoadLibraryExW() */
1750static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryExW(LPCWSTR pwszFilename, HANDLE hFile, DWORD fFlags)
1751{
1752 char szTmp[4096];
1753 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
1754 if (cchTmp < sizeof(szTmp))
1755 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, hFile, fFlags);
1756
1757 __debugbreak();
1758 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1759 return NULL;
1760}
1761
1762/** Kernel32 - LoadLibraryA() */
1763static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryA(LPCSTR pszFilename)
1764{
1765 return kwSandbox_Kernel32_LoadLibraryExA(pszFilename, NULL /*hFile*/, 0 /*fFlags*/);
1766}
1767
1768
1769/** Kernel32 - LoadLibraryW() */
1770static HMODULE WINAPI kwSandbox_Kernel32_LoadLibraryW(LPCWSTR pwszFilename)
1771{
1772 char szTmp[4096];
1773 KSIZE cchTmp = kwUtf16ToStr(pwszFilename, szTmp, sizeof(szTmp));
1774 if (cchTmp < sizeof(szTmp))
1775 return kwSandbox_Kernel32_LoadLibraryExA(szTmp, NULL /*hFile*/, 0 /*fFlags*/);
1776 __debugbreak();
1777 SetLastError(ERROR_FILENAME_EXCED_RANGE);
1778 return NULL;
1779}
1780
1781
1782/** Kernel32 - FreeLibrary() */
1783static BOOL WINAPI kwSandbox_Kernel32_FreeLibrary(HMODULE hmod)
1784{
1785 /* Ignored, we like to keep everything loaded. */
1786 return TRUE;
1787}
1788
1789
1790/** Kernel32 - GetModuleHandleA() */
1791static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleA(LPCSTR pszModule)
1792{
1793 if (pszModule == NULL)
1794 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
1795 __debugbreak();
1796 return NULL;
1797}
1798
1799
1800/** Kernel32 - GetModuleHandleW() */
1801static HMODULE WINAPI kwSandbox_Kernel32_GetModuleHandleW(LPCWSTR pwszModule)
1802{
1803 if (pwszModule == NULL)
1804 return (HMODULE)g_Sandbox.pTool->u.Sandboxed.pExe->hOurMod;
1805 __debugbreak();
1806 return NULL;
1807}
1808
1809
1810static PKWMODULE kwSandboxLocateModuleByHandle(PKWSANDBOX pSandbox, HMODULE hmod)
1811{
1812 PKWDYNLOAD pDynLoad;
1813
1814 /* The executable. */
1815 if ( hmod == NULL
1816 || pSandbox->pTool->u.Sandboxed.pExe->hOurMod == hmod)
1817 return kwLdrModuleRetain(pSandbox->pTool->u.Sandboxed.pExe);
1818
1819 /* Dynamically loaded images. */
1820 for (pDynLoad = pSandbox->pTool->u.Sandboxed.pDynLoadHead; pDynLoad != NULL; pDynLoad = pDynLoad->pNext)
1821 if (pDynLoad->hmod == hmod)
1822 {
1823 if (pDynLoad->pMod)
1824 return kwLdrModuleRetain(pDynLoad->pMod);
1825 __debugbreak();
1826 return NULL;
1827 }
1828
1829 return NULL;
1830}
1831
1832
1833/** Used to debug dynamically resolved procedures. */
1834static UINT WINAPI kwSandbox_BreakIntoDebugger(void *pv1, void *pv2, void *pv3, void *pv4)
1835{
1836 __debugbreak();
1837 return -1;
1838}
1839
1840
1841/** Kernel32 - GetProcAddress() */
1842static FARPROC WINAPI kwSandbox_Kernel32_GetProcAddress(HMODULE hmod, LPCSTR pszProc)
1843{
1844 /*
1845 * Try locate the module.
1846 */
1847 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
1848 if (pMod)
1849 {
1850 KLDRADDR uValue;
1851 int rc = kLdrModQuerySymbol(pMod->pLdrMod,
1852 pMod->fNative ? NULL : pMod->u.Manual.pvBits,
1853 pMod->fNative ? KLDRMOD_BASEADDRESS_MAP : (KUPTR)pMod->u.Manual.pvLoad,
1854 KU32_MAX /*iSymbol*/,
1855 pszProc,
1856 strlen(pszProc),
1857 NULL /*pszVersion*/,
1858 NULL /*pfnGetForwarder*/, NULL /*pvUser*/,
1859 &uValue,
1860 NULL /*pfKind*/);
1861 if (rc == 0)
1862 {
1863 static int s_cDbgGets = 0;
1864 s_cDbgGets++;
1865 kwDbgPrintf("GetProcAddress(%s, %s) -> %p [%d]\n", pMod->pszPath, pszProc, (KUPTR)uValue, s_cDbgGets);
1866 kwLdrModuleRelease(pMod);
1867 //if (s_cGets >= 3)
1868 // return (FARPROC)kwSandbox_BreakIntoDebugger;
1869 return (FARPROC)(KUPTR)uValue;
1870 }
1871
1872 __debugbreak();
1873 SetLastError(ERROR_PROC_NOT_FOUND);
1874 kwLdrModuleRelease(pMod);
1875 return NULL;
1876 }
1877
1878 __debugbreak();
1879 return GetProcAddress(hmod, pszProc);
1880}
1881
1882
1883/** Kernel32 - GetModuleFileNameA() */
1884static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameA(HMODULE hmod, LPSTR pszFilename, DWORD cbFilename)
1885{
1886 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
1887 if (pMod != NULL)
1888 {
1889 DWORD cbRet = kwStrCopyStyle1(pMod->pszPath, pszFilename, cbFilename);
1890 kwLdrModuleRelease(pMod);
1891 return cbRet;
1892 }
1893 __debugbreak();
1894 return 0;
1895}
1896
1897
1898/** Kernel32 - GetModuleFileNameW() */
1899static DWORD WINAPI kwSandbox_Kernel32_GetModuleFileNameW(HMODULE hmod, LPWSTR pwszFilename, DWORD cbFilename)
1900{
1901 PKWMODULE pMod = kwSandboxLocateModuleByHandle(&g_Sandbox, hmod);
1902 if (pMod)
1903 {
1904 DWORD cwcRet = kwUtf16CopyStyle1(pMod->pwszPath, pwszFilename, cbFilename);
1905 kwLdrModuleRelease(pMod);
1906 return cwcRet;
1907 }
1908
1909 __debugbreak();
1910 return 0;
1911}
1912
1913
1914
1915/**
1916 * Functions that needs replacing for sandboxed execution.
1917 */
1918KWREPLACEMENTFUNCTION const g_aSandboxReplacements[] =
1919{
1920#define TUPLE(a_sz) a_sz, sizeof(a_sz) - 1
1921 /*
1922 * Kernel32.dll and friends.
1923 */
1924 { TUPLE("ExitProcess"), NULL, (KUPTR)kwSandbox_Kernel32_ExitProcess },
1925 { TUPLE("TerminateProcess"), NULL, (KUPTR)kwSandbox_Kernel32_TerminateProcess },
1926
1927 { TUPLE("LoadLibraryA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryA },
1928 { TUPLE("LoadLibraryW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryW },
1929 { TUPLE("LoadLibraryExA"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExA },
1930 { TUPLE("LoadLibraryExW"), NULL, (KUPTR)kwSandbox_Kernel32_LoadLibraryExW },
1931 { TUPLE("FreeLibrary"), NULL, (KUPTR)kwSandbox_Kernel32_FreeLibrary },
1932 { TUPLE("GetModuleHandleA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleA },
1933 { TUPLE("GetModuleHandleW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleHandleW },
1934 { TUPLE("GetProcAddress"), NULL, (KUPTR)kwSandbox_Kernel32_GetProcAddress },
1935 { TUPLE("GetModuleFileNameA"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameA },
1936 { TUPLE("GetModuleFileNameW"), NULL, (KUPTR)kwSandbox_Kernel32_GetModuleFileNameW },
1937
1938 { TUPLE("GetCommandLineA"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineA },
1939 { TUPLE("GetCommandLineW"), NULL, (KUPTR)kwSandbox_Kernel32_GetCommandLineW },
1940 { TUPLE("GetStartupInfoA"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoA },
1941 { TUPLE("GetStartupInfoW"), NULL, (KUPTR)kwSandbox_Kernel32_GetStartupInfoW },
1942
1943 { TUPLE("CreateThread"), NULL, (KUPTR)kwSandbox_Kernel32_CreateThread },
1944
1945 { TUPLE("GetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableA },
1946 { TUPLE("GetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_GetEnvironmentVariableW },
1947 { TUPLE("SetEnvironmentVariableA"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableA },
1948 { TUPLE("SetEnvironmentVariableW"), NULL, (KUPTR)kwSandbox_Kernel32_SetEnvironmentVariableW },
1949 { TUPLE("ExpandEnvironmentStringsA"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsA },
1950 { TUPLE("ExpandEnvironmentStringsW"), NULL, (KUPTR)kwSandbox_Kernel32_ExpandEnvironmentStringsW },
1951
1952 /*
1953 * MS Visual C++ CRTs.
1954 */
1955 { TUPLE("exit"), NULL, (KUPTR)kwSandbox_msvcrt_exit },
1956 { TUPLE("_exit"), NULL, (KUPTR)kwSandbox_msvcrt__exit },
1957 { TUPLE("_cexit"), NULL, (KUPTR)kwSandbox_msvcrt__cexit },
1958 { TUPLE("_c_exit"), NULL, (KUPTR)kwSandbox_msvcrt__c_exit },
1959 { TUPLE("_amsg_exit"), NULL, (KUPTR)kwSandbox_msvcrt__amsg_exit },
1960
1961 { TUPLE("_beginthread"), NULL, (KUPTR)kwSandbox_msvcrt__beginthread },
1962 { TUPLE("_beginthreadex"), NULL, (KUPTR)kwSandbox_msvcrt__beginthreadex },
1963
1964 { TUPLE("__argc"), NULL, (KUPTR)&g_Sandbox.cArgs },
1965 { TUPLE("__argv"), NULL, (KUPTR)&g_Sandbox.papszArgs },
1966 { TUPLE("__wargv"), NULL, (KUPTR)&g_Sandbox.papwszArgs },
1967 { TUPLE("__p___argc"), NULL, (KUPTR)kwSandbox_msvcrt___p___argc },
1968 { TUPLE("__p___argv"), NULL, (KUPTR)kwSandbox_msvcrt___p___argv },
1969 { TUPLE("__p___wargv"), NULL, (KUPTR)kwSandbox_msvcrt___p___wargv },
1970 { TUPLE("_acmdln"), NULL, (KUPTR)&g_Sandbox.pszCmdLine },
1971 { TUPLE("_wcmdln"), NULL, (KUPTR)&g_Sandbox.pwszCmdLine },
1972 { TUPLE("__p__acmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__acmdln },
1973 { TUPLE("__p__wcmdln"), NULL, (KUPTR)kwSandbox_msvcrt___p__wcmdln },
1974 { TUPLE("_pgmptr"), NULL, (KUPTR)&g_Sandbox.pgmptr },
1975 { TUPLE("_wpgmptr"), NULL, (KUPTR)&g_Sandbox.wpgmptr },
1976 { TUPLE("_get_pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_pgmptr },
1977 { TUPLE("_get_wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt__get_wpgmptr },
1978 { TUPLE("__p__pgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__pgmptr },
1979 { TUPLE("__p__wpgmptr"), NULL, (KUPTR)kwSandbox_msvcrt___p__wpgmptr },
1980 { TUPLE("_wincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wincmdln },
1981 { TUPLE("_wwincmdln"), NULL, (KUPTR)kwSandbox_msvcrt__wwincmdln },
1982 { TUPLE("__getmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___getmainargs},
1983 { TUPLE("__wgetmainargs"), NULL, (KUPTR)kwSandbox_msvcrt___wgetmainargs},
1984
1985 { TUPLE("_putenv"), NULL, (KUPTR)kwSandbox_msvcrt__putenv},
1986 { TUPLE("_wputenv"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv},
1987 { TUPLE("_putenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__putenv_s},
1988 { TUPLE("_wputenv_s"), NULL, (KUPTR)kwSandbox_msvcrt__wputenv_s},
1989 { TUPLE("__initenv"), NULL, (KUPTR)&g_Sandbox.initenv },
1990 { TUPLE("__winitenv"), NULL, (KUPTR)&g_Sandbox.winitenv },
1991 { TUPLE("__p___initenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___initenv},
1992 { TUPLE("__p___winitenv"), NULL, (KUPTR)kwSandbox_msvcrt___p___winitenv},
1993 { TUPLE("_environ"), NULL, (KUPTR)&g_Sandbox.environ },
1994 { TUPLE("_wenviron"), NULL, (KUPTR)&g_Sandbox.wenviron },
1995 { TUPLE("_get_environ"), NULL, (KUPTR)kwSandbox_msvcrt__get_environ },
1996 { TUPLE("_get_wenviron"), NULL, (KUPTR)kwSandbox_msvcrt__get_wenviron },
1997 { TUPLE("__p__environ"), NULL, (KUPTR)kwSandbox_msvcrt___p__environ },
1998 { TUPLE("__p__wenviron"), NULL, (KUPTR)kwSandbox_msvcrt___p__wenviron },
1999 /// @todo terminate
2000};
2001/** Number of entries in g_aReplacements. */
2002KU32 const g_cSandboxReplacements = K_ELEMENTS(g_aSandboxReplacements);
2003
2004
2005/**
2006 * Used by kwSandboxExec to reset the state of the module tree.
2007 *
2008 * This is done recursively.
2009 *
2010 * @param pMod The root of the tree to consider.
2011 */
2012static void kwSandboxResetModuleState(PKWMODULE pMod)
2013{
2014 if ( !pMod->fNative
2015 && pMod->u.Manual.enmState != KWMODSTATE_NEEDS_BITS)
2016 {
2017 KSIZE iImp;
2018 pMod->u.Manual.enmState = KWMODSTATE_NEEDS_BITS;
2019 iImp = pMod->u.Manual.cImpMods;
2020 while (iImp-- > 0)
2021 kwSandboxResetModuleState(pMod->u.Manual.apImpMods[iImp]);
2022 }
2023}
2024
2025static PPEB kwSandboxGetProcessEnvironmentBlock(void)
2026{
2027#if K_ARCH == K_ARCH_X86_32
2028 return (PPEB)__readfsdword(0x030 /* offset of ProcessEnvironmentBlock in TEB */);
2029#elif K_ARCH == K_ARCH_AMD64
2030 return (PPEB)__readgsqword(0x060 /* offset of ProcessEnvironmentBlock in TEB */);
2031#else
2032# error "Port me!"
2033#endif
2034}
2035
2036
2037
2038
2039static int kwSandboxInit(PKWSANDBOX pSandbox, PKWTOOL pTool, const char *pszCmdLine)
2040{
2041 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
2042 wchar_t *pwcPool;
2043 KSIZE cbStrings;
2044 KSIZE cwc;
2045 int i;
2046
2047 /* Simple stuff. */
2048 g_Sandbox.rcExitCode = 256;
2049 g_Sandbox.pTool = pTool;
2050 g_Sandbox.idMainThread = GetCurrentThreadId();
2051 g_Sandbox.TibMainThread = *(PNT_TIB)NtCurrentTeb();
2052 g_Sandbox.pszCmdLine = pszCmdLine;
2053 g_Sandbox.pgmptr = (char *)pTool->pszPath;
2054 g_Sandbox.wpgmptr = (wchar_t *)pTool->pwszPath;
2055
2056 /*
2057 * Convert the command line to argc and argv.
2058 */
2059 cbStrings = parse_args(pszCmdLine, &pSandbox->cArgs, NULL /*papszArgs*/, NULL /*pchPool*/);
2060 pSandbox->papszArgs = (char **)kHlpAlloc(sizeof(char *) * (pSandbox->cArgs + 2) + cbStrings);
2061 if (!pSandbox->papszArgs)
2062 return KERR_NO_MEMORY;
2063 parse_args(pSandbox->pszCmdLine, &pSandbox->cArgs, pSandbox->papszArgs, (char *)&pSandbox->papszArgs[pSandbox->cArgs + 2]);
2064 pSandbox->papszArgs[pSandbox->cArgs + 0] = NULL;
2065 pSandbox->papszArgs[pSandbox->cArgs + 1] = NULL;
2066
2067 /*
2068 * Convert command line and argv to UTF-16.
2069 * We assume each ANSI char requires a surrogate pair in the UTF-16 variant.
2070 */
2071 pSandbox->papwszArgs = (wchar_t **)kHlpAlloc(sizeof(wchar_t *) * (pSandbox->cArgs + 2) + cbStrings * 2 * sizeof(wchar_t));
2072 if (!pSandbox->papwszArgs)
2073 return KERR_NO_MEMORY;
2074 pwcPool = (wchar_t *)&pSandbox->papwszArgs[pSandbox->cArgs + 2];
2075 for (i = 0; i < pSandbox->cArgs; i++)
2076 {
2077 *pwcPool++ = pSandbox->papszArgs[i][-1]; /* flags */
2078 pSandbox->papwszArgs[i] = pwcPool;
2079 pwcPool += kwStrToUtf16(pSandbox->papszArgs[i], pwcPool, (strlen(pSandbox->papszArgs[i]) + 1) * 2);
2080 pwcPool++;
2081 }
2082 pSandbox->papwszArgs[pSandbox->cArgs + 0] = NULL;
2083 pSandbox->papwszArgs[pSandbox->cArgs + 1] = NULL;
2084
2085 /*
2086 * Convert the commandline string to UTF-16, same pessimistic approach as above.
2087 */
2088 cbStrings = (kHlpStrLen(pSandbox->pszCmdLine) + 1) * 2 * sizeof(wchar_t);
2089 pSandbox->pwszCmdLine = kHlpAlloc(cbStrings);
2090 if (!pSandbox->pwszCmdLine)
2091 return KERR_NO_MEMORY;
2092 cwc = kwStrToUtf16(pSandbox->pszCmdLine, pSandbox->pwszCmdLine, cbStrings / sizeof(wchar_t));
2093
2094 pSandbox->SavedCommandLine = pPeb->ProcessParameters->CommandLine;
2095 pPeb->ProcessParameters->CommandLine.Buffer = pSandbox->pwszCmdLine;
2096 pPeb->ProcessParameters->CommandLine.Length = (USHORT)cwc * sizeof(wchar_t);
2097
2098 return 0;
2099}
2100
2101
2102static void kwSandboxCleanup(PKWSANDBOX pSandbox)
2103{
2104 PPEB pPeb = kwSandboxGetProcessEnvironmentBlock();
2105 pPeb->ProcessParameters->CommandLine = pSandbox->SavedCommandLine;
2106 /** @todo lots more to do here! */
2107}
2108
2109
2110static int kwSandboxExec(PKWTOOL pTool, const char *pszCmdLine, int *prcExitCode)
2111{
2112 int rc;
2113
2114 *prcExitCode = 256;
2115kwDbgPrintf("GetCommandLineA: '%s'\n", GetCommandLineA());
2116
2117 /*
2118 * Initialize the sandbox environment.
2119 */
2120 rc = kwSandboxInit(&g_Sandbox, pTool, pszCmdLine);
2121 if (rc == 0)
2122 {
2123
2124 /*
2125 * Do module initialization.
2126 */
2127 kwSandboxResetModuleState(pTool->u.Sandboxed.pExe);
2128 rc = kwLdrModuleInitTree(pTool->u.Sandboxed.pExe);
2129 if (rc == 0)
2130 {
2131 /*
2132 * Call the main function.
2133 */
2134 KUPTR uAddrMain;
2135 rc = kwLdrModuleQueryMainEntrypoint(pTool->u.Sandboxed.pExe, &uAddrMain);
2136 if (rc == 0)
2137 {
2138 int rcExitCode;
2139 int (*pfnWin64Entrypoint)(void *pvPeb, void *, void *, void *);
2140 *(KUPTR *)&pfnWin64Entrypoint = uAddrMain;
2141
2142 __try
2143 {
2144 if (setjmp(g_Sandbox.JmpBuf) == 0)
2145 {
2146#if K_ARCH == K_ARCH_AMD64
2147 *(KU64*)(g_Sandbox.JmpBuf) = 0; /** @todo find other way to prevent longjmp from doing unwind! */
2148#else
2149# error "Port me!"
2150#endif
2151 rcExitCode = pfnWin64Entrypoint(kwSandboxGetProcessEnvironmentBlock(), NULL, NULL, NULL);
2152 }
2153 else
2154 rcExitCode = g_Sandbox.rcExitCode;
2155 }
2156 __except (EXCEPTION_EXECUTE_HANDLER)
2157 {
2158 rcExitCode = 512;
2159 }
2160 *prcExitCode = rcExitCode;
2161
2162 /*
2163 * Restore the TIB and later some other stuff.
2164 */
2165 *(PNT_TIB)NtCurrentTeb() = g_Sandbox.TibMainThread;
2166 }
2167 }
2168 }
2169
2170 return rc;
2171}
2172
2173
2174static int kwExecCmdLine(const char *pszExe, const char *pszCmdLine)
2175{
2176 int rc;
2177 PKWTOOL pTool = kwToolLookup(pszExe);
2178 if (pTool)
2179 {
2180 int rc;
2181 int rcExitCode;
2182 switch (pTool->enmType)
2183 {
2184 case KWTOOLTYPE_SANDBOXED:
2185 kwDbgPrintf("Sandboxing tool %s\n", pTool->pszPath);
2186 rc = kwSandboxExec(pTool, pszCmdLine, &rcExitCode);
2187 break;
2188
2189 case KWTOOLTYPE_WATCOM:
2190 kwDbgPrintf("TODO: Watcom style tool %s\n", pTool->pszPath);
2191 rc = rcExitCode = 2;
2192 break;
2193
2194 case KWTOOLTYPE_EXEC:
2195 kwDbgPrintf("TODO: Direct exec tool %s\n", pTool->pszPath);
2196 rc = rcExitCode = 2;
2197 break;
2198
2199 default:
2200 kHlpAssertFailed();
2201 rc = rcExitCode = 2;
2202 break;
2203 }
2204 kwDbgPrintf("rcExitCode=%d (rc=%d)\n", rcExitCode, rc);
2205 }
2206 else
2207 rc = 1;
2208 return rc;
2209}
2210
2211
2212int main(int argc, char **argv)
2213{
2214 int i;
2215 int rc;
2216 argv[2] = "\"E:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/bin/amd64/cl.exe\" -c -c -TP -nologo -Zi -Zi -Zl -GR- -EHsc -GF -Zc:wchar_t- -Oy- -MT -W4 -Wall -wd4065 -wd4996 -wd4127 -wd4706 -wd4201 -wd4214 -wd4510 -wd4512 -wd4610 -wd4514 -wd4820 -wd4365 -wd4987 -wd4710 -wd4061 -wd4986 -wd4191 -wd4574 -wd4917 -wd4711 -wd4611 -wd4571 -wd4324 -wd4505 -wd4263 -wd4264 -wd4738 -wd4242 -wd4244 -WX -RTCsu -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -IE:/vbox/svn/trunk/tools/win.x86/sdk/v7.1/Include -IE:/vbox/svn/trunk/include -IE:/vbox/svn/trunk/out/win.amd64/debug -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/include -IE:/vbox/svn/trunk/tools/win.x86/vcc/v10sp1/atlmfc/include -DVBOX -DVBOX_WITH_64_BITS_GUESTS -DVBOX_WITH_REM -DVBOX_WITH_RAW_MODE -DDEBUG -DDEBUG_bird -DDEBUG_USERNAME=bird -DRT_OS_WINDOWS -D__WIN__ -DRT_ARCH_AMD64 -D__AMD64__ -D__WIN64__ -DVBOX_WITH_DEBUGGER -DRT_LOCK_STRICT -DRT_LOCK_STRICT_ORDER -DIN_RING3 -DLOG_DISABLED -DIN_BLD_PROG -D_CRT_SECURE_NO_DEPRECATE -FdE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker-obj.pdb -FD -FoE:/vbox/svn/trunk/out/win.amd64/debug/obj/VBoxBs2Linker/VBoxBs2Linker.obj E:\\vbox\\svn\\trunk\\src\\VBox\\ValidationKit\\bootsectors\\VBoxBs2Linker.cpp";
2217 //rc = kwExecCmdLine(argv[1], argv[2]);
2218 //rc = kwExecCmdLine(argv[1], argv[2]);
2219// run 2: 34/1024 = 0x0 (0.033203125)
2220// run 1: 37/1024 = 0x0 (0.0361328125)
2221// kmk 1: 44/1024 = 0x0 (0.04296875)
2222// cmd 1: 48/1024 = 0x0 (0.046875)
2223 g_cVerbose = 0;
2224 for (i = 0; i < 1024 && rc == 0; i++)
2225 rc = kwExecCmdLine(argv[1], argv[2]);
2226 return rc;
2227}
2228
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