Beispiel #1
0
def decrypt_Metadata(item, df_meta):
	if item['keyclass'] >=6 :
		bplist = BytesIO(item['encryptedMetadata_wrappedKey'])
		plist = ccl_bplist.load(bplist)
		metaDataWrappedKeyDeserialized = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
		authCode = metaDataWrappedKeyDeserialized['root']['SFAuthenticationCode']
		iv   = metaDataWrappedKeyDeserialized['root']['SFInitializationVector']
		ciphertext = metaDataWrappedKeyDeserialized['root']['SFCiphertext']
		unwrapped_metadata_key = unwrap_key(
			df_meta[df_meta.keyclass == int(item['keyclass'])].iloc[0].data, 
			item['keyclass']
			)
		gcm = AES.new(unhexlify(unwrapped_metadata_key)[:32], AES.MODE_GCM, iv)
		metadata_key = gcm.decrypt_and_verify(ciphertext, authCode)

		bplist = BytesIO(item['encryptedMetadata_ciphertext'])
		plist = ccl_bplist.load(bplist)
		metaDataDeserialized = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
		authCode = metaDataDeserialized['root']['SFAuthenticationCode']
		iv   = metaDataDeserialized['root']['SFInitializationVector']
		ciphertext = metaDataDeserialized['root']['SFCiphertext']

		gcm = AES.new(metadata_key[:32], AES.MODE_GCM, iv)
		decrypted = gcm.decrypt_and_verify(ciphertext, authCode)
		der_data = decode(decrypted)[0]
		item['decrypted'] = {}
		for k in der_data:
			if 'Octet' in str(type(k[1])):
				item['decrypted'][str(k[0])] = bytes(k[1])
			else:
				item['decrypted'][str(k[0])] = str(k[1])


	return item
def ParseSFL2(MRUFile):
    itemsLinkList = []
    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plistfile.close()
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)
        if plist_objects["root"]["NS.keys"][0] == "items":
            items = plist_objects["root"]["NS.objects"][0]["NS.objects"]
            for n, item in enumerate(items):
                attribute_keys = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.keys"]
                attribute_values = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.objects"]
                attributes = dict(zip(attribute_keys, attribute_values))
                if "Bookmark" in attributes:
                    if isinstance(attributes["Bookmark"], str):
                        itemLink = BLOBParser_human(attributes["Bookmark"])
                    else:
                        itemLink = BLOBParser_human(
                            attributes["Bookmark"]['NS.data'])
                    itemsLinkList.append(itemLink)
            return itemsLinkList
    except Exception as e:
        print e
Beispiel #3
0
def ParseSFL(MRUFile):
    
    plistfile = open(MRUFile, "rb")
    plist = ccl_bplist.load(plistfile)
    plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)

    if plist_objects["root"]["NS.objects"][1]["NS.keys"][0] == "com.apple.LSSharedFileList.MaxAmount":
        numberOfItems = plist_objects["root"]["NS.objects"][1]["NS.objects"][0]
        print "Max number of recent items in this plist: " + str(numberOfItems)

    if plist_objects["root"]["NS.keys"][2] == "items":
        items = plist_objects["root"]["NS.objects"][2]["NS.objects"] 
        for n,item in enumerate(items):
            print"    [Item Number: " + str(n) +  " | Order: " + str(item["order"]) + "] Name:'" + item["name"] + "' (URL:'" + item["URL"]['NS.relative'] + "'')"
            
            #UNCOMMENT FOR UNIQUE IDENTIFIER HEXDUMP
            #print "----------------------------------------------------------------------------"
            #print "Hexdump of Unique Identifier: "
            #print hexdump.hexdump(item["uniqueIdentifier"]["NS.uuidbytes"])
            #print "----------------------------------------------------------------------------"

            if args.blob == True:
                print "----------------------------------------------------------------------------"
                print "Hexdump of Bookmark BLOB: "
                hexdump_blob =  hexdump.hexdump(item["bookmark"])
                print hexdump_blob
                print "----------------------------------------------------------------------------"
Beispiel #4
0
def get_login_items_entries(btm_file):
    with open(btm_file, 'rb') as fp:
        plist = ccl_bplist.load(fp)
        ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)
        ccl_bplist.set_object_converter(
            ccl_bplist.NSKeyedArchiver_common_objects_convertor)
        return ns_keyed_archiver_obj['root']['backgroundItems'][
            'allContainers']
