[SHIMDBG] Add option to dump file properties.
[reactos.git] / rosapps / applications / devutils / shimdbg / shimdbg.c
1 /*
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
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <ctype.h>
11 #include <ntndk.h>
12
13 void CallApphelp(APPHELPCACHESERVICECLASS Service,
14 PAPPHELP_CACHE_SERVICE_LOOKUP CacheEntry)
15 {
16 NTSTATUS Status = NtApphelpCacheControl(Service, CacheEntry);
17 printf("NtApphelpCacheControl returned 0x%x\n", (unsigned int)Status);
18 }
19
20 HANDLE MapFile(char* filename, UNICODE_STRING* PathName, int MapIt)
21 {
22 OBJECT_ATTRIBUTES LocalObjectAttributes;
23 IO_STATUS_BLOCK IoStatusBlock;
24 NTSTATUS Status;
25 HANDLE FileHandle = NULL;
26 RtlCreateUnicodeStringFromAsciiz(PathName, filename);
27 if (MapIt)
28 {
29 InitializeObjectAttributes(&LocalObjectAttributes, PathName,
30 OBJ_CASE_INSENSITIVE, NULL, NULL);
31 Status = NtOpenFile(&FileHandle,
32 SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_EXECUTE,
33 &LocalObjectAttributes, &IoStatusBlock,
34 FILE_SHARE_READ | FILE_SHARE_DELETE,
35 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
36 if (!NT_SUCCESS(Status))
37 {
38 printf("Failed opening the file, using a NULL handle\n");
39 FileHandle = NULL;
40 }
41 }
42 return FileHandle;
43 }
44
45 void CallApphelpWithImage(char* filename, int MapIt,
46 APPHELPCACHESERVICECLASS Service, char* ServiceName)
47 {
48 UNICODE_STRING PathName = {0};
49 APPHELP_CACHE_SERVICE_LOOKUP CacheEntry;
50
51 HANDLE FileHandle = MapFile(filename, &PathName, MapIt);
52
53 printf("Calling %s %s mapping\n", ServiceName, (MapIt ? "with" : "without"));
54
55 RtlInitUnicodeString(&CacheEntry.ImageName, PathName.Buffer);
56 CacheEntry.ImageHandle = FileHandle ? FileHandle : (HANDLE)-1;
57 CallApphelp(Service, &CacheEntry);
58 // we piggy-back on the PathName, so let the Cleanup take care of the string
59 //RtlFreeUnicodeString(&CacheEntry.ImageName);
60
61 if (FileHandle)
62 NtClose(FileHandle);
63 RtlFreeUnicodeString(&PathName);
64 }
65
66 int IsOpt(char* argv, const char* check)
67 {
68 if( argv && (argv[0] == '-' || argv[0] == '/') ) {
69 return !_strnicmp(argv + 1, check, strlen(check));
70 }
71 return 0;
72 }
73
74 int HandleImageArg(int argc, char* argv[], int* pn, char MapItChar,
75 APPHELPCACHESERVICECLASS Service, char* ServiceName)
76 {
77 int n = *pn;
78 if (n+1 < argc)
79 {
80 int MapIt = argv[n][1] == MapItChar;
81 CallApphelpWithImage(argv[n+1], MapIt, Service, ServiceName);
82 (*pn) += 1;
83 return 0;
84 }
85 printf("Error: no image name specified\n");
86 return 1;
87 }
88
89 typedef WORD TAG;
90 typedef UINT64 QWORD;
91
92 #define TAG_TYPE_MASK 0xF000
93 #define TAG_TYPE_DWORD 0x4000
94 #define TAG_TYPE_QWORD 0x5000
95 #define TAG_TYPE_STRINGREF 0x6000
96
97 #define ATTRIBUTE_AVAILABLE 0x1
98 #define ATTRIBUTE_FAILED 0x2
99
100 typedef struct tagATTRINFO
101 {
102 TAG type;
103 DWORD flags; /* ATTRIBUTE_AVAILABLE, ATTRIBUTE_FAILED */
104 union
105 {
106 QWORD qwattr;
107 DWORD dwattr;
108 WCHAR *lpattr;
109 };
110 } ATTRINFO, *PATTRINFO;
111
112 static PVOID hdll;
113 static LPCWSTR (WINAPI *pSdbTagToString)(TAG);
114 static BOOL (WINAPI *pSdbGetFileAttributes)(LPCWSTR, PATTRINFO *, LPDWORD);
115 static BOOL (WINAPI *pSdbFreeFileAttributes)(PATTRINFO);
116
117 static BOOL InitApphelp()
118 {
119 if (!hdll)
120 {
121 static UNICODE_STRING DllName = RTL_CONSTANT_STRING(L"apphelp.dll");
122 static ANSI_STRING SdbTagToString = RTL_CONSTANT_STRING("SdbTagToString");
123 static ANSI_STRING SdbGetFileAttributes = RTL_CONSTANT_STRING("SdbGetFileAttributes");
124 static ANSI_STRING SdbFreeFileAttributes = RTL_CONSTANT_STRING("SdbFreeFileAttributes");
125 if (!NT_SUCCESS(LdrLoadDll(NULL, NULL, &DllName, &hdll)))
126 {
127 printf("Unable to load apphelp.dll\n");
128 return FALSE;
129 }
130 if (!NT_SUCCESS(LdrGetProcedureAddress(hdll, &SdbTagToString, 0, (PVOID)&pSdbTagToString)) ||
131 !NT_SUCCESS(LdrGetProcedureAddress(hdll, &SdbGetFileAttributes, 0, (PVOID)&pSdbGetFileAttributes)) ||
132 !NT_SUCCESS(LdrGetProcedureAddress(hdll, &SdbFreeFileAttributes, 0, (PVOID)&pSdbFreeFileAttributes)))
133 {
134 LdrUnloadDll(hdll);
135 hdll = NULL;
136 printf("Unable to resolve functions\n");
137 return FALSE;
138 }
139 }
140 return TRUE;
141 }
142
143
144 int HandleDumpAttributes(int argc, char* argv[], int* pn, const char* opt)
145 {
146 UNICODE_STRING FileName;
147 PATTRINFO attr;
148 DWORD num_attr, n;
149 int argn = *pn;
150 const char* arg;
151
152 if (!InitApphelp())
153 return 1;
154
155 if (strlen(argv[argn]) > (strlen(opt)+1))
156 {
157 arg = argv[argn] + strlen(opt);
158 }
159 else if (argn+1 >= argc)
160 {
161 printf("Error: no image name specified\n");
162 return 1;
163 }
164 else
165 {
166 arg = argv[argn+1];
167 (*pn) += 1;
168 }
169
170 RtlCreateUnicodeStringFromAsciiz(&FileName, arg);
171
172 if (pSdbGetFileAttributes(FileName.Buffer, &attr, &num_attr))
173 {
174 printf("Dumping attributes for %s\n", arg);
175 for (n = 0; n < num_attr; ++n)
176 {
177 TAG tagType;
178 LPCWSTR tagName;
179 if (attr[n].flags != ATTRIBUTE_AVAILABLE)
180 continue;
181
182 tagName = pSdbTagToString(attr[n].type);
183
184 tagType = attr[n].type & TAG_TYPE_MASK;
185 switch (tagType)
186 {
187 case TAG_TYPE_DWORD:
188 printf("<%ls>0x%lx</%ls><!-- %ld -->\n", tagName, attr[n].dwattr, tagName, attr[n].dwattr);
189 break;
190 case TAG_TYPE_STRINGREF:
191 printf("<%ls>0x%ls</%ls>\n", tagName, attr[n].lpattr, tagName);
192 break;
193 case TAG_TYPE_QWORD:
194 printf("<%ls>0x%I64x</%ls><!-- %I64d -->\n", tagName, attr[n].qwattr, tagName, attr[n].qwattr);
195 break;
196 default:
197 printf("<!-- Unknown tag type: 0x%x (from 0x%x)\n", tagType, attr[n].type);
198 break;
199 }
200 }
201 printf("Done\n");
202 }
203 else
204 {
205 printf("Unable to get attributes from %s\n", arg);
206 }
207
208
209 RtlFreeUnicodeString(&FileName);
210 return 0;
211 }
212
213 UNICODE_STRING AppCompatCacheKey = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatCache");
214 OBJECT_ATTRIBUTES AppCompatKeyAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&AppCompatCacheKey, OBJ_CASE_INSENSITIVE);
215 UNICODE_STRING AppCompatCacheValue = RTL_CONSTANT_STRING(L"AppCompatCache");
216 #define REG_BINARY ( 3 ) // Free form binary
217
218
219 /* produce a hex dump, stolen from rdesktop.c */
220 void hexdump(unsigned char *p, unsigned int len)
221 {
222 unsigned char *line = p;
223 unsigned int i, thisline, offset = 0;
224
225 while (offset < len)
226 {
227 printf("%04x ", offset);
228 thisline = len - offset;
229 if (thisline > 16)
230 thisline = 16;
231
232 for (i = 0; i < thisline; i++)
233 printf("%02x ", line[i]);
234
235 for (; i < 16; i++)
236 printf(" ");
237
238 for (i = 0; i < thisline; i++)
239 printf("%c", (line[i] >= 0x20 && line[i] < 0x7f) ? line[i] : '.');
240
241 printf("\n");
242 offset += thisline;
243 line += thisline;
244 }
245 }
246
247 void DumpRegistryData(int IncludeDump)
248 {
249 HANDLE KeyHandle;
250 NTSTATUS Status;
251 KEY_VALUE_PARTIAL_INFORMATION KeyValueObject;
252 PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation = &KeyValueObject;
253 ULONG KeyInfoSize, ResultSize;
254
255 printf("Dumping AppCompatCache registry key\n");
256
257 Status = NtOpenKey(&KeyHandle, KEY_QUERY_VALUE, &AppCompatKeyAttributes);
258
259 Status = NtQueryValueKey(KeyHandle, &AppCompatCacheValue,
260 KeyValuePartialInformation, KeyValueInformation,
261 sizeof(KeyValueObject), &ResultSize);
262
263 if (Status == STATUS_BUFFER_OVERFLOW)
264 {
265 KeyInfoSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + KeyValueInformation->DataLength;
266 KeyValueInformation = malloc(KeyInfoSize);
267 if (KeyValueInformation != NULL)
268 {
269 Status = NtQueryValueKey(KeyHandle, &AppCompatCacheValue,
270 KeyValuePartialInformation, KeyValueInformation,
271 KeyInfoSize, &ResultSize);
272 }
273 }
274
275 if (NT_SUCCESS(Status) && KeyValueInformation->Type == REG_BINARY)
276 {
277 ULONG crc;
278 if (IncludeDump)
279 hexdump(KeyValueInformation->Data, KeyValueInformation->DataLength);
280 crc = RtlComputeCrc32(0, KeyValueInformation->Data, KeyValueInformation->DataLength);
281 printf("Len: %lu, Crc: 0x%lx\n", KeyValueInformation->DataLength, crc);
282 }
283 else
284 {
285 printf("Failed reading AppCompatCache from registry (0x%lx)\n", Status);
286 }
287
288 if (KeyValueInformation != &KeyValueObject)
289 free(KeyValueInformation);
290
291 if (KeyHandle)
292 NtClose(KeyHandle);
293 }
294
295 int _getch();
296
297 int main(int argc, char* argv[])
298 {
299 int n, unhandled = 0, keepopen = 0;
300
301 for (n = 1; n < argc; ++n)
302 {
303 char* arg = argv[n];
304 if (IsOpt(arg, "d"))
305 {
306 printf("Calling ApphelpCacheServiceDump\n");
307 CallApphelp(ApphelpCacheServiceDump, NULL);
308 unhandled = 0;
309 }
310 else if (IsOpt(arg, "h"))
311 {
312 DumpRegistryData(arg[1] == 'h');
313 unhandled = 0;
314 }
315 else if (IsOpt(arg, "f"))
316 {
317 printf("Calling ApphelpCacheServiceFlush\n");
318 CallApphelp(ApphelpCacheServiceFlush, NULL);
319 unhandled = 0;
320 }
321 else if (IsOpt(arg, "z"))
322 {
323 printf("Calling ApphelpDBGReadRegistry\n");
324 CallApphelp(ApphelpDBGReadRegistry, NULL);
325 unhandled = 0;
326 }
327 else if (IsOpt(arg, "x"))
328 {
329 printf("Calling ApphelpDBGWriteRegistry\n");
330 CallApphelp(ApphelpDBGWriteRegistry, NULL);
331 unhandled = 0;
332 }
333 else if (IsOpt(arg, "l"))
334 {
335 unhandled |= HandleImageArg(argc, argv, &n, 'l',
336 ApphelpCacheServiceLookup, "ApphelpCacheServiceLookup");
337 }
338 else if (IsOpt(arg, "u"))
339 {
340 unhandled |= HandleImageArg(argc, argv, &n, 'u',
341 ApphelpCacheServiceUpdate, "ApphelpCacheServiceUpdate");
342 }
343 else if (IsOpt(arg, "r"))
344 {
345 unhandled |= HandleImageArg(argc, argv, &n, 'r',
346 ApphelpCacheServiceRemove, "ApphelpCacheServiceRemove");
347 }
348 else if (IsOpt(arg, "a"))
349 {
350 unhandled |= HandleDumpAttributes(argc, argv, &n, "a");
351 }
352 else if (IsOpt(arg, "k"))
353 {
354 keepopen = 1;
355 }
356 else
357 {
358 unhandled = 1;
359 }
360 }
361 if (unhandled || argc == 1)
362 {
363 printf("Usage: %s [-d|-z|-x|-h|-H|-f|-[l|L] <image>|-[u|U] <image>|-[r|R] <image>|-k]\n", argv[0]);
364 printf(" -d: Dump shim cache over debug output\n");
365 printf(" -z: DEBUG Read shim cache from registry\n");
366 printf(" -x: DEBUG Write shim cache to registry\n");
367 printf(" -h: Hexdump shim registry key\n");
368 printf(" -H: Crc + Length from shim registry key only\n");
369 printf(" -f: Flush (clear) the shim cache\n");
370 printf(" -l: Lookup <image> in the shim cache\n");
371 printf(" -L: Lookup <image> in the shim cache without mapping it\n");
372 printf(" -u: Update (insert) <image> in the shim cache\n");
373 printf(" -U: Update (insert) <image> in the shim cache without mapping it\n");
374 printf(" -r: Remove <image> from the shim cache\n");
375 printf(" -R: Remove <image> from the shim cache without mapping it\n");
376 printf(" -a: Dump file attributes as used in the appcompat database\n");
377 printf(" -k: Keep the console open\n");
378 }
379 if (keepopen)
380 {
381 _getch();
382 }
383 return unhandled;
384 }