windows-nt/Source/XPSP1/NT/ds/win32/ntcrypto/programs/signcsp/signcsp.cpp
2020-09-26 16:20:57 +08:00

1210 lines
33 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// FILE : client.cxx //
// DESCRIPTION : Crypto API interface //
// AUTHOR : //
// HISTORY : //
// Mar 8 1996 larrys New //
// dbarlow //
// //
// Copyright (C) 1996 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "mainrpc.h" // header file generated by the MIDL compiler
#include <imagehlp.h>
#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 <filename>\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);
}