Beispiel #5
0
def ParseSFL2_FavoriteVolumes(MRUFile):
    
    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)

        print "Item number has no bearing upon time of usage."
        print "Plist Properties:"
        if plist_objects["root"]["NS.keys"][1] == "properties":

            properties_keys = plist_objects["root"]["NS.objects"][1]["NS.keys"]
            properties_values = plist_objects["root"]["NS.objects"][1]["NS.objects"]
            properties = dict(zip(properties_keys,properties_values))
            for key in properties:
                print  "    " + key + ": " + str(properties[key])

        if plist_objects["root"]["NS.keys"][0] == "items":
            items = plist_objects["root"]["NS.objects"][0]["NS.objects"] 

            for n,item in enumerate(items):
                attribute_keys = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.keys"]
                attribute_values = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.objects"]
                attributes = dict(zip(attribute_keys,attribute_values))
                try:
                    uuid = attributes["uuid"]
                except:
                    uuid = "No 'UUID' Attribute"
                
                try:
                    visability = str(attributes["visibility"])
                except:
                    visability = "No 'Visability' Attribute"

                try:
                    name = attributes["Name"]
                except:
                    name = "No 'Name' Attribute (Use BLOB parser for name)"

                print "\n    [Item Number: " + str(n) +  " | (UUID:'" + uuid + "') | Visibility: " + visability + "] Name: '" + name + "'"

                if attributes["CustomItemProperties"]:
                    CIP_keys = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.objects"][1]["NS.keys"]
                    CIP_values = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.objects"][1]["NS.objects"]
                    CIP_attributes = dict(zip(CIP_keys,CIP_values))
                    print "\tCustomItemProperties:"
                    for key in CIP_attributes:
                        print  "\t  " + key + ": " + str(CIP_attributes[key])

                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = attributes["Bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob) 
                    BLOB_hex(blob)
    except:
        print "Cannot open file: " + MRUFile
Beispiel #6
0
def ParseSFL2(MRUFile):

    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)

        try:
            if plist_objects["root"]["NS.objects"][1]["NS.keys"][
                    0] == "com.apple.LSSharedFileList.MaxAmount":
                numberOfItems = plist_objects["root"]["NS.objects"][1][
                    "NS.objects"][0]
                print("Max number of recent items in this plist: " +
                      str(numberOfItems))
        except:
            pass

        if plist_objects["root"]["NS.keys"][0] == "items":
            items = plist_objects["root"]["NS.objects"][0]["NS.objects"]

            for n, item in enumerate(items):
                attribute_keys = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.keys"]
                attribute_values = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.objects"]
                attributes = dict(list(zip(attribute_keys, attribute_values)))
                try:
                    uuid = attributes["uuid"]
                except:
                    uuid = "No 'UUID' Attribute"

                try:
                    visability = str(attributes["visibility"])
                except:
                    visability = "No 'Visability' Attribute"

                try:
                    name = attributes["Name"]
                except:
                    name = "No 'Name' Attribute (Use BLOB parser for name)"

                print("    [Item Number: " + str(n) + " | (UUID:'" + uuid +
                      "') | Visibility: " + visability + "] Name:'" + name +
                      "'")

                # Unknown "CustomItemProperties" - Only seen blank, uncomment to see details.
                # print attributes["CustomItemProperties"]
                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = attributes["Bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob)
                    BLOB_hex(blob)
    except:
        print("Cannot open file: " + MRUFile)
Beispiel #7
0
def ParseSFL2(MRUFile):
    
    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)

        try:
            if plist_objects["root"]["NS.objects"][1]["NS.keys"][0] == "com.apple.LSSharedFileList.MaxAmount":
                numberOfItems = plist_objects["root"]["NS.objects"][1]["NS.objects"][0]
                print "Max number of recent items in this plist: " + str(numberOfItems)
        except:
            pass

        if plist_objects["root"]["NS.keys"][0] == "items":
            items = plist_objects["root"]["NS.objects"][0]["NS.objects"] 

            for n,item in enumerate(items):
                attribute_keys = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.keys"]
                attribute_values = plist_objects["root"]["NS.objects"][0]["NS.objects"][n]["NS.objects"]
                attributes = dict(zip(attribute_keys,attribute_values))
                try:
                    uuid = attributes["uuid"]
                except:
                    uuid = "No 'UUID' Attribute"
                
                try:
                    visability = str(attributes["visibility"])
                except:
                    visability = "No 'Visability' Attribute"

                try:
                    name = attributes["Name"]
                except:
                    name = "No 'Name' Attribute (Use BLOB parser for name)"

                print "    [Item Number: " + str(n) +  " | (UUID:'" + uuid + "') | Visibility: " + visability + "] Name:'" + name + "'"

                #Unknown "CustomItemProperties" - Only seen blank, uncomment to see details.
                #print attributes["CustomItemProperties"]
                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = attributes["Bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob) 
                    BLOB_hex(blob)
    except:
        print "Cannot open file: " + MRUFile
Beispiel #8
0
def main():
    parser = argparse.ArgumentParser(
        description=
        "NeXTSTEP Interface Builder (NIB) file parser prints a list of all connections defined in a NIB file"
    )
    parser.add_argument('nibfile', help='path to a NIB file')

    args = parser.parse_args()
    with open(args.nibfile, "rb") as rp:
        plist = ccl_bplist.load(rp)

    nib = ccl_bplist.deserialise_NsKeyedArchiver(plist)

    ibcons = nib['IB.objectdata']['NSConnections']['NS.objects']
    for i in range(len(ibcons)):
        if 'NSLabel' not in ibcons[i]:
            continue

        lbl = ibcons[i]['NSLabel']
        id = dict(nib['IB.objectdata']['NSConnections'])['NS.objects'][i].value
        sname = "NA"
        srcid = "NA"
        dname = "NA"
        dstid = "NA"

        if 'NSSource' in ibcons[i]:
            srcid = dict(ibcons[i])['NSSource'].value
            src = ibcons[i]['NSSource']
            sname = getClassName(src)
            scontents = getContents(src)

        if 'NSDestination' in ibcons[i]:
            dstid = dict(ibcons[i])['NSDestination'].value
            dst = ibcons[i]['NSDestination']
            dname = getClassName(dst)
            dcontents = getContents(dst)

        out = "%d: %s (%s) - %s " % (i, lbl, id, sname)
        if scontents:
            out += "[%s] " % scontents

        out += "(%s) ---> %s " % (srcid, dname)
        if dcontents:
            out += "[%s] " % dcontents

        out += "(%s)" % dstid
        print(out.encode("utf-8"))
Beispiel #9
0
def process_nsa_plist(input_path, f):
    '''Returns a deserialized plist. Input is NSKeyedArchive file. input_path field is not used'''
    global use_as_library
    try:
        if not use_as_library:
            print('Reading file .. ' + input_path)
        f = extract_nsa_plist(f)
        ccl_bplist.set_object_converter(
            ccl_bplist.NSKeyedArchiver_common_objects_convertor)
        plist = ccl_bplist.load(f)
        ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)

        root_names = getRootElementNames(f)
        top_level = []

        for root_name in root_names:
            root = ns_keyed_archiver_obj[root_name]
            if not use_as_library:
                print('Trying to deserialize binary plist $top = {}'.format(
                    root_name))
            if isinstance(root, dict):
                plist = {}
                recurseCreatePlist(plist, root,
                                   ns_keyed_archiver_obj.object_table)
                if root_name.lower() != 'root':
                    plist = {root_name: plist}
            elif isinstance(root, list):
                plist = []
                recurseCreatePlist(plist, root,
                                   ns_keyed_archiver_obj.object_table)
                if root_name.lower() != 'root':
                    plist = {root_name: plist}
            else:
                plist = {root_name: root}

            if len(root_names) == 1:
                top_level = plist
            else:  # > 1
                top_level.append(plist)

    except Exception as ex:
        print('Had an exception (error)')
        traceback.print_exc()

    return top_level
