I want to make a program that gets the positions of the icons on the screen. And with some research I found out that the values I needed were in a registry binary file called IconLayouts (Located in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\Shell\Bags\1\Desktop) I used python to get the positions using the winreg module. And succeeded on getting the values.
from winreg import *
aReg = ConnectRegistry(None, HKEY_CURRENT_USER)
aKey = OpenKey(aReg, r"Software\Microsoft\Windows\Shell\Bags\1\Desktop", REG_BINARY)
name, value, type_ = EnumValue(aKey, 9)
value = value.replace(b'\x00', b'')
This is the code I have. But the problem is I don't know what to do with these values. The program returns something like:
b'\x03\x01\x01\x01\x04,::{20D04FE0-3AEA-1069-A2D8-08002B30309D}> ,::{645FF040-5081-101B-9F08-00AA002F954E}> \x13Timetables.jpeg> \nfolder>\\ \x01\x02\x01\x01\x02\x01\x0c\x04\x01\x04\x80?\x01@\x020A\x03'
I would appreciate if you would help me decipher this output and get the positions from it.
The following code snippet could help. It's very, very simplified code combined from Windows Shellbag Forensics article and shellbags.py
script (the latter is written in Python 2.7 hence unserviceable for me).
import struct
from winreg import *
aReg = ConnectRegistry(None, HKEY_CURRENT_USER)
aKey = OpenKey(aReg, r"Software\Microsoft\Windows\Shell\Bags\1\Desktop", REG_BINARY)
name, value, type_ = EnumValue(aKey, 9)
offset = 0x10
head = [struct.unpack_from("<H", value[offset:],0)[0],
struct.unpack_from("<H", value[offset:],2)[0],
struct.unpack_from("<H", value[offset:],4)[0],
struct.unpack_from("<H", value[offset:],6)[0]]
number_of_items = struct.unpack_from("<I", value[offset:],8)[0] # 4 bytes (dword)
offset += 12
for x in range( number_of_items):
uint16_size = struct.unpack_from("<H", value[offset:],0)[0];
uint16_flags = struct.unpack_from("<H", value[offset:],2)[0];
uint32_filesize = struct.unpack_from("<I", value[offset:],4)[0];
dosdate_date = struct.unpack_from("<H", value[offset:],8)[0];
dostime_time = struct.unpack_from("<H", value[offset:],10)[0];
fileattr16_ = struct.unpack_from("<H", value[offset:],12)[0];
offset += 12
entry_name = value[offset:(offset + (2 * uint32_filesize - 8))].decode('utf-16-le')
offset += (2 * uint32_filesize - 4 )
if offset % 2:
offset += 1
print( x, uint32_filesize, entry_name)
print( '\nThere is', (len(value) - offset), 'bytes left' )
Output (truncated): .\SO\70039190.py
0 44 ::{59031A47-3F72-44A7-89C5-5595FE6B30EE}
1 44 ::{20D04FE0-3AEA-1069-A2D8-08002B30309D}
2 44 ::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}
3 31 Software602 Form Filler.lnk
4 8 test
5 32 Virtual Russian Keyboard.lnk
…
49 22 WTerminalAdmin.lnk
50 22 AVG Secure VPN.lnk
51 44 ::{645FF040-5081-101B-9F08-00AA002F954E}
52 29 powershell - Shortcut.lnk
There is 1176 bytes left
Honestly, I don't fully comprehend offset
around entry_name
…
I have found (partial) structure for the rest of value
. There are two tables containing row and column along with an index to desktop_items
list for each desktop icon.
Current row and column assignment is in the second table (see the picture below). The first table supposedly contains default assignments for automatic sort by (from desktop context menu).
Unfortunately, I have no clue for interpretation of row and column values (e.g. 16256, 16384
) to icon indexes (3rd row, 2nd column).
import struct
import winreg
import pprint
aReg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
aKey = winreg.OpenKey(aReg,
r"Software\Microsoft\Windows\Shell\Bags\1\Desktop",
winreg.REG_BINARY)
name, value, type_ = winreg.EnumValue(aKey, 9)
aKey.Close()
aReg.Close()
offset = 0x10
head = [struct.unpack_from("<H", value[offset:],0)[0], # 2 bytes (word)
struct.unpack_from("<H", value[offset:],2)[0],
struct.unpack_from("<H", value[offset:],4)[0],
struct.unpack_from("<H", value[offset:],6)[0],
struct.unpack_from("<I", value[offset:],8)[0] # 4 bytes (dword)
]
number_of_items = head[-1]
offset += 12
desktop_items = []
for x in range( number_of_items):
uint16_size = struct.unpack_from("<H", value[offset:],0)[0];
uint16_flags = struct.unpack_from("<H", value[offset:],2)[0];
uint32_filesize = struct.unpack_from("<I", value[offset:],4)[0];
dosdate_date = struct.unpack_from("<H", value[offset:],8)[0];
dostime_time = struct.unpack_from("<H", value[offset:],10)[0];
fileattr16_ = struct.unpack_from("<H", value[offset:],12)[0];
offset += 12
entry_name = value[offset:(offset + (2 * uint32_filesize - 8))].decode('utf-16-le')
offset += (2 * uint32_filesize - 4 )
# uint16_size = location
# 0x20 = %PUBLIC%\Desktop
# 0x7c = %USERPROFILE%\Desktop
desktop_items.append([x,
'{:04x}'.format(uint16_size),
0, 0,
'{:04x}'.format(fileattr16_),
entry_name])
print('{:2}'.format(x),
'{:04x}'.format(uint16_size),
# '{:04x}'.format(uint16_flags), # always zero
# '{:04x}'.format(dosdate_date), # always zero
# '{:04x}'.format(dostime_time), # always zero
'{:04x}'.format(fileattr16_),
entry_name)
print( '\nThere is', (len(value) - offset), 'bytes left' )
print('head (12 bytes):', head)
offs = offset
head2 = []
for x in range( 32):
head2.append(struct.unpack_from("<H", value[offs:],2*x)[0])
offs += 64
print( 'head2 (64 bytes):', head2)
for x in range( number_of_items):
item_list = [
struct.unpack_from("<H", value[offs:],0)[0], # 0
struct.unpack_from("<H", value[offs:],2)[0], # column
struct.unpack_from("<H", value[offs:],4)[0], # 0
struct.unpack_from("<H", value[offs:],6)[0], # row
struct.unpack_from("<H", value[offs:],8)[0] ] # index to desktop_items
# print( x, item_list)
desktop_items[item_list[-1]][2] = int( item_list[1])
desktop_items[item_list[-1]][3] = int( item_list[3])
offs += 10
print(len(value), offset, offs, (offs - offset), '1st table, from start:')
table_1st = desktop_items
table_1st.sort(key=lambda k: (k[2], k[3]))
pprint.pprint(table_1st)
#pprint.pprint(desktop_items)
# 2nd table from behind
offs = len(value)
for x in range( number_of_items):
offs -= 10
item_list = [
struct.unpack_from("<H", value[offs:],0)[0], # 0
struct.unpack_from("<H", value[offs:],2)[0], # column
struct.unpack_from("<H", value[offs:],4)[0], # 0
struct.unpack_from("<H", value[offs:],6)[0], # row
struct.unpack_from("<H", value[offs:],8)[0] ] # index to desktop_items
# print(item_list)
desktop_items[item_list[-1]][2] = int( item_list[1])
desktop_items[item_list[-1]][3] = int( item_list[3])
print(len(value), offset, offs, (offs - offset), '2nd table, from behind:')
table_2nd = desktop_items
table_2nd.sort(key=lambda k: (k[2], k[3]))
pprint.pprint(table_2nd)
# pprint.pprint(desktop_items)
Result (an illustrative picture):