コード例 #1
0
ファイル: tiktok.py プロジェクト: xtiankisutsa/FAMA
    def __init__(self, internal_path, external_path, report_path, app_name,
                 app_id):
        ModuleParent.__init__(self, internal_path, external_path, report_path,
                              app_name, app_id)

        self.timeline = Timeline()
        self.media = Media()
        logging.info("Module started")
コード例 #2
0
ファイル: tinder.py プロジェクト: xtiankisutsa/FAMA
class ModuleReport(ModuleParent):
    def __init__(self, internal_path, external_path, report_path, app_name,
                 app_id):
        ModuleParent.__init__(self, internal_path, external_path, report_path,
                              app_name, app_id)
        self.timeline = Timeline()
        self.locations = Location()
        self.media = Media()

        logging.info("Module started")

    def generate_report(self):
        self.report["freespace"] = self.get_info(self.get_undark_db)
        self.report["sqlparse"] = self.get_info(self.get_sqlparse)
        self.report["user_photos"] = self.get_info(self.get_user_photos)
        self.report["matches"] = self.get_info(self.get_user_matches)
        self.report["bio_changes"] = self.get_info(self.get_bio_changes)
        self.report["messages"] = self.get_info(self.get_user_messages)
        self.report["credit_cards"] = self.get_info(self.get_credit_cards)
        self.report["locations"] = self.get_info(self.get_locations)
        self.add_model(self.timeline)
        self.add_model(self.locations)
        self.add_model(self.media)

        logging.info("Report Generated")

        Utils.save_report(os.path.join(self.report_path, "Report.json"),
                          self.report)
        return self.report

    def get_user_messages(self):
        logging.info("Getting User Messages...")

        database_name = "tinder-3.db"

        db = os.path.join(self.internal_cache_path, "databases", database_name)

        database = Database(db)
        messages_list = []
        messages = database.execute_query(
            "select message_to_id, message_from_id , message_text, message_sent_date/1000 as message_sent_date, case when message_is_liked = 0 then 'Not liked' when message_is_liked = 1 then 'Liked' else message_is_liked end, case when message_is_seen = 0 then 'Not seen' when message_is_seen = 1 then 'Seen' else message_is_seen end, message_delivery_status from message_view order by message_sent_date;"
        )

        #getting messages from conversations
        for entry in messages:
            message = {}
            message["database"] = database_name
            message["to"] = entry[0]
            message["from"] = entry[1]
            message["message"] = entry[2]
            message["created_time"] = entry[3]
            message["is_liked"] = str(entry[4])
            message["is_seen"] = str(entry[5])
            message["delivery_status"] = str(entry[6]).lower()
            messages_list.append(message)

            timeline_event = {}
            timeline_event["from"] = message["from"]
            timeline_event["to"] = message["to"]
            timeline_event["message"] = message["message"]
            self.timeline.add(message["created_time"], "AF_message",
                              timeline_event)

        logging.info("{} messages found".format(len(messages_list)))

        return messages_list

    def get_user_photos(self):

        logging.info("Get User Photos...")
        db = os.path.join(self.internal_cache_path, "databases",
                          "tinder-3.db").encode('utf-8')

        database = Database(db)
        photos_list = database.execute_query(
            "select image_uri from profile_media;")
        user_photos = []
        for photo in photos_list:
            user_photos.append(photo[0])
            self.media.add(photo[0])

        logging.info("{} photo(s) found".format(len(photos_list)))
        return user_photos

    def get_bio_changes(self):

        logging.info("Get Biography Changes...")
        db = os.path.join(self.internal_cache_path, "databases", "tinder-3.db")
        database = Database(db)

        biography_changes = []
        bio_list = database.execute_query(
            "select old_bio, bio, timestamp from profile_change_bio order by timestamp"
        )
        for entry in bio_list:
            bio_change = {}
            bio_change["old"] = entry[0]
            bio_change["new"] = entry[1]
            bio_change["createdtime"] = entry[3]

            timeline_event = {}
            timeline_event["old"] = bio_change["old"]
            timeline_event["new"] = bio_change["new"]
            self.timeline.add(bio_change["createdtime"], "AF_user",
                              timeline_event)

            biography_changes.append(bio_change)

        logging.info("{} biography change(s) found".format(
            len(biography_changes)))
        return biography_changes

    def get_user_matches(self):
        logging.info("Getting User Matches...")
        matches = []

        db = os.path.join(self.internal_cache_path, "databases", "tinder-3.db")

        database = Database(db)
        results = database.execute_query(
            "select match_id, match_creation_date/1000 , match_last_activity_date, match_person_id, match_person_name, match_person_bio, match_person_birth_date/1000, case when match_is_blocked = 1 then 'Blocked' when match_is_blocked = 0 then 'Not Blocked ' else 'Invalid' end from match_view;"
        )
        for entry in results:
            match = {}
            match["id"] = entry[0]
            match["creation_date"] = entry[1]
            match["last_activity_date"] = entry[2]
            match["person_id"] = entry[3]
            match["person_name"] = entry[4]
            match["person_bio"] = entry[5]
            match["person_bithdate"] = entry[6]
            match["is_blocked"] = entry[7]
            matches.append(match)

            timeline_event = {}
            timeline_event["person_id"] = match["person_id"]
            timeline_event["person_name"] = match["person_name"]
            timeline_event["is_blocked"] = match["is_blocked"]
            self.timeline.add(match["creation_date"], "AF_relation",
                              timeline_event)

        logging.info("{} matches found".format(len(matches)))
        return matches

    def get_undark_db(self):
        logging.info("Getting undark output...")
        return Database.get_undark_output(self.databases, self.report_path)

    def get_credit_cards(self):

        logging.info("Getting User credit cards...")

        db = os.path.join(self.internal_cache_path, "app_webview", "Default",
                          "Web Data")

        database = Database(db)
        cards_list = []
        cards = database.execute_query(
            "select name_on_card, expiration_month, expiration_year, card_number_encrypted, date_modified, origin, use_count, use_date from credit_cards;"
        )

        for entry in cards:
            card = {}
            card["name"] = entry[0]
            card["expiration_date"] = "{}/{}".format(entry[1], entry[2])
            card["card_number_encrypted"] = str(entry[3])
            card["date_modified"] = str(entry[4])
            card["origin"] = str(entry[5])
            card["use_count"] = entry[6]
            card["use_date"] = str(entry[7])

            timeline_event = {}
            timeline_event["name"] = card["name"]
            self.timeline.add(card["use_date"], "AF_creditcard",
                              timeline_event)

            cards_list.append(card)

        logging.info("{} credit cards found".format(len(cards_list)))

        return cards_list

    def get_locations(self):

        logging.info("Getting User locations...")

        db = os.path.join(self.internal_cache_path, "databases",
                          "legacy_tinder-1.db")

        database = Database(db)
        locations_list = []
        cards = database.execute_query(
            "select latitude, longitude, state_province_long, country_short_name, country_long_name, address,route,street_number,city, last_seen_date/1000 as last_seen_date from tinder_locations;"
        )

        for entry in cards:
            location = {}
            location["latitude"] = entry[0]
            location["longitude"] = entry[1]
            location["province"] = entry[2]
            location["country_short"] = entry[3]
            location["country_long"] = entry[4]
            location["address"] = entry[5]
            location["route"] = entry[6]
            location["street_number"] = str(entry[7])
            location["city"] = entry[8]
            location["last_seen_date"] = entry[9]
            locations_list.append(location)

            timeline_event = {}
            timeline_event["latitude"] = location["latitude"]
            timeline_event["longitude"] = location["longitude"]
            timeline_event["address"] = location["address"]
            timeline_event["city"] = location["city"]
            timeline_event["country_long"] = location["country_long"]
            self.timeline.add(location["last_seen_date"], "AF_location",
                              timeline_event)

            self.locations.add(location["last_seen_date"],
                               location["latitude"], location["longitude"])

        logging.info("{} locations found".format(len(locations_list)))

        return locations_list

    def get_sqlparse(self):
        logging.info("Getting sqlparse...")
        return Database.get_drp_output(self.databases, self.report_path)