Beispiel #10
0
def DeserializeNSKeyedArchive(file_pointer):
    '''Pass an open file pointer (file must be opened as rb) and get a dict or list representation
       of the plist returned back
    '''
    ccl_bplist.set_object_converter(
        ccl_bplist.NSKeyedArchiver_common_objects_convertor)
    plist = ccl_bplist.load(file_pointer)
    ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
        plist, parse_whole_structure=True)
    root = ns_keyed_archiver_obj['root']

    if isinstance(root, dict):
        plist = {}
    else:
        plist = []

    recurseCreatePlist(plist, root)
    return plist
def GetProfileInfo(f):
    profiles = []
    ccl_bplist.set_object_converter(ccl_bplist.NSKeyedArchiver_common_objects_convertor)
    plist = ccl_bplist.load(f)
    ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
    md = ns_keyed_archiver_obj['mapData']

    for item in md:
        if md[item]['NSEntityName'] == 'MCX_Profile':
            profile_attribs = md[item]['NSAttributeValues']

            attributes = []
            attributes.append(profile_attribs[0]) # UUID if domain user, else name
            attributes.append(profile_attribs[1]) # user name
            attributes.append(profile_attribs[2]) # date first logged in (if domain user), else name
            # Not interpreting other attributes at this time!

            profiles.append(attributes)
    return profiles
def ParseSFL(MRUFile):
    itemsLinkList = []
    try:
        with open(MRUFile, "rb") as plistfile:
            plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)
        if plist_objects["root"]["NS.keys"][2] == "items":
            items = plist_objects["root"]["NS.objects"][2]["NS.objects"]
            for n, item in enumerate(items):
                # item["URL"]['NS.relative'] file:///xxx/xxx/xxx
                filePath = item["URL"]['NS.relative'][7:]
                # /xxx/xxx/xxx/ the last "/" make basename func not work
                if filePath[-1] == '/':
                    filePath = filePath[:-1]
                itemsLinkList.append(filePath)
            return itemsLinkList
    except Exception as e:
        print(e)
Beispiel #13
0
def ParseSFL(MRUFile):

    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)

        try:
            if plist_objects["root"]["NS.objects"][1]["NS.keys"][
                    0] == "com.apple.LSSharedFileList.MaxAmount":
                numberOfItems = plist_objects["root"]["NS.objects"][1][
                    "NS.objects"][0]
                print "Max number of recent items in this plist: " + str(
                    numberOfItems)
        except:
            pass

        if plist_objects["root"]["NS.keys"][2] == "items":
            items = plist_objects["root"]["NS.objects"][2]["NS.objects"]
            for n, item in enumerate(items):
                try:
                    name = item["name"]
                except:
                    name = "No 'name' Key"

                print "    [Item Number: " + str(n) + " | Order: " + str(
                    item["order"]) + "] Name:'" + name + "' (URL:'" + item[
                        "URL"]['NS.relative'] + "')"

                #UNCOMMENT FOR UNIQUE IDENTIFIER HEXDUMP
                #print "----------------------------------------------------------------------------"
                #print "Hexdump of Unique Identifier: "
                #print hexdump.hexdump(item["uniqueIdentifier"]["NS.uuidbytes"])
                #print "----------------------------------------------------------------------------"
                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = item["bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob)
                    BLOB_hex(blob)
    except:
        print "Cannot open file: " + MRUFile
def ParseSFL2(MRUFile):
    itemsLinkList = []
    try:
        with open(MRUFile, "rb") as plistfile:
            plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)
        if plist_objects["root"]["NS.keys"][0] == "items":
            for item in plist_objects["root"]["NS.objects"][0]["NS.objects"]:
                attributes = dict(zip(item["NS.keys"], item["NS.objects"]))
                if "Bookmark" in attributes:
                    if isinstance(attributes["Bookmark"], str):
                        itemLink = BLOBParser_human(attributes["Bookmark"])
                    else:
                        itemLink = BLOBParser_human(
                            attributes["Bookmark"]['NS.data'])
                    itemsLinkList.append(itemLink)
            return itemsLinkList
    except Exception as e:
        print e
Beispiel #15
0
def decrypt_secretData(item):
	if item['keyclass'] >=6 :
		unwrapped_key = unwrap_key(item['encryptedSecretData_wrappedKey'], item['keyclass'])
		bplist = BytesIO(item['encryptedSecretData_ciphertext'])
		plist = ccl_bplist.load(bplist)
		secretDataDeserialized = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
		authCode = secretDataDeserialized['root']['SFAuthenticationCode']
		iv   = secretDataDeserialized['root']['SFInitializationVector']
		ciphertext = secretDataDeserialized['root']['SFCiphertext']

		gcm = AES.new(unhexlify(unwrapped_key)[:32], AES.MODE_GCM, iv)
		decrypted = gcm.decrypt_and_verify(ciphertext, authCode)

		der_data = decode(decrypted)[0]
		for k in der_data:
			if 'Octet' in str(type(k[1])):
				item['decrypted'].update({str(k[0]) : bytes(k[1])})
			else:
				item['decrypted'].update({str(k[0]) : str(k[1])})
	return item
Beispiel #16
0
def main():
    global usage
    if sys.version_info.major == 2:
        print(
            'ERROR-This will not work with python2. Please run again with python3!'
        )
        return
    argc = len(sys.argv)

    if argc < 2 or sys.argv[1].lower() == '-h':
        print(usage)
        return

    input_path = sys.argv[1]
    if not os.path.exists(input_path):
        print('Error, file does not exist! Check file path!\r\n')
        print(usage)
        return

    # All OK, process the file now
    try:
        f = open(input_path, 'rb')
        print('Reading file .. ' + input_path)
        ccl_bplist.set_object_converter(
            ccl_bplist.NSKeyedArchiver_common_objects_convertor)
        plist = ccl_bplist.load(f)
        ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)
        root = ns_keyed_archiver_obj['root']

        print('Trying to deserialize binary plist ..')
        plist = {}
        recurseCreatePlist(plist, root)
        print('Writing it back out as .. ' + input_path +
              '_deserialized.plist')
        biplist.writePlist(plist, input_path + '_deserialized.plist')
        print('Done !')
    except Exception as ex:
        print('Had an exception (error)')
        traceback.print_exc()
