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.
1209 lines
34 KiB
1209 lines
34 KiB
/////////////////////////////////////////////////////////////////////////////
|
|
// 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);
|
|
}
|
|
|