///////////////////////////////////////////////////////////////////////////// // FILE : client.cxx // // DESCRIPTION : Crypto API interface // // AUTHOR : // // HISTORY : // // Mar 8 1996 larrys New // // dbarlow // // // // Copyright (C) 1996 Microsoft Corporation All Rights Reserved // ///////////////////////////////////////////////////////////////////////////// #include #include #include #include #include "mainrpc.h" // header file generated by the MIDL compiler #include #include "des.h" #include "modes.h" #include "skrpc.h" extern "C" { #include "md5.h" }; // designatred resource for in file signatures #define CRYPT_SIG_RESOURCE_NUMBER "#666" // MAC in file #define MAC_RESOURCE_NUMBER "#667" static DWORD dwMACInFileVersion = 0x100; BYTE rgbDESKey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}; BOOL HashTheFile( LPCSTR pszFile, DWORD dwCRCOffset, BYTE *pbHash, DWORD *pcbHash, DWORD cbImage ); DWORD GetCRCOffset( LPCSTR szFile, DWORD cbImage, DWORD *pdwCRCOffset ); static DWORD dwSigInFileVersion = 0x100; DWORD SetCryptSignatureResource( LPCSTR szFile, DWORD dwSigVersion, DWORD dwCRCOffset, PBYTE pbNewSig, DWORD cbNewSig, DWORD cbImage ); void ShowHelp(); BOOL DumpFile(LPCTSTR szFile, const BYTE *pb, UINT cb); void CallServer(void); BYTE pbSignature[256]; BYTE pbDigest[80]; DWORD cbDigestLen = sizeof(pbDigest); DWORD cbSignatureLen = sizeof(pbSignature); // The function MACs the given bytes. void MACBytes( IN DESTable *pDESKeyTable, IN BYTE *pbData, IN DWORD cbData, IN OUT BYTE *pbTmp, IN OUT DWORD *pcbTmp, IN OUT BYTE *pbMAC, IN BOOL fFinal ) { DWORD cb = cbData; DWORD cbMACed = 0; while (cb) { if ((cb + *pcbTmp) < DES_BLOCKLEN) { memcpy(pbTmp + *pcbTmp, pbData + cbMACed, cb); *pcbTmp += cb; break; } else { memcpy(pbTmp + *pcbTmp, pbData + cbMACed, DES_BLOCKLEN - *pcbTmp); CBC(des, DES_BLOCKLEN, pbMAC, pbTmp, pDESKeyTable, ENCRYPT, pbMAC); cbMACed = cbMACed + (DES_BLOCKLEN - *pcbTmp); cb = cb - (DES_BLOCKLEN - *pcbTmp); *pcbTmp = 0; } } } // Given hInst, allocs and returns pointers to MAC pulled from // resource BOOL GetResourcePtr( IN HMODULE hInst, IN LPSTR pszRsrcName, OUT BYTE **ppbRsrcMAC, OUT DWORD *pcbRsrcMAC ) { HRSRC hRsrc; BOOL fRet = FALSE; // Nab resource handle for our signature if (NULL == (hRsrc = FindResourceA(hInst, pszRsrcName, RT_RCDATA))) goto Ret; // get a pointer to the actual signature data if (NULL == (*ppbRsrcMAC = (PBYTE)LoadResource(hInst, hRsrc))) goto Ret; // determine the size of the resource if (0 == (*pcbRsrcMAC = SizeofResource(hInst, hRsrc))) goto Ret; fRet = TRUE; Ret: return fRet; } #define CSP_TO_BE_MACED_CHUNK 4096 // Given hFile, reads the specified number of bytes (cbToBeMACed) from the file // and MACs these bytes. The function does this in chunks. BOOL MACBytesOfFile( IN HANDLE hFile, IN DWORD cbToBeMACed, IN DESTable *pDESKeyTable, IN BYTE *pbTmp, IN DWORD *pcbTmp, IN BYTE *pbMAC, IN BYTE fFinal ) { BYTE rgbChunk[CSP_TO_BE_MACED_CHUNK]; DWORD cbRemaining = cbToBeMACed; DWORD cbToRead; DWORD dwBytesRead; BOOL fRet = FALSE; // // loop over the file for the specified number of bytes // updating the hash as we go. // while (cbRemaining > 0) { if (cbRemaining < CSP_TO_BE_MACED_CHUNK) cbToRead = cbRemaining; else cbToRead = CSP_TO_BE_MACED_CHUNK; if(!ReadFile(hFile, rgbChunk, cbToRead, &dwBytesRead, NULL)) goto Ret; if (dwBytesRead != cbToRead) goto Ret; MACBytes(pDESKeyTable, rgbChunk, dwBytesRead, pbTmp, pcbTmp, pbMAC, fFinal); cbRemaining -= cbToRead; } fRet = TRUE; Ret: return fRet; } BOOL MACTheFileWithSig( LPCSTR pszImage, DWORD cbImage, IN DWORD dwMACVersion, IN DWORD dwCRCOffset, OUT BYTE *pbMAC ) { HMODULE hInst = 0; MEMORY_BASIC_INFORMATION MemInfo; BYTE *pbRsrcMAC; DWORD cbRsrcMAC; BYTE *pbRsrcSig; DWORD cbRsrcSig; BYTE *pbStart; BYTE rgbMAC[DES_BLOCKLEN]; BYTE rgbZeroMAC[DES_BLOCKLEN + sizeof(DWORD) * 2]; BYTE rgbZeroSig[144]; BYTE *pbPostCRC; // pointer to just after CRC DWORD cbCRCToRsrc1; // number of bytes from CRC to first rsrc DWORD cbRsrc1ToRsrc2; // number of bytes from first rsrc to second DWORD cbPostRsrc; // size - (already hashed + signature size) BYTE *pbRsrc1ToRsrc2; BYTE *pbPostRsrc; BYTE *pbZeroRsrc1; BYTE *pbZeroRsrc2; DWORD cbZeroRsrc1; DWORD cbZeroRsrc2; DWORD dwZeroCRC = 0; DWORD dwBytesRead = 0; OFSTRUCT ImageInfoBuf; HFILE hFile = HFILE_ERROR; HANDLE hMapping = NULL; DESTable DESKeyTable; BYTE rgbTmp[DES_BLOCKLEN]; DWORD cbTmp = 0; BOOL fRet = FALSE; memset(&MemInfo, 0, sizeof(MemInfo)); memset(rgbMAC, 0, sizeof(rgbMAC)); memset(rgbTmp, 0, sizeof(rgbTmp)); // Load the file if (HFILE_ERROR == (hFile = OpenFile(pszImage, &ImageInfoBuf, OF_READ))) { goto Ret; } hMapping = CreateFileMapping((HANDLE)IntToPtr(hFile), NULL, PAGE_READONLY, 0, 0, NULL); if(hMapping == NULL) { goto Ret; } hInst = (HMODULE)MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); if(hInst == NULL) { goto Ret; } pbStart = (BYTE*)hInst; // Convert pointer to HMODULE, using the same scheme as // LoadLibrary (windows\base\client\module.c). *((ULONG_PTR*)&hInst) |= 0x00000001; // the MAC resource if (!GetResourcePtr(hInst, MAC_RESOURCE_NUMBER, &pbRsrcMAC, &cbRsrcMAC)) goto Ret; // the MAC resource if (!GetResourcePtr(hInst, CRYPT_SIG_RESOURCE_NUMBER, &pbRsrcSig, &cbRsrcSig)) goto Ret; if (cbRsrcMAC < (sizeof(DWORD) * 2)) goto Ret; // create a zero byte MAC memset(rgbZeroMAC, 0, sizeof(rgbZeroMAC)); // create a zero byte Sig memset(rgbZeroSig, 0, sizeof(rgbZeroSig)); // set up the pointers pbPostCRC = pbStart + dwCRCOffset + sizeof(DWORD); if (pbRsrcSig > pbRsrcMAC) // MAC is first Rsrc { cbCRCToRsrc1 = (DWORD)(pbRsrcMAC - pbPostCRC); pbRsrc1ToRsrc2 = pbRsrcMAC + cbRsrcMAC; cbRsrc1ToRsrc2 = (DWORD)(pbRsrcSig - pbRsrc1ToRsrc2); pbPostRsrc = pbRsrcSig + cbRsrcSig; cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart)); // zero pointers pbZeroRsrc1 = rgbZeroMAC; cbZeroRsrc1 = cbRsrcMAC; pbZeroRsrc2 = rgbZeroSig; cbZeroRsrc2 = cbRsrcSig; } else // Sig is first Rsrc { cbCRCToRsrc1 = (DWORD)(pbRsrcSig - pbPostCRC); pbRsrc1ToRsrc2 = pbRsrcSig + cbRsrcSig; cbRsrc1ToRsrc2 = (DWORD)(pbRsrcMAC - pbRsrc1ToRsrc2); pbPostRsrc = pbRsrcMAC + cbRsrcMAC; cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart)); // zero pointers pbZeroRsrc1 = rgbZeroSig; cbZeroRsrc1 = cbRsrcSig; pbZeroRsrc2 = rgbZeroMAC; cbZeroRsrc2 = cbRsrcMAC; } // init the key table deskey(&DESKeyTable, rgbDESKey); // MAC up to the CRC if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), dwCRCOffset, &DESKeyTable, rgbTmp, &cbTmp, rgbMAC, FALSE)) { goto Ret; } // pretend CRC is zeroed MACBytes(&DESKeyTable, (BYTE*)&dwZeroCRC, sizeof(DWORD), rgbTmp, &cbTmp, rgbMAC, FALSE); if (!SetFilePointer((HANDLE)IntToPtr(hFile), sizeof(DWORD), NULL, FILE_CURRENT)) { goto Ret; } // MAC from CRC to first resource if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbCRCToRsrc1, &DESKeyTable, rgbTmp, &cbTmp, rgbMAC, FALSE)) { goto Ret; } // pretend image has zeroed first resource MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc1, cbZeroRsrc1, rgbTmp, &cbTmp, rgbMAC, FALSE); if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc1, NULL, FILE_CURRENT)) { goto Ret; } // MAC from first resource to second if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbRsrc1ToRsrc2, &DESKeyTable, rgbTmp, &cbTmp, rgbMAC, FALSE)) { goto Ret; } // pretend image has zeroed second Resource MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc2, cbZeroRsrc2, rgbTmp, &cbTmp, rgbMAC, FALSE); if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc2, NULL, FILE_CURRENT)) { goto Ret; } // MAC after the resource if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbPostRsrc, &DESKeyTable, rgbTmp, &cbTmp, rgbMAC, TRUE)) { goto Ret; } memcpy(pbMAC, rgbMAC, DES_BLOCKLEN); fRet = TRUE; Ret: if(hInst) UnmapViewOfFile(hInst); if(hMapping) CloseHandle(hMapping); if (HFILE_ERROR != hFile) _lclose(hFile); return fRet; } // SetCryptMACResource // // slams MAC resource in file with the new MAC // DWORD SetCryptMACResource( IN LPCSTR szFile, IN DWORD dwMACVersion, IN DWORD dwCRCOffset, IN PBYTE pbNewMAC, IN DWORD cbImage ) { DWORD dwErr = 0x1; HANDLE hFileProv = NULL; HMODULE hInst = NULL; PBYTE pbFilePtr = NULL; DWORD cbImageSize, cbMACOffset; PBYTE pbMAC; DWORD cbMAC; MEMORY_BASIC_INFORMATION MemInfo; BYTE *pbStart; DWORD OldCheckSum; DWORD NewCheckSum; PIMAGE_NT_HEADERS pImageNTHdrs; HANDLE hFileMap = NULL; memset(&MemInfo, 0, sizeof(MemInfo)); // Load the file as a datafile if (NULL == (hInst = LoadLibraryEx(szFile, NULL, LOAD_LIBRARY_AS_DATAFILE))) { printf("Couldn't load file\n"); goto Ret; } if (!GetResourcePtr(hInst, MAC_RESOURCE_NUMBER, &pbMAC, &cbMAC)) { printf("Couldn't find MAC placeholder\n"); goto Ret; } // get image start address VirtualQuery(hInst, &MemInfo, sizeof(MemInfo)); pbStart = (BYTE*)MemInfo.BaseAddress; FreeLibrary(hInst); hInst = NULL; cbMACOffset = (DWORD)(pbMAC - pbStart); if (cbMAC != (DES_BLOCKLEN + sizeof(DWORD) * 2)) { printf("Attempt to replace %d zeros with new MAC!\n", cbMAC); goto Ret; } if (INVALID_HANDLE_VALUE == (hFileProv = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 0, // don't share NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0))) { printf("Couldn't CreateFile: 0x%x\n", GetLastError()); goto Ret; } if (NULL == (hFileMap = CreateFileMapping( hFileProv, NULL, PAGE_READWRITE, 0, 0, NULL))) { printf("Couldn't map file\n"); goto Ret; } if (NULL == (pbFilePtr = (PBYTE)MapViewOfFile( hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0))) { printf("Couldn't create view\n"); goto Ret; } // copy version, CRC offset and new sig CopyMemory(pbFilePtr+cbMACOffset, &dwMACVersion, sizeof(dwMACVersion)); cbMACOffset += sizeof(dwMACVersion); CopyMemory(pbFilePtr+cbMACOffset, &dwCRCOffset, sizeof(dwCRCOffset)); cbMACOffset += sizeof(dwCRCOffset); CopyMemory(pbFilePtr+cbMACOffset, pbNewMAC, DES_BLOCKLEN); // compute a new checksum if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage, &OldCheckSum, &NewCheckSum))) goto Ret; CopyMemory(&pImageNTHdrs->OptionalHeader.CheckSum, &NewCheckSum, sizeof(DWORD)); if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage, &OldCheckSum, &NewCheckSum))) goto Ret; if (OldCheckSum != NewCheckSum) goto Ret; dwErr = ERROR_SUCCESS; Ret: if (pbFilePtr) UnmapViewOfFile(pbFilePtr); if (hFileMap) CloseHandle(hFileMap); if (hInst) FreeLibrary(hInst); if (hFileProv) CloseHandle(hFileProv); return dwErr; } void MacCSP( LPCSTR pszInFile ) { DWORD cbImage; DWORD dwCRCOffset; HANDLE hFileProv = INVALID_HANDLE_VALUE; BYTE rgbMAC[DES_BLOCKLEN]; HMODULE hInst = NULL; PBYTE pbFilePtr = NULL; DWORD cbImageSize, cbMACOffset; PBYTE pbMAC; DWORD cbMAC; memset(rgbMAC, 0, sizeof(rgbMAC)); // check if the MAC resource is in the CSP and exit if not // Load the file as a datafile if (NULL == (hInst = LoadLibraryEx(pszInFile, NULL, LOAD_LIBRARY_AS_DATAFILE))) { printf("Couldn't load file\n"); goto Ret; } if (!GetResourcePtr(hInst, MAC_RESOURCE_NUMBER, &pbMAC, &cbMAC)) { goto Ret; } FreeLibrary(hInst); hInst = NULL; // get the file size if ((hFileProv = CreateFile(pszInFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) { printf("CSP specified was not found!\n"); goto Ret; } if (0xffffffff == (cbImage = GetFileSize(hFileProv, NULL))) { printf("CSP specified was not found!\n"); goto Ret; } CloseHandle(hFileProv); hFileProv = NULL; if (0 != GetCRCOffset(pszInFile, cbImage, &dwCRCOffset)) { printf("Unable to get CRC!\n"); goto Ret; } // calculate the MAC if (!MACTheFileWithSig(pszInFile, cbImage, dwMACInFileVersion, dwCRCOffset, rgbMAC)) { printf("MAC failed!\n"); goto Ret; } // // Place the MAC into the resource in the file // if (ERROR_SUCCESS != SetCryptMACResource(pszInFile, dwMACInFileVersion, dwCRCOffset, rgbMAC, cbImage)) { printf("Unable to set the MAC into the file resource!\n"); goto Ret; } Ret: if (hInst) { FreeLibrary(hInst); } if (INVALID_HANDLE_VALUE != hFileProv) { CloseHandle(hFileProv); } return; } /*++ main: This is the main entry point of the application. Arguments: argc - Count of arguments argv - array of arguments Return Value: 0 - Success 1 - Error Author: Doug Barlow (dbarlow) 1/25/1996 --*/ extern "C" void __cdecl main( int argc, char *argv[]) { DWORD exStatus = 1; DWORD index; LPCTSTR szBinFile = NULL; LPCTSTR szInFile = NULL; BOOL fOutput = FALSE; int status; DWORD ThreadId; HANDLE hThread; // RPC Specific variables. RPC_STATUS rpcStatus; unsigned char * pszUuid = NULL; char * pszProtocolSequence = "ncacn_np"; unsigned char * pszNetworkAddress = (LPBYTE)"\\\\enigma.ntdev.microsoft.com"; char * pszEndpoint = "\\pipe\\sign"; unsigned char * pszOptions = NULL; unsigned char * pszStringBinding = NULL; DWORD dwrt; DWORD i; DWORD cbImage; DWORD dwCRCOffset; HANDLE hFileProv = 0; // // Parse the command line. // if ((argc != 2) || (argv[1][0] == '?')) { ShowHelp(); exStatus = 0; goto ErrorExit; } szInFile = &argv[1][0]; // // Command consistency checks. // if (NULL == szInFile) { printf("No input file specified.\n"); goto ErrorExit; } MacCSP(szInFile); // get the file size if ((hFileProv = CreateFile(szInFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)) == INVALID_HANDLE_VALUE) { printf("CSP specified was not found!\n"); goto ErrorExit; } if (0xffffffff == (cbImage = GetFileSize(hFileProv, NULL))) { printf("CSP specified was not found!\n"); goto ErrorExit; } CloseHandle(hFileProv); hFileProv = NULL; if (ERROR_SUCCESS != GetCRCOffset(szInFile, cbImage, &dwCRCOffset)) { printf("Unable to get the CRC offset on the file!\n"); goto ErrorExit; } // // Compute the hash. // if (!HashTheFile(szInFile, dwCRCOffset, pbDigest, &cbDigestLen, cbImage)) { printf("Unable to hash the file!\n"); goto ErrorExit; } // // Get the signature. // // Try to make rpc connection rpcStatus = RpcStringBindingCompose(pszUuid, (unsigned char *) pszProtocolSequence, pszNetworkAddress, (unsigned char *) pszEndpoint, pszOptions, &pszStringBinding); #ifdef DEBUG printf("RpcStringBindingCompose returned 0x%x\n", rpcStatus); printf("pszStringBinding = %s\n", pszStringBinding); #endif if (0 != rpcStatus) { printf("Failed to compose binding string for target RPC server.\n"); goto ErrorExit; } /* Set the binding handle that will */ /* be used to bind to the server */ rpcStatus = RpcBindingFromStringBinding(pszStringBinding, &hello_IfHandle); #ifdef DEBUG printf("RpcBindingFromStringBinding returned 0x%x\n", rpcStatus); #endif if (0 != rpcStatus) { printf("Failed to bind to target RPC server.\n"); goto ErrorExit; } if ((hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CallServer, NULL, 0, &ThreadId)) == NULL) { printf("Call to CreateThread failed\n"); goto ErrorExit; } printf("Sending request to be signed, will wait 5 minutes\n"); for (i = 0; i < 20; i++) { printf("Waited %d seconds\n", i*30); dwrt = WaitForSingleObject(hThread, 15000); if (dwrt == WAIT_OBJECT_0) { break; } } if (i == 20) { printf("Call to Server timed out\n"); goto ErrorExit; } GetExitCodeThread(hThread, &dwrt); if (dwrt) { goto ErrorExit; } // // Place the signature into the resource in the file // if (ERROR_SUCCESS != SetCryptSignatureResource(szInFile, dwSigInFileVersion, dwCRCOffset, pbSignature, cbSignatureLen, cbImage)) { printf("Unable to set the signature into the file resource!\n"); goto ErrorExit; } // // Clean up and return. // exStatus = 0; ErrorExit: exit(exStatus); } void CallServer(void) { RpcTryExcept { cbSignatureLen = sizeof(pbSignature); if (GenSignature(pbDigest, &cbSignatureLen, pbSignature)) { printf("GenSignature returned an error \n"); ExitThread(TRUE); } } RpcExcept(1) { printf("RPC error -- exception code is 0x%X\n", RpcExceptionCode()); ExitThread(RpcExceptionCode()); } RpcEndExcept ExitThread(FALSE); } // Given hInst, allocs and returns pointers to signature pulled from // resource BOOL GetCryptSigResourcePtr( HMODULE hInst, BYTE **ppbRsrcSig, DWORD *pcbRsrcSig ) { HRSRC hRsrc; BOOL fRet = FALSE; // Nab resource handle for our signature if (NULL == (hRsrc = FindResource(hInst, CRYPT_SIG_RESOURCE_NUMBER, RT_RCDATA))) goto Ret; // get a pointer to the actual signature data if (NULL == (*ppbRsrcSig = (PBYTE)LoadResource(hInst, hRsrc))) goto Ret; // determine the size of the resource if (0 == (*pcbRsrcSig = SizeofResource(hInst, hRsrc))) goto Ret; fRet = TRUE; Ret: return fRet; } // Given hInst, hashes over the file skipping, hashing zero bytes where the // resource is BOOL HashTheFile( LPCSTR pszFile, DWORD dwCRCOffset, BYTE *pbHash, DWORD *pcbHash, DWORD cbImage ) { MEMORY_BASIC_INFORMATION MemInfo; BYTE *pbRsrcSig; DWORD cbRsrcSig; BYTE *pbStart; BYTE *pbZeroSig = NULL; MD5_CTX MD5Hash; DWORD dwZeroCRC = 0; DWORD cbPreCRC; // start of CRC DWORD cbCRCToSig; // end of CRC to start of sig BYTE *pbPostCRC; // just after CRC DWORD cbPostSig; // size - (already hashed + signature size) BYTE *pbPostSig; HMODULE hInst = 0; BOOL fRet = FALSE; memset(&MD5Hash, 0, sizeof(MD5Hash)); memset(&MemInfo, 0, sizeof(MemInfo)); // Load the file as a datafile if (NULL == (hInst = LoadLibraryEx(pszFile, NULL, LOAD_LIBRARY_AS_DATAFILE))) goto Ret; // get image start address VirtualQuery(hInst, &MemInfo, sizeof(MemInfo)); pbStart = (BYTE*)MemInfo.BaseAddress; // the resources signature if (!GetCryptSigResourcePtr(hInst, &pbRsrcSig, &cbRsrcSig)) goto Ret; // create a zero byte signature if (NULL == (pbZeroSig = (BYTE*)LocalAlloc(LMEM_ZEROINIT, cbRsrcSig))) goto Ret; // want to hash the version and the CRC offset CopyMemory(pbZeroSig, &dwSigInFileVersion, sizeof(dwSigInFileVersion)); CopyMemory(pbZeroSig + sizeof(dwSigInFileVersion), &dwCRCOffset, sizeof(dwCRCOffset)); // hash over the relevant data { pbPostCRC = pbStart + dwCRCOffset + sizeof(dwZeroCRC); cbCRCToSig = (DWORD)(pbRsrcSig - pbPostCRC); pbPostSig = pbRsrcSig + cbRsrcSig; cbPostSig = (cbImage - (DWORD)(pbPostSig - pbStart)); MD5Init(&MD5Hash); MD5Update(&MD5Hash, pbStart, dwCRCOffset); // pretend CRC is zeroed MD5Update(&MD5Hash, (BYTE*)&dwZeroCRC, sizeof(dwZeroCRC)); // pretend image has zeroed sig MD5Update(&MD5Hash, pbPostCRC, cbCRCToSig); // pretend image has zeroed sig MD5Update(&MD5Hash, pbZeroSig, cbRsrcSig); MD5Update(&MD5Hash, pbPostSig, cbPostSig); // Finish the hash MD5Final(&MD5Hash); *pcbHash = MD5DIGESTLEN; memcpy(pbHash, MD5Hash.digest, MD5DIGESTLEN); } fRet = TRUE; Ret: if (hInst) FreeLibrary(hInst); if (pbZeroSig) LocalFree(pbZeroSig); return fRet; } DWORD GetCRCOffset( LPCSTR szFile, DWORD cbImage, DWORD *pdwCRCOffset ) { DWORD dwErr = 0x1; HANDLE hFileProv = NULL; PBYTE pbFilePtr = NULL; DWORD OldCheckSum; DWORD NewCheckSum; PIMAGE_NT_HEADERS pImageNTHdrs; HANDLE hFileMap = NULL; if (INVALID_HANDLE_VALUE == (hFileProv = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 0, // don't share NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0))) { printf("Couldn't CreateFile: 0x%x\n", GetLastError()); goto Ret; } if (NULL == (hFileMap = CreateFileMapping( hFileProv, NULL, PAGE_READWRITE, 0, 0, NULL))) { printf("Couldn't map file\n"); goto Ret; } if (NULL == (pbFilePtr = (PBYTE)MapViewOfFile( hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0))) { printf("Couldn't create view\n"); goto Ret; } // compute a new checksum if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage, &OldCheckSum, &NewCheckSum))) goto Ret; *pdwCRCOffset = (DWORD)((BYTE*)&pImageNTHdrs->OptionalHeader.CheckSum - pbFilePtr); dwErr = ERROR_SUCCESS; Ret: if (pbFilePtr) UnmapViewOfFile(pbFilePtr); if (hFileMap) CloseHandle(hFileMap); if (hFileProv) CloseHandle(hFileProv); return dwErr; } // SetCryptSignatureResource // // slams signature resource in file with the new signature // // szFile is file to modify // pbNewSig is new signature // cbNewSig is new signature length DWORD SetCryptSignatureResource( LPCSTR szFile, DWORD dwSigVersion, DWORD dwCRCOffset, PBYTE pbNewSig, DWORD cbNewSig, DWORD cbImage ) { DWORD dwErr = 0x1; HANDLE hFileProv = NULL; HMODULE hInst = NULL; PBYTE pbFilePtr = NULL; DWORD cbImageSize, cbSigOffset; PBYTE pbSig; DWORD cbSig; MEMORY_BASIC_INFORMATION MemInfo; BYTE *pbStart; DWORD OldCheckSum; DWORD NewCheckSum; PIMAGE_NT_HEADERS pImageNTHdrs; HANDLE hFileMap = NULL; memset(&MemInfo, 0, sizeof(MemInfo)); // Load the file as a datafile if (NULL == (hInst = LoadLibraryEx(szFile, NULL, LOAD_LIBRARY_AS_DATAFILE))) { printf("Couldn't load file\n"); goto Ret; } if (!GetCryptSigResourcePtr(hInst, &pbSig, &cbSig)) { printf("Couldn't find signature placeholder\n"); goto Ret; } // get image start address VirtualQuery(hInst, &MemInfo, sizeof(MemInfo)); pbStart = (BYTE*)MemInfo.BaseAddress; FreeLibrary(hInst); hInst = NULL; cbSigOffset = (DWORD)(pbSig - pbStart); if (cbSig < (cbNewSig + (sizeof(DWORD) * 2))) { printf("Attempt to replace %d zeros with %d byte signature!\n", cbSig, cbNewSig); goto Ret; } if (INVALID_HANDLE_VALUE == (hFileProv = CreateFile(szFile, GENERIC_READ | GENERIC_WRITE, 0, // don't share NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0))) { printf("Couldn't CreateFile: 0x%x\n", GetLastError()); goto Ret; } if (NULL == (hFileMap = CreateFileMapping( hFileProv, NULL, PAGE_READWRITE, 0, 0, NULL))) { printf("Couldn't map file\n"); goto Ret; } if (NULL == (pbFilePtr = (PBYTE)MapViewOfFile( hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0))) { printf("Couldn't create view\n"); goto Ret; } // copy version, CRC offset and new sig CopyMemory(pbFilePtr+cbSigOffset, &dwSigVersion, sizeof(dwSigVersion)); cbSigOffset += sizeof(dwSigVersion); CopyMemory(pbFilePtr+cbSigOffset, &dwCRCOffset, sizeof(dwCRCOffset)); cbSigOffset += sizeof(dwCRCOffset); CopyMemory(pbFilePtr+cbSigOffset, pbNewSig, cbNewSig); if (cbSig > (cbNewSig + (sizeof(DWORD) * 2))) { ZeroMemory(pbFilePtr+cbSigOffset+cbNewSig, cbSig - (cbNewSig + (sizeof(DWORD) * 2))); } // compute a new checksum if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage, &OldCheckSum, &NewCheckSum))) goto Ret; CopyMemory(&pImageNTHdrs->OptionalHeader.CheckSum, &NewCheckSum, sizeof(DWORD)); if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage, &OldCheckSum, &NewCheckSum))) goto Ret; if (OldCheckSum != NewCheckSum) goto Ret; dwErr = ERROR_SUCCESS; Ret: if (pbFilePtr) UnmapViewOfFile(pbFilePtr); if (hFileMap) CloseHandle(hFileMap); if (hInst) FreeLibrary(hInst); if (hFileProv) CloseHandle(hFileProv); return dwErr; } /*++ ShowHelp: This routine displays a short help message to the given output stream. Arguments: ostr - The output stream to receive the help message. Return Value: None Author: Doug Barlow (dbarlow) 7/21/1995 --*/ void ShowHelp() { printf("CryptoAPI Internal CSP Signing Utility\n"); printf("signcsp \n"); } /* MIDL allocate and free */ void __RPC_FAR * __RPC_API midl_user_allocate(size_t len) { return(malloc(len)); } void __RPC_API midl_user_free(void __RPC_FAR * ptr) { free(ptr); }