需要帮助解码注册表二进制数据

dai*_*tzu 1 python windows registry winreg

我正在尝试使用 Windows 注册表中的 shellbag 构建一个小型应用程序。我正在尝试解码表单中的一些数据REG_BINARY,但不知道从哪里开始。如果你去:

Computer\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell\BagMRU\0

您会发现一系列值,0、1、2、3 等类型REG_BINARY,打开它们有时会显示似乎是一个文件夹的内容以及大量看似乱码的内容。

我还需要了解以下形式的键的二进制列 ('Sort'和):'Colinfo'

Computer\HKEY_CLASSES_ROOT\Local Settings\Software\Microsoft\Windows\Shell\Bags\1\Shell\{5C4F28B5-F869-4E84-8E60-F11DB97C5CC7}

我尝试在网上查看 shellbags python 程序,但老实说,我不知道它们在做什么,而且它们似乎是用 python2 编写的,所以没有骰子。

我已经编写了一个小的 python 程序来提供帮助,但它缺少获取节点槽的方法,并且我正在尝试将任何给定的文件夹名称链接到节点槽。这是我目前的程序。

from winreg import *
from codecs import decode

folder_reg_path = "Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\Shell\\Bags\\1375\\Shell"
bags_mru_path = "Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU"

def get_sniffed_folder_type(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'SniffedFolderType')
        return '%s' % (value[0])


def get_current_nodeid(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key, 0, KEY_READ) as key:
        #value = QueryValueEx(key, '0')
        #return value[0].hex().decode('utf-8')
        value = EnumValue(key, 2)
        return decode(value[1], 'ascii', 'ignore')