Beispiel #17
0
def _unpack_top_level(f, plist_biplist_obj):
    '''Does the work to actually unpack the NSKeyedArchive's top level. Returns 
    the top level object. 
    '''
    ccl_bplist.set_object_converter(
        ccl_bplist.NSKeyedArchiver_common_objects_convertor)
    plist = ccl_bplist.load(f)
    ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
        plist, parse_whole_structure=True)

    root_names = _get_root_element_names(plist_biplist_obj)
    top_level = []

    for root_name in root_names:
        root = ns_keyed_archiver_obj[root_name]
        if isinstance(root, dict):
            plist = {}
            _recurse_create_plist(plist, root,
                                  ns_keyed_archiver_obj.object_table)
            if root_name.lower() != 'root':
                plist = {root_name: plist}
        elif isinstance(root, list):
            plist = []
            _recurse_create_plist(plist, root,
                                  ns_keyed_archiver_obj.object_table)
            if root_name.lower() != 'root':
                plist = {root_name: plist}
        else:
            plist = {root_name: root}

        if len(root_names) == 1:
            top_level = plist
        else:  # > 1
            top_level.append(plist)

    return top_level
Beispiel #18
0
def ParseSFL(MRUFile):
    
    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)

        try:
            if plist_objects["root"]["NS.objects"][1]["NS.keys"][0] == "com.apple.LSSharedFileList.MaxAmount":
                numberOfItems = plist_objects["root"]["NS.objects"][1]["NS.objects"][0]
                print "Max number of recent items in this plist: " + str(numberOfItems)
        except:
            pass

        if plist_objects["root"]["NS.keys"][2] == "items":
            items = plist_objects["root"]["NS.objects"][2]["NS.objects"] 
            for n,item in enumerate(items):
                try:
                    name = item["name"]
                except:
                    name = "No 'name' Key"

                print"    [Item Number: " + str(n) +  " | Order: " + str(item["order"]) + "] Name:'" + name + "' (URL:'" + item["URL"]['NS.relative'] + "')"
                
                #UNCOMMENT FOR UNIQUE IDENTIFIER HEXDUMP
                #print "----------------------------------------------------------------------------"
                #print "Hexdump of Unique Identifier: "
                #print hexdump.hexdump(item["uniqueIdentifier"]["NS.uuidbytes"])
                #print "----------------------------------------------------------------------------"
                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = item["bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob) 
                    BLOB_hex(blob)
    except:
        print "Cannot open file: " + MRUFile
Beispiel #19
0
def knowledgec(filefound):
	print(f'Incepted bplist extractions in knowlwdgeC.db executing.')

	iOSversion = versionf
	supportediOS = ['11', '12', '13']

	if iOSversion not in supportediOS:
		print ("Unsupported version"+iOSversion)
		return()
		
	extension = '.bplist'
	dump = True
	#create directories
	outpath = reportfolderbase+'KnowledgeC Protobuf/'


	try: 
		os.mkdir(outpath)
		os.mkdir(outpath+"clean/")
		os.mkdir(outpath+"/dirty")
	except OSError:  
		print("Error making directories")
		
	#connect sqlite databases
	db = sqlite3.connect(filefound[0])
	cursor = db.cursor()

	#variable initializations
	dirtcount = 0
	cleancount = 0
	intentc = {}
	intentv = {}

	cursor.execute('''
	SELECT
	Z_PK,
	Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION,
	Z_DKINTENTMETADATAKEY__INTENTCLASS,
	Z_DKINTENTMETADATAKEY__INTENTVERB
	FROM ZSTRUCTUREDMETADATA
	WHERE Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION is not null
	''')

	all_rows = cursor.fetchall()

	for row in all_rows:
		pkv = str(row[0])
		pkvplist = pkv+extension
		f = row[1]
		intentclass = str(row[2])
		intententverb = str(row[3])
		output_file = open(outpath+'/dirty/D_Z_PK'+pkvplist, 'wb') #export dirty from DB
		output_file.write(f)
		output_file.close()	

		g = open(outpath+'/dirty/D_Z_PK'+pkvplist, 'rb')
		plistg = ccl_bplist.load(g)
		
		if (iOSversion == '11'):
			ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plistg)	
			newbytearray = ns_keyed_archiver_obj
		if (iOSversion == '12'):
			ns_keyed_archiver_objg = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
			newbytearray = (ns_keyed_archiver_objg["NS.data"])
		if (iOSversion == '13'):
			ns_keyed_archiver_objg = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
			newbytearray = (ns_keyed_archiver_objg["NS.data"])

		dirtcount = dirtcount+1
			
		binfile = open(outpath+'/clean/C_Z_PK'+pkvplist, 'wb')
		binfile.write(newbytearray)
		binfile.close()	
		
		#add to dictionaries
		intentc['C_Z_PK'+pkvplist] = intentclass
		intentv['C_Z_PK'+pkvplist] = intententverb
		
		cleancount = cleancount+1

	h = open(outpath+'/Report.html', 'w')	
	h.write('<html><body>')
	h.write('<h2>iOS ' + iOSversion + ' - KnowledgeC ZSTRUCTUREDMETADATA bplist report</h2>')
	h.write ('<style> table, th, td {border: 1px solid black; border-collapse: collapse;}</style>')
	h.write('<br/>')

	for filename in glob.glob(outpath+'/clean/*'+extension):	
		p = open(filename, 'rb')
		cfilename = os.path.basename(filename)
		plist = ccl_bplist.load(p)
		ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)#deserialize clean
		#Get dictionary values
		A = intentc.get(cfilename)
		B = intentv.get(cfilename)
		
		if A is None:
			A = 'No value'
		if B is None:
			A = 'No value'
		
		#print some values from clean bplist
		if iOSversion == '13':
			NSdata = (ns_keyed_archiver_obj['root']['intent']['backingStore']['bytes'])
		else:
			NSdata = (ns_keyed_archiver_obj["root"]["intent"]["backingStore"]["data"]["NS.data"])
		
		parsedNSData = ""
		#Default true
		if dump == True:	
			nsdata_file = outpath+'/clean/'+cfilename+'_nsdata.bin'
			binfile = open(nsdata_file, 'wb')
			if iOSversion == '13':
				binfile.write(ns_keyed_archiver_obj['root']['intent']['backingStore']['bytes'])
			else:
				binfile.write(ns_keyed_archiver_obj["root"]["intent"]["backingStore"]["data"]["NS.data"])
			binfile.close()
			messages = ParseProto(nsdata_file)
			messages_json_dump = json.dumps(messages, indent=4, sort_keys=True, ensure_ascii=False)
			parsedNSData = str(messages_json_dump).encode(encoding='UTF-8',errors='ignore')
		
		NSstartDate = ccl_bplist.convert_NSDate((ns_keyed_archiver_obj["root"]["dateInterval"]["NS.startDate"]))
		NSendDate = ccl_bplist.convert_NSDate((ns_keyed_archiver_obj["root"]["dateInterval"]["NS.endDate"]))
		NSduration = ns_keyed_archiver_obj["root"]["dateInterval"]["NS.duration"]
		Siri = ns_keyed_archiver_obj["root"]["_donatedBySiri"]
		
		h.write(cfilename)
		h.write('<br />')
		h.write('Intent Class: '+str(A))
		h.write('<br />')
		h.write('Intent Verb: '+str(B))
		h.write('<br />')
		h.write('<table>')
		
		
		h.write('<tr>')
		h.write('<th>Data type</th>')
		h.write('<th>Value</th>')
		h.write('</tr>')
		
		#Donated by Siri
		h.write('<tr>')
		h.write('<td>Siri</td>')
		h.write('<td>'+str(Siri)+'</td>')
		h.write('</tr>')
			
		#NSstartDate
		h.write('<tr>')
		h.write('<td>NSstartDate</td>')
		h.write('<td>'+str(NSstartDate)+' Z</td>')
		h.write('</tr>')
		
		#NSsendDate
		h.write('<tr>')
		h.write('<td>NSendDate</td>')
		h.write('<td>'+str(NSendDate)+' Z</td>')
		h.write('</tr>')
		
		#NSduration
		h.write('<tr>')
		h.write('<td>NSduration</td>')
		h.write('<td>'+str(NSduration)+'</td>')
		h.write('</tr>')
		
		#NSdata
		h.write('<tr>')
		h.write('<td>NSdata</td>')
		h.write('<td>'+str(NSdata)+'</td>')
		h.write('</tr>')

		#NSdata better formatting
		if parsedNSData:
			h.write('<tr>')
			h.write('<td>NSdata - Protobuf Decoded</td>')
			h.write('<td><pre id=\"json\">'+str(parsedNSData).replace('\\n', '<br>')+'</pre></td>')
			h.write('</tr>')
		else:
			#This will only run if -nd is used
			h.write('<tr>')
			h.write('<td>NSdata - Protobuf</td>')
			h.write('<td>'+str(NSdata).replace('\\n', '<br>')+'</td>')
			h.write('</tr>')	
		
		h.write('<table>')
		h.write('<br />')
		
		#print(NSstartDate)
		#print(NSendDate)
		#print(NSduration)
		#print(NSdata)
		#print('')


	print("")	
	print("iOS - KnowledgeC ZSTRUCTUREDMETADATA bplist extractor")
	print("By: @phillmoore & @AlexisBrignoni")
	print("thinkdfir.com & abrignoni.com")
	print("")
	print("Bplists from the Z_DKINTENTMETADATAKEY__SERIALIZEDINTERACTION field.")
	print("Exported bplists (dirty): "+str(dirtcount))
	print("Exported bplists (clean): "+str(cleancount))
	print("")
	print(f'Triage report completed. See Reports.html.')
	print('Incepted bplist extractions in knowlwdgeC.db completed')
