Index: applications/devutils/CMakeLists.txt =================================================================== --- applications/devutils/CMakeLists.txt (revision 68592) +++ applications/devutils/CMakeLists.txt (working copy) @@ -1,6 +1,7 @@ add_subdirectory(gdb2) add_subdirectory(gdihv) add_subdirectory(genguid) +add_subdirectory(shimdbg) add_subdirectory(symdump) add_subdirectory(syscalldump) add_subdirectory(vgafontedit) Index: applications/devutils/shimdbg/CMakeLists.txt =================================================================== --- applications/devutils/shimdbg/CMakeLists.txt (revision 0) +++ applications/devutils/shimdbg/CMakeLists.txt (working copy) @@ -0,0 +1,6 @@ + +add_executable(shimdbg shimdbg.c) + +set_module_type(shimdbg win32cui) +add_importlibs(shimdbg ntdll msvcrt kernel32) +add_cd_file(TARGET shimdbg DESTINATION reactos/system32 FOR all) Index: applications/devutils/shimdbg/shimdbg.c =================================================================== --- applications/devutils/shimdbg/shimdbg.c (revision 0) +++ applications/devutils/shimdbg/shimdbg.c (working copy) @@ -0,0 +1,256 @@ +/* + * PROJECT: shimdbg utility for WINE and ReactOS + * LICENSE: BSD - See COPYING.ARM in the top level directory + * PURPOSE: Test tool for SHIM engine caching. + * PROGRAMMER: Mark Jansen + */ + +#include +#include +#include +#include + +void CallApphelp(APPHELPCACHESERVICECLASS Service, + PAPPHELP_CACHE_SERVICE_LOOKUP CacheEntry) +{ + NTSTATUS Status = NtApphelpCacheControl(Service, CacheEntry); + printf("NtApphelpCacheControl returned 0x%x\n", (unsigned int)Status); +} + +HANDLE MapFile(char* filename, UNICODE_STRING* PathName, int MapIt) +{ + OBJECT_ATTRIBUTES LocalObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + HANDLE FileHandle = NULL; + RtlCreateUnicodeStringFromAsciiz(PathName, filename); + if (MapIt) + { + InitializeObjectAttributes(&LocalObjectAttributes, PathName, + OBJ_CASE_INSENSITIVE, NULL, NULL); + Status = NtOpenFile(&FileHandle, + SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE, + &LocalObjectAttributes, &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE); + if (!NT_SUCCESS(Status)) + { + printf("Failed opening the file, using a NULL handle\n"); + FileHandle = NULL; + } + } + return FileHandle; +} + +void CallApphelpWithImage(char* filename, int MapIt, + APPHELPCACHESERVICECLASS Service, char* ServiceName) +{ + UNICODE_STRING PathName = {0}; + APPHELP_CACHE_SERVICE_LOOKUP CacheEntry; + + HANDLE FileHandle = MapFile(filename, &PathName, MapIt); + + printf("Calling %s %s mapping\n", ServiceName, (MapIt ? "with" : "without")); + + RtlInitUnicodeString(&CacheEntry.ImageName, PathName.Buffer); + CacheEntry.ImageHandle = FileHandle ? FileHandle : (HANDLE)-1; + CallApphelp(Service, &CacheEntry); + // we piggy-back on the PathName, so let the Cleanup take care of the string + //RtlFreeUnicodeString(&CacheEntry.ImageName); + + if (FileHandle) + NtClose(FileHandle); + RtlFreeUnicodeString(&PathName); +} + +int IsOpt(char* argv, const char* check) +{ + if( argv && (argv[0] == '-' || argv[0] == '/') ) { + return !stricmp(argv + 1, check); + } + return 0; +} + +int HandleImageArg(int argc, char* argv[], int* pn, char MapItChar, + APPHELPCACHESERVICECLASS Service, char* ServiceName) +{ + int n = *pn; + if (n+1 < argc) + { + int MapIt = argv[n][1] == MapItChar; + CallApphelpWithImage(argv[n+1], MapIt, Service, ServiceName); + (*pn) += 1; + return 0; + } + printf("Error: no image name specified\n"); + return 1; +} + + +UNICODE_STRING AppCompatCacheKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatCache"); +OBJECT_ATTRIBUTES AppCompatKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey, OBJ_CASE_INSENSITIVE); +UNICODE_STRING AppCompatCacheValue = RTL_CONSTANT_STRING(L"AppCompatCache"); +#define REG_BINARY ( 3 ) // Free form binary + + +/* produce a hex dump, stolen from rdesktop.c */ +void hexdump(unsigned char *p, unsigned int len) +{ + unsigned char *line = p; + unsigned int i, thisline, offset = 0; + + while (offset < len) + { + printf("%04x ", offset); + thisline = len - offset; + if (thisline > 16) + thisline = 16; + + for (i = 0; i < thisline; i++) + printf("%02x ", line[i]); + + for (; i < 16; i++) + printf(" "); + + for (i = 0; i < thisline; i++) + printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.'); + + printf("\n"); + offset += thisline; + line += thisline; + } +} + +void DumpRegistryData(int IncludeDump) +{ + HANDLE KeyHandle; + NTSTATUS Status; + KEY_VALUE_PARTIAL_INFORMATION KeyValueObject; + PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = &KeyValueObject; + ULONG KeyInfoSize, ResultSize; + + printf("Dumping AppCompatCache registry key\n"); + + Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &AppCompatKeyAttributes); + + Status = NtQueryValueKey(KeyHandle, &AppCompatCacheValue, + KeyValuePartialInformation, KeyValueInformation, + sizeof(KeyValueObject), &ResultSize); + + if (Status == STATUS_BUFFER_OVERFLOW) + { + KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyValueInformation->DataLength; + KeyValueInformation = malloc(KeyInfoSize); + if (KeyValueInformation != NULL) + { + Status = NtQueryValueKey(KeyHandle, &AppCompatCacheValue, + KeyValuePartialInformation, KeyValueInformation, + KeyInfoSize, &ResultSize); + } + } + + if (NT_SUCCESS(Status) && KeyValueInformation->Type == REG_BINARY) + { + ULONG crc; + if (IncludeDump) + hexdump(KeyValueInformation->Data, KeyValueInformation->DataLength); + crc = RtlComputeCrc32(0, KeyValueInformation->Data, KeyValueInformation->DataLength); + printf("Len: %d, Crc: 0x%lx\n", KeyValueInformation->DataLength, crc); + } + else + { + printf("Failed reading AppCompatCache from registry (0x%lx)\n", Status); + } + + if (KeyValueInformation != &KeyValueObject) + free(KeyValueInformation); + + if (KeyHandle) + NtClose(KeyHandle); +} + +int _getch(); + +int main(int argc, char* argv[]) +{ + int n, unhandled = 0, keepopen = 0; + + for (n = 1; n < argc; ++n) + { + char* arg = argv[n]; + if (IsOpt(arg, "d")) + { + printf("Calling ApphelpCacheServiceDump\n"); + CallApphelp(ApphelpCacheServiceDump, NULL); + unhandled = 0; + } + else if (IsOpt(arg, "h")) + { + DumpRegistryData(arg[1] == 'h'); + unhandled = 0; + } + else if (IsOpt(arg, "f")) + { + printf("Calling ApphelpCacheServiceFlush\n"); + CallApphelp(ApphelpCacheServiceFlush, NULL); + unhandled = 0; + } + else if (IsOpt(arg, "z")) + { + printf("Calling ApphelpDBGReadRegistry\n"); + CallApphelp(ApphelpDBGReadRegistry, NULL); + unhandled = 0; + } + else if (IsOpt(arg, "x")) + { + printf("Calling ApphelpDBGWriteRegistry\n"); + CallApphelp(ApphelpDBGWriteRegistry, NULL); + unhandled = 0; + } + else if (IsOpt(arg, "l")) + { + unhandled |= HandleImageArg(argc, argv, &n, 'l', + ApphelpCacheServiceLookup, "ApphelpCacheServiceLookup"); + } + else if (IsOpt(arg, "u")) + { + unhandled |= HandleImageArg(argc, argv, &n, 'u', + ApphelpCacheServiceUpdate, "ApphelpCacheServiceUpdate"); + } + else if (IsOpt(arg, "r")) + { + unhandled |= HandleImageArg(argc, argv, &n, 'r', + ApphelpCacheServiceRemove, "ApphelpCacheServiceRemove"); + } + else if (IsOpt(arg, "k")) + { + keepopen = 1; + } + else + { + unhandled = 1; + } + } + if (unhandled || argc == 1) + { + printf("Usage: %s [-d|-z|-x|-h|-H|-f|-[l|L] |-[u|U] |-[r|R] |-k]\n", argv[0]); + printf(" -d: Dump shim cache over debug output\n"); + printf(" -z: DEBUG Read shim cache from registry\n"); + printf(" -x: DEBUG Write shim cache to registry\n"); + printf(" -h: Hexdump shim registry key\n"); + printf(" -H: Crc + Length from shim registry key only\n"); + printf(" -f: Flush (clear) the shim cache\n"); + printf(" -l: Lookup in the shim cache\n"); + printf(" -L: Lookup in the shim cache without mapping it\n"); + printf(" -u: Update (insert) in the shim cache\n"); + printf(" -U: Update (insert) in the shim cache without mapping it\n"); + printf(" -r: Remove from the shim cache\n"); + printf(" -R: Remove from the shim cache without mapping it\n"); + printf(" -k: Keep the console open\n"); + } + if (keepopen) + { + _getch(); + } + return unhandled; +}