|
|
#include "nt.h"
#include "ntdef.h"
#include "ntrtl.h"
#include "nturtl.h"
#include "stdio.h"
#include "sxs-rtl.h"
#include "fasterxml.h"
#include "skiplist.h"
#include "namespacemanager.h"
#include "xmlstructure.h"
#include "stdlib.h"
#include "xmlassert.h"
#include "manifestinspection.h"
#include "manifestcooked.h"
#include "stringpool.h"
#undef INVALID_HANDLE_VALUE
#include "windows.h"
#include "sha.h"
#include "environment.h"
#include "sha2.h"
#include "assemblygac.h"
ASSEMBLY_CACHE_LISTING s_AssemblyCaches[] = { { &CDotNetSxsAssemblyCache::CacheIdentifier, CDotNetSxsAssemblyCache::CreateSelf }, { NULL, NULL } };
LONG OurFilter( PEXCEPTION_POINTERS pExceptionPointers ) { DbgBreakPoint(); return EXCEPTION_CONTINUE_SEARCH; }
#define RTL_ANALYZE_MANIFEST_GET_FILES (0x00000001)
#define RTL_ANALYZE_MANIFEST_GET_WINDOW_CLASSES (0x00000002)
#define RTL_ANALYZE_MANIFEST_GET_COM_CLASSES (0x00000004)
#define RTL_ANALYZE_MANIFEST_GET_DEPENDENCIES (0x00000008)
#define RTL_ANALYZE_MANIFEST_GET_SIGNATURES (0x00000010)
#define RTLSXS_INSTALLER_REGION_SIZE (128*1024)
NTSTATUS RtlAnalyzeManifest( ULONG ulFlags, PUNICODE_STRING pusPath, PMANIFEST_COOKED_DATA *ppusCookedData ) { PVOID pvAllocation = NULL; SIZE_T cbAllocationSize = 0; LARGE_INTEGER liFileSize; HANDLE hFile = INVALID_HANDLE_VALUE; CEnv::StatusCode StatusCode; SIZE_T cbReadFileSize; PRTL_MANIFEST_CONTENT_RAW pManifestContent = NULL; XML_TOKENIZATION_STATE XmlState; NTSTATUS status; PMANIFEST_COOKED_DATA pCookedContent = NULL; SIZE_T cbCookedContent; ULONG ulGatherFlags = 0; CEnv::CConstantUnicodeStringPair ManifestPath;
//
// Snag a region of memory to stash the file into
//
StatusCode = CEnv::VirtualAlloc(NULL, RTLSXS_INSTALLER_REGION_SIZE, MEM_RESERVE, PAGE_READWRITE, &pvAllocation); if (CEnv::DidFail(StatusCode)) { goto Exit; }
//
// Convert the input flags into the "gather" flagset
//
if (ulFlags & RTL_ANALYZE_MANIFEST_GET_FILES) ulGatherFlags |= RTLIMS_GATHER_FILES; if (ulFlags & RTL_ANALYZE_MANIFEST_GET_WINDOW_CLASSES) ulGatherFlags |= RTLIMS_GATHER_WINDOWCLASSES; if (ulFlags & RTL_ANALYZE_MANIFEST_GET_COM_CLASSES) ulGatherFlags |= RTLIMS_GATHER_COMCLASSES; if (ulFlags & RTL_ANALYZE_MANIFEST_GET_DEPENDENCIES) ulGatherFlags |= RTLIMS_GATHER_DEPENDENCIES; if (ulFlags & RTL_ANALYZE_MANIFEST_GET_SIGNATURES) ulGatherFlags |= RTLIMS_GATHER_SIGNATURES;
//
// Acquire a handle on the file, get its size.
//
ManifestPath = CEnv::StringFrom(pusPath); if (CEnv::DidFail(StatusCode = CEnv::GetFileHandle(&hFile, ManifestPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING))) { goto Exit; }
if (CEnv::DidFail(StatusCode = CEnv::GetFileSize(hFile, &liFileSize))) { goto Exit; }
//
// Commit enough space to hold the file contents
//
cbAllocationSize = (SIZE_T)liFileSize.QuadPart; StatusCode = CEnv::VirtualAlloc(pvAllocation, cbAllocationSize, MEM_COMMIT, PAGE_READWRITE, &pvAllocation); if (CEnv::DidFail(StatusCode)) { goto Exit; }
// Read the file data - in the future, we'll want to respect overlapped
// IO so this can move into the kernel
StatusCode = CEnv::ReadFile(hFile, pvAllocation, cbAllocationSize, cbReadFileSize); if (CEnv::DidFail(StatusCode)) { goto Exit; }
// Initialize our callback stuff. We want to know only about the files that this
// manifest contains - anything else is superflous. Of course, we also want the
// xml signature data contained herein as well.
status = RtlSxsInitializeManifestRawContent(ulGatherFlags, &pManifestContent, NULL, 0); if (CNtEnvironment::DidFail(status)) { StatusCode = CNtEnvironment::ConvertStatusToOther<CEnv::StatusCode>(status); goto Exit; }
// Now run through the file looking for useful things
status = RtlInspectManifestStream( ulGatherFlags, pvAllocation, cbAllocationSize, pManifestContent, &XmlState); if (CNtEnvironment::DidFail(status)) { StatusCode = CNtEnvironment::ConvertStatusToOther<CEnv::StatusCode>(status); goto Exit; }
//
// Convert the raw content to cooked content that we can use
//
status = RtlConvertRawToCookedContent(pManifestContent, &XmlState.RawTokenState, NULL, 0, &cbCookedContent); if (CNtEnvironment::DidFail(status) && (status != CNtEnvironment::NotEnoughBuffer)) { StatusCode = CNtEnvironment::ConvertStatusToOther<CEnv::StatusCode>(status); goto Exit; }
//
// Allocate some heap to contain the raw content
//
else if (status == CNtEnvironment::NotEnoughBuffer) { SIZE_T cbDidWrite; if (CEnv::DidFail(StatusCode = CEnv::AllocateHeap(cbCookedContent, (PVOID*)&pCookedContent, NULL))) { goto Exit; } status = RtlConvertRawToCookedContent( pManifestContent, &XmlState.RawTokenState, (PVOID)pCookedContent, cbCookedContent, &cbDidWrite); }
*ppusCookedData = pCookedContent; pCookedContent = NULL;
// Spiffy. We now have converted all the strings that make up the file table -
// let's start installing them!
StatusCode = CEnv::SuccessCode; Exit: if (hFile != INVALID_HANDLE_VALUE) { CEnv::CloseHandle(hFile); }
if (pvAllocation != NULL) { CEnv::VirtualFree(pvAllocation, cbAllocationSize, MEM_DECOMMIT); CEnv::VirtualFree(pvAllocation, 0, MEM_RELEASE); pvAllocation = NULL; }
RtlSxsDestroyManifestContent(pManifestContent);
if (pCookedContent != NULL) { CEnv::FreeHeap(pCookedContent, NULL); } return CEnv::DidFail(StatusCode) ? STATUS_UNSUCCESSFUL : STATUS_SUCCESS; }
NTSTATUS InstallAssembly( PCWSTR pcwszPath, LPGUID lpgGacIdent ) { PMANIFEST_COOKED_DATA pCookedData = NULL; UNICODE_STRING usManifestFile; UNICODE_STRING usManifestPath; CNtEnvironment::StatusCode Result; COSAssemblyCache *pTargetCache = NULL; ULONG ul = 0;
RtlInitUnicodeString(&usManifestFile, pcwszPath);
if ((lpgGacIdent == NULL) || (pcwszPath == NULL)) { return STATUS_INVALID_PARAMETER; }
for (ul = 0; s_AssemblyCaches[ul].CacheIdent != NULL; ul++) { if (*s_AssemblyCaches[ul].CacheIdent == *lpgGacIdent) { pTargetCache = s_AssemblyCaches[ul].pfnCreator(0, lpgGacIdent); if (pTargetCache) break; } }
if (pTargetCache == NULL) { return STATUS_INVALID_PARAMETER; }
//
// Gather junk from the manifest
//
Result = RtlAnalyzeManifest( RTL_ANALYZE_MANIFEST_GET_SIGNATURES | RTL_ANALYZE_MANIFEST_GET_FILES, &usManifestFile, &pCookedData); if (CNtEnvironment::DidFail(Result)) { goto Exit; }
usManifestPath = usManifestFile; while (usManifestPath.Length && (usManifestPath.Buffer[(usManifestPath.Length / sizeof(usManifestPath.Buffer[0])) - 1] != L'\\')) usManifestPath.Length -= sizeof(usManifestPath.Buffer[0]); //
// Do the installation. Build the path to the
//
Result = pTargetCache->InstallAssembly(0, pCookedData, CEnv::StringFrom(&usManifestPath));
Exit: if (pCookedData != NULL) { CEnv::FreeHeap(pCookedData, NULL); pCookedData = NULL; }
if (pTargetCache) { pTargetCache->~COSAssemblyCache(); CEnv::FreeHeap(pTargetCache, NULL); } return Result; }
int __cdecl wmain(int argc, WCHAR** argv) { static int iFrobble = 0; NTSTATUS status; UNICODE_STRING usGuid; GUID gGacGuid; WCHAR wch[5]; int i = _snwprintf(wch, 5, L"123456");
iFrobble = iFrobble + 1;
__try { RtlInitUnicodeString(&usGuid, argv[2]); if (NT_SUCCESS(status = RtlGUIDFromString(&usGuid, &gGacGuid))) { status = InstallAssembly(argv[1], &gGacGuid); } } __except(OurFilter(GetExceptionInformation())) { }
return (int)status; }
|