Beispiel #20
0
def get_protonMail(files_found, report_folder, seeker):
    data_list = []

    p = Path(__file__).parents[1]

    my_path = Path(p).joinpath('keychain')

    #platform = is_platform_windows()
    #if platform:
    #  my_path = my_path.replace('/', '\\')

    if len(os.listdir(my_path)) == 1:
        logfunc("No keychain provided")
        return

    else:
        file = os.listdir(my_path)
        for x in file:
            if x.endswith('plist'):
                keychain_plist_path = Path(my_path).joinpath(x)

    for file_found in files_found:
        if 'group.ch.protonmail.protonmail.plist' in file_found:
            plist_name = file_found
        if file_found.endswith('ProtonMail.sqlite'):
            db_name = file_found

    with open(keychain_plist_path, 'rb') as f:
        plist = plistlib.load(f)

    keychainVal = {}
    if type(plist) == list:
        for dd in plist:
            if type(dd) == dict:
                if 'svce' in dd:
                    if 'protonmail' in str(dd['svce']):
                        #print(dd)
                        keychainVal[dd['acct']] = dd['v_Data']
    else:
        for d in plist:
            for dd in plist[d]:
                if type(dd) == dict:
                    if 'svce' in dd:
                        if 'protonmail' in str(dd['svce']):
                            #print(dd)
                            keychainVal[dd['acct']] = dd['v_Data']

    mainKey = keychainVal[b'NoneProtection']
    IVsize = 16

    def decryptWithMainKey(encrypted):
        iv = encrypted[:IVsize]
        cipher = AES.new(mainKey, AES.MODE_CTR, initial_value=iv, nonce=b'')
        return cipher.decrypt(encrypted[IVsize:])

    with open(plist_name, 'rb') as p:
        prefplist = plistlib.load(p)

    enc_val = prefplist.get('authKeychainStoreKeyProtectedWithMainKey',
                            'empty')
    if enc_val != 'empty':
        pass
    elif keychainVal[b'authKeychainStoreKeyProtectedWithMainKey']:
        enc_val = keychainVal[b'authKeychainStoreKeyProtectedWithMainKey']
    else:
        logfunc(
            'Decryption key not found in the keychain or the application plist.'
        )
        return

    dec_val = decryptWithMainKey(enc_val)

    keychainStorePlist1 = ccl_bplist.load(BytesIO(dec_val))
    keychainStorePlist = ccl_bplist.load(BytesIO(keychainStorePlist1[0]))
    keychainStore = ccl_bplist.deserialise_NsKeyedArchiver(
        keychainStorePlist, parse_whole_structure=True)
    privateKeyCoderKey = keychainStore['root']['NS.objects'][0][
        'privateKeyCoderKey']

    key, _ = pgpy.PGPKey.from_blob(privateKeyCoderKey)
    pwdKey = keychainStore['root']['NS.objects'][0]['AuthCredential.Password']

    def decrypt_message(encm):
        if ('-----BEGIN PGP MESSAGE-----') in encm:
            with key.unlock(pwdKey):
                assert key.is_unlocked
                message_from_blob = pgpy.PGPMessage.from_blob(encm)
                decm = key.decrypt(message_from_blob).message
                #print(decm)
                return html.unescape(
                    decm.encode('cp1252',
                                errors='ignore').decode('utf8',
                                                        errors='ignore'))
        else:
            return encm

    def decrypt_attachment(proton_path, out_path, key, pwdKey, keyPacket,
                           encfilename, decfilename):
        att = None
        for r, _, f in os.walk(proton_path):
            for file in f:
                if encfilename in file:
                    att = os.path.join(r, file)
                    break
        if att:
            with key.unlock(pwdKey):
                assert key.is_unlocked
                with open(att, 'rb') as attfh:
                    buf = b64decode(keyPacket)
                    buf += attfh.read()
                    att_from_blob = pgpy.PGPMessage.from_blob(buf)
                    decatt = key.decrypt(att_from_blob).message
                    itemnum = str(random.random())
                    with open(os.path.join(out_path, itemnum + decfilename),
                              'wb') as outatt:
                        outatt.write(decatt)
                    return os.path.join(out_path, itemnum + decfilename)

        return None

    db = open_sqlite_db_readonly(db_name)
    cursor = db.cursor()
    cursor.execute('''SELECT
    ZMESSAGE.ZTIME,
    ZMESSAGE.ZBODY,
    ZMESSAGE.ZMIMETYPE,
    ZMESSAGE.ZTOLIST,
    ZMESSAGE.ZREPLYTOS,
    ZMESSAGE.ZSENDER,
    ZMESSAGE.ZTITLE,
    ZMESSAGE.ZISENCRYPTED,
    ZMESSAGE.ZNUMATTACHMENTS,
    ZATTACHMENT.ZFILESIZE,
    ZATTACHMENT.ZFILENAME,
    ZATTACHMENT.ZMIMETYPE,
    ZATTACHMENT.ZHEADERINFO,
    ZATTACHMENT.ZLOCALURL,
    ZATTACHMENT.ZKEYPACKET
    FROM ZMESSAGE
    LEFT JOIN ZATTACHMENT ON ZMESSAGE.Z_PK = ZATTACHMENT.ZMESSAGE
              ''')

    all_rows = cursor.fetchall()
    data_list = []
    if len(all_rows) > 0:
        for row in all_rows:
            aggregatorto = ''
            aggregatorfor = ''

            time = row[0]
            decryptedtime = datetime.fromtimestamp(time + 978307200)

            decryptedbody = decrypt_message(row[1])

            mime = row[2]

            to = json.loads(plistlib.loads(decryptWithMainKey(row[3]))[0])
            for r in to:
                address = r['Address']
                name = r['Name']
                aggregatorto = f"{address} {name}"

            try:
                replyto = json.loads(
                    plistlib.loads(decryptWithMainKey(row[4]))[0])
                for r in replyto:
                    address = r['Address']
                    name = r['Name']
                    aggregatorfor = f"{address} {name}"
            except:
                aggregatorfor = ''

            try:
                sender = json.loads(
                    plistlib.loads(decryptWithMainKey(row[5]))[0])
                name = sender['Name']
                address = sender['Address']
                sender_info = f'{address} {name}'
            except:
                sender_info = '<Not Decoded>'

            title = plistlib.loads(decryptWithMainKey(row[6]))[0]

            isencrypted = row[7]

            ZNUMATTACHMENTS = row[8]

            ZFILESIZE = row[9]

            try:
                ZFILENAME = plistlib.loads(decryptWithMainKey(row[10]))[0]
            except:
                ZFILENAME = ""

            try:
                AMIMETYPE = plistlib.loads(decryptWithMainKey(row[11]))[0]
            except:
                AMIMETYPE = ""

            if row[12]:
                zheaderinfo = decryptWithMainKey(row[12])

            attpath = ''
            if row[13]:
                encfilename = plistlib.loads(
                    row[13])['$objects'][2].split('/')[-1]
                guidi = plistlib.loads(row[13])['$objects'][2].split('/')[-4]
                out_path = report_folder

                for match in files_found:
                    if f'/Data/Application/{guidi}/tmp/attachments' in match:
                        proton_path = match.split('/attachments')[0]
                        break
                    elif f'\\Data\\Application\\{guidi}\\tmp\\attachments' in match:
                        proton_path = match.split('\\attachments')[0]

                attpath = decrypt_attachment(proton_path, out_path, key,
                                             pwdKey, row[14], encfilename,
                                             ZFILENAME)

                mimetype = magic.from_file(attpath, mime=True)

                if 'video' in mimetype:
                    attpath = f'<video width="320" height="240" controls="controls"><source src="{attpath}" type="video/mp4">Your browser does not support the video tag.</video>'
                elif 'image' in mimetype:
                    attpath = f'<img src="{attpath}"width="300"></img>'
                else:
                    attpath = f'<a href="{attpath}"> Link to {mimetype} </>'

            data_list.append(
                (decryptedtime, sender_info, aggregatorto, aggregatorfor,
                 title, decryptedbody, mime, isencrypted, ZFILESIZE, attpath,
                 ZFILENAME, AMIMETYPE))

            encfilename = ''

    if len(data_list) > 0:
        report = ArtifactHtmlReport('Proton Mail - Decrypted Emails')
        report.start_artifact_report(report_folder,
                                     'Proton Mail - Decrypted Emails')
        report.add_script()
        data_headers = ('Timestamp', 'Sender', 'To', 'Reply To', 'Title',
                        'Body', 'Mime', 'Is encrypted?', 'File Size',
                        'Attachment', 'Decrypted Attachment Filename', 'Type')
        report.write_artifact_data_table(data_headers,
                                         data_list,
                                         file_found,
                                         html_no_escape=[
                                             'Sender', 'To', 'Reply To',
                                             'Body', 'File Name', 'Type',
                                             'Attachment'
                                         ])
        report.end_artifact_report()

        tsvname = 'Proton Mail - Decrypted Emails'
        tsv(report_folder, data_headers, data_list, tsvname)

        tlactivity = 'Proton Mail - Decrypted Emails'
        timeline(report_folder, tlactivity, data_list, data_headers)

    else:
        logfunc('No Proton Mail - Decrypted Emails')
