/*++ Copyright 1996 - 1997 Microsoft Corporation Module Name: symedit.c Abstract: Author: Wesley A. Witt (wesw) 19-April-1993 Environment: Win32, User Mode --*/ #include #include #include #include #include #include #include "strings.h" #include #undef UNICODE #define MAX_PATH 260 // prototypes for this module BOOL CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po ); void ProcessCommandLineArgs( int argc, WCHAR *argv[] ); void PrintCopyright( void ); void PrintUsage( void ); void FatalError( int, ... ); BOOL MapOutputFile ( PPOINTERS p, char *fname, int ); void ComputeChecksum( char *szExeFile ); void ReadDebugInfo( PPOINTERS p ); void WriteDebugInfo( PPOINTERS p, BOOL); void MungeDebugHeadersCoffToCv( PPOINTERS p, BOOL fAddCV ); void MungeExeName( PPOINTERS p, char * szExeName ); void DoCoffToCv(char *, char *, BOOL); void DoSymToCv(char *, char *, char *, char *); void DoNameChange(char *, char *, char *); void DoExtract(char *, char *, char *); void DoStrip(char *, char *); IMAGE_DEBUG_DIRECTORY DbgDirSpare; #define AdjustPtr(ptr) (((ptr) != NULL) ? \ ((DWORD)ptr - (DWORD)pi->fptr + (DWORD)po->fptr) : \ ((DWORD)(ptr))) int _cdecl wmain( int argc, WCHAR * argv[] ) /*++ Routine Description: Shell for this utility. Arguments: argc - argument count argv - argument pointers Return Value: 0 - image was converted >0 - image could not be converted --*/ { // Scan the command line and check what operations we are doing ProcessCommandLineArgs( argc, argv ); return 0; } __inline void PrintCopyright( void ) { puts( "\nMicrosoft(R) Windows NT SymEdit Version 1.0\n" "(C) 1989-1995 Microsoft Corp. All rights reserved.\n"); } __inline void PrintUsage( void ) { PrintCopyright(); puts ("\nUsage: SYMEDIT -q -o \n\n" "\t is:\n" "\tC\tModify CodeView symbol information\n" "\tN\tEdit name field\n" "\tX\tExtract debug information\n" "\tS\tStrip all debug information\n\n" "Options:\n" "\t-a\t\tAdd CodeView debug info to file\n" "\t-n\tName to change to\n" "\t-o\tspecify output file\n" "\t-q\t\tquiet mode\n" "\t-r\t\tReplace COFF debug info with CV info\n" "\t-s\tSym file source"); } void ProcessCommandLineArgs( int argc, WCHAR *argv[] ) /*++ Routine Description: Processes the command line arguments and sets global flags to indicate the user's desired behavior. Arguments: argc - argument count argv - argument pointers Return Value: void --*/ { int i; BOOL fQuiet = FALSE; BOOL fSilent = FALSE; char szOutputFile[MAX_PATH]; char szInputFile[MAX_PATH]; char szExeName[MAX_PATH]; char szDbgFile[MAX_PATH]; char szSymFile[MAX_PATH]; int iOperation; BOOLEAN fAddCV = FALSE; // Minimun number of of arguments is 2 -- program and operation if (argc < 2 || (wcscmp(argv[1], L"-?") == 0) || (wcscmp(argv[1], L"?") == 0) ) { PrintUsage(); exit(1); } // All operations on 1 character wide if (argv[1][1] != 0) { FatalError(ERR_OP_UNKNOWN, argv[1]); } // Validate the operation switch( argv[1][0] ) { case L'C': case L'N': case L'X': case L'S': iOperation = argv[1][0]; break; default: FatalError(ERR_OP_UNKNOWN, argv[1]); } // Parse out any other switches on the command line for (i=2; iCV) // Optional DBG file case 'C': if (szSymFile == NULL) { DoCoffToCv(szInputFile, szOutputFile, fAddCV); } else { DoSymToCv(szInputFile, szOutputFile, szDbgFile, szSymFile); } break; // For changing the name of the debuggee -- // Must specify input file // Must specify new name // Optional output file case 'N': DoNameChange(szInputFile, szOutputFile, szExeName); break; // For extraction of debug information // Must specify input file // Optional output file name // Optional debug file name case 'X': DoExtract(szInputFile, szOutputFile, szDbgFile); break; // For full strip of debug information // Must specify input file // Optional output file case 'S': DoStrip(szInputFile, szOutputFile); break; } } } return; } void ReadDebugInfo( PPOINTERS p ) /*++ Routine Description: This function will go out and read in all of the debug information into memory -- this is required because the input and output files might be the same, if so then writing out informaiton may destory data we need at a later time. Arguments: p - Supplies a pointer to the structure describing the debug info file Return Value: None. --*/ { int i; // int cb; // char * pb; // PIMAGE_COFF_SYMBOLS_HEADER pCoffDbgInfo; // Allocate space to save pointers to debug info p->iptrs.rgpbDebugSave = (PCHAR *) malloc(p->iptrs.cDebugDir * sizeof(PCHAR)); memset(p->iptrs.rgpbDebugSave, 0, p->iptrs.cDebugDir * sizeof(PCHAR)); // Check each possible debug type record for (i=0; iiptrs.cDebugDir; i++) { // If there was debug information then copy over the // description block and cache in the actual debug data. if (p->iptrs.rgDebugDir[i] != NULL) { p->iptrs.rgpbDebugSave[i] = malloc( p->iptrs.rgDebugDir[i]->SizeOfData ); if (p->iptrs.rgpbDebugSave[i] == NULL) { FatalError(ERR_NO_MEMORY); } __try { memcpy(p->iptrs.rgpbDebugSave[i], p->iptrs.fptr + p->iptrs.rgDebugDir[i]->PointerToRawData, p->iptrs.rgDebugDir[i]->SizeOfData ); } __except(EXCEPTION_EXECUTE_HANDLER ) { free(p->iptrs.rgpbDebugSave[i]); p->iptrs.rgpbDebugSave[i] = NULL; } } } return; } void WriteDebugInfo( PPOINTERS p, BOOL fAddCV ) /*++ Routine Description: This function will go out and read in all of the debug information into memory -- this is required because the input and output files might be the same, if so then writing out informaiton may destory data we need at a later time. Arguments: p - Supplies a pointer to the structure describing the debug info file Return Value: None. --*/ { ULONG PointerToDebugData = 0; // Offset from the start of the file // to the current location to write // debug information out. ULONG BaseOfDebugData = 0; int i, flen; PIMAGE_DEBUG_DIRECTORY pDir, pDbgDir = NULL; if (p->optrs.debugSection) { BaseOfDebugData = PointerToDebugData = p->optrs.debugSection->PointerToRawData; } else if (p->optrs.sepHdr) { BaseOfDebugData = PointerToDebugData = sizeof(IMAGE_SEPARATE_DEBUG_HEADER) + p->optrs.sepHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + p->optrs.sepHdr->ExportedNamesSize; } // Step 2. If the debug information is mapped, we know this // from the section headers, then we may need to write // out a new debug director to point to the debug information if (fAddCV) { if (p->optrs.optHdr) { p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]. VirtualAddress = p->optrs.debugSection->VirtualAddress; p->optrs.optHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size += sizeof(IMAGE_DEBUG_DIRECTORY); } else if (p->optrs.sepHdr) { p->optrs.sepHdr->DebugDirectorySize += sizeof(IMAGE_DEBUG_DIRECTORY); } else { exit(1); } if (p->optrs.sepHdr) { pDbgDir = (PIMAGE_DEBUG_DIRECTORY) malloc(p->optrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY)); for (i=0; ioptrs.cDebugDir; i++) { if (p->optrs.rgDebugDir[i] != NULL) { pDbgDir[i] = *(p->optrs.rgDebugDir[i]); p->optrs.rgDebugDir[i] = &pDbgDir[i]; } } } for (i=0; ioptrs.cDebugDir; i++) { if (p->optrs.rgDebugDir[i]) { pDir = (PIMAGE_DEBUG_DIRECTORY) (PointerToDebugData + p->optrs.fptr); *pDir = *(p->optrs.rgDebugDir[i]); p->optrs.rgDebugDir[i] = pDir; PointerToDebugData += sizeof(IMAGE_DEBUG_DIRECTORY); } } } // Step 3. For every debug info type, write out the debug information // and update any header information required for (i=0; ioptrs.cDebugDir; i++) { if (p->optrs.rgDebugDir[i] != NULL) { if (p->optrs.rgpbDebugSave[i] != NULL) { p->optrs.rgDebugDir[i]->PointerToRawData = PointerToDebugData; if (p->optrs.debugSection) { p->optrs.rgDebugDir[i]->AddressOfRawData = p->optrs.debugSection->VirtualAddress + PointerToDebugData - BaseOfDebugData; } memcpy(p->optrs.fptr + PointerToDebugData, p->optrs.rgpbDebugSave[i], p->optrs.rgDebugDir[i]->SizeOfData); if ((i == IMAGE_DEBUG_TYPE_COFF) && (p->optrs.fileHdr != NULL)) { PIMAGE_COFF_SYMBOLS_HEADER pCoffDbgInfo; pCoffDbgInfo = (PIMAGE_COFF_SYMBOLS_HEADER)p->optrs.rgpbDebugSave[i]; p->optrs.fileHdr->PointerToSymbolTable = PointerToDebugData + pCoffDbgInfo->LvaToFirstSymbol; } } PointerToDebugData += p->optrs.rgDebugDir[i]->SizeOfData; } } // Step 4. Clean up any COFF structures if we are replacing // the coff information with CV info. if ((p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_COFF] == NULL) && (p->optrs.fileHdr != NULL)) { // Since there is no coff debug information -- clean out // both fields pointing to the debug info p->optrs.fileHdr->PointerToSymbolTable = 0; p->optrs.fileHdr->NumberOfSymbols = 0; } // Step 5. Correct the alignments if needed. If there is a real .debug // section in the file (i.e. it is mapped) then update it. if (p->optrs.debugSection) { p->optrs.debugSection->SizeOfRawData = FileAlign(PointerToDebugData - BaseOfDebugData); // update the optional header with the new image size p->optrs.optHdr->SizeOfImage = SectionAlign(p->optrs.debugSection->VirtualAddress + p->optrs.debugSection->SizeOfRawData); p->optrs.optHdr->SizeOfInitializedData += p->optrs.debugSection->SizeOfRawData; } // calculate the new file size if (p->optrs.optHdr != NULL) { flen = FileAlign(PointerToDebugData); } else { flen = PointerToDebugData; } // finally, update the eof pointer and close the file UnmapViewOfFile( p->optrs.fptr ); if (!SetFilePointer( p->optrs.hFile, flen, 0, FILE_BEGIN )) { FatalError( ERR_FILE_PTRS ); } if (!SetEndOfFile( p->optrs.hFile )) { FatalError( ERR_SET_EOF ); } CloseHandle( p->optrs.hFile ); // Exit -- we are done. return; } void MungeDebugHeadersCoffToCv( PPOINTERS p, BOOL fAddCV ) /*++ Routine Description: Arguments: p - pointer to a POINTERS structure (see symcvt.h) Return Value: void --*/ { if (!fAddCV) { CV_DIR(&p->optrs) = COFF_DIR(&p->optrs); COFF_DIR(&p->optrs) = 0; } else { CV_DIR(&p->optrs) = &DbgDirSpare; *(COFF_DIR(&p->optrs)) = *(COFF_DIR(&p->iptrs)); }; *CV_DIR(&p->optrs) = *(COFF_DIR(&p->iptrs)); CV_DIR(&p->optrs)->Type = IMAGE_DEBUG_TYPE_CODEVIEW; CV_DIR(&p->optrs)->SizeOfData = p->pCvStart.size; p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_CODEVIEW] = p->pCvStart.ptr; return; } BOOL MapOutputFile ( PPOINTERS p, char *fname, int cb ) /*++ Routine Description: Maps the output file specified by the fname argument and saves the file handle & file pointer in the POINTERS structure. Arguments: p - pointer to a POINTERS structure (see symcvt.h) fname - ascii string for the file name Return Value: TRUE - file mapped ok FALSE - file could not be mapped --*/ { BOOL rval; HANDLE hMap = NULL; DWORD oSize; rval = FALSE; p->optrs.hFile = CreateFileA( fname, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL ); if (p->optrs.hFile == INVALID_HANDLE_VALUE) { goto exit; } oSize = p->iptrs.fsize; if (p->pCvStart.ptr != NULL) { oSize += p->pCvStart.size; } oSize += cb; oSize += p->iptrs.cDebugDir * sizeof(IMAGE_DEBUG_DIRECTORY); hMap = CreateFileMapping( p->optrs.hFile, NULL, PAGE_READWRITE, 0, oSize, NULL ); if (hMap == NULL) { goto exit; } p->optrs.fptr = MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, 0 ); CloseHandle(hMap); if (p->optrs.fptr == NULL) { goto exit; } rval = TRUE; exit: return rval; } BOOL CalculateOutputFilePointers( PIMAGEPOINTERS pi, PIMAGEPOINTERS po ) /*++ Routine Description: This function calculates the output file pointers based on the input file pointers. The same address is used but they are all re-based off the output file's file pointer. Arguments: p - pointer to a IMAGEPOINTERS structure (see symcvt.h) Return Value: TRUE - pointers were created FALSE - pointers could not be created --*/ { int i; // fixup the pointers relative the fptr for the output file po->dosHdr = (PIMAGE_DOS_HEADER) AdjustPtr(pi->dosHdr); po->ntHdr = (PIMAGE_NT_HEADERS) AdjustPtr(pi->ntHdr); po->fileHdr = (PIMAGE_FILE_HEADER) AdjustPtr(pi->fileHdr); po->optHdr = (PIMAGE_OPTIONAL_HEADER) AdjustPtr(pi->optHdr); po->sectionHdrs = (PIMAGE_SECTION_HEADER) AdjustPtr(pi->sectionHdrs); po->sepHdr = (PIMAGE_SEPARATE_DEBUG_HEADER) AdjustPtr(pi->sepHdr); po->debugSection = (PIMAGE_SECTION_HEADER) AdjustPtr(pi->debugSection); po->AllSymbols = (PIMAGE_SYMBOL) AdjustPtr(pi->AllSymbols); po->stringTable = (PUCHAR) AdjustPtr(pi->stringTable); // move the data from the input file to the output file memcpy( po->fptr, pi->fptr, pi->fsize ); po->cDebugDir = pi->cDebugDir; po->rgDebugDir = malloc(po->cDebugDir * sizeof(po->rgDebugDir[0])); memset(po->rgDebugDir, 0, po->cDebugDir * sizeof(po->rgDebugDir[0])); for (i=0; icDebugDir; i++) { po->rgDebugDir[i] = (PIMAGE_DEBUG_DIRECTORY) AdjustPtr(pi->rgDebugDir[i]); } po->rgpbDebugSave = pi->rgpbDebugSave; return TRUE; } void FatalError( int idMsg, ... ) /*++ Routine Description: Prints a message string to stderr and then exits. Arguments: s - message string to be printed Return Value: void --*/ { va_list marker; char rgchFormat[256]; char rgch[256]; LoadStringA(GetModuleHandle(NULL), idMsg, rgchFormat, sizeof(rgchFormat)); va_start(marker, idMsg); vsprintf(rgch, rgchFormat, marker); va_end(marker); fprintf(stderr, "%s\n", rgch); exit(1); } void ComputeChecksum( char *szExeFile ) /*++ Routine Description: Computes a new checksum for the image by calling imagehlp.dll Arguments: szExeFile - exe file name Return Value: void --*/ { DWORD dwHeaderSum = 0; DWORD dwCheckSum = 0; HANDLE hFile; DWORD cb; IMAGE_DOS_HEADER dosHdr; IMAGE_NT_HEADERS ntHdr; if (MapFileAndCheckSumA(szExeFile, &dwHeaderSum, &dwCheckSum) != CHECKSUM_SUCCESS) { FatalError( ERR_CHECKSUM_CALC ); } hFile = CreateFileA( szExeFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); // seek to the beginning of the file SetFilePointer( hFile, 0, 0, FILE_BEGIN ); // read in the dos header if ((ReadFile(hFile, &dosHdr, sizeof(dosHdr), &cb, 0) == FALSE) || (cb != sizeof(dosHdr))) { FatalError( ERR_CHECKSUM_CALC ); } // read in the pe header if ((dosHdr.e_magic != IMAGE_DOS_SIGNATURE) || (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L)) { FatalError( ERR_CHECKSUM_CALC ); } // read in the nt header if ((!ReadFile(hFile, &ntHdr, sizeof(ntHdr), &cb, 0)) || (cb != sizeof(ntHdr))) { FatalError( ERR_CHECKSUM_CALC ); } if (SetFilePointer(hFile, dosHdr.e_lfanew, 0, FILE_BEGIN) == -1L) { FatalError( ERR_CHECKSUM_CALC ); } ntHdr.OptionalHeader.CheckSum = dwCheckSum; if (!WriteFile(hFile, &ntHdr, sizeof(ntHdr), &cb, NULL)) { FatalError( ERR_CHECKSUM_CALC ); } CloseHandle(hFile); return; } void MungeExeName( PPOINTERS p, char * szExeName ) /*++ Routine Description: description-of-function. Arguments: argument-name - Supplies | Returns description of argument. . . Return Value: None. --*/ { PIMAGE_DEBUG_MISC pMiscIn; PIMAGE_DEBUG_MISC pMiscOut; int cb; int i; for (i=0; iiptrs.cDebugDir; i++) { if (p->optrs.rgDebugDir[i] != 0) { *(p->optrs.rgDebugDir[i]) = *(p->iptrs.rgDebugDir[i]); } } pMiscIn = (PIMAGE_DEBUG_MISC) p->iptrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC]; if (p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] == NULL) { p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC] = &DbgDirSpare; memset(&DbgDirSpare, 0, sizeof(DbgDirSpare)); } pMiscOut = (PIMAGE_DEBUG_MISC) p->optrs.rgpbDebugSave[IMAGE_DEBUG_TYPE_MISC] = malloc(p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData + strlen(szExeName)); cb = p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData; while ( cb > 0 ) { if (pMiscIn->DataType == IMAGE_DEBUG_MISC_EXENAME) { pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME; pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) + strlen(szExeName) + 3) & ~3; pMiscOut->Unicode = FALSE; strcpy(&pMiscOut->Data[0], szExeName); szExeName = NULL; } else { memcpy(pMiscOut, pMiscIn, pMiscIn->Length); } p->optrs.rgDebugDir[IMAGE_DEBUG_TYPE_MISC]->SizeOfData += (pMiscOut->Length - pMiscIn->Length); cb -= pMiscIn->Length; pMiscIn = (PIMAGE_DEBUG_MISC) (((char *) pMiscIn) + pMiscIn->Length); pMiscOut = (PIMAGE_DEBUG_MISC) (((char *) pMiscOut) + pMiscOut->Length); } if (szExeName) { pMiscOut->DataType = IMAGE_DEBUG_MISC_EXENAME; pMiscOut->Length = (sizeof(IMAGE_DEBUG_MISC) + strlen(szExeName) + 3) & ~3; pMiscOut->Unicode = FALSE; strcpy(&pMiscOut->Data[0], szExeName); } return; } /*** DoCoffToCv * * */ void DoCoffToCv( char * szInput, char * szOutput, BOOL fAddCV ) { POINTERS p; // Do default checking if (szOutput == NULL) { szOutput = szInput; } // Open the input file name and setup the pointers into the file if (!MapInputFile( &p, NULL, szInput )) { FatalError( ERR_OPEN_INPUT_FILE, szInput ); } // Now, if we thing we are playing with PE exes then we need // to setup the pointers into the map file if (!CalculateNtImagePointers( &p.iptrs )) { FatalError( ERR_INVALID_PE, szInput ); } // We are about to try and do the coff to cv symbol conversion. // // Verify that the operation is legal. // // 1. We need to have coff debug information to start with // 2. If the debug info is not mapped then we must not // be trying to add CodeView info. if ((p.iptrs.AllSymbols == NULL) || (COFF_DIR(&p.iptrs) == NULL)) { FatalError( ERR_NO_COFF ); } if (fAddCV && (p.iptrs.debugSection == 0) && (p.iptrs.sepHdr == NULL)) { FatalError( ERR_NOT_MAPPED ); } // Now go out an preform the acutal conversion. if (!ConvertCoffToCv( &p )) { FatalError( ERR_COFF_TO_CV ); } // Read in any additional debug information in the file ReadDebugInfo(&p); // Open the output file and adjust the pointers so that we are ok. if (!MapOutputFile( &p, szOutput, 0 )) { FatalError( ERR_MAP_FILE, szOutput ); } CalculateOutputFilePointers( &p.iptrs, &p.optrs ); // Munge the various debug information structures to preform the correct // operations MungeDebugHeadersCoffToCv( &p, fAddCV ); // Free our handles on the input file UnMapInputFile(&p); // Write out the debug information to the end of the exe WriteDebugInfo( &p, fAddCV ); // and finally compute the checksum if (p.iptrs.fileHdr != NULL) { ComputeChecksum( szOutput ); } return; } /*** DoSymToCv * */ void DoSymToCv( char * szInput, char * szOutput, char * szDbg, char * szSym ) { POINTERS p; HANDLE hFile; DWORD cb; OFSTRUCT ofs; // Open the input file name and setup the pointers into the file if (!MapInputFile( &p, NULL, szSym )) { FatalError(ERR_OPEN_INPUT_FILE, szSym); } // Now preform the desired operation if ((szOutput == NULL) && (szDbg == NULL)) { szOutput = szInput; } ConvertSymToCv( &p ); if (szOutput) { if (szOutput != szInput) { if (OpenFile(szInput, &ofs, OF_EXIST) == 0) { FatalError(ERR_OPEN_INPUT_FILE, szInput); } if (CopyFileA(szInput, szOutput, FALSE) == 0) { FatalError(ERR_OPEN_WRITE_FILE, szOutput); } } hFile = CreateFileA(szOutput, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { FatalError(ERR_OPEN_WRITE_FILE, szOutput); } SetFilePointer(hFile, 0, 0, FILE_END); } else if (szDbg) { hFile = CreateFileA(szDbg, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) { FatalError(ERR_OPEN_WRITE_FILE, szDbg); } } WriteFile(hFile, p.pCvStart.ptr, p.pCvStart.size, &cb, NULL); CloseHandle(hFile); return; } void DoNameChange( char * szInput, char * szOutput, char * szNewName ) { POINTERS p; // Open the input file name and setup the pointers into the file if (!MapInputFile( &p, NULL, szInput )) { FatalError(ERR_OPEN_INPUT_FILE, szInput); } // Now, if we thing we are playing with PE exes then we need // to setup the pointers into the map file if (!CalculateNtImagePointers( &p.iptrs )) { FatalError(ERR_INVALID_PE, szInput); } // Now preform the desired operation if (szOutput == NULL) { szOutput = szInput; } if (szNewName == NULL) { szNewName = szOutput; } if (p.iptrs.sepHdr != NULL) { FatalError(ERR_EDIT_DBG_FILE); } // Read in all of the debug information ReadDebugInfo(&p); // Open the output file and adjust the pointers. if (!MapOutputFile(&p, szOutput, sizeof(szNewName) * 2 + sizeof(IMAGE_DEBUG_MISC))) { FatalError(ERR_MAP_FILE, szOutput); } CalculateOutputFilePointers(&p.iptrs, &p.optrs); // Munge the name of the file MungeExeName(&p, szNewName); // Close the input file UnMapInputFile(&p); // Write out the debug information to the end of the exe WriteDebugInfo(&p, FALSE); // and finally compute the checksum if (p.iptrs.fileHdr != NULL) { ComputeChecksum( szOutput ); } return; } void DoStrip( char * szInput, char * szOutput ) { char OutputFile[_MAX_PATH]; // Make sure we only have the path to the output file (it will always be // named filename.DBG) if (szOutput != NULL) { CopyFileA(szInput, szOutput, FALSE); } SplitSymbols(szOutput, NULL, OutputFile, SPLITSYM_EXTRACT_ALL); // Always delete the output file. DeleteFileA(OutputFile); return; } void DoExtract( char * szInput, char * szOutput, char * szDbgFile ) { char OutputFile[_MAX_PATH]; char szExt[_MAX_EXT]; char szFileName[_MAX_FNAME]; if (szOutput != NULL) { CopyFileA(szInput, szOutput, FALSE); szInput = _strdup(szOutput); _splitpath(szOutput, NULL, NULL, szFileName, szExt); *(szOutput + strlen(szOutput) - strlen(szFileName) - strlen(szExt)) = '\0'; } SplitSymbols(szInput, szOutput, OutputFile, 0); CopyFileA(szDbgFile, OutputFile, TRUE); if (szOutput) { free(szInput); } return; }