# which clsid should be used? the last one in the list
def get_current_clsid(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        key_idx = 0
        value = None
        # keep looping until the last clsid entry is found
        while 1:
            try:
                temp = EnumKey(key, key_idx)
                key_idx += 1
                value = temp
            except:
                break
        return value


# the size of icons used by the folder
def get_folder_icon_size(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'IconSize')
        return '%d pixels' % (value[0])

# the folder view. details, list, tiles e.t.c
def get_logical_view_mode(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'LogicalViewMode')
        logical_view_mode_dict = {1 : "Details view", 2 : "Tiles view", 3 : "Icons view", 4 : "List view", 5 : "Content view"}
        return logical_view_mode_dict[value[0]]


# folder view is based on view mode. so you can have a  logical view mode of icons view with a view mode of large icons for instance
def get_folder_view_mode(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'Mode')
        # view_mode 7 is only available on xp. A dead os
        view_mode_dict = {1 : "Medium icons", 2 : "Small icons", 3 : "List", 4 : "Details", 5 : "Thumbnail icons", 6 : "Large icons", 8 : "Content"}
        return view_mode_dict[value[0]]


# how is the folder being sorted
def get_folder_sort_by(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'Sort')
        folder_sort_dict = {"0E000000" : "Date Modified", "10000000" : "Date Accessed", "0F000000" : "Date Created", "0B000000" : "Type", "0C000000" : "Size", "0A000000" : "Name", "02000000" : "Title", "05000000" : "Tags"}
        # we get a byte value which we will hexify and get a rather long string
        # similar to : 000000000000000000000000000000000100000030f125b7ef471a10a5f102608c9eebac0c000000ffffffff
        reg_value = value[0].hex()
        # now for this string, we need to get the last 16 strings. then we now get the first 8 out of it. so we will have
        folder_sort_dict_key = (reg_value[-16:][:8]).upper()
        #return folder_sort_dict[folder_sort_dict_key]
        print (reg_value)
        return folder_sort_dict_key

# in what order is the folder being sorted. ascending or descending???
def get_folder_sort_by_order(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'Sort')
        folder_sort_dict = {"01000000" : "Ascending", "FFFFFFFF" : "Descending"}
        # we get a byte value which we will hexify and get a rather long string
        # similar to : 000000000000000000000000000000000100000030f125b7ef471a10a5f102608c9eebac0c000000ffffffff
        reg_value = value[0].hex()
        # now for this string, we need to get the last 16 strings. then we now get the last 8 out of it. so we will have
        folder_sort_dict_key = (reg_value[-16:][-8:]).upper()
        return folder_sort_dict[folder_sort_dict_key]

# How is the folder being grouped
def get_folder_group_by(reg_key):
    with OpenKey(HKEY_CURRENT_USER, reg_key) as key:
        value = QueryValueEx(key, 'GroupByKey:PID')
        folder_group_dict = {'10' : "Name", '14' : "Date Modified", '4*' : "Type", '12' : "Size", '15' : "Date Created", '5' : "Tags", '2' : "Title", '16' : "Date Accessed", '0' : "No Group Applied"}
        return folder_group_dict[str(value[0])]


# Registry is of the form:
# HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\Bags\1375\Shell\{5C4F28B5-F869-4E84-8E60-F11DB97C5CC7}
# where 1375 is a value called the NodeList, and {5C4F28B5-F869-4E84-8E60-F11DB97C5CC7} is a value under Shell chosen based on creation date

print ( 'The suggested folder type is %s' % get_sniffed_folder_type(folder_reg_path) )

# lets start by getting a value similar to {5C4F28B5-F869-4E84-8E60-F11DB97C5CC7} by finding the last child of folder_reg_path
folder_reg_path = folder_reg_path + '\\' + get_current_clsid(folder_reg_path)

print ( get_current_nodeid(bags_mru_path) )
print ( 'The registry path is %s' % (folder_reg_path) )
icon_size = get_folder_icon_size(folder_reg_path)
logical_view_mode = get_logical_view_mode(folder_reg_path)
view_mode = get_folder_view_mode(folder_reg_path)
sorted_by = get_folder_sort_by(folder_reg_path)
sorted_by_order = get_folder_sort_by_order(folder_reg_path)
folder_group_by = get_folder_group_by(folder_reg_path)
print ('The folder icon size is %s' % icon_size)
print('The folder logical view mode is %s' % logical_view_mode)
print('The folder view mode is %s' % view_mode)
print('The folder is sorted by %s in %s order' % (sorted_by, sorted_by_order))
print('The folder is grouped by: %s' % folder_group_by)
Run Code Online (Sandbox Code Playgroud)

Kei*_*ler 11

正在回答。请耐心等待...

\n\n

当在新创建的帐户中第一次打开资源管理器时,文件夹视图将由注册表中定义的相应FolderType的TopView设置决定:

\n
HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderTypes\n
Run Code Online (Sandbox Code Playgroud)\n

大多数用户都熟悉其中的一部分,即文件夹属性对话框的“自定义”选项卡上提供的模板:

\n
    \n
  • 一般项目(通用)
  • \n
  • 文件
  • \n
  • 图片
  • \n
  • 音乐
  • \n
  • 视频
  • \n
\n

联系人和下载模板也存在,但它们仅使用以下路径分配到各自的系统文件夹:

\n
HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\n
Run Code Online (Sandbox Code Playgroud)\n

可以使用以下PowerShell代码生成文件夹类型ID 及其各自名称的完整列表:

\n
gp (gci HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FolderTypes).PSPath |\n   select PSChildName, CanonicalName | sort CanonicalName |\nOut-GridView # or Out-File FTList.txt # or Set-Clipboard\n\n\nPSChildName CanonicalName\n----------- -------------\n{db2a5d8f-06e6-4007-aba6-af877d526ea6} AccountPictures\n{91475fe5-586b-4eba-8d75-d17434b8cdf6} Communications\n{503a4e73-1734-441a-8eab-01b3f3861156} Communications.SearchResults\n{80213e82-bcfd-4c4f-8817-bb27601267a9} CompressedFolder\n...\n{5fa96407-7e77-483c-ac93-691d05850de8} Videos\n{631958a6-ad0f-4035-a745-28ac066dc6ed} Videos.Library\n{292108be-88ab-4f33-9a26-7748e62e37ad} Videos.LibraryFolder\n{ea25fbd7-3bf7-409e-b97f-3352240903f4} Videos.SearchResults\n
Run Code Online (Sandbox Code Playgroud)\n

在资源管理器中查看文件夹后,Windows会将该单个文件夹的查看设置保存在两个注册表项下。如果文件夹是本地的,则键为:

\n
HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU\n
Run Code Online (Sandbox Code Playgroud)\n

- - 和 - -

\n
HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\n
Run Code Online (Sandbox Code Playgroud)\n

网络位置和一个特殊的包,桌面布局,都在这里:

\n
HKCU\\Software\\Microsoft\\Windows\\Shell\\BagMRU\n
Run Code Online (Sandbox Code Playgroud)\n

- - 和 - -

\n
HKCU\\Software\\Microsoft\\Windows\\Shell\\Bags\n
Run Code Online (Sandbox Code Playgroud)\n

Bags下的每个编号子项对应一个文件夹。每个都可以保存三个单独的视图状态:Shell(资源管理器)、ComDLg(例如记事本)和ComDlgLegacy(例如Reg Export)。它们每个都可以有一个以 GUID 命名的子项,该子项对应于应用于文件夹的FolderType的 ID 。该子键包含视图的各种属性:

\n
PS C:\\> $Bags = \'HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\'\nPS C:\\> (gci $bags -Recurse | ? PSChildName -like "{*}" | select -first 2)[1] | ft -AutoSize\n\n   Hive: HKEY_CURRENT_USER\\Software\\Classes\\Local\n   Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\\1\\Shell\n\nName                                   Property\n----                                   --------\n{5C4F28B5-F869-4E84-8E60-F11DB97C5CC7} Rev              : 67\n                                       FFlags           : 1090519041\n                                       Vid              : {137E7700-3573-11CF-AE69-08002B2E1262}\n                                       Mode             : 4\n                                       LogicalViewMode  : 1\n                                       IconSize         : 16\n                                       Sort             : {0, 0, 0, 0...}\n                                       ColInfo          : {0, 0, 0, 0...}\n                                       GroupView        : 0\n                                       GroupByKey:FMTID : {00000000-0000-0000-0000-000000000000}\n                                       GroupByKey:PID   : 0\n                                       GroupByDirection : 1\n
Run Code Online (Sandbox Code Playgroud)\n
Value Name       Description\n----------       -----------\nRev              \xe2\x80\xa2 Seems to be a counter that increments when BagMRU/Bags are deleted or Reset\n                 Folders is executed from the Folder Options dialog\nFflags           \xe2\x80\xa2 The FolderFlags that apply to the folder view.\nGroupView        A DWORD flag determining whether or not the view is grouped:\n                     \xe2\x80\xa2 0x00000000 = No grouping\n                     \xe2\x80\xa2 0xffffffff = View grouped by column specified by the GroupByKey pair.\nGroupByDirection A DWORD flag determing sort direction of group names:\n                     \xe2\x80\xa2 0x00000001 = Ascending\n                     \xe2\x80\xa2 0xffffffff = Descending\n
Run Code Online (Sandbox Code Playgroud)\n

Vid、Mode、LogicalViewMode、IconSize 均由 Icon 模式决定:

\n
Name        LVM Mode Vid                                    IconSize\n----        --- ---- ---                                    --------\nDetails     1   4    {137E7700-3573-11CF-AE69-08002B2E1262} 16\nTiles       2   8    {65F125E5-7BE1-4810-BA9D-D271C8432CE3} 48\nSmIcons     3   1    {089000C0-3573-11CF-AE69-08002B2E1262} 16..31\nIcons(M-XL) 3   1    {0057D0E0-3573-11CF-AE69-08002B2E1262} 33..256\nList        4   3    {0E1FA5E0-3573-11CF-AE69-08002B2E1262} 16\nContent     5   8    {30C2C434-0889-4C8D-985D-A9F71830B0A9} 32\n
Run Code Online (Sandbox Code Playgroud)\n

指定列的所有值:

\n
    \n
  • 列信息
  • \n
  • 通过...分组
  • \n
  • 种类
  • \n
\n

通过将相应的属性指定为FMTID-PID对来执行此操作。确定给定属性对的最简单方法是对该属性上的文件夹进行分组,关闭它,然后检查相应Bag中生成的GroupByKey:FMTID和GroupByKey:PID值。这里\xe2\x80\x99是我到目前为止得到的\xe2\x80\x99:

\n
FMTID                                  PID    Name\n-----                                  ---    ----\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x010f Camera Maker\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x0110 Camera Model\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x829a Exposure Time\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x8822 Expsure Program\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x9003 Date Taken\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x9204 Expsure Bias\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x9209 Flash Mode\n{14B81DA1-0135-4D31-96D9-6CBFC9671A99} 0x920a Focal Length\n{28636AA6-953D-11D2-B5D6-00C04FD918D0} 0x05   Computer\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x02   Contributing Artists\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x04   Album\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x05   Year\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x07   #\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x0b   Genre\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x0d   Album Artist\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x23   Beats-per-minute\n{56A3372E-CE9C-11D2-9F0E-006097C686F6} 0x24   Conductor\n{5CBF2787-48CF-4208-B90E-EE5E5D420294} 0x15   Description\n{5CBF2787-48CF-4208-B90E-EE5E5D420294} 0x17   DateVisited\n{6444048F-4C8B-11D1-8B70-080036B11A03} 0x0d   Dimensions\n{64440491-4C8B-11D1-8B70-080036B11A03} 0x03   Frame Width\n{64440491-4C8B-11D1-8B70-080036B11A03} 0x04   Frame Height\n{64440491-4C8B-11D1-8B70-080036B11A03} 0x06   Frame Rate\n{64440492-4C8B-11D1-8B70-080036B11A03} 0x04   Bit Rate\n{64440492-4C8B-11D1-8B70-080036B11A03} 0x0b   Copyright\n{64440492-4C8B-11D1-8B70-080036B11A03} 0x13   Composer\n{9B174B34-40FF-11D2-A27E-00C04FC30871} 0x04   Owner\n{A0E74609-B84D-4F49-B860-462BD9971F98} 0x64   35 mm Focal Length\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x02   FolderName\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x04   Type\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0a   Name\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0c   Size\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0d   Attributes\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0e   DateModified\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0f   DateCreated\n{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x10   DateAccessed\n{D35F743A-EB2E-47F2-A286-844132CB1427} 0x64   EXIF Version\n{D5CDD502-2E9C-101B-9397-08002B2CF9AE} 0x02   Categories\n{DABD30ED-0043-4789-A7F8-D013A4736622} 0x64   Folder\n{E3E0584C-B788-4A5A-BB20-7F5A44C9ACDD} 0x06   FolderPath\n{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 0x02   Title\n{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 0x04   Authors\n{F29F85E0-4FF9-1068-AB91-08002B27B3D9} 0x05   Tags\n{F7DB74B4-4287-4103-AFBA-F1B13DCD75CF} 0x64   Date\n
Run Code Online (Sandbox Code Playgroud)\n

在ColInfo & Sort中,该对采用二进制格式,即PROPERTYKEY结构:

\n
typedef struct {\n  GUID fmtid;\n  DWORD pid;\n} PROPERTYKEY;\n
Run Code Online (Sandbox Code Playgroud)\n

将 CLSID 样式的 GUID 转换为其二进制等效项时需要进行一些字节混排。以名称为例:

\n

{B725F130-47EF-101A-A5F1-02608C9EEBAC} 0x0a

\n

变成

\n

[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac][0a 00 00 00] (在注册表中连续,为清晰起见分组)

\n

我使用此PowerShell代码片段将二进制 GUID/CLSID 转换为其更熟悉的文本表示形式:

\n
$Bags = \'HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\'\n$Sample = gci $rp.Bags -Recurse | ? Property -Contains Sort | Select -First 5 | gp\n$Sample | ForEach{ \'{{{0}}}\' -f [GUID][Byte[]]$_.Sort[20..35] }\n\nOutput:\n{b725f130-47ef-101a-a5f1-02608c9eebac}\n{b725f130-47ef-101a-a5f1-02608c9eebac}\n{f29f85e0-4ff9-1068-ab91-08002b27b3d9}\n{83914d1a-c270-48bf-b00d-1c4e451b0150}\n{f7db74b4-4287-4103-afba-f1b13dcd75cf}\n
Run Code Online (Sandbox Code Playgroud)\n

PROPERTYKEY结构用于构建定义ColInfo和Sort 的结构。如果我们将文件夹设置为具有单列Name,并检查生成的ColInfo值,我们会看到以下字节:

\n
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \\ Constant\nfd df df fd 10 00 00 00 00 00 00 00 00 00 00 00 / Header\n[01 00 00 00] \xe2\x86\x90 Column Count\n[18 00 00 00] \xe2\x86\x90 Byte count per column?\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac] \xe2\x86\x90 FMTID\n[0a 00 00 00] \xe2\x86\x90 PID ] \xe2\x86\x90 PROPERTYKEY\n[da 01 00 00] \xe2\x86\x90 Width (Pixels?) ] <- PROPERTYKEY/Width pair\n
Run Code Online (Sandbox Code Playgroud)\n