def deserialize_plist(path_or_file):
    '''
        Returns a deserialized plist as a dictionary/list. 

        Parameters
        ----------
        path_or_file:
            Path or file-like object of an NSKeyedArchive file
        
        Returns
        -------
        A dictionary or list is returned depending on contents of 
        the plist

        Exceptions
        ----------
        nska_deserialize.DeserializeError, 
        biplist.NotBinaryPlistException, 
        ccl_bplist.BplistError,
        ValueError, 
        TypeError, 
        OSError, 
        OverflowError
    '''
    path = ''
    f = None
    if isinstance(path_or_file, str):
        path = path_or_file
        f = open(path, 'rb')
    else:  # its a file
        f = path_or_file

    f = _get_valid_nska_plist(f)
    ccl_bplist.set_object_converter(
        ccl_bplist.NSKeyedArchiver_common_objects_convertor)
    plist = ccl_bplist.load(f)
    ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(
        plist, parse_whole_structure=True)

    root_names = _get_root_element_names(f)
    top_level = []

    for root_name in root_names:
        root = ns_keyed_archiver_obj[root_name]
        if isinstance(root, dict):
            plist = {}
            _recurse_create_plist(plist, root,
                                  ns_keyed_archiver_obj.object_table)
            if root_name.lower() != 'root':
                plist = {root_name: plist}
        elif isinstance(root, list):
            plist = []
            _recurse_create_plist(plist, root,
                                  ns_keyed_archiver_obj.object_table)
            if root_name.lower() != 'root':
                plist = {root_name: plist}
        else:
            plist = {root_name: root}

        if len(root_names) == 1:
            top_level = plist
        else:  # > 1
            top_level.append(plist)

    return top_level