コード例 #3
0
ファイル: tiktok.py プロジェクト: xtiankisutsa/FAMA
class ModuleReport(ModuleParent):
    def __init__(self, internal_path, external_path, report_path, app_name,
                 app_id):
        ModuleParent.__init__(self, internal_path, external_path, report_path,
                              app_name, app_id)

        self.timeline = Timeline()
        self.media = Media()
        logging.info("Module started")

    def generate_report(self):
        self.report["freespace"] = self.get_info(self.get_undark_db)
        self.report["sqlparse"] = self.get_info(self.get_sqlparse)
        self.report["profile"] = self.get_info(self.get_user_profile)
        self.report["messages"] = self.get_info(self.get_user_messages)
        self.report["users"] = self.get_info(self.get_user_profiles)
        self.report["logged_users"] = self.get_info(self.get_logged_users)

        self.report["searches"] = self.get_info(self.get_user_searches)
        self.report["videos"] = self.get_info(self.get_videos)
        self.report["published_videos"] = self.get_info(
            self.get_videos_publish)
        self.report["log"] = self.get_info(self.get_last_session)
        self.report["cache_images"] = self.get_info(self.get_fresco_cache)
        self.report["open_events"] = self.get_info(self.get_open_events)

        self.add_model(self.timeline)
        self.add_model(self.media)

        logging.info("Report Generated")

        Utils.save_report(os.path.join(self.report_path, "Report.json"),
                          self.report)
        return self.report

    #TIKTOK
    def get_user_messages(self):
        logging.info("Getting User Messages...")

        # db1 = os.path.join(self.internal_cache_path, "databases", "db_im_xx")
        # db2 = None

        # if not db2:
        #     print("[Tiktok] User Messages database not found!")
        #     return ""

        # db2 = os.path.join(self.internal_path, db2)
        # attach = "ATTACH '{}' AS 'db2'".format(db2)

        conversations_list = [
        ]  #each entry means 1 conversation, including participants information and messages

        for db in self.databases:
            if not db.endswith("_im.db"):
                continue

            database = Database(db)

            conversations_ids_list = database.execute_query(
                "select conversation_id from conversation_core"
            )  #list if conversations

            for conversation in conversations_ids_list:
                conversation_output = {}

                id1 = conversation[0].split(':')[2]
                id2 = conversation[0].split(':')[3]

                conversation_output["database"] = os.path.basename(db)
                conversation_output[
                    "participant_1"] = self.get_user_uniqueid_by_id(id1)
                conversation_output[
                    "participant_2"] = self.get_user_uniqueid_by_id(id2)
                conversation_output["messages"] = []

                #messages from conversations
                messages_list = database.execute_query(
                    "select created_time/1000 as created_time, content as message, case when read_status = 0 then 'Not read' when read_status = 1 then 'Read' else read_status end read_not_read, local_info, type, case when deleted = 0 then 'Not deleted' when deleted = 1 then 'Deleted' else deleted end, sender from msg where conversation_id='{}' order by created_time;"
                    .format(conversation[0]))

                #getting messages from conversations
                for entry in messages_list:
                    message = {}
                    message["createdtime"] = entry[0]
                    message["readstatus"] = str(entry[2])
                    message["localinfo"] = entry[3]
                    if entry[6] == int(id1):
                        message["sender"] = conversation_output[
                            "participant_1"]
                        message["receiver"] = conversation_output[
                            "participant_2"]
                    else:
                        message["sender"] = conversation_output[
                            "participant_2"]
                        message["receiver"] = conversation_output[
                            "participant_1"]

                    message["type"] = self.get_message_type_by_id(entry[4])
                    message["message"] = self.parse_body_message_by_id(
                        entry[4], json.loads(entry[1]))
                    message["deleted"] = str(entry[5])
                    conversation_output["messages"].append(message)

                    timeline_event = {}
                    timeline_event["from"] = message["sender"]
                    timeline_event["to"] = message["receiver"]
                    timeline_event["message"] = message["message"]
                    self.timeline.add(message["createdtime"], "AF_message",
                                      timeline_event)

                #adding conversation and participants information to main array
                conversations_list.append(conversation_output)

        logging.info("{} messages found".format(
            len(conversation_output.get("messages"))))

        return conversations_list

    def get_logged_users(self):

        logging.info("Get User Profile...")
        xml_file = os.path.join(self.internal_cache_path, "shared_prefs",
                                "aweme_user.xml")
        user_profiles = []
        user_profile = {}
        values = Utils.xml_attribute_finder(xml_file)
        for key, value in values.items():
            if key.endswith("_significant_user_info"):
                user_profile = {}
                dump = json.loads(value)
                atributes = [
                    "uid", "short_id", "unique_id", "nickname", "nickname",
                    "avatar_url"
                ]

                for index in atributes:
                    user_profile[index] = dump.get(index)
                if user_profile.get("unique_id"):
                    user_profile["url"] = "https://www.tiktok.com/@{}".format(
                        user_profile["unique_id"])

                user_profiles.append(user_profile)

        return user_profiles

    def get_open_events(self):
        logging.info("Get application open events...")

        open_events = []
        db = os.path.join(self.internal_cache_path, "databases", "TIKTOK.db")
        database = Database(db)
        results = database.execute_query(
            "select open_time/1000 from app_open;")

        for event in results:
            open_events.append(event[0])
            timeline_event = {}
            timeline_event["event"] = "Open Application"
            self.timeline.add(event[0], "AF_system", timeline_event)

        return open_events

    def get_user_profile(self):

        logging.info("Get User Profile...")
        xml_file = os.path.join(self.internal_cache_path, "shared_prefs",
                                "aweme_user.xml")
        user_profile = {}
        values = Utils.xml_attribute_finder(xml_file)
        for key, value in values.items():
            if key.endswith("_aweme_user_info"):
                #try:
                dump = json.loads(value)
                atributes = [
                    "account_region", "follower_count", "following_count",
                    "gender", "google_account", "is_blocked", "is_minor",
                    "nickname", "register_time", "sec_uid", "short_id", "uid",
                    "unique_id"
                ]

                for index in atributes:
                    user_profile[index] = dump.get(index)
                break

        if user_profile.get("unique_id"):
            user_profile["url"] = "https://www.tiktok.com/@{}".format(
                user_profile["unique_id"])

        if user_profile.get("uniqueid") and user_profile.get("url"):
            timeline_event = {}
            timeline_event["uniqueid"] = user_profile["unique_id"]
            timeline_event["url"] = user_profile["url"]

            self.timeline.add(user_profile["register_time"], "AF_user",
                              timeline_event)

        return user_profile

    def get_user_uniqueid_by_id(self, uid):
        db = os.path.join(self.internal_cache_path, "databases", "db_im_xx")
        database = Database(db)
        name = database.execute_query(
            "select UNIQUE_ID from SIMPLE_USER where uid={}".format(uid))
        if name:
            name = name[0][0]
        else:
            name = str(uid)
        return name

    def get_user_searches(self):
        logging.info("Getting User Search History...")

        xml_file = os.path.join(self.internal_cache_path, "shared_prefs",
                                "search.xml")
        searches = []
        #verify if recent hisotry tag exists
        try:
            dump = json.loads(
                Utils.xml_attribute_finder(xml_file,
                                           "recent_history")["recent_history"])
            for i in dump:
                searches.append(i["keyword"])
        except:
            pass

        logging.info("{} search entrys found".format(len(searches)))
        return searches

    def get_user_profiles(self):
        logging.info("Getting User Profiles...")
        profiles = {}

        db = os.path.join(self.internal_cache_path, "databases", "db_im_xx")

        database = Database(db)
        results = database.execute_query(
            "select UID, UNIQUE_ID, NICK_NAME, AVATAR_THUMB, case when follow_status = 1 then 'Following' when follow_status = 2 then 'Followed and Following ' else 'Invalid' end from SIMPLE_USER"
        )
        for entry in results:
            message = {}
            message["uid"] = entry[0]
            message["uniqueid"] = entry[1]
            message["nickname"] = entry[2]
            dump_avatar = json.loads(entry[3])
            message["avatar"] = dump_avatar["url_list"][0]
            message["follow_status"] = entry[4]
            message["url"] = "https://www.tiktok.com/@{}".format(
                message["uniqueid"])
            profiles[message["uniqueid"]] = message

        logging.info("{} profiles found".format(len(profiles.keys())))
        return profiles

    def get_user_id(self):
        xml_file = os.path.join(self.internal_cache_path, "shared_prefs",
                                "iuserstate.xml")
        return Utils.xml_attribute_finder(xml_file, "userid")["userid"]

    def get_videos(self):
        logging.info("Getting Videos...")
        videos = []
        db = os.path.join(self.internal_cache_path, "databases", "video.db")

        database = Database(db)
        results = database.execute_query(
            "select key, extra from video_http_header_t")

        for entry in results:
            video = {}
            video["key"] = entry[0]
            dump = json.loads(entry[1])
            for line in dump["responseHeaders"].splitlines():
                if 'Last-Modified:' in line:
                    video["last_modified"] = Utils.date_parser(
                        line.split(": ")[1], "%a, %d %b %Y %H:%M:%S %Z")

                    timeline_event = {}
                    timeline_event["video"] = video["key"]

                    self.timeline.add(video["last_modified"], "AF_video",
                                      timeline_event)
                    break
            self.media.add(
                os.path.join(self.internal_cache_path, "cache", "cache",
                             video["key"]))
            videos.append(video)

        for entry in MDLFixer.folder_scanner(
                os.path.join(self.internal_cache_path, "cache", "cachev2")):
            self.media.add(
                os.path.join(self.internal_cache_path, "cache", "cachev2",
                             entry))

            video = {}
            video["key"] = os.path.basename(entry)
            video["last_modified"] = 0
            videos.append(video)

        logging.info("{} video(s) found".format(len(videos)))
        return videos

    def get_undark_db(self):
        logging.info("Getting undark output...")
        return Database.get_undark_output(self.databases, self.report_path)

    def get_sqlparse(self):
        logging.info("Getting sqlparse...")
        return Database.get_drp_output(self.databases, self.report_path)

    def get_videos_publish(self):
        logging.info("Getting published videos")
        videos = []
        base_path = os.path.join(self.internal_cache_path, "cache",
                                 "aweme_publish")
        if not os.path.exists(base_path):
            return videos

        aweme_publish_files = os.listdir(base_path)

        for aweme_file in aweme_publish_files:
            dump = Utils.read_json(os.path.join(base_path, aweme_file))
            aweme_list = dump.get("aweme_list")
            if aweme_list:
                for entry in aweme_list:
                    video = {}
                    video["created_time"] = entry.get("create_time")
                    # if entry.get("video"):
                    #     if entry.get("video").get("animated_cover"):
                    #         if entry.get("video").get("animated_cover").get("url_list"):
                    #             video["video"] = str(entry.get("video").get("animated_cover").get("url_list")[0])
                    #         else:
                    #             video["video"] = entry.get("video").get("animated_cover")
                    #     else:
                    #         video["video"] = entry.get("video")

                    video["video"] = ""
                    video["duration"] = ""
                    video["cover"] = ""
                    video["api_address"] = ""

                    if entry.get("video"):
                        if entry.get("video").get("animated_cover"):
                            video["video"] = entry.get("video").get(
                                "animated_cover").get("url_list")[0]
                        else:
                            video["video"] = str(entry)

                        video["duration"] = entry.get("video").get("duration")

                        try:
                            video["cover"] = str(
                                entry.get("video").get("cover").get("url_list")
                                [0])
                        except:
                            pass
                        try:
                            video["api_address"] = entry.get("video").get(
                                "play_addr").get("url_list")[-1]
                        except:
                            pass

                    video["share_url"] = entry.get("share_url")
                    video["music"] = entry.get("music").get("play_url").get(
                        "url_list")[0]

                    timeline_event = {}
                    timeline_event["url"] = video["video"]

                    self.timeline.add(video["created_time"], "AF_publish",
                                      timeline_event)
                    videos.append(video)

        logging.info("{} video(s) found".format(len(videos)))
        return videos

    def get_fresco_cache(self):
        logging.info("Getting cache...")
        cache_path = os.path.join(self.external_cache_path, "cache", "picture",
                                  "fresco_cache", "v2.ols100.1")
        numerate_dirs = os.listdir(cache_path)
        fresco_images = []

        for directory in numerate_dirs:
            for cache_file in os.listdir(os.path.join(cache_path, directory)):
                fresco_images.append(cache_file)
                self.media.add(os.path.join(cache_path, directory, cache_file))

        logging.info("{} cache file(s) found".format(len(fresco_images)))
        return fresco_images

    def get_last_session(self):
        logging.info("Getting last session...")
        session = []

        relevant_keys = [
            "device", "name", "status", "ab_sdk_version",
            "storage_available_internal_size",
            "storage_available_external_size", "app_storage_size", "brand",
            "page", "request_method", "is_first", "duration", "is_first",
            "rip", "duration", "author_id", "access2", "video_duration",
            "video_quality", "access", "page_uid", "previous_page",
            "enter_method", "enter_page", "key_word", "search_keyword",
            "next_tab", "search_type", "play_duration", "content",
            "manufacturer", "os_version"
        ]

        db = os.path.join(self.internal_cache_path, "databases",
                          "ss_app_log.db")
        database = Database(db)
        results = database.execute_query(
            "select tag, ext_json, datetime(timestamp/1000, 'unixepoch', 'localtime'), session_id from event order by timestamp"
        )

        for entry in results:
            session_entry = {}
            session_entry["action"] = entry[0]

            body_dump = json.loads(entry[1])
            session_entry["time"] = Utils.date_parser(entry[2],
                                                      "%Y-%m-%d %H:%M:%S")
            session_entry["session_id"] = entry[3]

            timeline_event = {}
            timeline_event["action"] = session_entry["action"]

            self.timeline.add(session_entry["time"], "AF_system",
                              timeline_event)

            session.append(session_entry)

            #json body parser
            body = {}
            for key, value in body_dump.items():
                if key in relevant_keys:
                    body[key] = value

            session_entry["body"] = body

        logging.info("{} entrys found".format(len(results)))
        return session

    @staticmethod
    def parse_body_message_by_id(message_type, message_dump):
        body = ""
        if message_type == 7:
            body = message_dump.get("text")
        elif message_type == 8:
            body = "https://www.tiktok.com/@tiktok/video/{}".format(
                message_dump.get("itemId"))
        elif message_type == 5:
            body = message_dump.get("url").get("url_list")[0]
        elif message_type == 15:
            body = message_dump.get("joker_stickers")[0].get("static_url").get(
                "url_list")[0]
        elif message_type == 25:
            body = "https://www.tiktok.com/@{}".format(
                message_dump.get("desc")
            )  # or body = "https://m.tiktok.com/h5/share/usr/{}.html".format(message_dump.get("uid"))
        elif message_type == 19:
            body = message_dump.get("push_detail")
        elif message_type == 22:
            body = "https://www.tiktok.com/music/tiktok-{}".format(
                message_dump.get("music_id"))
        else:
            body = str(message_dump)

        return body

    @staticmethod
    def get_message_type_by_id(message_type_id):
        if message_type_id == 7: return "text"
        if message_type_id == 8: return "video"
        if message_type_id == 5: return "gif"
        if message_type_id == 15: return "gif"
        if message_type_id == 22: return "audio"
        if message_type_id == 25: return "profile"
        if message_type_id == 19: return "hashtag"
        return "unknown"