def FileExtensionBlockParser(_extension_block, _extension_version, _extension_block_result): # TODO : WinXP ~ Win 8 추가 필요. (FILE_EXTENSION_BLOCK_COMMON, pos) = cv.FormatParser(_extension_block, data_format.FILE_EXTENSION_BLOCK_COMMON_FORMAT, 0) _extension_block_result["ctime"] = cv.TSFat(FILE_EXTENSION_BLOCK_COMMON["fat_ctime"]) _extension_block_result["atime"] = cv.TSFat(FILE_EXTENSION_BLOCK_COMMON["fat_atime"]) if _extension_version == 9: # Win8.1 ~ Win10 (FILE_EXTENSION_BLOCK_DATA, pos) = cv.FormatParser(FILE_EXTENSION_BLOCK_COMMON["data"], data_format.FILE_EXTENSION_BLOCK_WIN81_FORMAT, 0) mft_reference = FILE_EXTENSION_BLOCK_DATA["mft_reference"] name_size = cv.Bytes2Int(FILE_EXTENSION_BLOCK_DATA["name_size"]) dummy_name = FILE_EXTENSION_BLOCK_DATA["long_name"] _extension_block_result["mft_entry_number"] = cv.Bytes2Int(mft_reference[0:4]) _extension_block_result["mft_sequence_number"] = cv.Bytes2Int(mft_reference[4:6]) if name_size == 0: long_name = dummy_name[:-4].decode("UTF-16LE") _extension_block_result["long_name"] = long_name elif name_size > 0: offset = cv.FindEndOfStream(dummy_name, 2, b"\x00\x00") long_name = dummy_name[:offset].decode("UTF-16LE") local_name = dummy_name[offset+2:-4].decode("UTF-16LE") _extension_block_result["long_name"] = long_name _extension_block_result["localized_name"] = local_name return _extension_block_result
def Volume(_regData, _shell_item_result, _info): (shell_item_size, shell_item_type, shell_item_data, pos) = _info volume_type_flag = cv.Bytes2Int(shell_item_type) & 0x0F if volume_type_flag == 0x0E: # Root Shell item (doesn't have name flags.) -> Shell folder volume_item_data = shell_item_data[1:] (guid, name) = cv.GUID2Text(volume_item_data[0x00:0x10]) extension_blocks = volume_item_data[0x10:] _shell_item_result["shell_type"] = "Root folder: GUID" _shell_item_result["mapped_guid"] = (guid, name) _shell_item_result["value"] = name elif volume_type_flag == 0x0F: offset = cv.FindEndOfStream(shell_item_data, 2, b"\x00\x00") - 2 volume_letter = shell_item_data[:offset].decode() _shell_item_result["shell_type"] = "Drive" _shell_item_result["value"] = volume_letter extension_blocks = "" else: raise ShellItemFormatError("New volume type flag (Volume Shell Item)") extension_block_result = parse_extension_block.Parse( extension_blocks, _regData) _shell_item_result["extension_block_result"] = extension_block_result return _shell_item_result
def HttpURIParser(_htu_data, _parsing_result): _parsing_result["shell_type"] = "HTTP URI" loop = 0 while True: if len(_htu_data) < 20: return _parsing_result (HTU_DATA, pos) = cv.FormatParser(_htu_data, data_format.HTU_SHELL_ITEM_FORMAT, 0) htu_url_size = cv.Bytes2Int(HTU_DATA["htu_url_size"]) if loop == 0: _parsing_result["value"] = urllib.parse.unquote( _htu_data[pos:pos + htu_url_size].decode("UTF-16LE")) elif loop == 1: _parsing_result["full_url"] = _htu_data[pos:pos + htu_url_size].decode( "UTF-16LE") else: if htu_url_size == 8 and HTU_DATA["htu_url"][-1] == 1: unknown_win64_time = cv.TSWin64bit(HTU_DATA["htu_url"]) _parsing_result["unknown_data"] = ("Unknown Time", unknown_win64_time) else: raise ShellItemFormatError( "New HTTP URI(HTU) format (Users Property View Shell Item)" ) _htu_data = _htu_data[pos + htu_url_size:] loop += 1
def FileEntry(_regData, _shell_item_result, _info): (shell_item_size, shell_item_type, shell_item_data, pos) = _info (ITEM_DATA, pos) = cv.FormatParser(shell_item_data, data_format.FILE_ENTRY_SHELL_ITEM_FORMAT, pos) _shell_item_result["file_size"] = cv.Bytes2Int(ITEM_DATA["file_size"]) _shell_item_result["fat_mtime"] = cv.TSFat(ITEM_DATA["fat_mtime"]) offset = cv.FindEndOfStream(ITEM_DATA["short_name"], 2, b"\x04\x00\xef\xbe") - 4 _shell_item_result["short_name"] = cv.EncodingWizard( ITEM_DATA["short_name"][:offset]).replace("\x00", "") extension_blocks = ITEM_DATA["short_name"][offset:] if _shell_item_result["file_size"] == 0: _shell_item_result["shell_type"] = "Directory" elif _shell_item_result["file_size"] > 0: _shell_item_result["shell_type"] = "File" else: raise ShellItemFormatError("New file size (File Shell Item)") extension_block_result = parse_extension_block.Parse( extension_blocks, _regData) _shell_item_result["extension_block_result"] = extension_block_result for extension_block_dict in extension_block_result: if extension_block_dict["extension_sig"] == "0xbeef0004": _shell_item_result["value"] = extension_block_dict["long_name"] return _shell_item_result
def MRUDataParser(_regData): shell_item_result = { "last_written_time" : None, "shell_type" : None, "file_size" : 0, "fat_mtime" : None, "short_name" : None, "full_url" : None, "value" : None, "mapped_guid" : None, "unknown_data" : None, "extension_block_result" : [], "sps_result" : [], # sps_result can have shell_item_result. so, it can have extension_block_result also. # "registry_data" : _regData } (MRU_DATA, shell_item_pos) = cv.FormatParser(_regData, data_format.MRU_DATA_FORMAT, 0) shell_item_size = cv.Bytes2Int(MRU_DATA["shell_item_size"]) shell_item_type = cv.ReturnType(MRU_DATA["shell_item_type"], data_format.SHELL_ITEM_TYPES) shell_item_data = MRU_DATA["shell_item_data"] shell_item_info = (shell_item_size, MRU_DATA["shell_item_type"], shell_item_data, shell_item_pos) if shell_item_type == "root_folder_shell_item": # Shell folder (GUID) shell_item_result = parse_shell_items.RootFolder(_regData, shell_item_result, shell_item_info) elif shell_item_type == "volume_shell_item": # My Computer in Explorer shell_item_result = parse_shell_items.Volume(_regData, shell_item_result, shell_item_info) elif shell_item_type == "file_entry_shell_item": shell_item_result = parse_shell_items.FileEntry(_regData, shell_item_result, shell_item_info) # elif shell_item_type == "network_location_shell_item": # # Never seen. elif shell_item_type == "control_panel_shell_item": shell_item_result = parse_shell_items.ControlPanel(_regData, shell_item_result, shell_item_info) elif shell_item_type == "control_panel_category_shell_item": shell_item_result = parse_shell_items.ControlPanelCategory(_regData, shell_item_result, shell_item_info) elif shell_item_type == "users_property_view_shell_item": shell_item_result = parse_shell_items.UsersPropertyView(_regData, shell_item_result, shell_item_info) else: # df.PrintHexString(MRU_DATA["shell_item_type"]) return None pass if shell_item_result["value"] == None: shell_item_result["value"] == "Comming Soon" pass # df.PrintBeauty(shell_item_result, _sept_count=67) return shell_item_result
def SplitShellItems(_shell_item_blocks): shell_item_list = [] shell_item_blocks = _shell_item_blocks while True: shell_item_size = cv.Bytes2Int(shell_item_blocks[0:2]) shell_item = shell_item_blocks[:shell_item_size] shell_item_blocks = shell_item_blocks[shell_item_size:] shell_item_list.append(shell_item) if shell_item_blocks[:2] == b"\x00\x00" or shell_item_blocks == b"": return shell_item_list
def SplitPropertyValues(_spv_blocks): spv_list = [] spv_blocks = _spv_blocks while True: spv_size = cv.Bytes2Int(spv_blocks[0:4]) spv = spv_blocks[:spv_size] spv_blocks = spv_blocks[spv_size:] spv_list.append(spv) if spv_blocks[:4] == b"\x00\x00\x00\x00": return spv_list
def SplitExtensionBlocks(_extension_blocks): extension_block_list = [] extension_blocks = _extension_blocks while True: (EXTENSION_BLOCK_SIG, pos) = cv.FormatParser(extension_blocks, data_format.EXTENSION_BLOCK_SIGNATURE_FORMAT, 0) block_size = cv.Bytes2Int(EXTENSION_BLOCK_SIG["extension_size"]) extension_block = extension_blocks[:block_size] extension_blocks = extension_blocks[block_size:] extension_block_list.append(extension_block) if extension_blocks[:2] == b"\x00\x00" or extension_blocks == b"": return extension_block_list
def SplitPropertyStorageBlocks(_sps_blocks): sps_block_list = [] sps_blocks = _sps_blocks while True: (SPS_DATA, pos) = cv.FormatParser(sps_blocks, data_format.SPS_FORMAT, 0) sps_size = cv.Bytes2Int(SPS_DATA["storage_size"]) sps_block = sps_blocks[:sps_size] sps_blocks = sps_blocks[sps_size:] sps_block_list.append(sps_block) if sps_blocks[:4] == b"\x00\x00\x00\x00" or sps_blocks == b"": return sps_block_list
def MRUListExParser(_regData): loop = 0 result = [] while loop < len(_regData): mru_index_bytes = _regData[loop:loop+0x04] if mru_index_bytes == b"\xFF\xFF\xFF\xFF": break mru_index = cv.Bytes2Int(mru_index_bytes) result.append(mru_index) loop += 4 return result
def ControlPanelCategory(_regData, _shell_item_result, _info): (shell_item_size, shell_item_type, shell_item_data, pos) = _info (ITEM_DATA, pos) = cv.FormatParser( shell_item_data, data_format.CONTROL_PANEL_CATEGORY_SHELL_ITEM_FORMAT, pos) if ITEM_DATA["sig"] != b"\x84\x21\xDE\x39": raise ShellItemFormatError("New signature (Control Panel Category)") category_id = cv.Bytes2Int(ITEM_DATA["category_id"]) if category_id in data_id.CONTROL_PANEL_CATEGORY_ID.keys(): _shell_item_result["value"] = data_id.CONTROL_PANEL_CATEGORY_ID[ category_id] else: raise ShellItemFormatError("New category id (Control Panel Category)") extension_blocks = ITEM_DATA["extension_block"] extension_block_result = parse_extension_block.Parse( extension_blocks, _regData) _shell_item_result["extension_block_result"] = extension_block_result return _shell_item_result
def UsersPropertyView(_regData, _shell_item_result, _info): (shell_item_size, shell_item_type, shell_item_data, pos) = _info (ITEM_DATA, pos) = cv.FormatParser(shell_item_data, data_format.USERS_SHELL_ITEM_FORMAT, pos) _shell_item_result["shell_type"] = "Users property view" sps_blocks = "" extension_blocks = "" upv_size = cv.Bytes2Int(ITEM_DATA["upv_size"]) upv_data_size = cv.Bytes2Int(ITEM_DATA["upv_data_size"]) upv_id_size = cv.Bytes2Int(ITEM_DATA["upv_id_size"]) if ITEM_DATA["upv_sig"] in [b"\x81\x19\x14\x10", b"\x00\xEE\xEB\xBE"]: upv_id_data = ITEM_DATA["upv_id_data"][: upv_id_size] # unknown 32 bytes sps_blocks = ITEM_DATA["upv_id_data"][upv_id_size:] elif ITEM_DATA["upv_sig"] == b"\xEE\xBB\xFE\x23": upv_id_data = ITEM_DATA["upv_id_data"][:upv_id_size] (guid, name) = cv.GUID2Text(upv_id_data) _shell_item_result["mapped_guid"] = (guid, name) _shell_item_result["value"] = name if upv_data_size == 0: extension_blocks = ITEM_DATA["upv_id_data"][upv_id_size + 2:] elif upv_id_size > 0: sps_blocks = ITEM_DATA["upv_id_data"][upv_id_size:] else: raise ShellItemFormatError( "New upv_id_size (Users property view Shell Item --> \\xEE\\xBB\\xFE\\x23)" ) elif ITEM_DATA["upv_sig"] == b"\xBB\xAF\x93\x3B": raise ShellItemFormatError( "New upv_sig (Users property view Shell Item --> \\xBB\\xAF\\x93\\x3B)" ) elif ITEM_DATA["upv_sig"] == b"\x10\xB7\xA6\xF5": volume_shell_item_data = shell_item_data[pos - 2:upv_size] two_guids = shell_item_data[upv_size + 3:] offset = cv.FindEndOfStream(volume_shell_item_data, 2, b"\x00\x00") volume_letter = volume_shell_item_data[:offset].decode() guid1 = cv.GUID2Text(two_guids[:16]) guid2 = cv.GUID2Text(two_guids[16:32]) extension_blocks = two_guids[32:] _shell_item_result["value"] = volume_letter _shell_item_result["mapped_guid"] = [guid1, guid2] elif ITEM_DATA["upv_sig"] == b"\xD5\xDF\xA3\x23": # size(upv_size, upv_sig, upv_data_size, upv_id_size) == 10 sps_blocks = ITEM_DATA["upv_id_data"][upv_id_size:upv_size - 10] root_item = ITEM_DATA["upv_id_data"][upv_size - 8:] # 8 == 10 - len(\x00\x00) guid1 = cv.GUID2Text(root_item[:16]) guid2 = cv.GUID2Text(root_item[16:32]) extension_blocks = root_item[32:] (guid, name) = guid2 _shell_item_result["value"] = name _shell_item_result["mapped_guid"] = [guid1, guid2] else: htu_size = cv.Bytes2Int(shell_item_data[5:9]) htu_data = shell_item_data[1:htu_size - 3] if shell_item_data[1:5] == b"\x00\xB0\x01\xC0": _shell_item_result = HttpURIParser(htu_data, _shell_item_result) else: raise ShellItemFormatError( "New HTTP URI(UTU) sig (Users Property View Shell Item) --> %s" % repr(ITEM_DATA["upv_sig"])) sps_result = parse_sps_block.Parse(sps_blocks, _debug=_regData) _shell_item_result["sps_result"] = sps_result if sps_result: RefineSPSResult(sps_result) extension_block_result = parse_extension_block.Parse( extension_blocks, _regData) _shell_item_result["extension_block_result"] = extension_block_result return _shell_item_result
def PropertyValueParser(_sps_guid, _idx, _spv, _debug=None): spv_result = { "value_id": None, "value": None, "shell_item_result": [], } (SPV, pos) = cv.FormatParser(_spv, data_format.SPV_FORMAT, 0) value_id = cv.Bytes2Int(SPV["value_id"]) value_type = cv.Bytes2Int(SPV["value_type"]) value_data = SPV["value_data"] spv_result["value_id"] = value_id # all spv are named property if _sps_guid == "D5CDD505-2E9C-101B-9397-08002B2CF9AE": spv_data = SPV["value_type"] + SPV["reserved2"] + value_data spv_result["value_id"] = spv_data[:value_id - 2].decode( "UTF-16LE") # value id is name_size value_type = cv.Bytes2Int(spv_data[value_id:value_id + 4]) value_data = spv_data[value_id + 4:] if value_type == 0x0001: # VT_NULL spv_result["value"] = "NULL" elif value_type == 0x0002: # VT_I2 (signed 16-bit) spv_result["value"] = cv.Bytes2SignedInt(16, value_data[:2]) elif value_type in [0x0003, 0x0016]: # VT_I4, VT_INT (signed 32-bit) spv_result["value"] = cv.Bytes2SignedInt(32, value_data) elif value_type == 0x000B: # VT_BOOL if value_data[:2] == b"\xFF\xFF": spv_result["value"] = "TRUE" elif value_data[:2] == b"\x00\x00": spv_result["value"] = "FALSE" else: raise WindowsPropertyFormatError("New value_type (VT_BOOL)") elif value_type == 0x0010: # VT_I1 (signed 8-bit) spv_result["value"] = cv.Bytes2SignedInt(8, value_data) elif value_type == 0x0011: # VT_UI1 (unsigned 8-bit) spv_result["value"] = cv.Bytes2Int(value_data) elif value_type == 0x0012: # VT_UI2 (unsigned 16-bit) spv_result["value"] = cv.Bytes2Int(value_data) elif value_type in [ 0x0013, 0x0017, 0x0015 ]: # VT_UI4, VT_UINT (unsigned 32-bit), VT_UI8 (unsigned 64-bit) spv_result["value"] = cv.Bytes2Int(value_data) elif value_type == 0x0014: # VT_I8 (signed 64-bit) spv_result["value"] = cv.Bytes2SignedInt(64, value_data) elif value_type == 0x001F: # VT_LPWSTR (Unicode string) str_size = (cv.Bytes2Int(value_data[0:4]) * 2) - 2 string = value_data[4:4 + str_size].decode("UTF-16LE") spv_result["value"] = string elif value_type == 0x0040: # VT_FILETIME (aka. Windows 64-bit timestamp) spv_result["value"] = cv.TSWin64bit(value_data) elif value_type == 0x0042: # VT_STREAM spv_result["value"] = "VT_STREAM (0x0042)" prop_name_size = cv.Bytes2Int(value_data[0x00:0x04]) prop_name = value_data[0x04:0x04 + prop_name_size].decode("UTF-16LE") value_data = value_data[0x04 + prop_name_size:][2:] # \x00\x00 if prop_name[:4] != "prop": raise WindowsPropertyFormatError( "new value_type (VT_STREAM) : Not a prop~") idk_block_size = cv.Bytes2Int(value_data[0x00:0x02]) idk_block = value_data[:idk_block_size] idk_block_guid = cv.GUID2Text(idk_block[0x04:0x04 + 0x10]) dummy_shell_item_blocks = idk_block[0x04 + 0x10 + 0x24:] shell_item_blocks_size = cv.Bytes2Int( dummy_shell_item_blocks[0x00:0x02]) shell_item_blocks = dummy_shell_item_blocks[ 0x02:shell_item_blocks_size] # 0x02 is shell_item_blocks_size last_idk_block = dummy_shell_item_blocks[shell_item_blocks_size:] shell_item_result_list = ShellItemParser(shell_item_blocks) spv_result["shell_item_result"] = shell_item_result_list (LAST_IDK_BLOCK, pos) = cv.FormatParser(last_idk_block, data_format.LAST_IDK_BLOCK, 0) item_field = LAST_IDK_BLOCK["item_field"] offset = cv.FindEndOfStream(item_field, 2, b"\x00\x00") str_item = item_field[:offset].decode("UTF-16LE") if str_item != "item": raise WindowsPropertyFormatError( "new value_type (VT_STREAM) : Not \"item\" in last_idk_block") last_idk_block_guid = cv.GUID2Text(LAST_IDK_BLOCK["guid"]) dummy_search_result = LAST_IDK_BLOCK["search_result"] offset = cv.FindEndOfStream(dummy_search_result, 2, "\x00\x00") search_result = dummy_search_result[:offset].decode("UTF-16LE") # print("#"*100) # df.PrintBeauty(shell_item_result_list) # print(str_item) # print(search_result) elif value_type == 0x101F: # VT_VECTOR(0x1000) | VT_LPWSTR vector_count = cv.Bytes2Int(value_data[0:4]) str_size = (cv.Bytes2Int(value_data[4:8]) * 2) - 2 string = value_data[8:8 + str_size].decode("UTF-16LE") spv_result["value"] = string if vector_count != 1: raise WindowsPropertyFormatError("New value_type (0x101F)") elif value_type == 0x1011: if value_data[5:8] == "\x00\x00\x00": vector_count = cv.Bytes2Int(value_data[0:4]) spv_result["value"] = cv.Bytes2Int(value_data[4:8]) if vector_count != 1: raise WindowsPropertyFormatError("New value_type (0x1011)") else: spv_result["value"] = "VT_VECTOR with data (0x011)" shell_item_result_list = ShellItemParser(value_data[4:]) spv_result["shell_item_result"] = shell_item_result_list else: output_spv_id = "0x" + hex(value_type)[2:].zfill(4) raise WindowsPropertyFormatError("New value_id (Others : %s)" % output_spv_id) # df.PrintBeauty(spv_result) return spv_result
def ExtensionBlockParser(_extension_block): extension_block_result = { "extension_sig" : None, "mapped_guid" : None, # [(guid, name), (guid, name), ...] "filesystem" : None, "mft_entry_number": None, "mft_sequence_number" : None, "ctime" : None, "mtime" : None, "atime" : None, "long_name" : None, "localized_name" : None, "comment" : None, "sps_result" : [] } (EXTENSION_BLOCK_SIGNATURE, pos) = cv.FormatParser(_extension_block, data_format.EXTENSION_BLOCK_SIGNATURE_FORMAT, 0) extension_size = cv.Bytes2Int(EXTENSION_BLOCK_SIGNATURE["extension_size"]) extension_version = cv.Bytes2Int(EXTENSION_BLOCK_SIGNATURE["extension_version"]) extension_sig = EXTENSION_BLOCK_SIGNATURE["extension_sig"] extension_block_result["extension_sig"] = "0x" + hex(cv.Bytes2Int(extension_sig))[2:].zfill(8) if extension_sig in [b"\x00\x00\xef\xbe", b"\x19\x00\xef\xbe"]: (EXTENSION_BLOCK_0000, pos) = cv.FormatParser(_extension_block, data_format.EXTENSION_BLOCK_0000_FORMAT, 0) if extension_size == 14: # Unknown Data pass elif extension_size == 42: mapped_guid1 = cv.GUID2Text(EXTENSION_BLOCK_0000["folder_type_id1"]) mapped_guid2 = cv.GUID2Text(EXTENSION_BLOCK_0000["folder_type_id2"]) extension_block_result["mapped_guid"] = [mapped_guid1, mapped_guid2] else: raise ExtensionBlockFormatError("New BEEF0000, BEEF0019 block size.") elif extension_sig == b"\x03\x00\xef\xbe": (EXTENSION_BLOCK_0003, pos) = cv.FormatParser(_extension_block, data_format.EXTENSION_BLOCK_0003_FORMAT, 0) extension_block_result["mapped_guid"] = cv.GUID2Text(EXTENSION_BLOCK_0003["guid"]) elif extension_sig == b"\x04\x00\xef\xbe": extension_block_result = FileExtensionBlockParser(_extension_block, extension_version, extension_block_result) elif extension_sig == b"\x13\x00\xef\xbe": extension_block_result["comment"] = "Unknown extension block." elif extension_sig == b"\x26\x00\xef\xbe": (EXTENSION_BLOCK_0026, pos) = cv.FormatParser(_extension_block, data_format.EXTENSION_BLOCK_0026_FORMAT, 0) extension_block_result["ctime"] = cv.TSWin64bit(EXTENSION_BLOCK_0026["win64_ctime"]) extension_block_result["mtime"] = cv.TSWin64bit(EXTENSION_BLOCK_0026["win64_mtime"]) extension_block_result["atime"] = cv.TSWin64bit(EXTENSION_BLOCK_0026["win64_atime"]) elif extension_sig == b"\x27\x00\xef\xbe": (EXTENSION_BLOCK, pos) = cv.FormatParser(_extension_block, data_format.EXTENSION_BLOCK_SIGNATURE_FORMAT, 0) extension_data = EXTENSION_BLOCK["extension_data"] # TODO : SPS 파싱 끝나면, 여기에 반영하기. parse_sps_block.Parse(extension_data) else: sig = repr(extension_sig)[1:].replace("'", "") raise ExtensionBlockFormatError("New extension block (%s)" %sig) return extension_block_result