对于添加到视图中的每一列,列计数都会增加,并添加适当的 PROPERTYKEY/Width 对:

\n
[00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\nfd df df fd 10 00 00 00 00 00 00 00 00 00 00 00]\n[03 00 00 00]\n[18 00 00 00]\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[0d 00 00 00]] \xe2\x86\x90 \'Attributes\'\n[53 00 00 00]]\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[0a 00 00 00]] \xe2\x86\x90 \'Name\'\n[10 01 00 00]]\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[04 00 00 00]] \xe2\x86\x90 \'Type\'\n[0a 01 00 00]]\n
Run Code Online (Sandbox Code Playgroud)\n

排序使用SORTCOLUMN结构:

\n
typedef struct SORTCOLUMN {\nPROPERTYKEY propkey;\nSORTDIRECTION direction; \n} SORTCOLUMN;\n
Run Code Online (Sandbox Code Playgroud)\n

排序结构包括:

\n
    \n
  • 由 16 个零值字节组成的标头
  • \n
  • SORTCOLUMN 计数(DWORD)
  • \n
  • 一个或多个 SORTCOLUMN 结构
  • \n
\n

名称,升序:

\n
[00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00] <- Header\n[01 00 00 00] <- SORTCOLUMN count\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac] <- FMTID\n[0a 00 00 00] <- PID ] <- PROPERTYKEY\n[01 00 00 00] <- Direction ] <- SORTCOLUMN\n
Run Code Online (Sandbox Code Playgroud)\n

