/*
CVSNT Automatic manifest generator
Copyright (C) 2006 Tony Hoyle and March-Hare Software Ltd
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// chkmanifest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "../../version.h"
static bool debug;
struct manifestStruct
{
manifestStruct() { found = false; }
_bstr_t version,name,type,processor,language;
bool found;
};
typedef std::vector<manifestStruct> manifestArray;
int checkSub(const char *szDll, std::map<std::string, int> & toCheck);
int load_manifest(const char *xml, manifestArray& array)
{
MSXML2::IXMLDOMDocument2Ptr doc;
doc.CreateInstance("Msxml2.DOMDocument.6.0");
if(doc==NULL)
{
printf("Unable to create MSXML instance\n");
exit(1);
}
if(!doc->loadXML(xml))
return -1;
doc->setProperty("SelectionLanguage","XPath");
doc->setProperty("SelectionNamespaces", "xmlns:ns='urn:schemas-microsoft-com:asm.v1'");
_bstr_t version,name,type,processor,language;
MSXML2::IXMLDOMNodePtr node,val;
node = doc->selectSingleNode("/ns:assembly/ns:assemblyIdentity");
if(node==NULL)
return -1;
val = node->attributes->getNamedItem("version");
if(val) version = val->text;
else return -1;
val = node->attributes->getNamedItem("name");
if(val) name = val->text;
else return -1;
val = node->attributes->getNamedItem("processorArchitecture");
if(val) processor = val->text;
else processor="*";
val = node->attributes->getNamedItem("language"); // No examples of this so this may be wrong
if(val) language = val->text;
else language="*";
val = node->attributes->getNamedItem("type");
if(val) type = val->text;
else type="Win32";
if(debug)
{
printf("name: %s\n",(const char *)name);
printf("version: %s\n",(const char *)version);
printf("architecture: %s\n",(const char *)processor);
printf("language: %s\n",(const char *)language);
printf("type: %s\n",(const char *)type);
}
MSXML2::IXMLDOMNodeListPtr nodeList;
nodeList = doc->selectNodes("/ns:assembly/ns:dependency/ns:dependentAssembly/ns:assemblyIdentity");
array.clear();
for(short n=0; n<nodeList->length; n++)
{
node = nodeList->item[n];
val = node->attributes->getNamedItem("version");
if(val) version = val->text;
else return -1;
val = node->attributes->getNamedItem("name");
if(val) name = val->text;
else return -1;
val = node->attributes->getNamedItem("processorArchitecture");
if(val) processor = val->text;
else processor="*";
val = node->attributes->getNamedItem("language"); // No examples of this so this may be wrong
if(val) language = val->text;
else language="*";
val = node->attributes->getNamedItem("type");
if(val) type = val->text;
else type="Win32";
if(debug)
{
printf("\n");
printf("depname: %s\n",(const char *)name);
printf("depversion: %s\n",(const char *)version);
printf("deparchitecture: %s\n",(const char *)processor);
printf("deplanguage: %s\n",(const char *)language);
printf("deptype: %s\n",(const char *)type);
}
manifestStruct str;
str.name = name;
str.version = version;
str.processor = processor;
str.language = language;
str.type = type;
array.push_back(str);
}
return 0;
}
int parse_manifest(const char *xml, manifestArray& array, const char *szPath)
{
MSXML2::IXMLDOMDocument2Ptr doc;
doc.CreateInstance("Msxml2.DOMDocument.6.0");
if(doc==NULL)
{
printf("Unable to create MSXML instance\n");
exit(1);
}
if(!doc->loadXML(xml))
return -1;
doc->setProperty("SelectionLanguage","XPath");
doc->setProperty("SelectionNamespaces", "xmlns:ns='urn:schemas-microsoft-com:asm.v1'");
_bstr_t version,name,type,processor,language;
MSXML2::IXMLDOMNodePtr node,val;
node = doc->selectSingleNode("/ns:assembly/ns:assemblyIdentity");
if(node==NULL)
return -1;
val = node->attributes->getNamedItem("version");
if(val) version = val->text;
else return -1;
val = node->attributes->getNamedItem("name");
if(val) name = val->text;
else return -1;
val = node->attributes->getNamedItem("processorArchitecture");
if(val) processor = val->text;
else processor="*";
val = node->attributes->getNamedItem("language"); // No examples of this so this may be wrong
if(val) language = val->text;
else language="*";
val = node->attributes->getNamedItem("type");
if(val) type = val->text;
else type="Win32";
if(debug)
{
printf("name: %s\n",(const char *)name);
printf("version: %s\n",(const char *)version);
printf("architecture: %s\n",(const char *)processor);
printf("language: %s\n",(const char *)language);
printf("type: %s\n",(const char *)type);
}
bool error = false;
for(manifestArray::iterator i = array.begin(); i!=array.end(); ++i)
{
if(strcmp(i->name,name))
continue;
if(strcmp(i->version,"*") && strcmp(i->version,version))
{
printf(" ** Incorrect version: Expected %s found %s\n",(const char *)i->version,(const char *)version);
error = true;
}
if(strcmp(i->processor,"*") && strcmp(i->processor,processor))
{
printf(" ** Incorrect processor: Expected %s found %s\n",(const char *)i->processor,(const char *)processor);
error = true;
}
if(strcmp(i->language,"*") && strcmp(i->language,language))
{
printf(" ** Incorrect language: Expected %s found %s\n",(const char *)i->language,(const char *)language);
error = true;
}
if(strcmp(i->type,"*") && strcmp(i->type,type))
{
printf(" ** Incorrect type: Expected %s found %s\n",(const char *)i->type,(const char *)type);
}
i->found = true;
}
return error?1:0;
}
static WORD g_wManifestLanguage=MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
BOOL CALLBACK EnumResLangProc(
HANDLE hModule,
LPCTSTR lpszType,
LPCTSTR lpszName,
WORD wIDLanguage,
LONG_PTR lParam)
{
g_wManifestLanguage=wIDLanguage;
return FALSE;
}
int main(int argc, char* argv[])
{
std::map<std::string, int> toCheck, beenChecked;
CoInitialize(NULL);
debug=false;
while(argc>1 && argv[1][0]=='-')
{
switch(argv[1][1])
{
case 'd':
debug = true;
break;
default:
printf("cvsnt manifest checker "CVSNT_PRODUCTVERSION_STRING"\n");
printf("usage: chkmanifest <file>\n");
return -1;
}
argv++;
argc--;
}
if(argc<2)
{
printf("cvsnt manifest checker "CVSNT_PRODUCTVERSION_STRING"\n");
printf("usage: chkmanifest <file>\n");
return -1;
}
bool done;
int err = 0;
toCheck.clear();
err += checkSub(argv[1],toCheck);
do
{
done = false;
for(std::map<std::string, int>::const_iterator i = toCheck.begin(); i!=toCheck.end(); ++i)
{
if(beenChecked[i->first]++)
continue;
err += checkSub(i->first.c_str(), toCheck);
done = true;
break;
}
} while(done);
if(err)
{
printf("** there were errors! Program may not run correctly\n");
}
}
int checkSub(const char *szDll, std::map<std::string, int> & toCheck)
{
LOADED_IMAGE *loaded_image;
char szPath[4096];
manifestArray array;
HMODULE hRes = LoadLibraryEx(szDll,NULL,DONT_RESOLVE_DLL_REFERENCES);
if(!hRes)
{
printf("Couldn't load image %s!\n",szDll);
return 0;
}
GetModuleFileName(hRes, szPath, sizeof(szPath));
printf("Module %s\n\n",szPath);
HRSRC hRsrc = FindResource(hRes,MAKEINTRESOURCE(1),RT_MANIFEST);
if(!hRsrc)
hRsrc = FindResource(hRes,MAKEINTRESOURCE(2),RT_MANIFEST);
if(!hRsrc)
hRsrc = FindResource(hRes,MAKEINTRESOURCE(3),RT_MANIFEST);
if(hRsrc)
{
EnumResourceLanguages(hRes,RT_MANIFEST,MAKEINTRESOURCE(1),(ENUMRESLANGPROC)EnumResLangProc,NULL);
LPVOID pRsrc = LoadResource(hRes, hRsrc);
DWORD dwLen = SizeofResource(hRes, hRsrc);
DWORD dwOldProtect;
VirtualProtect(pRsrc,dwLen+1,PAGE_READWRITE,&dwOldProtect);
((LPBYTE)pRsrc)[dwLen]='\0'; // This is cheating but we don't care since this is the only data we need
if(load_manifest((const char *)pRsrc, array))
{
if(debug)
printf("%s\n",pRsrc);
printf(" ** Invalid manifest\n");
FreeResource(hRsrc);
return 1;
}
FreeResource(hRsrc);
}
else
{
if(debug)
printf(" ** No manifest\n");
return 0;
}
loaded_image=ImageLoad((PSTR)szDll,NULL);
if(!loaded_image)
{
printf(" ** Couldn't load image!\n");
return 0;
}
DWORD dwSize;
PBYTE pDllName;
int err = 0;
PIMAGE_IMPORT_DESCRIPTOR pimage_import_descriptor= (PIMAGE_IMPORT_DESCRIPTOR)
ImageDirectoryEntryToData(loaded_image->MappedAddress,FALSE,IMAGE_DIRECTORY_ENTRY_IMPORT,&dwSize);
printf("Dependencies:\n");
while(pimage_import_descriptor->Name!=0)
{
pDllName = (PBYTE)ImageRvaToVa(loaded_image->FileHeader,loaded_image->MappedAddress,pimage_import_descriptor->Name,NULL);
HMODULE hRes = LoadLibraryEx((LPCSTR)pDllName,NULL,DONT_RESOLVE_DLL_REFERENCES);
if(hRes)
{
HRSRC hRsrc = FindResource(hRes,MAKEINTRESOURCE(1),RT_MANIFEST);
GetModuleFileName(hRes, szPath, sizeof(szPath));
if(hRsrc)
{
LPVOID pRsrc = LoadResource(hRes, hRsrc);
DWORD dwLen = SizeofResource(hRes, hRsrc);
DWORD dwOldProtect;
VirtualProtect(pRsrc,dwLen+1,PAGE_READWRITE,&dwOldProtect);
((LPBYTE)pRsrc)[dwLen]='\0'; // This is cheating but we don't care since this is the only data we need
printf(" %s\n",szPath);
err+=parse_manifest((const char *)pRsrc, array, szPath);
FreeResource(hRsrc);
}
else
printf(" %s\n",szPath);
FreeLibrary(hRes);
toCheck[szPath]++;
}
else
{
printf(" %s **MISSING**\n",pDllName);
err++;
}
pimage_import_descriptor++;
}
ImgDelayDescr *pimage_delay_descriptor= (ImgDelayDescr*)
ImageDirectoryEntryToData(loaded_image->MappedAddress,FALSE,IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,&dwSize);
printf("\nDelayload dependencies:\n");
#if (DELAYLOAD_VERSION >= 0x0200) || (_DELAY_IMP_VER > 1)
while(pimage_delay_descriptor && pimage_delay_descriptor->rvaDLLName!=0)
#else
while(pimage_delay_descriptor && pimage_delay_descriptor->szName!=NULL)
#endif
{
#if (DELAYLOAD_VERSION >= 0x0200) || (_DELAY_IMP_VER > 1)
pDllName = (PBYTE)ImageRvaToVa(loaded_image->FileHeader,loaded_image->MappedAddress,pimage_delay_descriptor->rvaDLLName,NULL);
#else
pDllName = (PBYTE)pimage_delay_descriptor->szName;
#endif
HMODULE hRes = LoadLibraryEx((LPCSTR)pDllName,NULL,DONT_RESOLVE_DLL_REFERENCES);
if(hRes)
{
GetModuleFileName(hRes, szPath, sizeof(szPath));
HRSRC hRsrc = FindResource(hRes,MAKEINTRESOURCE(1),RT_MANIFEST);
if(hRsrc)
{
LPVOID pRsrc = LoadResource(hRes, hRsrc);
DWORD dwLen = SizeofResource(hRes, hRsrc);
DWORD dwOldProtect;
VirtualProtect(pRsrc,dwLen+1,PAGE_READWRITE,&dwOldProtect);
((LPBYTE)pRsrc)[dwLen]='\0'; // This is cheating but we don't care since this is the only data we need
printf(" %s\n",szPath);
err+=parse_manifest((const char *)pRsrc, array, szPath);
FreeResource(hRsrc);
}
else
printf(" %s\n",szPath);
FreeLibrary(hRes);
toCheck[szPath]++;
}
else
printf(" %s ** MISSING **\n",pDllName); // This is not an error since it's delayload
pimage_delay_descriptor++;
}
printf("\n");
for(manifestArray::const_iterator i = array.begin(); i!=array.end(); ++i)
{
if(i->found)
continue;
printf(" ** Module dependency missing - %s version %s\n",(const char *)i->name,(const char *)i->version);
err++;
}
printf("\n");
return err;
}
syntax highlighted by Code2HTML, v. 0.9.1