Beispiel #22
0
def ParseSFL2_FavoriteVolumes(MRUFile):

    try:
        plistfile = open(MRUFile, "rb")
        plist = ccl_bplist.load(plistfile)
        plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
            plist, parse_whole_structure=True)

        print("Item number has no bearing upon time of usage.")
        print("Plist Properties:")
        if plist_objects["root"]["NS.keys"][1] == "properties":

            properties_keys = plist_objects["root"]["NS.objects"][1]["NS.keys"]
            properties_values = plist_objects["root"]["NS.objects"][1][
                "NS.objects"]
            properties = dict(list(zip(properties_keys, properties_values)))
            for key in properties:
                print("    " + key + ": " + str(properties[key]))

        if plist_objects["root"]["NS.keys"][0] == "items":
            items = plist_objects["root"]["NS.objects"][0]["NS.objects"]

            for n, item in enumerate(items):
                attribute_keys = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.keys"]
                attribute_values = plist_objects["root"]["NS.objects"][0][
                    "NS.objects"][n]["NS.objects"]
                attributes = dict(list(zip(attribute_keys, attribute_values)))
                try:
                    uuid = attributes["uuid"]
                except:
                    uuid = "No 'UUID' Attribute"

                try:
                    visability = str(attributes["visibility"])
                except:
                    visability = "No 'Visability' Attribute"

                try:
                    name = attributes["Name"]
                except:
                    name = "No 'Name' Attribute (Use BLOB parser for name)"

                print("\n    [Item Number: " + str(n) + " | (UUID:'" + uuid +
                      "') | Visibility: " + visability + "] Name: '" + name +
                      "'")

                if attributes["CustomItemProperties"]:
                    CIP_keys = plist_objects["root"]["NS.objects"][0][
                        "NS.objects"][n]["NS.objects"][1]["NS.keys"]
                    CIP_values = plist_objects["root"]["NS.objects"][0][
                        "NS.objects"][n]["NS.objects"][1]["NS.objects"]
                    CIP_attributes = dict(list(zip(CIP_keys, CIP_values)))
                    print("\tCustomItemProperties:")
                    for key in CIP_attributes:
                        print("\t  " + key + ": " + str(CIP_attributes[key]))

                if "LSSharedFileList.RecentHosts" not in MRUFile:
                    blob = attributes["Bookmark"]
                    BLOBParser_raw(blob)
                    BLOBParser_human(blob)
                    BLOB_hex(blob)
    except:
        print("Cannot open file: " + MRUFile)
    \n\t\thexdump.py: https://pypi.python.org/pypi/hexdump\
    \n\t\tccl_bplist.py: https://github.com/jorik041/ccl-bplist'
        , prog='dump_freq_locs.py'
        , formatter_class=RawTextHelpFormatter)
    parser.add_argument('-output', choices=['k','c','e'], action="store", help="k=KML, c=CSV, e=EVERTHING")
    parser.add_argument('State_Model_Plist_File')
    args = parser.parse_args()

    global output_type
    output_type = None

    statemodelfile = args.State_Model_Plist_File

    plistfile = open(statemodelfile, "rb")
    plist = ccl_bplist.load(plistfile)
    plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
    objects = plist_objects["root"]["stateModelLut"]['NS.objects']
    metadata_objects = plist["$top"]
    meta_uids = plist_objects["root"]

    if args.output == 'c' or args.output == 'e':
        output_type = 'c'
        with open('dump_freq_locs_output.csv', 'wb') as csvfile:
            loccsv = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
            loccsv.writerow(['Timestamp', 'Timestamp Type','Data Type', 'Latitude', 'Longitude', 'Other Data'])

            getMetadata()
            RTVisitMonitor()
            getLocations()

    if args.output == 'k' or args.output =='e':
Beispiel #24
0
 def decode(self, plist):
     try:
         return ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=True)
     except:
         return None
