Sunday, September 10, 2006

Fixing the problem that DevDiv has with Authenticode

Someone(s) in the developer division at Microsoft do strong name signing. And they don't get Authenticode signing. Authenticode signing is the underlying junk that causes those popups you get in IE about whether or not to trust some publisher when you download an app. Strong name signing is about managed code and CLR stuffs. How does DevDiv not get Authenticode? Well . . . at some point in their building and strong name signing process, they remove the Authenticode signature from an EXE, but leave the info in the file's header that says an Authenticode signature is present. Result? A file that can no longer be Authenticode-signed, so the app either 1) can't ship or 2) will have some popup about an unknown publisher.

Bummer.

Here's code for a simple command line app that strips out all Authenticode signature info from a file, including just the entries in the file's header in case Visual Studio worked some nasty mojo on it. Enjoy!


// delcert.cpp
//
// An app to make hiterto unsignable file signable again.
//
// 8/10/2006 - Drew
//
#define WIN32_LEAN_AND_MEAN
#include
#include
#include
#include

int wmain(DWORD argc, LPWSTR argv[])
{
HANDLE hFile = INVALID_HANDLE_VALUE;
LOADED_IMAGE image;
DWORD dwResult = ERROR_SUCCESS;
LPSTR lpszImageName = NULL;
size_t cchImageName = 0;

wprintf(L"\n");
if(2 != argc 0 == wcscmp(L"-?",argv[1]) 0 == wcscmp(L"/?",argv[1]))
{
wprintf(L"%s takes one parameter - a file name to strip of its embedded Authenticode signature.\n\n", argv[0]);
return 0;
}

hFile = CreateFile(argv[1], GENERIC_READ GENERIC_WRITE, FILE_SHARE_READ FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
dwResult = GetLastError();
wprintf(L"CreateFile failed with error 0x%08x\n", dwResult);
goto cleanupAndExit;
}

if(ImageRemoveCertificate(hFile,0))
{
goto cleanupAndExit;
}
else
{
dwResult = GetLastError();
wprintf(L"ImageRemoveCertificate failed with error 0x%08x\n", dwResult);
if(ERROR_INVALID_PARAMETER != dwResult)
{
goto cleanupAndExit;
}
else
{
wprintf(L"This happens when there's a listing in IMAGE_DIRECTORY_SECURITY\nin the PE's header, but the acutal Authenticode signature has been stripped.\nLet's fix that . . .\n");
dwResult = ERROR_SUCCESS;
}
}
if(CloseHandle(hFile)) hFile = INVALID_HANDLE_VALUE;


// This is somewhat sloppy, but if we're here we've almost certainly found a PE with an
// IMAGE_DIRECTORY_SECURITY that has nonzero SizeOfRawData and/or PointerToRawData,
// but the actual signature (that raw data) has been removed.
//
// What causes this? IIRC, strong name signing something that's already been Authenticode-signed.
//
// The workaround is to crack open the PE and write zeros into the directory entry so that everything
// that eventually calls through the Image*Certificate* APIs won't choke.

cchImageName = wcslen(argv[1]) +1;
lpszImageName = (LPSTR)malloc(cchImageName); // Yeah - so I'm all old-school mallocy!
if(!lpszImageName)
{
dwResult = GetLastError();
wprintf(L"Malloc failed. GLE == 0x%08x\n", dwResult);
goto cleanupAndExit;
}

if (-1 == sprintf_s(lpszImageName, cchImageName, "%S", argv[1]))
{
dwResult = GetLastError();
wprintf(L"Failed to copy argv[1] to string of chars. GLE == x0%08x\n", dwResult);
goto cleanupAndExit;
}

if(! MapAndLoad(lpszImageName, NULL, &image, FALSE, FALSE))
{
dwResult = GetLastError();
wprintf(L"MapAndLoad failed. GLE == 0x%08x", dwResult);
goto cleanupAndExit;
}

wprintf(L"certificates->Size == 0x%08x\n", image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size);
wprintf(L"certificates->VA == 0x%08x\n", image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress);
wprintf(L"Setting both fields to zero . . .\n");
image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].Size = 0;
image.FileHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY].VirtualAddress = 0;

if(! UnMapAndLoad(&image))
{
dwResult = GetLastError();
wprintf(L"Failed to UnMapAndLoad. GLE == 0x%08x\n", dwResult);
goto cleanupAndExit;
}

cleanupAndExit:
if(INVALID_HANDLE_VALUE != hFile) CloseHandle(hFile);
if(lpszImageName) free(lpszImageName);
if(ERROR_SUCCESS == dwResult) wprintf(L"Succeeded.\n");
wprintf(L"\n");
return dwResult;
}

Comments: Post a Comment

Links to this post:

Create a Link



<< Home

This page is powered by Blogger. Isn't yours?