2 * PROJECT: shimdbg utility for WINE and ReactOS
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: Test tool for SHIM engine caching.
5 * PROGRAMMER: Mark Jansen
13 NTSYSAPI ULONG NTAPI
vDbgPrintEx(_In_ ULONG ComponentId
, _In_ ULONG Level
, _In_z_ PCCH Format
, _In_
va_list ap
);
14 #define DPFLTR_ERROR_LEVEL 0
16 void xprintf(const char *fmt
, ...)
22 vDbgPrintEx(-1, DPFLTR_ERROR_LEVEL
, fmt
, ap
);
26 void CallApphelp(APPHELPCACHESERVICECLASS Service
,
27 PAPPHELP_CACHE_SERVICE_LOOKUP CacheEntry
)
29 NTSTATUS Status
= NtApphelpCacheControl(Service
, CacheEntry
);
30 xprintf("NtApphelpCacheControl returned 0x%x\n", (unsigned int)Status
);
33 HANDLE
MapFile(char* filename
, UNICODE_STRING
* PathName
, int MapIt
)
35 OBJECT_ATTRIBUTES LocalObjectAttributes
;
36 IO_STATUS_BLOCK IoStatusBlock
;
38 HANDLE FileHandle
= NULL
;
39 RtlCreateUnicodeStringFromAsciiz(PathName
, filename
);
42 InitializeObjectAttributes(&LocalObjectAttributes
, PathName
,
43 OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
44 Status
= NtOpenFile(&FileHandle
,
45 SYNCHRONIZE
| FILE_READ_ATTRIBUTES
| FILE_READ_DATA
| FILE_EXECUTE
,
46 &LocalObjectAttributes
, &IoStatusBlock
,
47 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
48 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
49 if (!NT_SUCCESS(Status
))
51 xprintf("Failed opening the file, using a NULL handle\n");
58 void CallApphelpWithImage(char* filename
, int MapIt
,
59 APPHELPCACHESERVICECLASS Service
, char* ServiceName
)
61 UNICODE_STRING PathName
= {0};
62 APPHELP_CACHE_SERVICE_LOOKUP CacheEntry
;
64 HANDLE FileHandle
= MapFile(filename
, &PathName
, MapIt
);
66 xprintf("Calling %s %s mapping\n", ServiceName
, (MapIt
? "with" : "without"));
68 RtlInitUnicodeString(&CacheEntry
.ImageName
, PathName
.Buffer
);
69 CacheEntry
.ImageHandle
= FileHandle
? FileHandle
: (HANDLE
)-1;
70 CallApphelp(Service
, &CacheEntry
);
71 // we piggy-back on the PathName, so let the Cleanup take care of the string
72 //RtlFreeUnicodeString(&CacheEntry.ImageName);
76 RtlFreeUnicodeString(&PathName
);
79 int IsOpt(char* argv
, const char* check
)
81 if( argv
&& (argv
[0] == '-' || argv
[0] == '/') ) {
82 return !_strnicmp(argv
+ 1, check
, strlen(check
));
87 int HandleImageArg(int argc
, char* argv
[], int* pn
, char MapItChar
,
88 APPHELPCACHESERVICECLASS Service
, char* ServiceName
)
93 int MapIt
= argv
[n
][1] == MapItChar
;
94 CallApphelpWithImage(argv
[n
+1], MapIt
, Service
, ServiceName
);
98 xprintf("Error: no image name specified\n");
103 typedef UINT64 QWORD
;
105 #define TAG_TYPE_MASK 0xF000
106 #define TAG_TYPE_DWORD 0x4000
107 #define TAG_TYPE_QWORD 0x5000
108 #define TAG_TYPE_STRINGREF 0x6000
110 #define ATTRIBUTE_AVAILABLE 0x1
111 #define ATTRIBUTE_FAILED 0x2
113 typedef struct tagATTRINFO
116 DWORD flags
; /* ATTRIBUTE_AVAILABLE, ATTRIBUTE_FAILED */
123 } ATTRINFO
, *PATTRINFO
;
126 static LPCWSTR (WINAPI
*pSdbTagToString
)(TAG
);
127 static BOOL (WINAPI
*pSdbGetFileAttributes
)(LPCWSTR
, PATTRINFO
*, LPDWORD
);
128 static BOOL (WINAPI
*pSdbFreeFileAttributes
)(PATTRINFO
);
130 static BOOL
InitApphelp()
134 static UNICODE_STRING DllName
= RTL_CONSTANT_STRING(L
"apphelp.dll");
135 static ANSI_STRING SdbTagToString
= RTL_CONSTANT_STRING("SdbTagToString");
136 static ANSI_STRING SdbGetFileAttributes
= RTL_CONSTANT_STRING("SdbGetFileAttributes");
137 static ANSI_STRING SdbFreeFileAttributes
= RTL_CONSTANT_STRING("SdbFreeFileAttributes");
138 if (!NT_SUCCESS(LdrLoadDll(NULL
, NULL
, &DllName
, &hdll
)))
140 xprintf("Unable to load apphelp.dll\n");
143 if (!NT_SUCCESS(LdrGetProcedureAddress(hdll
, &SdbTagToString
, 0, (PVOID
)&pSdbTagToString
)) ||
144 !NT_SUCCESS(LdrGetProcedureAddress(hdll
, &SdbGetFileAttributes
, 0, (PVOID
)&pSdbGetFileAttributes
)) ||
145 !NT_SUCCESS(LdrGetProcedureAddress(hdll
, &SdbFreeFileAttributes
, 0, (PVOID
)&pSdbFreeFileAttributes
)))
149 xprintf("Unable to resolve functions\n");
157 int HandleDumpAttributes(int argc
, char* argv
[], int* pn
, const char* opt
)
159 UNICODE_STRING FileName
;
168 if (strlen(argv
[argn
]) > (strlen(opt
)+1))
170 arg
= argv
[argn
] + strlen(opt
);
172 else if (argn
+1 >= argc
)
174 xprintf("Error: no image name specified\n");
183 RtlCreateUnicodeStringFromAsciiz(&FileName
, arg
);
185 if (pSdbGetFileAttributes(FileName
.Buffer
, &attr
, &num_attr
))
187 xprintf("Dumping attributes for %s\n", arg
);
188 for (n
= 0; n
< num_attr
; ++n
)
192 if (attr
[n
].flags
!= ATTRIBUTE_AVAILABLE
)
195 tagName
= pSdbTagToString(attr
[n
].type
);
197 tagType
= attr
[n
].type
& TAG_TYPE_MASK
;
201 xprintf("<%ls>0x%lx</%ls>\n", tagName
, attr
[n
].dwattr
, tagName
);
203 case TAG_TYPE_STRINGREF
:
204 xprintf("<%ls>%ls</%ls>\n", tagName
, attr
[n
].lpattr
, tagName
);
207 xprintf("<%ls>0x%I64x</%ls>\n", tagName
, attr
[n
].qwattr
, tagName
);
210 xprintf("<!-- Unknown tag type: 0x%x (from 0x%x)\n", tagType
, attr
[n
].type
);
218 xprintf("Unable to get attributes from %s\n", arg
);
222 RtlFreeUnicodeString(&FileName
);
226 UNICODE_STRING AppCompatCacheKey
= RTL_CONSTANT_STRING(L
"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatCache");
227 OBJECT_ATTRIBUTES AppCompatKeyAttributes
= RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey
, OBJ_CASE_INSENSITIVE
);
228 UNICODE_STRING AppCompatCacheValue
= RTL_CONSTANT_STRING(L
"AppCompatCache");
229 #define REG_BINARY ( 3 ) // Free form binary
232 /* produce a hex dump, stolen from rdesktop.c */
233 void hexdump(unsigned char *p
, unsigned int len
)
235 unsigned char *line
= p
;
236 unsigned int i
, thisline
, offset
= 0;
240 xprintf("%04x ", offset
);
241 thisline
= len
- offset
;
245 for (i
= 0; i
< thisline
; i
++)
246 xprintf("%02x ", line
[i
]);
251 for (i
= 0; i
< thisline
; i
++)
252 xprintf("%c", (line
[i
] >= 0x20 && line
[i
] < 0x7f) ? line
[i
] : '.');
260 void DumpRegistryData(int IncludeDump
)
264 KEY_VALUE_PARTIAL_INFORMATION KeyValueObject
;
265 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation
= &KeyValueObject
;
266 ULONG KeyInfoSize
, ResultSize
;
268 xprintf("Dumping AppCompatCache registry key\n");
270 Status
= NtOpenKey(&KeyHandle
, KEY_QUERY_VALUE
, &AppCompatKeyAttributes
);
272 Status
= NtQueryValueKey(KeyHandle
, &AppCompatCacheValue
,
273 KeyValuePartialInformation
, KeyValueInformation
,
274 sizeof(KeyValueObject
), &ResultSize
);
276 if (Status
== STATUS_BUFFER_OVERFLOW
)
278 KeyInfoSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + KeyValueInformation
->DataLength
;
279 KeyValueInformation
= malloc(KeyInfoSize
);
280 if (KeyValueInformation
!= NULL
)
282 Status
= NtQueryValueKey(KeyHandle
, &AppCompatCacheValue
,
283 KeyValuePartialInformation
, KeyValueInformation
,
284 KeyInfoSize
, &ResultSize
);
288 if (NT_SUCCESS(Status
) && KeyValueInformation
->Type
== REG_BINARY
)
292 hexdump(KeyValueInformation
->Data
, KeyValueInformation
->DataLength
);
293 crc
= RtlComputeCrc32(0, KeyValueInformation
->Data
, KeyValueInformation
->DataLength
);
294 xprintf("Len: %lu, Crc: 0x%lx\n", KeyValueInformation
->DataLength
, crc
);
298 xprintf("Failed reading AppCompatCache from registry (0x%lx)\n", Status
);
301 if (KeyValueInformation
!= &KeyValueObject
)
302 free(KeyValueInformation
);
310 int main(int argc
, char* argv
[])
312 int n
, unhandled
= 0, keepopen
= 0;
314 for (n
= 1; n
< argc
; ++n
)
319 xprintf("Calling ApphelpCacheServiceDump\n");
320 CallApphelp(ApphelpCacheServiceDump
, NULL
);
323 else if (IsOpt(arg
, "h"))
325 DumpRegistryData(arg
[1] == 'h');
328 else if (IsOpt(arg
, "f"))
330 xprintf("Calling ApphelpCacheServiceFlush\n");
331 CallApphelp(ApphelpCacheServiceFlush
, NULL
);
334 else if (IsOpt(arg
, "z"))
336 xprintf("Calling ApphelpDBGReadRegistry\n");
337 CallApphelp(ApphelpDBGReadRegistry
, NULL
);
340 else if (IsOpt(arg
, "x"))
342 xprintf("Calling ApphelpDBGWriteRegistry\n");
343 CallApphelp(ApphelpDBGWriteRegistry
, NULL
);
346 else if (IsOpt(arg
, "l"))
348 unhandled
|= HandleImageArg(argc
, argv
, &n
, 'l',
349 ApphelpCacheServiceLookup
, "ApphelpCacheServiceLookup");
351 else if (IsOpt(arg
, "u"))
353 unhandled
|= HandleImageArg(argc
, argv
, &n
, 'u',
354 ApphelpCacheServiceUpdate
, "ApphelpCacheServiceUpdate");
356 else if (IsOpt(arg
, "r"))
358 unhandled
|= HandleImageArg(argc
, argv
, &n
, 'r',
359 ApphelpCacheServiceRemove
, "ApphelpCacheServiceRemove");
361 else if (IsOpt(arg
, "a"))
363 unhandled
|= HandleDumpAttributes(argc
, argv
, &n
, "a");
365 else if (IsOpt(arg
, "k"))
374 if (unhandled
|| argc
== 1)
376 xprintf("Usage: %s [-d|-z|-x|-h|-H|-f|-[l|L] <image>|-[u|U] <image>|-[r|R] <image>|-k]\n", argv
[0]);
377 xprintf(" -d: Dump shim cache over debug output\n");
378 xprintf(" -z: DEBUG Read shim cache from registry\n");
379 xprintf(" -x: DEBUG Write shim cache to registry\n");
380 xprintf(" -h: Hexdump shim registry key\n");
381 xprintf(" -H: Crc + Length from shim registry key only\n");
382 xprintf(" -f: Flush (clear) the shim cache\n");
383 xprintf(" -l: Lookup <image> in the shim cache\n");
384 xprintf(" -L: Lookup <image> in the shim cache without mapping it\n");
385 xprintf(" -u: Update (insert) <image> in the shim cache\n");
386 xprintf(" -U: Update (insert) <image> in the shim cache without mapping it\n");
387 xprintf(" -r: Remove <image> from the shim cache\n");
388 xprintf(" -R: Remove <image> from the shim cache without mapping it\n");
389 xprintf(" -a: Dump file attributes as used in the appcompat database\n");
390 xprintf(" -k: Keep the console open\n");