Beispiel #25
0
for row in all_rows:
	pkv = str(row[0])
	pkvplist = pkv+extension
	f = row[1]
	intentclass = str(row[2])
	intententverb = str(row[3])
	output_file = open('./'+foldername+'/dirty/D_Z_PK'+pkvplist, 'wb') #export dirty from DB
	output_file.write(f)
	output_file.close()	

	g = open('./'+foldername+'/dirty/D_Z_PK'+pkvplist, 'rb')
	plistg = ccl_bplist.load(g)
	
	if (iOSversion == '11'):
		ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plistg)	
		newbytearray = ns_keyed_archiver_obj
	if (iOSversion == '12'):
		ns_keyed_archiver_objg = ccl_bplist.deserialise_NsKeyedArchiver(plistg)
		newbytearray = (ns_keyed_archiver_objg["NS.data"])

	dirtcount = dirtcount+1
		
	binfile = open('./'+foldername+'/clean/C_Z_PK'+pkvplist, 'wb')
	binfile.write(newbytearray)
	binfile.close()	
	
	#add to dictionaries
	intentc['C_Z_PK'+pkvplist] = intentclass
	intentv['C_Z_PK'+pkvplist] = intententverb
	
                                     formatter_class=RawTextHelpFormatter)
    parser.add_argument('-output',
                        choices=['k', 'c', 'e'],
                        action="store",
                        help="k=KML, c=CSV, e=EVERTHING")
    parser.add_argument('State_Model_Plist_File')
    args = parser.parse_args()

    global output_type
    output_type = None

    statemodelfile = args.State_Model_Plist_File

    plistfile = open(statemodelfile, "rb")
    plist = ccl_bplist.load(plistfile)
    plist_objects = ccl_bplist.deserialise_NsKeyedArchiver(
        plist, parse_whole_structure=True)
    objects = plist_objects["root"]["stateModelLut"]['NS.objects']
    metadata_objects = plist["$top"]
    meta_uids = plist_objects["root"]

    if args.output == 'c' or args.output == 'e':
        output_type = 'c'
        with open('dump_freq_locs_output.csv', 'wb') as csvfile:
            loccsv = csv.writer(csvfile,
                                delimiter=',',
                                quotechar='|',
                                quoting=csv.QUOTE_MINIMAL)
            loccsv.writerow([
                'Timestamp', 'Timestamp Type', 'Data Type', 'Latitude',
                'Longitude', 'Other Data'
            ])
Beispiel #27
0
def applicationstate(filefound):
	iOSversion = versionf
	print(f'ApplicationState.db queries executing.')
	outpath = reportfolderbase +'Application State/'
	
	try: 
		os.mkdir(outpath)
		os.mkdir(outpath+"exported-dirty/")
		os.mkdir(outpath+"exported-clean/")
	except OSError:  
		print("Error making directories")
	
	freepath = 1
	
	for pathfile in filefound:
		if isinstance(pathfile, pathlib.PurePath):
			freepath = os.path.abspath(pathfile)
			if freepath.endswith('.db'):
				apstatefiledb = freepath
		elif pathfile.endswith('.db'):		
			apstatefiledb = pathfile	

	#connect sqlite databases
	db = sqlite3.connect(apstatefiledb)
	cursor = db.cursor()

	cursor.execute('''
		select
		application_identifier_tab.[application_identifier],
		kvs.[value]
		from kvs, key_tab,application_identifier_tab
		where 
		key_tab.[key]='compatibilityInfo' and kvs.[key] = key_tab.[id]
		and application_identifier_tab.[id] = kvs.[application_identifier]
		order by application_identifier_tab.[id]
		''')

	all_rows = cursor.fetchall()
	
	#poner un try except por si acaso
	extension = '.bplist'
	count = 0
	
	for row in all_rows:
		bundleid = str(row[0])
		bundleidplist = bundleid+'.bplist'
		f = row[1]
		output_file = open(outpath+'/exported-dirty/'+bundleidplist, 'wb') #export dirty from DB
		output_file.write(f)
		output_file.close()	

		g = open(outpath+'/exported-dirty/'+bundleidplist, 'rb')
		#plist = plistlib.load(g)
		
		plist = ccl_bplist.load(g)
		
		output_file = open(outpath+'exported-clean/'+bundleidplist, 'wb') 
		output_file.write(plist)
		output_file.close()
	
	#create html headers
	filedatahtml = open(outpath+'Application State.html', mode='a+')
	filedatahtml.write('<html><body>')
	filedatahtml.write('<h2>iOS ApplicationState.db Report </h2>')
	filedatahtml.write ('<style> table, th, td {border: 1px solid black; border-collapse: collapse;}</style>')
	filedatahtml.write('<br/>')
	filedatahtml.write('<table>')
	filedatahtml.write(f'<tr><td colspan = "4">{apstatefiledb}</td></tr>')
	filedatahtml.write('<tr><td>Bundle ID</td><td>Bundle Path</td><td>Bundle Container</td><td>Sandbox Path</td></tr>')
	
		
	for filename in glob.glob(outpath+'exported-clean/*.bplist'):	
		p = open(filename, 'rb')
		#cfilename = os.path.basename(filename)
		plist = ccl_bplist.load(p)
		ns_keyed_archiver_obj = ccl_bplist.deserialise_NsKeyedArchiver(plist, parse_whole_structure=False)#deserialize clean 
		#print(cfilename)
		bid = (ns_keyed_archiver_obj['bundleIdentifier'])
		bpath = (ns_keyed_archiver_obj['bundlePath'])
		bcontainer = (ns_keyed_archiver_obj['bundleContainerPath'])
		bsandbox = (ns_keyed_archiver_obj['sandboxPath'])
		
		if bsandbox == '$null':
			bsandbox = ''
		if bcontainer == '$null':
			bcontainer = ''
		
		
		#csv report
		filedata = open(outpath+'ApplicationState_InstalledAppInfo.csv', mode='a+')
		filewrite = csv.writer(filedata, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
		filewrite.writerow([bid, bpath, bcontainer, bsandbox])
		count = count + 1
		filedata.close()
		
		#html report
		filedatahtml.write(f'<tr><td>{bid}</td><td>{bpath}</td><td>{bcontainer}</td><td>{bsandbox}</td></tr>')
		
		
		filemetadata = open(outpath+'ApplicationState_InstalledAppInfo_Path.txt', mode='w')
		filemetadata.write(f'Artifact name and file path: {apstatefiledb} ')
		filemetadata.close()
	
	#close html footer
	filedatahtml.write('</table></html>')
	filedatahtml.close()
	
	print(f'Installed app GUIDs and app locations processed: {count}')
	print(f'ApplicationState.db queries completed.')