Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winedump/lnk.c
4389 views
1
/*
2
* Dump a shortcut (lnk) file
3
*
4
* Copyright 2005 Mike McCormack
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*/
20
21
#include "config.h"
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <stdarg.h>
26
#include <fcntl.h>
27
28
#include "windef.h"
29
#include "winbase.h"
30
#include "winedump.h"
31
32
#pragma pack(push,1)
33
34
typedef enum {
35
SLDF_HAS_ID_LIST = 0x00000001,
36
SLDF_HAS_LINK_INFO = 0x00000002,
37
SLDF_HAS_NAME = 0x00000004,
38
SLDF_HAS_RELPATH = 0x00000008,
39
SLDF_HAS_WORKINGDIR = 0x00000010,
40
SLDF_HAS_ARGS = 0x00000020,
41
SLDF_HAS_ICONLOCATION = 0x00000040,
42
SLDF_UNICODE = 0x00000080,
43
SLDF_FORCE_NO_LINKINFO = 0x00000100,
44
SLDF_HAS_EXP_SZ = 0x00000200,
45
SLDF_RUN_IN_SEPARATE = 0x00000400,
46
SLDF_HAS_LOGO3ID = 0x00000800,
47
SLDF_HAS_DARWINID = 0x00001000,
48
SLDF_RUNAS_USER = 0x00002000,
49
SLDF_HAS_EXP_ICON_SZ = 0x00004000,
50
SLDF_NO_PIDL_ALIAS = 0x00008000,
51
SLDF_FORCE_UNCNAME = 0x00010000,
52
SLDF_RUN_WITH_SHIMLAYER = 0x00020000,
53
SLDF_FORCE_NO_LINKTRACK = 0x00040000,
54
SLDF_ENABLE_TARGET_METADATA = 0x00080000,
55
SLDF_DISABLE_KNOWNFOLDER_RELATIVE_TRACKING = 0x00200000,
56
SLDF_RESERVED = 0x80000000,
57
} SHELL_LINK_DATA_FLAGS;
58
59
#define EXP_SZ_LINK_SIG 0xa0000001
60
#define EXP_SPECIAL_FOLDER_SIG 0xa0000005
61
#define EXP_DARWIN_ID_SIG 0xa0000006
62
#define EXP_SZ_ICON_SIG 0xa0000007
63
#define EXP_PROPERTYSTORAGE_SIG 0xa0000009
64
65
typedef struct tagDATABLOCKHEADER
66
{
67
UINT cbSize;
68
UINT dwSignature;
69
} DATABLOCK_HEADER;
70
71
typedef struct _LINK_HEADER
72
{
73
UINT dwSize; /* 0x00 size of the header - 0x4c */
74
GUID MagicGuid; /* 0x04 is CLSID_ShellLink */
75
UINT dwFlags; /* 0x14 describes elements following */
76
UINT dwFileAttr; /* 0x18 attributes of the target file */
77
FILETIME Time1; /* 0x1c */
78
FILETIME Time2; /* 0x24 */
79
FILETIME Time3; /* 0x2c */
80
UINT dwFileLength; /* 0x34 File length */
81
UINT nIcon; /* 0x38 icon number */
82
UINT fStartup; /* 0x3c startup type */
83
UINT wHotKey; /* 0x40 hotkey */
84
UINT Unknown5; /* 0x44 */
85
UINT Unknown6; /* 0x48 */
86
} LINK_HEADER, * PLINK_HEADER;
87
88
typedef struct tagLINK_SZ_BLOCK
89
{
90
UINT size;
91
UINT magic;
92
CHAR bufA[MAX_PATH];
93
WCHAR bufW[MAX_PATH];
94
} LINK_SZ_BLOCK;
95
96
typedef struct tagLINK_PROPERTYSTORAGE_GUID
97
{
98
UINT size;
99
UINT magic;
100
GUID fmtid;
101
} LINK_PROPERTYSTORAGE_GUID;
102
103
typedef struct tagLINK_PROPERTYSTORAGE_VALUE
104
{
105
UINT size;
106
UINT pid;
107
BYTE unknown8;
108
UINT vt;
109
UINT unknown25;
110
} LINK_PROPERTYSTORAGE_VALUE;
111
112
typedef struct _LOCATION_INFO
113
{
114
UINT dwTotalSize;
115
UINT dwHeaderSize;
116
UINT dwFlags;
117
UINT dwVolTableOfs;
118
UINT dwLocalPathOfs;
119
UINT dwNetworkVolTableOfs;
120
UINT dwFinalPathOfs;
121
} LOCATION_INFO;
122
123
typedef struct _LOCAL_VOLUME_INFO
124
{
125
UINT dwSize;
126
UINT dwType;
127
UINT dwVolSerial;
128
UINT dwVolLabelOfs;
129
} LOCAL_VOLUME_INFO;
130
131
typedef struct _NETWORK_VOLUME_INFO
132
{
133
UINT dwSize;
134
UINT dwUnknown1;
135
UINT dwShareNameOfs;
136
UINT dwReserved;
137
UINT dwUnknown2;
138
} NETWORK_VOLUME_INFO;
139
140
typedef struct
141
{
142
UINT cbSize;
143
UINT dwSignature;
144
UINT idSpecialFolder;
145
UINT cbOffset;
146
} EXP_SPECIAL_FOLDER;
147
148
typedef struct lnk_string_tag
149
{
150
unsigned short size;
151
union {
152
unsigned short w[1];
153
unsigned char a[1];
154
} str;
155
} lnk_string;
156
157
#pragma pack(pop)
158
159
static unsigned offset;
160
161
static const void* fetch_block(void)
162
{
163
const unsigned* u;
164
const void* ret;
165
166
if (!(u = PRD(offset, sizeof(*u)))) return 0;
167
if ((ret = PRD(offset, *u))) offset += *u;
168
return ret;
169
}
170
171
static const lnk_string* fetch_string(int unicode)
172
{
173
const unsigned short* s;
174
unsigned short len;
175
const void* ret;
176
177
if (!(s = PRD(offset, sizeof(*s)))) return 0;
178
len = *s * (unicode ? sizeof(WCHAR) : sizeof(char));
179
if ((ret = PRD(offset, sizeof(*s) + len))) offset += sizeof(*s) + len;
180
return ret;
181
}
182
183
184
static void dump_pidl(void)
185
{
186
const lnk_string *pidl;
187
int i, n = 0, sz = 0;
188
189
pidl = fetch_string(FALSE);
190
if (!pidl)
191
return;
192
193
printf("PIDL\n");
194
printf("----\n\n");
195
196
while(sz<pidl->size)
197
{
198
const lnk_string *segment = (const lnk_string*) &pidl->str.a[sz];
199
200
if(!segment->size)
201
break;
202
sz+=segment->size;
203
if(sz>pidl->size)
204
{
205
printf("bad pidl\n");
206
break;
207
}
208
n++;
209
printf("segment %d (%2d bytes) : ",n,segment->size);
210
for(i=0; i<segment->size; i++)
211
printf("%02x ",segment->str.a[i]);
212
printf("\n");
213
}
214
printf("\n");
215
}
216
217
static void dump_string(const char *what, int unicode)
218
{
219
const lnk_string *data;
220
unsigned sz;
221
222
data = fetch_string(unicode);
223
if (!data)
224
return;
225
printf("%s : ", what);
226
sz = data->size;
227
if (unicode)
228
while (sz) printf("%c", data->str.w[data->size - sz--]);
229
else
230
while (sz) printf("%c", data->str.a[data->size - sz--]);
231
printf("\n");
232
}
233
234
static void dump_location(void)
235
{
236
const LOCATION_INFO *loc;
237
const char *p;
238
239
loc = fetch_block();
240
if (!loc)
241
return;
242
p = (const char*)loc;
243
244
printf("Location\n");
245
printf("--------\n\n");
246
printf("Total size = %d\n", loc->dwTotalSize);
247
printf("Header size = %d\n", loc->dwHeaderSize);
248
printf("Flags = %08x\n", loc->dwFlags);
249
250
/* dump information about the local volume the link points to */
251
printf("Local volume ofs = %08x ", loc->dwVolTableOfs);
252
if (loc->dwVolTableOfs &&
253
loc->dwVolTableOfs + sizeof(LOCAL_VOLUME_INFO) < loc->dwTotalSize)
254
{
255
const LOCAL_VOLUME_INFO *vol = (const LOCAL_VOLUME_INFO *)&p[loc->dwVolTableOfs];
256
257
printf("size %d type %d serial %08x label %d ",
258
vol->dwSize, vol->dwType, vol->dwVolSerial, vol->dwVolLabelOfs);
259
if(vol->dwVolLabelOfs)
260
printf("(\"%s\")", &p[loc->dwVolTableOfs + vol->dwVolLabelOfs]);
261
}
262
printf("\n");
263
264
/* dump information about the network volume the link points to */
265
printf("Network volume ofs = %08x ", loc->dwNetworkVolTableOfs);
266
if (loc->dwNetworkVolTableOfs &&
267
loc->dwNetworkVolTableOfs + sizeof(NETWORK_VOLUME_INFO) < loc->dwTotalSize)
268
{
269
const NETWORK_VOLUME_INFO *vol = (const NETWORK_VOLUME_INFO *)&p[loc->dwNetworkVolTableOfs];
270
271
printf("size %d name %d ", vol->dwSize, vol->dwShareNameOfs);
272
if(vol->dwShareNameOfs)
273
printf("(\"%s\")", &p[loc->dwNetworkVolTableOfs + vol->dwShareNameOfs]);
274
}
275
printf("\n");
276
277
/* dump out the path the link points to */
278
printf("LocalPath ofs = %08x ", loc->dwLocalPathOfs);
279
if( loc->dwLocalPathOfs && (loc->dwLocalPathOfs < loc->dwTotalSize) )
280
printf("(\"%s\")", &p[loc->dwLocalPathOfs]);
281
printf("\n");
282
283
printf("Net Path ofs = %08x\n", loc->dwNetworkVolTableOfs);
284
printf("Final Path = %08x ", loc->dwFinalPathOfs);
285
if( loc->dwFinalPathOfs && (loc->dwFinalPathOfs < loc->dwTotalSize) )
286
printf("(\"%s\")", &p[loc->dwFinalPathOfs]);
287
printf("\n");
288
printf("\n");
289
}
290
291
static const unsigned char table_dec85[0x80] = {
292
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
293
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
294
0xff,0x00,0xff,0xff,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0xff,
295
0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0xff,0xff,0xff,0x16,0xff,0x17,
296
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
297
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0x34,0x35,0x36,
298
0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,
299
0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0xff,0x53,0x54,0xff,
300
};
301
302
static BOOL base85_to_guid( const char *str, LPGUID guid )
303
{
304
DWORD i, val = 0, base = 1, *p;
305
unsigned char ch;
306
307
p = (DWORD*) guid;
308
for( i=0; i<20; i++ )
309
{
310
if( (i%5) == 0 )
311
{
312
val = 0;
313
base = 1;
314
}
315
ch = str[i];
316
if( ch >= 0x80 )
317
return FALSE;
318
val += table_dec85[ch] * base;
319
if( table_dec85[ch] == 0xff )
320
return FALSE;
321
if( (i%5) == 4 )
322
p[i/5] = val;
323
base *= 85;
324
}
325
return TRUE;
326
}
327
328
static void dump_special_folder_block(const DATABLOCK_HEADER* bhdr)
329
{
330
const EXP_SPECIAL_FOLDER *sfb = (const EXP_SPECIAL_FOLDER*)bhdr;
331
printf("Special folder block\n");
332
printf("--------------------\n\n");
333
printf("folder = 0x%04x\n", sfb->idSpecialFolder);
334
printf("offset = %d\n", sfb->cbOffset);
335
printf("\n");
336
}
337
338
static void dump_sz_block(const DATABLOCK_HEADER* bhdr, const char* label)
339
{
340
const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
341
printf("String block\n");
342
printf("-----------\n\n");
343
printf("magic = %x\n", szp->magic);
344
printf("%s = %s\n", label, szp->bufA);
345
printf("\n");
346
}
347
348
static void dump_darwin_id(const DATABLOCK_HEADER* bhdr)
349
{
350
const LINK_SZ_BLOCK *szp = (const LINK_SZ_BLOCK*)bhdr;
351
char comp_str[40];
352
const char *feat, *comp, *prod_str, *feat_str;
353
GUID guid;
354
355
printf("Advertise Info\n");
356
printf("--------------\n\n");
357
printf("msi string = %s\n", szp->bufA);
358
359
if (base85_to_guid(szp->bufA, &guid))
360
prod_str = get_guid_str(&guid);
361
else
362
prod_str = "?";
363
364
comp = &szp->bufA[20];
365
feat = strchr(comp, '>');
366
if (!feat)
367
feat = strchr(comp, '<');
368
if (feat)
369
{
370
memcpy(comp_str, comp, feat - comp);
371
comp_str[feat-comp] = 0;
372
}
373
else
374
{
375
strcpy(comp_str, "?");
376
}
377
378
if (feat && feat[0] == '>' && base85_to_guid( &feat[1], &guid ))
379
feat_str = get_guid_str( &guid );
380
else
381
feat_str = "";
382
383
printf(" product: %s\n", prod_str);
384
printf(" component: %s\n", comp_str );
385
printf(" feature: %s\n", feat_str);
386
printf("\n");
387
}
388
389
static void dump_property_storage_value(const LINK_PROPERTYSTORAGE_VALUE *lnk_value_hdr,
390
DWORD data_size)
391
{
392
BOOL got_terminator = FALSE;
393
int i, value_size;
394
const unsigned char *value;
395
396
while (data_size >= sizeof(DWORD))
397
{
398
if (!lnk_value_hdr->size)
399
{
400
got_terminator = TRUE;
401
break;
402
}
403
404
if (lnk_value_hdr->size > data_size || lnk_value_hdr->size < sizeof(*lnk_value_hdr))
405
{
406
printf(" size: %d (invalid)\n", lnk_value_hdr->size);
407
return;
408
}
409
410
printf(" pid: %d\n", lnk_value_hdr->pid);
411
printf(" unknown8: %d\n", lnk_value_hdr->unknown8);
412
printf(" vartype: %d\n", lnk_value_hdr->vt);
413
printf(" unknown25: %d\n", lnk_value_hdr->unknown25);
414
415
value_size = lnk_value_hdr->size - sizeof(*lnk_value_hdr);
416
value = (const unsigned char*)(lnk_value_hdr+1);
417
418
printf(" value (%2d bytes) : ",value_size);
419
for(i=0; i<value_size; i++)
420
printf("%02x ",value[i]);
421
printf("\n\n");
422
423
data_size -= lnk_value_hdr->size;
424
lnk_value_hdr = (void*)((char*)lnk_value_hdr + lnk_value_hdr->size);
425
}
426
427
if (!got_terminator)
428
printf(" missing terminator!\n");
429
}
430
431
static void dump_property_storage(const DATABLOCK_HEADER* bhdr)
432
{
433
int data_size;
434
const LINK_PROPERTYSTORAGE_GUID *lnk_guid_hdr;
435
BOOL got_terminator = FALSE;
436
437
printf("Property Storage\n");
438
printf("--------------\n\n");
439
440
data_size=bhdr->cbSize-sizeof(*bhdr);
441
442
lnk_guid_hdr=(void*)((const char*)bhdr+sizeof(*bhdr));
443
444
while (data_size >= sizeof(DWORD))
445
{
446
if (!lnk_guid_hdr->size)
447
{
448
got_terminator = TRUE;
449
break;
450
}
451
452
if (lnk_guid_hdr->size > data_size || lnk_guid_hdr->size < sizeof(*lnk_guid_hdr))
453
{
454
printf("size: %d (invalid)\n", lnk_guid_hdr->size);
455
return;
456
}
457
458
if (lnk_guid_hdr->magic != 0x53505331)
459
printf("magic: %x\n", lnk_guid_hdr->magic);
460
461
printf("fmtid: %s\n", get_guid_str(&lnk_guid_hdr->fmtid));
462
463
dump_property_storage_value((void*)(lnk_guid_hdr + 1), lnk_guid_hdr->size - sizeof(*lnk_guid_hdr));
464
465
data_size -= lnk_guid_hdr->size;
466
467
lnk_guid_hdr = (void*)((char*)lnk_guid_hdr + lnk_guid_hdr->size);
468
}
469
470
if (!got_terminator)
471
printf("missing terminator!\n");
472
473
printf("\n");
474
}
475
476
static void dump_raw_block(const DATABLOCK_HEADER* bhdr)
477
{
478
int data_size;
479
480
printf("Raw Block\n");
481
printf("---------\n\n");
482
printf("size = %d\n", bhdr->cbSize);
483
printf("magic = %x\n", bhdr->dwSignature);
484
485
data_size=bhdr->cbSize-sizeof(*bhdr);
486
if (data_size > 0)
487
{
488
int i;
489
const unsigned char *data;
490
491
printf("data = ");
492
data=(const unsigned char*)bhdr+sizeof(*bhdr);
493
while (data_size > 0)
494
{
495
for (i=0; i < 16; i++)
496
{
497
if (i < data_size)
498
printf("%02x ", data[i]);
499
else
500
printf(" ");
501
}
502
for (i=0; i < data_size && i < 16; i++)
503
printf("%c", (data[i] >= 32 && data[i] < 128 ? data[i] : '.'));
504
printf("\n");
505
data_size-=16;
506
if (data_size <= 0)
507
break;
508
data+=16;
509
printf(" ");
510
}
511
}
512
printf("\n");
513
}
514
515
static const GUID CLSID_ShellLink = {0x00021401L, 0, 0, {0xC0,0,0,0,0,0,0,0x46}};
516
517
enum FileSig get_kind_lnk(void)
518
{
519
const LINK_HEADER* hdr;
520
521
hdr = PRD(0, sizeof(*hdr));
522
if (hdr && hdr->dwSize == sizeof(LINK_HEADER) &&
523
!memcmp(&hdr->MagicGuid, &CLSID_ShellLink, sizeof(GUID)))
524
return SIG_LNK;
525
return SIG_UNKNOWN;
526
}
527
528
void lnk_dump(void)
529
{
530
const LINK_HEADER* hdr;
531
const DATABLOCK_HEADER* bhdr;
532
UINT dwFlags;
533
534
offset = 0;
535
hdr = fetch_block();
536
if (!hdr)
537
return;
538
539
printf("Header\n");
540
printf("------\n\n");
541
printf("Size: %04x\n", hdr->dwSize);
542
printf("GUID: %s\n", get_guid_str(&hdr->MagicGuid));
543
544
printf("FileAttr: %08x\n", hdr->dwFileAttr);
545
printf("FileLength: %08x\n", hdr->dwFileLength);
546
printf("nIcon: %d\n", hdr->nIcon);
547
printf("Startup: %d\n", hdr->fStartup);
548
printf("HotKey: %08x\n", hdr->wHotKey);
549
printf("Unknown5: %08x\n", hdr->Unknown5);
550
printf("Unknown6: %08x\n", hdr->Unknown6);
551
552
/* dump out all the flags */
553
printf("Flags: %04x ( ", hdr->dwFlags);
554
dwFlags=hdr->dwFlags;
555
#define FLAG(x) do \
556
{ \
557
if (dwFlags & SLDF_##x) \
558
{ \
559
printf("%s ", #x); \
560
dwFlags&=~SLDF_##x; \
561
} \
562
} while (0)
563
FLAG(HAS_ID_LIST);
564
FLAG(HAS_LINK_INFO);
565
FLAG(HAS_NAME);
566
FLAG(HAS_RELPATH);
567
FLAG(HAS_WORKINGDIR);
568
FLAG(HAS_ARGS);
569
FLAG(HAS_ICONLOCATION);
570
FLAG(UNICODE);
571
FLAG(FORCE_NO_LINKINFO);
572
FLAG(HAS_EXP_SZ);
573
FLAG(RUN_IN_SEPARATE);
574
FLAG(HAS_LOGO3ID);
575
FLAG(HAS_DARWINID);
576
FLAG(RUNAS_USER);
577
FLAG(HAS_EXP_ICON_SZ);
578
FLAG(NO_PIDL_ALIAS);
579
FLAG(FORCE_UNCNAME);
580
FLAG(RUN_WITH_SHIMLAYER);
581
FLAG(FORCE_NO_LINKTRACK);
582
FLAG(ENABLE_TARGET_METADATA);
583
FLAG(DISABLE_KNOWNFOLDER_RELATIVE_TRACKING);
584
FLAG(RESERVED);
585
#undef FLAG
586
if (dwFlags)
587
printf("+%04x", dwFlags);
588
printf(")\n");
589
590
printf("Length: %04x\n", hdr->dwFileLength);
591
printf("\n");
592
593
if (hdr->dwFlags & SLDF_HAS_ID_LIST)
594
dump_pidl();
595
if (hdr->dwFlags & SLDF_HAS_LINK_INFO)
596
dump_location();
597
if (hdr->dwFlags & SLDF_HAS_NAME)
598
dump_string("Description", hdr->dwFlags & SLDF_UNICODE);
599
if (hdr->dwFlags & SLDF_HAS_RELPATH)
600
dump_string("Relative path", hdr->dwFlags & SLDF_UNICODE);
601
if (hdr->dwFlags & SLDF_HAS_WORKINGDIR)
602
dump_string("Working directory", hdr->dwFlags & SLDF_UNICODE);
603
if (hdr->dwFlags & SLDF_HAS_ARGS)
604
dump_string("Arguments", hdr->dwFlags & SLDF_UNICODE);
605
if (hdr->dwFlags & SLDF_HAS_ICONLOCATION)
606
dump_string("Icon path", hdr->dwFlags & SLDF_UNICODE);
607
608
bhdr=fetch_block();
609
while (bhdr)
610
{
611
if (!bhdr->cbSize)
612
break;
613
switch (bhdr->dwSignature)
614
{
615
case EXP_SZ_LINK_SIG:
616
dump_sz_block(bhdr, "exp.link");
617
break;
618
case EXP_SPECIAL_FOLDER_SIG:
619
dump_special_folder_block(bhdr);
620
break;
621
case EXP_SZ_ICON_SIG:
622
dump_sz_block(bhdr, "icon");
623
break;
624
case EXP_DARWIN_ID_SIG:
625
dump_darwin_id(bhdr);
626
break;
627
case EXP_PROPERTYSTORAGE_SIG:
628
dump_property_storage(bhdr);
629
break;
630
default:
631
dump_raw_block(bhdr);
632
}
633
bhdr=fetch_block();
634
}
635
}
636
637