/*++ Copyright (c) 1992 Microsoft Corporation Module Name: imagecfg.c Abstract: This function change the image loader configuration information in an image file. Author: Steve Wood (stevewo) 8-Nov-1994 Revision History: --*/ #include #include #include #include struct { DWORD Flag; LPSTR ClearPrefix; LPSTR SetPrefix; LPSTR Description; } NtGlobalFlagNames[] = { {FLG_STOP_ON_EXCEPTION, "Don't ", "", "Stop on exception"}, {FLG_SHOW_LDR_SNAPS, "Don't ", "", "Show Loader Debugging Information"}, {FLG_DEBUG_INITIAL_COMMAND, "Don't ", "", "Debug Initial Command (WINLOGON)"}, {FLG_STOP_ON_HUNG_GUI, "Don't ", "", "Stop on Hung GUI"}, {FLG_HEAP_ENABLE_TAIL_CHECK, "Disable", "Enable", " Heap Tail Checking"}, {FLG_HEAP_ENABLE_FREE_CHECK, "Disable", "Enable", " Heap Free Checking"}, {FLG_HEAP_VALIDATE_PARAMETERS, "Disable", "Enable", " Heap Parameter Validation"}, {FLG_HEAP_VALIDATE_ALL, "Disable", "Enable", " Heap Validate on Call"}, {FLG_POOL_ENABLE_TAGGING, "Disable", "Enable", " Pool Tagging"}, {FLG_HEAP_ENABLE_TAGGING, "Disable", "Enable", " Heap Tagging"}, {FLG_USER_STACK_TRACE_DB, "Disable", "Enable", " User Mode Stack Backtrace DB (x86 checked only)"}, {FLG_KERNEL_STACK_TRACE_DB, "Disable", "Enable", " Kernel Mode Stack Backtrace DB (x86 checked only)"}, {FLG_MAINTAIN_OBJECT_TYPELIST, "Don't ", "", "Maintain list of kernel mode objects by type"}, {FLG_HEAP_ENABLE_TAG_BY_DLL, "Disable", "Enable", " Heap DLL Tagging"}, {FLG_ENABLE_CSRDEBUG, "Disable", "Enable", " Debugging of CSRSS"}, {FLG_ENABLE_KDEBUG_SYMBOL_LOAD, "Disable", "Enable", " Kernel Debugger Symbol load"}, {FLG_DISABLE_PAGE_KERNEL_STACKS, "Enable", "Disable", " Paging of Kernel Stacks"}, {FLG_HEAP_DISABLE_COALESCING, "Enable", "Disable", " Heap Coalescing on Free"}, {FLG_ENABLE_CLOSE_EXCEPTIONS, "Disable", "Enable", " Close Exceptions"}, {FLG_ENABLE_EXCEPTION_LOGGING, "Disable", "Enable", " Exception Logging"}, {FLG_ENABLE_HANDLE_TYPE_TAGGING, "Disable", "Enable", " Handle type tagging"}, {FLG_HEAP_PAGE_ALLOCS, "Disable", "Enable", " Heap page allocs"}, {FLG_DEBUG_INITIAL_COMMAND_EX, "Disable", "Enable", " Extended debug initial command"}, {FLG_DISABLE_DBGPRINT, "Enable", "Disable"," DbgPrint to debugger"}, {0, NULL} }; void DisplayGlobalFlags( LPSTR IndentString, DWORD NtGlobalFlags, BOOLEAN Set ) { ULONG i; for (i=0; NtGlobalFlagNames[i].Description; i++) { if (NtGlobalFlagNames[i].Flag & NtGlobalFlags) { printf( "%s%s%s\n", IndentString, Set ? NtGlobalFlagNames[i].SetPrefix : NtGlobalFlagNames[i].ClearPrefix, NtGlobalFlagNames[i].Description ); } } return; } BOOL fVerbose; BOOL fUsage; BOOL fConfigInfoChanged; BOOL fImageHasConfigInfo; BOOL fImageHeaderChanged; LPSTR CurrentImageName; BOOL f64bitImage; LOADED_IMAGE CurrentImage; PIMAGE_LOAD_CONFIG_DIRECTORY pConfigInfo; CHAR DebugFilePath[_MAX_PATH]; LPSTR SymbolPath; ULONG GlobalFlagsClear; ULONG GlobalFlagsSet; ULONG CriticalSectionDefaultTimeout; ULONG ProcessHeapFlags; ULONG MajorSubsystemVersion; ULONG MinorSubsystemVersion; ULONG Win32VersionValue; ULONG Win32CSDVerValue; BOOLEAN fUniprocessorOnly; BOOLEAN fRestrictedWorkingSet; BOOLEAN fEnableLargeAddresses; BOOLEAN fNoBind; BOOLEAN fEnableTerminalServerAware; BOOLEAN fDisableTerminalServerAware; BOOLEAN fSwapRunNet; BOOLEAN fSwapRunCD; BOOLEAN fQuiet; ULONGLONG DeCommitFreeBlockThreshold; ULONGLONG DeCommitTotalFreeThreshold; ULONGLONG MaximumAllocationSize; ULONGLONG VirtualMemoryThreshold; ULONGLONG ImageProcessAffinityMask; ULONGLONG SizeOfStackReserve; ULONGLONG SizeOfStackCommit; VOID DisplayImageInfo( BOOL HasConfigInfo ); PVOID GetAddressOfExportedData( PLOADED_IMAGE Dll, LPSTR ExportedName ); ULONGLONG ConvertNum( char *s ) { ULONGLONG result; int n; if (!_strnicmp( s, "0x", 2 )) { s += 2; n = sscanf( s, "%I64x", &result ); } else { n = sscanf( s, "%I64d", &result ); } return( ( n != 1 ) ? 0 : result ); } // ConvertNum() __inline PVOID GetVaForRva( PLOADED_IMAGE Image, ULONG Rva ) { PVOID Va; Va = ImageRvaToVa( Image->FileHeader, Image->MappedAddress, Rva, &Image->LastRvaSection ); return Va; } PVOID GetAddressOfExportedData( PLOADED_IMAGE Dll, LPSTR ExportedName ) { PIMAGE_EXPORT_DIRECTORY Exports; ULONG ExportSize; USHORT HintIndex; USHORT OrdinalNumber; PULONG NameTableBase; PUSHORT NameOrdinalTableBase; PULONG FunctionTableBase; LPSTR NameTableName; Exports = (PIMAGE_EXPORT_DIRECTORY)ImageDirectoryEntryToData( (PVOID)Dll->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize ); if (Exports) { NameTableBase = (PULONG)GetVaForRva( Dll, Exports->AddressOfNames ); NameOrdinalTableBase = (PUSHORT)GetVaForRva( Dll, Exports->AddressOfNameOrdinals ); FunctionTableBase = (PULONG)GetVaForRva( Dll, Exports->AddressOfFunctions ); if (NameTableBase != NULL && NameOrdinalTableBase != NULL && FunctionTableBase != NULL ) { for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++) { NameTableName = (LPSTR)GetVaForRva( Dll, NameTableBase[ HintIndex ] ); if (NameTableName) { if (!strcmp( ExportedName, NameTableName )) { OrdinalNumber = NameOrdinalTableBase[ HintIndex ]; return FunctionTableBase[ OrdinalNumber ] + Dll->MappedAddress; } } } } } return NULL; } VOID DisplayConfigInfo32(PIMAGE_LOAD_CONFIG_DIRECTORY32 LoadConfig) { if (LoadConfig->GlobalFlagsClear) { printf( " NtGlobalFlags to clear: %08x\n", LoadConfig->GlobalFlagsClear); DisplayGlobalFlags( " ", LoadConfig->GlobalFlagsClear, FALSE ); } if (LoadConfig->GlobalFlagsSet) { printf( " NtGlobalFlags to set: %08x\n", LoadConfig->GlobalFlagsSet); DisplayGlobalFlags( " ", LoadConfig->GlobalFlagsSet, TRUE ); } if (LoadConfig->CriticalSectionDefaultTimeout) { printf( " Default Critical Section Timeout: %u milliseconds\n", LoadConfig->CriticalSectionDefaultTimeout); } if (LoadConfig->DeCommitFreeBlockThreshold) { printf( " Process Heap DeCommit Free Block threshold: %08x\n", (DWORD)LoadConfig->DeCommitFreeBlockThreshold); } if (LoadConfig->DeCommitTotalFreeThreshold) { printf( " Process Heap DeCommit Total Free threshold: %08x\n", (DWORD)LoadConfig->DeCommitTotalFreeThreshold); } if (LoadConfig->LockPrefixTable) { printf( " Lock Prefix Table: %x\n", LoadConfig->LockPrefixTable); } if (LoadConfig->MaximumAllocationSize) { printf( " Process Heap Maximum Allocation Size: %08x\n", LoadConfig->MaximumAllocationSize); } if (LoadConfig->VirtualMemoryThreshold) { printf( " Process Heap VirtualAlloc Threshold: %08x\n", LoadConfig->VirtualMemoryThreshold); } if (LoadConfig->ProcessHeapFlags) { printf( " Process Heap Flags: %08x\n", LoadConfig->ProcessHeapFlags); } if (LoadConfig->ProcessAffinityMask) { printf( " Process Affinity Mask: %08x\n", LoadConfig->ProcessAffinityMask); } if (LoadConfig->CSDVersion) { printf( " CSD version: %d\n", LoadConfig->CSDVersion); } if (LoadConfig->Size >= FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount)) { if (LoadConfig->SecurityCookie) { printf( " Security Cookie offset: %x\n", LoadConfig->SecurityCookie); } if (LoadConfig->SEHandlerTable) { printf( " SEH handler table: %x\n", LoadConfig->SEHandlerTable); } if (LoadConfig->SEHandlerCount) { printf( " SEH Handler count: %d\n", LoadConfig->SEHandlerCount); } } } VOID DisplayConfigInfo64(PIMAGE_LOAD_CONFIG_DIRECTORY64 LoadConfig) { if (LoadConfig->GlobalFlagsClear) { printf( " NtGlobalFlags to clear: %08x\n", LoadConfig->GlobalFlagsClear); DisplayGlobalFlags( " ", LoadConfig->GlobalFlagsClear, FALSE ); } if (LoadConfig->GlobalFlagsSet) { printf( " NtGlobalFlags to set: %08x\n", LoadConfig->GlobalFlagsSet); DisplayGlobalFlags( " ", LoadConfig->GlobalFlagsSet, TRUE ); } if (LoadConfig->CriticalSectionDefaultTimeout) { printf( " Default Critical Section Timeout: %u milliseconds\n", LoadConfig->CriticalSectionDefaultTimeout); } if (LoadConfig->DeCommitFreeBlockThreshold) { printf( " Process Heap DeCommit Free Block threshold: %I64x\n", LoadConfig->DeCommitFreeBlockThreshold); } if (LoadConfig->DeCommitTotalFreeThreshold) { printf( " Process Heap DeCommit Total Free threshold: %I64x\n", LoadConfig->DeCommitTotalFreeThreshold); } if (LoadConfig->LockPrefixTable) { printf( " Lock Prefix Table: %I64x\n", LoadConfig->LockPrefixTable); } if (LoadConfig->MaximumAllocationSize) { printf( " Process Heap Maximum Allocation Size: %I64x\n", LoadConfig->MaximumAllocationSize); } if (LoadConfig->VirtualMemoryThreshold) { printf( " Process Heap VirtualAlloc Threshold: %I64x\n", LoadConfig->VirtualMemoryThreshold); } if (LoadConfig->ProcessHeapFlags) { printf( " Process Heap Flags: %08x\n", LoadConfig->ProcessHeapFlags); } if (LoadConfig->ProcessAffinityMask) { printf( " Process Affinity Mask: %I64x\n", LoadConfig->ProcessAffinityMask); } if (LoadConfig->CSDVersion) { printf( " CSD version: %d\n", LoadConfig->CSDVersion); } if (LoadConfig->Size >= FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerCount)) { if (LoadConfig->SecurityCookie) { printf( " Security Cookie offset: %I64x\n", LoadConfig->SecurityCookie); } if (LoadConfig->SEHandlerTable) { printf( " SEH handler table: %I64x\n", LoadConfig->SEHandlerTable); } if (LoadConfig->SEHandlerCount) { printf( " SEH Handler count: %d\n", LoadConfig->SEHandlerCount); } } } VOID DisplayHeaderInfo32(PIMAGE_NT_HEADERS32 NtHeader) { printf( " Subsystem Version of %u.%u\n", NtHeader->OptionalHeader.MajorSubsystemVersion, NtHeader->OptionalHeader.MinorSubsystemVersion); if (NtHeader->OptionalHeader.Win32VersionValue) { printf( " Win32 GetVersion return value: %08x\n", NtHeader->OptionalHeader.Win32VersionValue); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) { printf( " Image can handle large (>2GB) addresses\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) { printf( " Image will run from swapfile if located on net\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) { printf( " Image will run from swapfile if located on removable media\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) { printf( " Image can only run in uni-processor mode on multi-processor systems\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) { printf( " Image working set trimmed aggressively on small memory systems\n" ); } if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) { printf( " Image is Terminal Server aware\n" ); } if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) { printf( " Image does not support binding\n" ); } if (NtHeader->OptionalHeader.SizeOfStackReserve) { printf( " Stack Reserve Size: 0x%x\n", NtHeader->OptionalHeader.SizeOfStackReserve ); } if (NtHeader->OptionalHeader.SizeOfStackCommit) { printf( " Stack Commit Size: 0x%x\n", NtHeader->OptionalHeader.SizeOfStackCommit ); } } VOID DisplayHeaderInfo64(PIMAGE_NT_HEADERS64 NtHeader) { printf( " Subsystem Version of %u.%u\n", NtHeader->OptionalHeader.MajorSubsystemVersion, NtHeader->OptionalHeader.MinorSubsystemVersion); if (NtHeader->OptionalHeader.Win32VersionValue) { printf( " Win32 GetVersion return value: %08x\n", NtHeader->OptionalHeader.Win32VersionValue); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE) { printf( " Image can handle large (>2GB) addresses\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP) { printf( " Image will run from swapfile if located on net\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) { printf( " Image will run from swapfile if located on removable media\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY) { printf( " Image can only run in uni-processor mode on multi-processor systems\n" ); } if (NtHeader->FileHeader.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM) { printf( " Image working set trimmed aggressively on small memory systems\n" ); } if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) { printf( " Image is Terminal Server aware\n" ); } if (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND) { printf( " Image does not support binding\n" ); } if (NtHeader->OptionalHeader.SizeOfStackReserve) { printf( " Stack Reserve Size: 0x%I64x\n", NtHeader->OptionalHeader.SizeOfStackReserve ); } if (NtHeader->OptionalHeader.SizeOfStackCommit) { printf( " Stack Commit Size: 0x%I64x\n", NtHeader->OptionalHeader.SizeOfStackCommit ); } } BOOL CheckIfConfigInfoChanged64(PIMAGE_LOAD_CONFIG_DIRECTORY64 LoadConfig) { if ((GlobalFlagsClear && (LoadConfig->GlobalFlagsClear != GlobalFlagsClear)) || (GlobalFlagsSet && (LoadConfig->GlobalFlagsSet != GlobalFlagsSet)) || (CriticalSectionDefaultTimeout && (LoadConfig->CriticalSectionDefaultTimeout != CriticalSectionDefaultTimeout)) || (ProcessHeapFlags && (LoadConfig->ProcessHeapFlags != ProcessHeapFlags)) || (DeCommitFreeBlockThreshold && (LoadConfig->DeCommitFreeBlockThreshold != DeCommitFreeBlockThreshold)) || (DeCommitTotalFreeThreshold && (LoadConfig->DeCommitTotalFreeThreshold != DeCommitTotalFreeThreshold)) || (MaximumAllocationSize && (LoadConfig->MaximumAllocationSize != MaximumAllocationSize)) || (VirtualMemoryThreshold && (LoadConfig->VirtualMemoryThreshold != VirtualMemoryThreshold)) || (ImageProcessAffinityMask && (LoadConfig->ProcessAffinityMask != ImageProcessAffinityMask))) { return TRUE; } else { return FALSE; } } BOOL CheckIfConfigInfoChanged32(PIMAGE_LOAD_CONFIG_DIRECTORY32 LoadConfig) { if ((GlobalFlagsClear && (LoadConfig->GlobalFlagsClear != GlobalFlagsClear)) || (GlobalFlagsSet && (LoadConfig->GlobalFlagsSet != GlobalFlagsSet)) || (CriticalSectionDefaultTimeout && (LoadConfig->CriticalSectionDefaultTimeout != CriticalSectionDefaultTimeout)) || (ProcessHeapFlags && (LoadConfig->ProcessHeapFlags != ProcessHeapFlags)) || (DeCommitFreeBlockThreshold && (LoadConfig->DeCommitFreeBlockThreshold != (DWORD)DeCommitFreeBlockThreshold)) || (DeCommitTotalFreeThreshold && (LoadConfig->DeCommitTotalFreeThreshold != (DWORD)DeCommitTotalFreeThreshold)) || (MaximumAllocationSize && (LoadConfig->MaximumAllocationSize != (DWORD)MaximumAllocationSize)) || (VirtualMemoryThreshold && (LoadConfig->VirtualMemoryThreshold != (DWORD)VirtualMemoryThreshold)) || (ImageProcessAffinityMask && (LoadConfig->ProcessAffinityMask != (DWORD)ImageProcessAffinityMask))) { return TRUE; } else { return FALSE; } } BOOL CheckIfImageHeaderChanged32(PIMAGE_NT_HEADERS32 NtHeader) { if ((MajorSubsystemVersion && NtHeader->OptionalHeader.MajorSubsystemVersion != (USHORT)MajorSubsystemVersion || NtHeader->OptionalHeader.MinorSubsystemVersion != (USHORT)MinorSubsystemVersion) || (Win32VersionValue && (NtHeader->OptionalHeader.Win32VersionValue != Win32VersionValue)) || (fEnableLargeAddresses && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) || (fNoBind && !(NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND)) || (fEnableTerminalServerAware && !(NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) || (fDisableTerminalServerAware && (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) || (fSwapRunNet && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)) || (fSwapRunCD && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)) || (fUniprocessorOnly && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)) || (fRestrictedWorkingSet && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM)) || (SizeOfStackReserve && (NtHeader->OptionalHeader.SizeOfStackReserve != (DWORD)SizeOfStackReserve)) || (SizeOfStackCommit && (NtHeader->OptionalHeader.SizeOfStackCommit != (DWORD)SizeOfStackCommit)) ) { return TRUE; } else { return FALSE; } } BOOL CheckIfImageHeaderChanged64(PIMAGE_NT_HEADERS64 NtHeader) { if ((MajorSubsystemVersion && NtHeader->OptionalHeader.MajorSubsystemVersion != (USHORT)MajorSubsystemVersion || NtHeader->OptionalHeader.MinorSubsystemVersion != (USHORT)MinorSubsystemVersion) || (Win32VersionValue && (NtHeader->OptionalHeader.Win32VersionValue != Win32VersionValue)) || (fEnableLargeAddresses && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)) || (fNoBind && !(NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NO_BIND)) || (fEnableTerminalServerAware && !(NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) || (fDisableTerminalServerAware && (NtHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE)) || (fSwapRunNet && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_NET_RUN_FROM_SWAP)) || (fSwapRunCD && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP)) || (fUniprocessorOnly && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_UP_SYSTEM_ONLY)) || (fRestrictedWorkingSet && !(NtHeader->FileHeader.Characteristics & IMAGE_FILE_AGGRESIVE_WS_TRIM)) || (SizeOfStackReserve && (NtHeader->OptionalHeader.SizeOfStackReserve != SizeOfStackReserve)) || (SizeOfStackCommit && (NtHeader->OptionalHeader.SizeOfStackCommit != SizeOfStackCommit)) ) { return TRUE; } else { return FALSE; } } BOOL SetImageConfigInformation32( PLOADED_IMAGE LoadedImage, PIMAGE_LOAD_CONFIG_DIRECTORY32 ImageConfigInformation ) { PIMAGE_LOAD_CONFIG_DIRECTORY32 ImageConfigData; ULONG i; ULONG DirectoryAddress; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DATA_DIRECTORY pLoadCfgDataDir; // We can only write native loadcfg struct ULONG V1LoadCfgLength = FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable); ULONG NewDataSize; if (LoadedImage->hFile == INVALID_HANDLE_VALUE) { return FALSE; } ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY32) ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &i ); if (ImageConfigData && (i == V1LoadCfgLength)) { if (ImageConfigInformation->Size) { // Incoming size specified? if (ImageConfigData->Size == ImageConfigInformation->Size) { // Current size same as new size? Do the copy memcpy( ImageConfigData, ImageConfigInformation, ImageConfigInformation->Size); return TRUE; } if (ImageConfigData->Size > ImageConfigInformation->Size) { // New size < old size - can't allow that return FALSE; } // Last case is new size > old size - fall through and find room for new data. } else { // Incoming size not set - must be an V1 user. if (ImageConfigData->Size) { // Existing size set? Can't overwrite new data with old data return FALSE; } // New and old are both V1 structs. memcpy( ImageConfigData, ImageConfigInformation, V1LoadCfgLength); return TRUE; } } NewDataSize = ImageConfigInformation->Size ? ImageConfigInformation->Size : V1LoadCfgLength; DirectoryAddress = GetImageUnusedHeaderBytes( LoadedImage, &i ); if (i < NewDataSize) { return FALSE; } NtHeaders = LoadedImage->FileHeader; pLoadCfgDataDir = &((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]; pLoadCfgDataDir->VirtualAddress = DirectoryAddress; pLoadCfgDataDir->Size = V1LoadCfgLength; ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY32) ((PCHAR)LoadedImage->MappedAddress + DirectoryAddress); memcpy( ImageConfigData, ImageConfigInformation, sizeof( *ImageConfigData ) ); return TRUE; } BOOL SetImageConfigInformation64( PLOADED_IMAGE LoadedImage, PIMAGE_LOAD_CONFIG_DIRECTORY64 ImageConfigInformation ) { PIMAGE_LOAD_CONFIG_DIRECTORY64 ImageConfigData; ULONG i; ULONG DirectoryAddress; PIMAGE_NT_HEADERS NtHeaders; PIMAGE_DATA_DIRECTORY pLoadCfgDataDir; // We can only write native loadcfg struct ULONG V1LoadCfgLength = FIELD_OFFSET(IMAGE_LOAD_CONFIG_DIRECTORY64, SEHandlerTable); ULONG NewDataSize; if (LoadedImage->hFile == INVALID_HANDLE_VALUE) { return FALSE; } ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY64) ImageDirectoryEntryToData( LoadedImage->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &i ); if (ImageConfigData && (i == V1LoadCfgLength)) { if (ImageConfigInformation->Size) { // Incoming size specified? if (ImageConfigData->Size == ImageConfigInformation->Size) { // Current size same as new size? Do the copy memcpy( ImageConfigData, ImageConfigInformation, ImageConfigInformation->Size); return TRUE; } if (ImageConfigData->Size > ImageConfigInformation->Size) { // New size < old size - can't allow that return FALSE; } // Last case is new size > old size - fall through and find room for new data. } else { // Incoming size not set - must be an V1 user. if (ImageConfigData->Size) { // Existing size set? Can't overwrite new data with old data return FALSE; } // New and old are both V1 structs. memcpy( ImageConfigData, ImageConfigInformation, V1LoadCfgLength); return TRUE; } } NewDataSize = ImageConfigInformation->Size ? ImageConfigInformation->Size : V1LoadCfgLength; DirectoryAddress = GetImageUnusedHeaderBytes( LoadedImage, &i ); if (i < NewDataSize) { return FALSE; } NtHeaders = LoadedImage->FileHeader; pLoadCfgDataDir = &((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG]; pLoadCfgDataDir->VirtualAddress = DirectoryAddress; pLoadCfgDataDir->Size = V1LoadCfgLength; ImageConfigData = (PIMAGE_LOAD_CONFIG_DIRECTORY64) ((PCHAR)LoadedImage->MappedAddress + DirectoryAddress); memcpy( ImageConfigData, ImageConfigInformation, sizeof( *ImageConfigData ) ); return TRUE; } int __cdecl main( int argc, char *argv[], char *envp[] ) { UCHAR c; LPSTR p, sMajor, sMinor, sReserve, sCommit; ULONG HeaderSum; SYSTEMTIME SystemTime; FILETIME LastWriteTime; DWORD OldChecksum; PVOID pNewConfigData, pOldConfigData; DWORD ImageConfigSize; fUsage = FALSE; fVerbose = FALSE; _tzset(); if (argc <= 1) { goto showUsage; } while (--argc) { p = *++argv; if (*p == '/' || *p == '-') { while (c = *++p) switch (toupper( c )) { case '?': fUsage = TRUE; break; case 'A': if (--argc) { ImageProcessAffinityMask = ConvertNum( *++argv ); if (ImageProcessAffinityMask == 0) { fprintf( stderr, "IMAGECFG: invalid affinity mask specified to /a switch.\n" ); fUsage = TRUE; } } else { fprintf( stderr, "IMAGECFG: /a switch missing argument.\n" ); fUsage = TRUE; } break; case 'C': if (--argc) { if (sscanf( *++argv, "%x", &Win32CSDVerValue ) != 1) { fprintf( stderr, "IMAGECFG: invalid version string specified to /c switch.\n" ); fUsage = TRUE; } } else { fprintf( stderr, "IMAGECFG: /c switch missing argument.\n" ); fUsage = TRUE; } break; case 'D': if (argc >= 2) { argc -= 2; DeCommitFreeBlockThreshold = ConvertNum( *++argv ); DeCommitTotalFreeThreshold = ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /d switch missing arguments.\n" ); fUsage = TRUE; } break; case 'G': if (argc >= 2) { argc -= 2; GlobalFlagsClear = (ULONG) ConvertNum( *++argv ); GlobalFlagsSet = (ULONG) ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /g switch missing arguments.\n" ); fUsage = TRUE; } break; case 'H': if (argc > 2) { INT flag = -1; if (sscanf( *++argv, "%d", &flag ) != 1) { fprintf( stderr, "IMAGECFG: invalid option string specified to /h switch.\n" ); fUsage = TRUE; } else { --argc; if (flag == 0) { fDisableTerminalServerAware = TRUE; } else if (flag == 1) { fEnableTerminalServerAware = TRUE; } else { fprintf( stderr, "IMAGECFG: /h switch invalid argument.\n" ); fUsage = TRUE; } } } else { fprintf( stderr, "IMAGECFG: /h switch missing argument.\n" ); fUsage = TRUE; } break; case 'K': if (--argc) { sReserve = *++argv; sCommit = strchr( sReserve, '.' ); if (sCommit != NULL) { *sCommit++ = '\0'; SizeOfStackCommit = ConvertNum( sCommit ); SizeOfStackCommit = ((SizeOfStackCommit + 0x00000FFFui64) & ~0x00000FFFui64); if (SizeOfStackCommit == 0) { fprintf( stderr, "IMAGECFG: invalid stack commit size specified to /k switch.\n" ); fUsage = TRUE; } } SizeOfStackReserve = ConvertNum( sReserve ); SizeOfStackReserve = ((SizeOfStackReserve + 0x0000FFFFui64) & ~0x0000FFFFui64); if (SizeOfStackReserve == 0) { fprintf( stderr, "IMAGECFG: invalid stack reserve size specified to /k switch.\n" ); fUsage = TRUE; } } else { fprintf( stderr, "IMAGECFG: /w switch missing argument.\n" ); fUsage = TRUE; } break; case 'L': fEnableLargeAddresses = TRUE; break; case 'M': if (--argc) { MaximumAllocationSize = ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /m switch missing argument.\n" ); fUsage = TRUE; } break; case 'N': fNoBind = TRUE; break; case 'O': if (--argc) { CriticalSectionDefaultTimeout = (ULONG) ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /o switch missing argument.\n" ); fUsage = TRUE; } break; case 'P': if (--argc) { ProcessHeapFlags = (ULONG) ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /p switch missing argument.\n" ); fUsage = TRUE; } break; case 'Q': fQuiet = TRUE; break; case 'R': fRestrictedWorkingSet = TRUE; break; case 'S': if (--argc) { SymbolPath = *++argv; } else { fprintf( stderr, "IMAGECFG: /s switch missing path argument.\n" ); fUsage = TRUE; } break; case 'T': if (--argc) { VirtualMemoryThreshold = ConvertNum( *++argv ); } else { fprintf( stderr, "IMAGECFG: /t switch missing argument.\n" ); fUsage = TRUE; } break; case 'U': fUniprocessorOnly = TRUE; break; case 'V': if (--argc) { sMajor = *++argv; sMinor = strchr( sMajor, '.' ); if (sMinor != NULL) { *sMinor++ = '\0'; MinorSubsystemVersion = (ULONG) ConvertNum( sMinor ); } MajorSubsystemVersion = (ULONG) ConvertNum( sMajor ); if (MajorSubsystemVersion == 0) { fprintf( stderr, "IMAGECFG: invalid version string specified to /v switch.\n" ); fUsage = TRUE; } } else { fprintf( stderr, "IMAGECFG: /v switch missing argument.\n" ); fUsage = TRUE; } break; case 'W': if (--argc) { if (sscanf( *++argv, "%x", &Win32VersionValue ) != 1) { fprintf( stderr, "IMAGECFG: invalid version string specified to /w switch.\n" ); fUsage = TRUE; } } else { fprintf( stderr, "IMAGECFG: /w switch missing argument.\n" ); fUsage = TRUE; } break; case 'X': fSwapRunNet = TRUE; break; case 'Y': fSwapRunCD = TRUE; break; default: fprintf( stderr, "IMAGECFG: Invalid switch - /%c\n", c ); fUsage = TRUE; break; } if ( fUsage ) { showUsage: fprintf( stderr, "usage: IMAGECFG [switches] image-names... \n" " [-?] display this message\n" " [-a Process Affinity mask value in hex]\n" " [-c Win32 GetVersionEx Service Pack return value in hex]\n" " [-d decommit thresholds]\n" " [-g bitsToClear bitsToSet]\n" " [-h 1|0 (Enable/Disable Terminal Server Compatible bit)\n" " [-k StackReserve[.StackCommit]\n" " [-l enable large (>2GB) addresses\n" " [-m maximum allocation size]\n" " [-n bind no longer allowed on this image\n" " [-o default critical section timeout\n" " [-p process heap flags]\n" " [-q only print config info if changed\n" " [-r run with restricted working set]\n" " [-s path to symbol files]\n" " [-t VirtualAlloc threshold]\n" " [-u Marks image as uniprocessor only]\n" " [-v MajorVersion.MinorVersion]\n" " [-w Win32 GetVersion return value in hex]\n" " [-x Mark image as Net - Run From Swapfile\n" " [-y Mark image as Removable - Run From Swapfile\n" ); exit( 1 ); } } else { // // Map and load the current image // CurrentImageName = p; if (MapAndLoad( CurrentImageName, NULL, &CurrentImage, FALSE, TRUE // Read only ) ) { if (CurrentImage.FileHeader->OptionalHeader.Magic == IMAGE_ROM_OPTIONAL_HDR_MAGIC) { // Don't muck with ROM images. UnMapAndLoad( &CurrentImage ); continue; } if (CurrentImage.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { f64bitImage = TRUE; } pNewConfigData = malloc(f64bitImage ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64) : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)); if (!pNewConfigData) { printf("Out of memory\n"); exit(-1); } pOldConfigData = ImageDirectoryEntryToData(CurrentImage.MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &ImageConfigSize); if (pOldConfigData) { if (!fQuiet) { if (f64bitImage) { DisplayConfigInfo64(pOldConfigData); } else { DisplayConfigInfo32(pOldConfigData); } } if (((PIMAGE_LOAD_CONFIG_DIRECTORY)pOldConfigData)->Size) { // New format - Size is the real size. ImageConfigSize = ((PIMAGE_LOAD_CONFIG_DIRECTORY)pOldConfigData)->Size; } memcpy(pNewConfigData, pOldConfigData, ImageConfigSize); } else { ZeroMemory(pNewConfigData, f64bitImage ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64) : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)); ((PIMAGE_LOAD_CONFIG_DIRECTORY)pNewConfigData)->Size = f64bitImage ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64) : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32); } fConfigInfoChanged = f64bitImage ? CheckIfConfigInfoChanged64(pNewConfigData) : CheckIfConfigInfoChanged32(pNewConfigData); fImageHeaderChanged = f64bitImage ? CheckIfImageHeaderChanged64((PIMAGE_NT_HEADERS64)&CurrentImage.FileHeader) : CheckIfImageHeaderChanged32((PIMAGE_NT_HEADERS32)&CurrentImage.FileHeader); UnMapAndLoad( &CurrentImage ); if (fConfigInfoChanged || fImageHeaderChanged) { if (MapAndLoad( CurrentImageName, NULL, &CurrentImage, FALSE, FALSE )) { // Set Load Config data if (GlobalFlagsClear) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->GlobalFlagsClear = GlobalFlagsClear; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->GlobalFlagsClear = GlobalFlagsClear; } } if (GlobalFlagsSet) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->GlobalFlagsSet = GlobalFlagsSet; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->GlobalFlagsSet = GlobalFlagsSet; } } if (CriticalSectionDefaultTimeout) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->CriticalSectionDefaultTimeout = CriticalSectionDefaultTimeout; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->CriticalSectionDefaultTimeout = CriticalSectionDefaultTimeout; } } if (ProcessHeapFlags) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->ProcessHeapFlags = ProcessHeapFlags; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->ProcessHeapFlags = ProcessHeapFlags; } } if (DeCommitFreeBlockThreshold) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->DeCommitFreeBlockThreshold = DeCommitFreeBlockThreshold; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->DeCommitFreeBlockThreshold = (DWORD)DeCommitFreeBlockThreshold; } } if (DeCommitTotalFreeThreshold) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->DeCommitTotalFreeThreshold = DeCommitTotalFreeThreshold; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->DeCommitTotalFreeThreshold = (DWORD)DeCommitTotalFreeThreshold; } } if (MaximumAllocationSize) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->MaximumAllocationSize = MaximumAllocationSize; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->MaximumAllocationSize = (DWORD)MaximumAllocationSize; } } if (VirtualMemoryThreshold) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->VirtualMemoryThreshold = VirtualMemoryThreshold; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->VirtualMemoryThreshold = (DWORD)VirtualMemoryThreshold; } } if (ImageProcessAffinityMask) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->ProcessAffinityMask = ImageProcessAffinityMask; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->ProcessAffinityMask = (DWORD)ImageProcessAffinityMask; } } if (Win32CSDVerValue != 0) { if (f64bitImage) { ((PIMAGE_LOAD_CONFIG_DIRECTORY64)pNewConfigData)->CSDVersion = (USHORT)Win32CSDVerValue; } else { ((PIMAGE_LOAD_CONFIG_DIRECTORY32)pNewConfigData)->CSDVersion = (USHORT)Win32CSDVerValue; } } // Set File header values if (fEnableLargeAddresses) { CurrentImage.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE; } if (fSwapRunNet) { CurrentImage.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_NET_RUN_FROM_SWAP; } if (fSwapRunCD) { CurrentImage.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP; } if (fUniprocessorOnly) { CurrentImage.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_UP_SYSTEM_ONLY; } if (fRestrictedWorkingSet) { CurrentImage.FileHeader->FileHeader.Characteristics |= IMAGE_FILE_AGGRESIVE_WS_TRIM; } // Set Optional header values if (fNoBind) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_BIND; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_NO_BIND; } } if (fEnableTerminalServerAware) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; } } if (fDisableTerminalServerAware) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.DllCharacteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; } } if (MajorSubsystemVersion != 0) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.MajorSubsystemVersion = (USHORT)MajorSubsystemVersion; ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.MinorSubsystemVersion = (USHORT)MinorSubsystemVersion; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.MajorSubsystemVersion = (USHORT)MajorSubsystemVersion; ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.MinorSubsystemVersion = (USHORT)MinorSubsystemVersion; } } if (Win32VersionValue != 0) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.Win32VersionValue = Win32VersionValue; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.Win32VersionValue = Win32VersionValue; } } if (SizeOfStackReserve) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.SizeOfStackReserve = SizeOfStackReserve; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.SizeOfStackReserve = (DWORD)SizeOfStackReserve; } } if (SizeOfStackCommit) { if (f64bitImage) { ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.SizeOfStackCommit = SizeOfStackCommit; } else { ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.SizeOfStackCommit = (DWORD)SizeOfStackCommit; } } if (fConfigInfoChanged) { if (f64bitImage) { if (SetImageConfigInformation64( &CurrentImage, pNewConfigData )) { if (!fQuiet) { printf( "%s updated with the following configuration information:\n", CurrentImageName ); DisplayConfigInfo64(pNewConfigData); } } else { fprintf( stderr, "IMAGECFG: Unable to update configuration information in image.\n" ); } } else { if (SetImageConfigInformation32( &CurrentImage, pNewConfigData )) { if (!fQuiet) { printf( "%s updated with the following configuration information:\n", CurrentImageName ); DisplayConfigInfo32(pNewConfigData); } } else { fprintf( stderr, "IMAGECFG: Unable to update configuration information in image.\n" ); } } } // // recompute the checksum. // if (f64bitImage) { OldChecksum = ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.CheckSum; ((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.CheckSum = 0; CheckSumMappedFile( (PVOID)CurrentImage.MappedAddress, CurrentImage.SizeOfImage, &HeaderSum, &((PIMAGE_NT_HEADERS64)CurrentImage.FileHeader)->OptionalHeader.CheckSum ); } else { OldChecksum = ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.CheckSum; ((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.CheckSum = 0; CheckSumMappedFile( (PVOID)CurrentImage.MappedAddress, CurrentImage.SizeOfImage, &HeaderSum, &((PIMAGE_NT_HEADERS32)CurrentImage.FileHeader)->OptionalHeader.CheckSum ); } // And update the .dbg file (if requested) if (SymbolPath && CurrentImage.FileHeader->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED) { if (UpdateDebugInfoFileEx( CurrentImageName, SymbolPath, DebugFilePath, (PIMAGE_NT_HEADERS32)CurrentImage.FileHeader, OldChecksum ) ) { if (GetLastError() == ERROR_INVALID_DATA) { printf( "Warning: Old checksum did not match for %s\n", DebugFilePath); } printf( "Updated symbols for %s\n", DebugFilePath ); } else { printf( "Unable to update symbols: %s\n", DebugFilePath ); } } GetSystemTime( &SystemTime ); if (SystemTimeToFileTime( &SystemTime, &LastWriteTime )) { SetFileTime( CurrentImage.hFile, NULL, NULL, &LastWriteTime ); } UnMapAndLoad( &CurrentImage ); } } } else if (!CurrentImage.fDOSImage) { fprintf( stderr, "IMAGECFG: unable to map and load %s GetLastError= %d\n", CurrentImageName, GetLastError() ); } else { fprintf( stderr, "IMAGECFG: unable to modify DOS or Windows image file - %s\n", CurrentImageName ); } } } exit( 1 ); return 1; } #define STANDALONE_MAP #include