Skip to content

Commit

Permalink
Worked on jump list script and documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz committed Mar 10, 2024
1 parent e0caebc commit 17c8080
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 34 deletions.
40 changes: 29 additions & 11 deletions documentation/Jump lists format.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ directory and have the extension .customDestinations-ms.
The custom destinations file consists of:

* File header
* One or more categories
* Zero or more categories

=== File header

Expand All @@ -249,27 +249,39 @@ A custom destinations category is of variable size and consists of:
| 0 | 4 | | Category type +
See section: <<category_types,Category types>>
4+| _If category type == 0_
| 4 | 2 | | String number of characters
| 6 | ... | | Title string +
| 4 | 2 | | Number of characters in category name string
| 6 | ... | | Category name string +
Contains an UTF-16 little-endian string without an end-of-string character
4+| _Common_
| ... | 4 | | Number of entries
| ... | ... | | Entries +
| ... | Number of entries | | Entries +
Contains an array shell object entries
4+| _If category type == 1_
| ... | 4 | | Category identifier
4+| _If category type == 2_
| ... | 4 | | Number of entries
| ... | Number of entries | | Entries +
Contains an array shell object entries
4+| _Common_
| ... | 4 | 0xbabffbab | Footer signature
|===

[NOTE]
The number of entries is not reliable.

==== [[category_types]]Category types

[cols="1,1,5",options="header"]
|===
| Value | Identifier | Description
| 0 | | Custom destinations
| 1 | | Known destinations
| 2 | | Custom tasks
| 0 | | Custom category
| 1 | | Known category
| 2 | | User tasks
|===

==== [[category_identifier]]Category identifier

[cols="1,1,5",options="header"]
|===
| Value | Identifier | Description
| 1 | KDC_FREQUENT | Frequent category
| 2 | KDC_RECENT | Recent category
|===

==== Shell object entry
Expand Down Expand Up @@ -357,6 +369,12 @@ Where %ID% a 64-bit CRC of full path of executable file of the corresponding app
[appendix]
== References

[cols="1,5",options="header"]
|===
| Title: | ICustomDestinationList interface (shobjidl_core.h)
| URL: | https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nn-shobjidl_core-icustomdestinationlist
|===

`[LIBLNK]`

[cols="1,5",options="header"]
Expand Down
7 changes: 5 additions & 2 deletions dtformats/jump_list.debug.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@ attributes:
- name: number_of_characters
description: "Number of characters"
format: decimal
- name: title
description: "Title"
- name: cateogy_name
description: "Category name"
format: string
- name: category_identifier
description: "Category identifier"
format: decimal
- name: number_of_entries
description: "Number of entries"
format: decimal
Expand Down
30 changes: 17 additions & 13 deletions dtformats/jump_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,12 +249,14 @@ class CustomDestinationsFile(data_format.BinaryDataFile):
'jump_list.debug.yaml', custom_format_callbacks={
'category_type': '_FormatIntegerAsCategoryType'})

# TODO: add callback for known category identifier.

_CATEGORY_FOOTER_SIGNATURE = b'\xab\xfb\xbf\xba'

_CATEGORY_TYPES = {
0: 'Custom destinations',
1: 'Known destinations',
2: 'Custom tasks'}
0: 'Custom category',
1: 'Known category',
2: 'User tasks'}

_LNK_GUID = (
b'\x01\x14\x02\x00\x00\x00\x00\x00\xc0\x00\x00\x00\x00\x00\x00\x46')
Expand Down Expand Up @@ -334,23 +336,24 @@ def _ReadCategoryHeader(self, file_object, file_offset):
file_offset += bytes_read
total_bytes_read = bytes_read

if category_header.category_type == 0:
data_type_map_name = 'custom_category_header_type_0'
else:
data_type_map_name = 'custom_category_header_type_1_or_2'

data_type_map = self._GetDataTypeMap(data_type_map_name)
data_type_map = self._GetDataTypeMap(
f'custom_category_header_type_{category_header.category_type:d}')

category_header_value, bytes_read = self._ReadStructureFromFileObject(
file_object, file_offset, data_type_map, 'category header values')

if category_header.category_type == 0:
setattr(category_header, 'number_of_characters',
category_header_value.number_of_characters)
setattr(category_header, 'title', category_header_value.title)
setattr(category_header, 'category_name',
category_header_value.category_name)

setattr(category_header, 'number_of_entries',
category_header_value.number_of_entries)
if category_header.category_type in (0, 2):
setattr(category_header, 'number_of_entries',
category_header_value.number_of_entries)
else:
setattr(category_header, 'category_identifier',
category_header_value.category_identifier)

if self._debug:
debug_info = self._DEBUG_INFORMATION.get('custom_category_header', None)
Expand Down Expand Up @@ -444,7 +447,8 @@ def ReadFileObject(self, file_object):

file_offset += bytes_read

for entry_index in range(category_header.number_of_entries):
number_of_entries = getattr(category_header, 'number_of_entries', 0)
for entry_index in range(number_of_entries):
if self._file_size - file_offset < 16:
break

Expand Down
12 changes: 10 additions & 2 deletions dtformats/jump_list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -192,15 +192,23 @@ attributes:
members:
- name: number_of_characters
data_type: uint16
- name: title
- name: category_name
type: string
encoding: utf-16-le
element_data_type: wchar16
number_of_elements: custom_category_header_type_0.number_of_characters
- name: number_of_entries
data_type: uint32
---
name: custom_category_header_type_1_or_2
name: custom_category_header_type_1
type: structure
attributes:
byte_order: little-endian
members:
- name: category_identifier
data_type: uint32
---
name: custom_category_header_type_2
type: structure
attributes:
byte_order: little-endian
Expand Down
13 changes: 7 additions & 6 deletions scripts/jump_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def _WritePropertyStore(self, fwps_store):
elif fwps_record.value_type == 0x0042:
# TODO: add support
value_string = '<VT_STREAM>'
elif fwps_record.value_type == 0x0048:
value_string = fwps_record.get_data_as_guid()
elif fwps_record.value_type & 0xf000 == 0x1000:
# TODO: add support
value_string = '<VT_VECTOR>'
Expand Down Expand Up @@ -214,9 +216,7 @@ def _WriteShellItem(self, fwsi_item):

self.WriteValue('\t\t\tFile reference', file_reference)

# TODO: add support for 0xbeef0000
# TODO: add support for 0xbeef0019
# TODO: add support for 0xbeef0025
# TODO: add support for other extension blocks

self.WriteText('\n')

Expand Down Expand Up @@ -422,10 +422,11 @@ def _WriteShortcutMetadataPropertyStore(self, lnk_data_block):
Args:
lnk_data_block (pylnk.data_block): Windows Shortcut data block.
"""
fwps_store = pyfwps.store()
fwps_store.copy_from_byte_stream(lnk_data_block.data)
if lnk_data_block.data:
fwps_store = pyfwps.store()
fwps_store.copy_from_byte_stream(lnk_data_block.data)

self._WritePropertyStore(fwps_store)
self._WritePropertyStore(fwps_store)

def WriteShortcut(self, lnk_file):
"""Writes a Windows Shortcut file to stdout.
Expand Down

0 comments on commit 17c8080

Please sign in to comment.