Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

704 lines
20 KiB

#include <windows.h>
#include "crc32.h"
#include "chksect.h"
#define CHECK_SECTION
#ifndef offsetof
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
#define RoundUp(n,scale) (scale * ((n + scale - 1) / scale))
#define IsMemZero(pv,cb) (!(*((char *)pv) || memcmp(pv,((char *)pv)+1,cb-1)))
#pragma intrinsic(memcpy,memcmp)
enum
{
EX_CHECKSUM,
EX_SECURITY,
EX_CRC32FILE,
EX_EOF,
MAX_EXCLUDE
};
#define MAX_BUFFER (256*1024) /* must be even */
typedef struct
{
DWORD signature;
DWORD crc32File;
DWORD cbCabFile;
} SELFTEST_SECTION;
#define SECTION_NAME "Ext_Cab1"
#define SECTION_SIGNATURE (0x4D584653)
#ifdef ADD_SECTION
SELFTEST_RESULT AddSection(char *pszEXEFileName,char *pszCABFileName)
#else
#ifdef CHECK_SECTION
SELFTEST_RESULT CheckSection(char *pszEXEFileName)
#else
SELFTEST_RESULT SelfTest(char *pszEXEFileName,
unsigned long *poffCabinet,unsigned long *pcbCabinet)
#endif
#endif
{
HANDLE hFile; // handle to the file we're updating
enum SELFTEST_RESULT result; // our return code
union
{
IMAGE_DOS_HEADER dos;
IMAGE_NT_HEADERS nt;
IMAGE_SECTION_HEADER section;
} header; // used to examine the file
DWORD offNTHeader; // file offset to NT header
int cSections; // number of sections in the file
unsigned char *pBuffer; // general-purpose buffer
DWORD cbActual; // # of bytes actual read/written
#ifndef CHECK_SECTION
unsigned long crc32; // computed CRC-32
struct
{
DWORD offExclude;
DWORD cbExclude;
} excludeList[MAX_EXCLUDE]; // list of ranges to exclude from CRC
int iExclude; // exclude list index
DWORD offSelfTestSection; // file offset of our added section
SELFTEST_SECTION SelfTestSection; // added section header
DWORD cbFile; // number of bytes in file/region
DWORD cbChunk; // number of bytes in current chunk
DWORD offFile; // current file offset
#endif
#ifdef ADD_SECTION
DWORD offSectionHeader; // file offset of section header
DWORD offMaxVirtualAddress; // lowest unused virtual address
DWORD cbAlignVirtual; // virtual address alignment increment
DWORD cbAlignFile; // file address alignment increment
HANDLE hCABFile; // cabinet file handle
DWORD cbCABFile; // cabinet file size
DWORD checksum; // generated checksum
WORD *pBufferW; // used to generate checksum
#endif
#ifdef CHECK_SECTION
DWORD offSectionHeaderEnd; // first unused byte after section headers
DWORD offFirstSection; // first used byte after that
DWORD offImportStart; // where the import entries start
DWORD cbImport; // size of import entry data
#endif
#ifndef CHECK_SECTION
GenerateCRC32Table();
#endif
pBuffer = (void *) GlobalAlloc(GMEM_FIXED,MAX_BUFFER);
if (pBuffer == NULL)
{
result = SELFTEST_NO_MEMORY;
goto done_no_buffer;
}
#ifdef ADD_SECTION
/* get size of cabinet */
hCABFile = CreateFile(pszCABFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hCABFile == INVALID_HANDLE_VALUE)
{
result = SELFTEST_FILE_NOT_FOUND;
goto done_no_cab;
}
cbCABFile = GetFileSize(hCABFile,NULL);
#endif
/* open EXE image */
#ifdef ADD_SECTION
hFile = CreateFile(pszEXEFileName,GENERIC_READ|GENERIC_WRITE,0,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
#else
hFile = CreateFile(pszEXEFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
#endif
if (hFile == INVALID_HANDLE_VALUE)
{
result = SELFTEST_FILE_NOT_FOUND;
goto done_no_exe;
}
/* read MS-DOS header */
if ((ReadFile(hFile,&header.dos,sizeof(IMAGE_DOS_HEADER),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_DOS_HEADER)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if (header.dos.e_magic != IMAGE_DOS_SIGNATURE)
{
offNTHeader = 0;
}
else
{
offNTHeader = header.dos.e_lfanew;
}
/* read PE header */
SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
if ((ReadFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_NT_HEADERS)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if (header.nt.Signature != IMAGE_NT_SIGNATURE)
{
result = SELFTEST_NOT_PE_FILE;
goto done;
}
cSections = header.nt.FileHeader.NumberOfSections;
#ifdef ADD_SECTION
cbAlignVirtual = header.nt.OptionalHeader.SectionAlignment;
cbAlignFile = header.nt.OptionalHeader.FileAlignment;
offMaxVirtualAddress = 0;
#endif
#ifndef CHECK_SECTION
/* determine current file size */
cbFile = GetFileSize(hFile,NULL);
if (cbFile == 0xFFFFFFFF)
{
result = SELFTEST_READ_ERROR;
goto done;
}
#endif
#ifndef CHECK_SECTION
/* see if we've been signed */
if (header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress != 0)
{
#ifdef ADD_SECTION
result = SELFTEST_SIGNED;
goto done;
#else
/* make sure certificate is at the end of the file */
if (cbFile !=
(header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress
+ header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size))
{
result = SELFTEST_FAILED;
goto done;
}
else
{
/* ignore anything starting at the certificate */
cbFile = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress;
}
#endif
}
#endif
#ifdef ADD_SECTION
/* determine lowest un-used virtual address */
#else
/* locate our added section */
#endif
#ifndef CHECK_SECTION
offSelfTestSection = 0;
#endif
#ifdef ADD_SECTION
offSectionHeader = offNTHeader +
sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
header.nt.FileHeader.SizeOfOptionalHeader +
cSections * sizeof(IMAGE_SECTION_HEADER);
#endif
SetFilePointer(hFile,(offNTHeader + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
header.nt.FileHeader.SizeOfOptionalHeader),NULL,FILE_BEGIN);
#ifdef CHECK_SECTION
offSectionHeaderEnd = offNTHeader +
sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) +
header.nt.FileHeader.SizeOfOptionalHeader +
cSections * sizeof(IMAGE_SECTION_HEADER);
offImportStart = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress;
cbImport = header.nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size;
if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_SECTION_HEADER)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
offFirstSection = header.section.PointerToRawData;
if ((offFirstSection - offSectionHeaderEnd) > 0)
{
SetFilePointer(hFile,offSectionHeaderEnd,NULL,FILE_BEGIN);
if ((ReadFile(hFile,pBuffer,(offFirstSection - offSectionHeaderEnd),&cbActual,NULL) != TRUE)
|| (cbActual != (DWORD) (offFirstSection - offSectionHeaderEnd)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if ((offImportStart >= offSectionHeaderEnd) &&
((offImportStart + cbImport) <= offFirstSection))
{
memset(pBuffer + (offImportStart - offSectionHeaderEnd),0,cbImport);
}
if ((*pBuffer != '\0') ||
(((offFirstSection - offSectionHeaderEnd) > 1) &&
(memcmp(pBuffer,pBuffer + 1,(offFirstSection - offSectionHeaderEnd - 1)) != 0)))
{
result = SELFTEST_DIRTY;
}
else
{
result = SELFTEST_NO_ERROR;
}
}
else
{
result = SELFTEST_NO_ERROR;
}
#else
while (cSections--)
{
if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_SECTION_HEADER)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if (!memcmp(header.section.Name,SECTION_NAME,sizeof(header.section.Name)))
{
/* found our added section */
#ifdef ADD_SECTION
result = SELFTEST_ALREADY;
goto done;
#else
offSelfTestSection = header.section.PointerToRawData;
break;
#endif
}
#ifdef ADD_SECTION
if (offMaxVirtualAddress <
(header.section.VirtualAddress + header.section.Misc.VirtualSize))
{
offMaxVirtualAddress =
(header.section.VirtualAddress + header.section.Misc.VirtualSize);
}
#endif
}
#ifdef ADD_SECTION
/* increase number of sections in the file; whack checksum */
SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
if ((ReadFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_NT_HEADERS)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
header.nt.FileHeader.NumberOfSections++;
header.nt.OptionalHeader.CheckSum = 0;
header.nt.OptionalHeader.SizeOfImage =
RoundUp(offMaxVirtualAddress,cbAlignVirtual) +
RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignVirtual);
SetFilePointer(hFile,offNTHeader,NULL,FILE_BEGIN);
if ((WriteFile(hFile,&header.nt,sizeof(IMAGE_NT_HEADERS),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_NT_HEADERS)))
{
result = SELFTEST_WRITE_ERROR;
goto done;
}
/* make sure there's room for another section header */
SetFilePointer(hFile,offSectionHeader,NULL,FILE_BEGIN);
if ((ReadFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_SECTION_HEADER)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if (!IsMemZero(&header.section,sizeof(IMAGE_SECTION_HEADER)))
{
result = SELFTEST_NO_SECTION;
goto done;
}
/* create the new section header */
memcpy(header.section.Name,SECTION_NAME,sizeof(header.section.Name));
header.section.SizeOfRawData =
RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignFile);
header.section.PointerToRawData =
RoundUp(cbFile,cbAlignFile);
header.section.VirtualAddress =
RoundUp(offMaxVirtualAddress,cbAlignVirtual);
header.section.Misc.VirtualSize =
RoundUp((sizeof(SELFTEST_SECTION) + cbCABFile),cbAlignVirtual);
header.section.Characteristics = (IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ);
/* write the new section header */
SetFilePointer(hFile,offSectionHeader,NULL,FILE_BEGIN);
if ((WriteFile(hFile,&header.section,sizeof(IMAGE_SECTION_HEADER),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(IMAGE_SECTION_HEADER)))
{
result = SELFTEST_WRITE_ERROR;
goto done;
}
/* create the new section data */
memset(&SelfTestSection,0,sizeof(SelfTestSection));
SelfTestSection.signature = SECTION_SIGNATURE;
SelfTestSection.cbCabFile = cbCABFile;
offSelfTestSection = header.section.PointerToRawData;
SetFilePointer(hFile,offSelfTestSection,NULL,FILE_BEGIN);
if ((WriteFile(hFile,&SelfTestSection,sizeof(SelfTestSection),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(SelfTestSection)))
{
result = SELFTEST_WRITE_ERROR;
goto done;
}
/* copy cabinet into section */
SetFilePointer(hCABFile,0,NULL,FILE_BEGIN);
cbFile = cbCABFile;
while (cbFile)
{
if (cbFile > MAX_BUFFER)
{
cbChunk = MAX_BUFFER;
}
else
{
cbChunk = cbFile;
}
if ((ReadFile(hCABFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
|| (cbActual != cbChunk))
{
result = SELFTEST_READ_ERROR;
goto done;
}
if ((WriteFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
|| (cbActual != cbChunk))
{
result = SELFTEST_WRITE_ERROR;
}
cbFile -= cbChunk;
}
/* pad added section as needed */
cbChunk = header.section.SizeOfRawData - sizeof(SelfTestSection) - cbCABFile;
if (cbChunk != 0)
{
memset(pBuffer,0,cbChunk);
if ((WriteFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
|| (cbActual != cbChunk))
{
result = SELFTEST_WRITE_ERROR;
}
}
/* we've now increased total size of the file */
cbFile = offSelfTestSection + header.section.SizeOfRawData;
#else
/* make sure our added section was found */
if (offSelfTestSection == 0)
{
result = SELFTEST_NO_SECTION;
goto done;
}
#endif
/* If this EXE gets signed, the checksum will be changed. */
excludeList[EX_CHECKSUM].offExclude = offNTHeader +
offsetof(IMAGE_NT_HEADERS,OptionalHeader.CheckSum);
excludeList[EX_CHECKSUM].cbExclude =
sizeof(header.nt.OptionalHeader.CheckSum);
/* If this EXE gets signed, the security entry will be changed. */
excludeList[EX_SECURITY].offExclude = offNTHeader +
offsetof(IMAGE_NT_HEADERS,
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]);
excludeList[EX_SECURITY].cbExclude = sizeof(IMAGE_DATA_DIRECTORY);
/* Can't CRC our own CRC field. */
excludeList[EX_CRC32FILE].offExclude = offSelfTestSection +
offsetof(SELFTEST_SECTION,crc32File);
excludeList[EX_CRC32FILE].cbExclude = sizeof(SelfTestSection.crc32File);
/* Stop at end of known file. */
/* Note: current code assumes that the only thing which could */
/* be appended to the file after this is the certificate from */
/* codesigning, and that it will be pointed at by the security */
/* entry. If anything else appends, or padding is added before */
/* the certificate, we'll have to store this file size in the */
/* added section, and retrieve it before running the CRC. */
excludeList[EX_EOF].offExclude = cbFile;
/* Compute the CRC-32 of the file, skipping excluded extents. */
/* This code assumes excludeList is sorted by offExclude. */
crc32 = CRC32_INITIAL_VALUE;
offFile = 0;
#ifdef ADD_SECTION
/* Along the way, compute the correct checksum for this new */
/* image. We know that each of the sections on the exclude */
/* list just happened to be zeroed right now, so they won't */
/* affect our checksum. But we will have to add our new CRC32 */
/* value to the checksum, because it will be in the file when */
/* we're done. It helps that we know that all the exclusions */
/* on the list are WORD aligned and have even lengths. */
/* The checksum in a PE file is a 16-bit sum of 16-bit words */
/* in the file, with wrap-around carry, while the checksum */
/* field is filled with zero. The file's length is added, */
/* yielding a 32-bit result. */
checksum = 0;
#endif
for (iExclude = 0; iExclude < MAX_EXCLUDE; iExclude++)
{
SetFilePointer(hFile,offFile,NULL,FILE_BEGIN);
cbFile = excludeList[iExclude].offExclude - offFile;
while (cbFile)
{
if (cbFile > MAX_BUFFER)
{
cbChunk = MAX_BUFFER;
}
else
{
cbChunk = cbFile;
}
if ((ReadFile(hFile,pBuffer,cbChunk,&cbActual,NULL) != TRUE)
|| (cbActual != cbChunk))
{
result = SELFTEST_READ_ERROR;
goto done;
}
CRC32Update(&crc32,pBuffer,cbChunk);
offFile += cbChunk;
cbFile -= cbChunk;
#ifdef ADD_SECTION
/* roll buffer into checksum */
pBufferW = (WORD *) pBuffer;
cbChunk >>= 1;
while (cbChunk--)
{
checksum += *pBufferW++;
if (checksum > 0x0000FFFF)
{
checksum -= 0x0000FFFF;
}
}
#endif
/*
* INSERT PROGRESS GAUGE HERE:
* %complete = (offFile * 100.0) / excludeList[EX_EOF].offExclude
*/
}
offFile += excludeList[iExclude].cbExclude;
}
#ifdef ADD_SECTION
/* account for CRC32 value in checksum */
checksum += (WORD) crc32;
checksum += (crc32 >> 16);
while (checksum > 0x0000FFFF)
{
checksum -= 0x0000FFFF;
}
/* add file length to checksum */
checksum += excludeList[EX_EOF].offExclude;
/* update CRC-32 value in added section */
SetFilePointer(hFile,excludeList[EX_CRC32FILE].offExclude,NULL,FILE_BEGIN);
if ((WriteFile(hFile,&crc32,sizeof(crc32),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(crc32)))
{
result = SELFTEST_WRITE_ERROR;
goto done;
}
/* update checksum value in header */
SetFilePointer(hFile,excludeList[EX_CHECKSUM].offExclude,NULL,FILE_BEGIN);
if ((WriteFile(hFile,&checksum,sizeof(checksum),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(checksum)))
{
result = SELFTEST_WRITE_ERROR;
goto done;
}
/* done */
if (CloseHandle(hFile) != TRUE)
{
result = SELFTEST_WRITE_ERROR;
}
else
{
result = SELFTEST_NO_ERROR;
}
goto done_no_exe;
#else
/* read the header from the added section */
SetFilePointer(hFile,offSelfTestSection,NULL,FILE_BEGIN);
if ((ReadFile(hFile,&SelfTestSection,sizeof(SelfTestSection),&cbActual,NULL) != TRUE)
|| (cbActual != sizeof(SelfTestSection)))
{
result = SELFTEST_READ_ERROR;
goto done;
}
/* verify CRC-32 value in added section */
if ((SelfTestSection.signature != SECTION_SIGNATURE) ||
(crc32 != SelfTestSection.crc32File))
{
result = SELFTEST_FAILED;
}
else
{
*poffCabinet = offSelfTestSection + sizeof(SelfTestSection);
*pcbCabinet = SelfTestSection.cbCabFile;
result = SELFTEST_NO_ERROR;
}
#endif
#endif // CHECK_SECTION
done:
CloseHandle(hFile);
done_no_exe:
#ifdef ADD_SECTION
CloseHandle(hCABFile);
done_no_cab:
#endif
GlobalFree((HGLOBAL) pBuffer);
done_no_buffer:
#ifdef ADD_SECTION
/* destroy failed attempt */
if (result != SELFTEST_NO_ERROR)
{
DeleteFile(pszEXEFileName);
}
#endif
return(result);
}