和名称,降序:

\n
[00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]\n[01 00 00 00]\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[0a 00 00 00]]\n[ff ff ff ff] <- Direction ] <- SORTCOLUMN\n
Run Code Online (Sandbox Code Playgroud)\n

当通过< Shift > 键并单击列标题选择二级、三级或四级属性时,相应的 SORTCOLUMN 将添加到排序结构中。

\n

输入,降序,然后输入名称,升序:

\n
(gp \'HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\Bags\\66\\Shell\\{7D49D726-3C21-4F05-99AA-FDC2C9474656}\\\').Sort | Format-Hex                                               \n\n           Path:\n\n           00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n00000000   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................\n00000010   02 00 00 00 30 F1 25 B7 EF 47 1A 10 A5 F1 02 60  ....0\xc3\xb1%\xc2\xb7\xc3\xafG..\xc2\xa5\xc3\xb1.`\n00000020   8C 9E EB AC 04 00 00 00 FF FF FF FF 30 F1 25 B7  \xc3\xab\xc2\xac........0\xc3\xb1%\xc2\xb7\n00000030   EF 47 1A 10 A5 F1 02 60 8C 9E EB AC 0A 00 00 00  \xc3\xafG..\xc2\xa5\xc3\xb1.`\xc3\xab\xc2\xac....\n00000040   01 00 00 00                                      ....\n\n[00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]\n[02 00 00 00] <- Two columns specified\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[04 00 00 00]] <- \'TYpe\'\n[ff ff ff ff]]\n[[[30 f1 25 b7 ef 47 1a 10 a5 f1 02 60 8c 9e eb ac]\n[0a 00 00 00]] <- \'Name\'\n[01 00 00 00]]\n
Run Code Online (Sandbox Code Playgroud)\n
\n

袋MRU

\n

BagMRU及其子键是树形结构索引,它将文件夹的路径与其编号的Bag ( NodeSlot ) 相关联。BagMRU及其子项镜像Shell 命名空间,BagMRU项本身对应于 root(虚拟)Desktop。BagMRU中的每个节点对应于 Shell 命名空间中的一个文件夹。文件夹由其名称空间路径引用这一事实意味着一个文件系统文件夹(例如Documents)将具有三个单独的视图:

\n
    \n
  • 桌面\\此电脑\\文档
  • \n
  • 外壳:UsersFilesFolder\\Documents
  • \n
  • 桌面\\此电脑\\C:\\用户<用户名>\\文档
  • \n
\n

检查BagMRU时,没有明显的文件夹名称;节点具有简单的整数名称,并且没有字符串值。人类可读的路径在哪里?!?!?为什么 MS 让一切变得如此困难?!?!?:D\n好吧,每个整数命名的节点在其父节点中都有一个相应的整数命名的 REG_BINARY 值。正是该值标识了其关联的子密钥。谜底的关键?这些二进制值是项目 ID (实际上是ITEMIDLIST 结构的相应ITEMID_CHILD类型)。因此,我们可以使用节点及其祖先的 ID 列表来构造 IDLIST_ABSOLUTE ,类似于完全限定路径:\n在此输入图像描述

\n

但它仍然只是一个神秘字节数组。为了提取有意义的信息,我们求助于 Windows API,特别是SHGetNameFromIDList。根据文档:

\n
\n

“检索由 IDList 标识的项目的显示名称。”

\n
\n

幸运的是,PowerShell可以通过Add-Type合并 API 。不幸的是,如果 PInvoke.net 的数据库中没有 C# 签名/包装器,那么发现有效的签名和包装器可能会令人沮丧。但通过研究其他签名和反复试验,我找到了一个,然后定义了一个包装函数:

\n
Add-Type -TypeDefinition  @\'\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\npublic class API\n{\n    [DllImport("shell32.dll", SetLastError=true, CharSet=CharSet.Unicode)]\n    [return: MarshalAs(UnmanagedType.Error)]\n    static extern int SHGetNameFromIDList(IntPtr pidl, uint sigdnName, out StringBuilder ppszName);\n\n    public static string GetFolderName(Byte[] IDL) {\n        GCHandle pinnedArray = GCHandle.Alloc(IDL, GCHandleType.Pinned);\n        IntPtr PIDL          = pinnedArray.AddrOfPinnedObject();\n        StringBuilder name   = new StringBuilder(2048);\n        int result           = SHGetNameFromIDList(PIDL, 0x0, out name);\n        pinnedArray.Free();\n        return name.ToString();\n    }\n}\n\'@\n\n# Invocation:\n# $FolderName = [API]::GetFolderName($IDL)\n# Where $IDL is a [Byte[]] ItemIDList\n
Run Code Online (Sandbox Code Playgroud)\n

这足以解码桌面上根文件夹的 IDL :

\n
$BagMRU = \'HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU\'\n((Get-ItemProperty $Bagmru).PsObject.Properties).Where{$_.Name -match \'\\d+\'} |\nForEach -Process{\n    [PSCustomObject]@{\n        \'KeyName\'  = $_.Name\n        \'Folder\'   = [API]::GetFolderName($_.Value)\n}}\n
Run Code Online (Sandbox Code Playgroud)\n

输出:(具体结果会有所不同:D)

\n
KeyName Folder\n------- ------\n0       Quick access\n1       This PC\n2       Keith Miller\n3       Libraries\n4       Control Panel\n5       Sandbox\n6       Search Results in Sandbox\n7       Search Results in Sandbox\n8       Search Results in Desktop\n9       Search Results in Desktop\n10      Keith Miller\n11      ::{1434B6DB-0A53-454A-B1C7-69A56B454078}\n12      Search Results in System32\n13      Search Results in System32\n14      Search Results in Keith Miller\n15      Search Results in Altenate Folder Tree\n16      Search Results in Altenate Folder Tree\n17      H:\\\n18      I:\\\n19      Reg Transfers\n20      Quick access\n21      Quick access\n22      This PC\n23      Recent folders\n24      OneDrive - Personal\n25      This Device\n26      Recent files\n
Run Code Online (Sandbox Code Playgroud)\n

漂亮吧?别担心,那些看似重复的“搜索结果...”行实际上并不是重复的——它们是一起工作的。由于.SearchResults和.Library FolderTypes具有多个可用的TopView(通过 进行选择ArrangeBy >),因此一个包指定最后使用的TopView(因此在重新显示文件夹时使用),而其他包则保存特定TopView. 稍后会详细介绍——我们还没有完成路径。

\n

要构造子文件夹的 IDL,请从“父”字节数组中去除两个终止空字节,然后附加“子”字节数组。如果子文件夹有子文件夹,请使用新构建的 IDL 重复该过程。

\n

TypeDefinition通过包含SIGDN常量的缩写枚举的充实内容,可以使用递归函数来获取BagMRU键的快照,并将每个节点与其在 Shell 命名空间中的相应路径以及文件系统路径相关联(如果适用)以及虚拟位置的解析路径:

\n
Add-Type -TypeDefinition @\'\nusing System;\nusing System.Runtime.InteropServices;\nusing System.Text;\n\n[FlagsAttribute]\npublic enum SIGDN : uint {\n    NORMALDISPLAY            = 0x00000000,\n    DESKTOPABSOLUTEPARSING   = 0x80028000,\n    FILESYSPATH              = 0x80058000,\n    URL                      = 0x80068000,\n};\n\npublic class API\n{\n    [DllImport("shell32.dll", SetLastError=true, CharSet=CharSet.Unicode)]\n    [return: MarshalAs(UnmanagedType.Error)]\n    static extern int SHGetNameFromIDList(IntPtr pidl, SIGDN sigdnName, out StringBuilder ppszName);\n\n    public static string Get_FolderName(Byte[] IDL , SIGDN sigdnName) {\n        GCHandle pinnedArray = GCHandle.Alloc(IDL, GCHandleType.Pinned);\n        IntPtr PIDL          = pinnedArray.AddrOfPinnedObject();\n        StringBuilder name   = new StringBuilder(2048);\n        int result           = SHGetNameFromIDList(PIDL, sigdnName, out name);\n        pinnedArray.Free();\n        return name.ToString();\n    }\n}\n\'@\n\nFunction Get-BagMRU\n\n#   Parametrs are for recursive calls only. Calling the function\n#   with no parameters returns the complete collection.\n\n{\n    Param(\n        [PSObject[]]$Keys  = ( Get-Item @(\n            \'HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\BagMRU\',\n            \'HKCU:\\Software\\Microsoft\\Windows\\Shell\\BagMRU\'\n        )),\n        [Byte[]]$IDL          = [Byte[]]@(),\n        [String]$ParentPath   = $null,\n        [Byte[]]$ParentIDL    = [Byte[]]@()\n    )\n    ForEach ($key in $Keys)\n    {\n        If ( $IDL )\n        {\n            ### Build nameSpacePath ###\n\n            [Byte[]]$absIDL = [Byte[]]($ParentIDL + $IDL)\n\n            Try { $nameSpacePath = $ParentPath + [API]::Get_FolderName( $absIDL ,