教 程 目 录

本章将介绍移动设备上的Python数字取证及其涉及的概念.

简介

移动设备取证是数字取证的一个分支它涉及移动设备的获取和分析,以恢复调查兴趣的数字证据.这个分支与计算机取证不同,因为移动设备有一个内置的通信系统,可用于提供与位置相关的有用信息.

尽管智能手机在数字取证方面的使用日益增加 - 由于其异质性,它仍然被认为是非标准的.另一方面,计算机硬件(例如硬盘)被认为是标准的并且也被发展为稳定的规则.在数字取证行业,对非标准设备使用的技术存在很多争议,有短暂的证据,如智能手机.

可从移动设备中提取的工件

与仅具有通话记录或SMS消息的旧手机相比,现代移动设备拥有大量数字信息.因此,移动设备可以为调查人员提供有关其用户的大量见解.可以从移动设备中提取的一些工件如下所述 :消息 :  ;这些是有用的工件,可以揭示所有者的心态,甚至可以向研究者提供一些以前未知的信息.

位置历史 : 去;位置历史数据是一个有用的工件,调查人员可以使用它来验证人的特定位置.

已安装的应用程序 : 通过访问安装的应用程序类型,调查人员可以深入了解移动用户的习惯和想法.

证据来源和处理Python

智能手机将SQLite数据库和PLIST文件作为主要证据来源.在本节中,我们将在python中处理证据来源.

分析PLIST文件

PLIST(属性列表)是一个灵活的用于存储应用数据的便捷格式,尤其是在iPhone设备上它使用扩展名.plist.这种文件用于存储有关包和应用程序的信息.它可以采用两种格式:XML和二进制.以下Python代码将打开并读取PLIST文件.请注意,在继续此操作之前,我们必须创建自己的Info.plist文件.

首先,安装名为biplist 通过以下命令 :Pip install biplist

现在,导入一些有用的库来处理plist文件 :import biplist

import os

import sys

现在,在main方法下使用以下命令可以将plist文件读入变量 :def main(plist):

try:

data = biplist.readPlist(plist)

except (biplist.InvalidPlistException,biplist.NotBinaryPlistException) as e:

print("[-] Invalid PLIST file - unable to be opened by biplist")

sys.exit(1)

现在,我们可以从这个变量读取控制台上的数据或直接打印它.

SQLite Databas es

SQLite充当移动设备上的主要数据存储库. SQLite是一个进程内库,它实现了一个独立的,无服务器,零配置的事务SQL数据库引擎.它是一个零配置的数据库,您不需要在系统中配置它,与其他数据库不同.

如果您是新手或不熟悉SQLite数据库,您可以按照链接 www.it1352.comhttps://www.tutorialspoint.com/sqlite/index.htm 此外,您可以点击链接 www.it1352.comhttps://www.tutorialspoint.com/sqlite/sqlite_python.htm ,以便您详细了解SQLite与Python.

在移动取证期间,我们可以与移动设备的sms.db文件进行交互,并可以从消息中提取有价值的信息表. Python有一个名为sqlite3的内置库,用于连接SQLite数据库.您可以使用以下命令导入相同的内容 :import sqlite3

现在,在以下命令的帮助下,我们可以连接数据库,例如sms.db,如果是移动设备 :Conn = sqlite3.connect('sms.db')

C = conn.cursor()

在这里, C是游标对象,借助它我们可以与数据库交互.

现在,假设我们想要执行特定命令,比如从获取详细信息abc table,它可以在以下命令的帮助下完成;c.execute("Select * from abc" )

c.close()

上述命令的结果将存储在游标对象中.类似地,我们可以使用fetchall()方法将结果转储到我们可以操作的变量中.

我们可以使用以下命令获取消息的列名数据表中sms.db :c.execute("pragma table_info(message)")

table_data = c.fetchall()

columns = [x [1] for table in the table_data

注意这里我们使用的是SQLite PRAGMA命令这是用于在SQLite环境中控制各种环境变量和状态标志的特殊命令.在上面的命令中,fetchall()方法返回结果元组.每个列的名称都存储在每个元组的第一个索引中.

现在,在以下命令的帮助下,我们可以在表中查询其所有数据并将其存储在名为c.execute("Select * from message")

data_msg = c.fetchall ()

上面的命令会将数据存储在变量中,我们还可以使用csv.writer将上述数据写入CSV文件中()方法.

iTunes备份

可以对iTunes进行的备份执行iPhone移动取证.法医检查员依靠分析通过iTunes获得的iPhone逻辑备份. iTunes使用AFC(Apple文件连接)协议进行备份.此外,除了托管密钥记录之外,备份过程不会修改iPhone上的任何内容.

现在,问题出现了为什么数字取证专家理解iTunes上的技术很重要备份?重要的是,如果我们直接访问嫌疑人的计算机而不是iPhone,因为当使用计算机与iPhone同步时,iPhone上的大部分信息都可能会在计算机上备份.

备份过程及其位置

每当Apple产品备份到计算机时,它都会与iTunes同步,并且会有一个带有设备唯一ID的特定文件夹.在最新的备份格式中,文件存储在包含文件名的前两个十六进制字符的子文件夹中.从这些备份文件中,有一些文件,如info.plist,它们与名为Manifest.db的数据库一起使用.下表显示了备份位置,这些位置因iTunes备份的操作系统而有所不同;OS备份位置

Win7C:\ Users \ [用户名] \ AppData \Roaming\AppleComputer \ MobileSync \ Backup \

MAC OS X〜/Library/Application Suport/MobileSync/Backup/

要使用Python处理iTunes备份,我们需要首先识别所有备份根据我们的操作系统备份位置.然后我们将遍历每个备份并读取数据库Manifest.db.

现在,在下面的Python代码的帮助下,我们可以做同样的 :

首先,按以下方式导入必要的库;from __future__ import print_function

import argparse

import logging

import os

from shutil import copyfile

import sqlite3

import sys

logger = logging.getLogger(__name__)

现在,提供两个位置参数,即INPUT_DIR和OUTPUT_DIR,它代表iTunes备份和所需的输出文件夹 :if __name__ == "__main__":

parser.add_argument("INPUT_DIR",help = "Location of folder containing iOS backups, ""e.g. ~\Library\Application Support\MobileSync\Backup folder")

parser.add_argument("OUTPUT_DIR", help = "Output Directory")

parser.add_argument("-l", help = "Log file path",default = __file__[:-2] + "log")

parser.add_argument("-v", help = "Increase verbosity",action = "store_true") args = parser.parse_args()

现在,设置日志如下 :if args.v:

logger.setLevel(logging.DEBUG)

else:

logger.setLevel(logging.INFO)

现在,设置此日志的消息格式如下 :msg_fmt = logging.Formatter("%(asctime)-15s %(funcName)-13s""%(levelname)-8s %(message)s")

strhndl = logging.StreamHandler(sys.stderr)

strhndl.setFormatter(fmt = msg_fmt)

fhndl = logging.FileHandler(args.l, mode = 'a')

fhndl.setFormatter(fmt = msg_fmt)

logger.addHandler(strhndl)

logger.addHandler(fhndl)

logger.info("Starting iBackup Visualizer")

logger.debug("Supplied arguments: {}".format(" ".join(sys.argv[1:])))

logger.debug("System: " + sys.platform)

logger.debug("Python Version: " + sys.version)

以下代码行将使用os.makedirs()函数 :if not os.path.exists(args.OUTPUT_DIR):

os.makedirs(args.OUTPUT_DIR)

现在,传递提供的输入并将目录输出到main()函数,如下所示 :if os.path.exists(args.INPUT_DIR) and os.path.isdir(args.INPUT_DIR):

main(args.INPUT_DIR, args.OUTPUT_DIR)

else:

logger.error("Supplied input directory does not exist or is not ""a directory")

sys.exit(1)

现在,写一下main()函数,它将进一步调用backup_summary()用于标识输入文件夹中存在的所有备份的函数 :def main(in_dir, out_dir):

backups = backup_summary(in_dir)

def backup_summary(in_dir):

logger.info("Identifying all iOS backups in {}".format(in_dir))

root = os.listdir(in_dir)

backups = {}

for x in root:

temp_dir = os.path.join(in_dir, x)

if os.path.isdir(temp_dir) and len(x) == 40:

num_files = 0

size = 0

for root, subdir, files in os.walk(temp_dir):

num_files += len(files)

size += sum(os.path.getsize(os.path.join(root, name))

for name in files)

backups[x] = [temp_dir, num_files, size]

return backups

现在,将每个备份的摘要打印到控制台,如下所示;print("Backup Summary")

print("=" * 20)

if len(backups) > 0:

for i, b in enumerate(backups):

print("Backup No.: {} \n""Backup Dev. Name: {} \n""# Files: {} \n""Backup Size (Bytes): {}\n".format(i, b, backups[b][1], backups[b][2]))

现在,将Manifest.db文件的内容转储到名为db_items的变量.try:

db_items = process_manifest(backups[b][0])

except IOError:

logger.warn("Non-iOS 10 backup encountered or " "invalid backup. Continuing to next backup.")

continue

现在,让我们定义一个将采用目录路径的函数of backup :def process_manifest(backup):

manifest = os.path.join(backup, "Manifest.db")

if not os.path.exists(manifest):

logger.error("Manifest DB not found in {}".format(manifest))

raise IOError

现在,使用SQLite3,我们将通过名为c : 的游标连接到数据库;c = conn.cursor()

items = {}

for row in c.execute("SELECT * from Files;"):

items[row[0]] = [row[2], row[1], row[3]]

return items

create_files(in_dir, out_dir, b, db_items)

print("=" * 20)

else:

logger.warning("No valid backups found. The input directory should be

" "the parent-directory immediately above the SHA-1 hash " "iOS device backups")

sys.exit(2)

现在,将create_files()方法定义如下 :def create_files(in_dir, out_dir, b, db_items):

msg = "Copying Files for backup {} to {}".format(b, os.path.join(out_dir, b))

logger.info(msg)

现在,遍历db_items字典中的每个键 :for x, key in enumerate(db_items):

if db_items[key][0] is None or db_items[key][0] == "":

continue

else:

dirpath = os.path.join(out_dir, b,

os.path.dirname(db_items[key][0]))

filepath = os.path.join(out_dir, b, db_items[key][0])

if not os.path.exists(dirpath):

os.makedirs(dirpath)

original_dir = b + "/" + key[0:2] + "/" + key

path = os.path.join(in_dir, original_dir)

if os.path.exists(filepath):

filepath = filepath + "_{}".format(x)

现在,使用shutil.copyfile()方法将备份文件复制如下 :try:

copyfile(path, filepath)

except IOError:

logger.debug("File not found in backup: {}".format(path))

files_not_found += 1

if files_not_found > 0:

logger.warning("{} files listed in the Manifest.db not" "found in

backup".format(files_not_found))

copyfile(os.path.join(in_dir, b, "Info.plist"), os.path.join(out_dir, b,

"Info.plist"))

copyfile(os.path.join(in_dir, b, "Manifest.db"), os.path.join(out_dir, b,

"Manifest.db"))

copyfile(os.path.join(in_dir, b, "Manifest.plist"), os.path.join(out_dir, b,

"Manifest.plist"))

copyfile(os.path.join(in_dir, b, "Status.plist"),os.path.join(out_dir, b,

"Status.plist"))

使用上面的Python脚本,我们可以获得更新的备份文件结构在我们的输出文件夹中我们可以使用pycrypto python库来解密备份.

Wi-Fi

移动设备可用于连接通过无处不在的Wi-Fi网络连接到外部世界.有时设备会自动连接到这些开放网络.

如果是iPhone,设备已连接的开放式Wi-Fi连接列表存储在名为

我们需要使用Python从标准Cellebrite XML报告中提取Wi-Fi详细信息.为此,我们需要使用来自无线地理日志引擎(WIGLE)的API,这是一个流行的平台,可用于使用Wi-Fi网络的名称查找设备的位置.

我们可以使用名为requests的Python库从WIGLE访问API.它可以安装如下 :pip install requests

来自WIGLE的API

我们需要在WIGLE的网站上注册 https://wigle.net/account 从WIGLE获取免费API.用于通过WIGEL的API获取有关用户设备及其连接的信息的Python脚本将在下面讨论 :

首先,导入以下库以处理不同的东西和减号;from __future__ import print_function

import argparse

import csv

import os

import sys

import xml.etree.ElementTree as ET

import requests

现在,提供两个位置参数,即INPUT_FILE和OUTPUT_CSV分别表示具有Wi-Fi MAC地址和所需输出CSV文件的输入文件 :if __name__ == "__main__":

parser.add_argument("INPUT_FILE", help = "INPUT FILE with MAC Addresses")

parser.add_argument("OUTPUT_CSV", help = "Output CSV File")

parser.add_argument("-t", help = "Input type: Cellebrite XML report or TXT

file",choices = ('xml', 'txt'), default = "xml")

parser.add_argument('--api', help = "Path to API key

file",default = os.path.expanduser("~/.wigle_api"),

type = argparse.FileType('r'))

args = parser.parse_args()

现在,下面的代码行将检查输入文件是否存在且是否为文件.如果没有,它退出脚本 :if not os.path.exists(args.INPUT_FILE) or \ not os.path.isfile(args.INPUT_FILE):

print("[-] {} does not exist or is not a

file".format(args.INPUT_FILE))

sys.exit(1)

directory = os.path.dirname(args.OUTPUT_CSV)

if directory != '' and not os.path.exists(directory):

os.makedirs(directory)

api_key = args.api.readline().strip().split(":")

现在,将参数传递给main,如下所示 :main(args.INPUT_FILE, args.OUTPUT_CSV, args.t, api_key)

def main(in_file, out_csv, type, api_key):

if type == 'xml':

wifi = parse_xml(in_file)

else:

wifi = parse_txt(in_file)

query_wigle(wifi, out_csv, api_key)

现在,我们将解析XML文件,如下所示;def parse_xml(xml_file):

wifi = {}

xmlns = "{http://pa.cellebrite.com/report/2.0}"

print("[+] Opening {} report".format(xml_file))

xml_tree = ET.parse(xml_file)

print("[+] Parsing report for all connected WiFi addresses")

root = xml_tree.getroot()

现在,循环遍历根的子元素,如下所示;for child in root.iter():

if child.tag == xmlns + "model":

if child.get("type") == "Location":

for field in child.findall(xmlns + "field"):

if field.get("name") == "TimeStamp":

ts_value = field.find(xmlns + "value")

try:

ts = ts_value.text

except AttributeError:

continue

现在,我们将检查'ssid'字符串是否存在于值的文本中或不是 :if "SSID" in value.text:

bssid, ssid = value.text.split("\t")

bssid = bssid[7:]

ssid = ssid[6:]

现在,我们需要在wifi字典中添加BSSID,SSID和时间戳,如下所示;if bssid in wifi.keys():

wifi[bssid]["Timestamps"].append(ts)

wifi[bssid]["SSID"].append(ssid)

else:

wifi[bssid] = {"Timestamps": [ts], "SSID":

[ssid],"Wigle": {}}

return wifi

文本解析器更简单,XML解析器显示在下面 :def parse_txt(txt_file):

wifi = {}

print("[+] Extracting MAC addresses from {}".format(txt_file))

with open(txt_file) as mac_file:

for line in mac_file:

wifi[line.strip()] = {"Timestamps": ["N/A"], "SSID":

["N/A"],"Wigle": {}}

return wifi

现在,让我们使用请求模块进行WIGLE API调用,然后需要转到query_wigle()方法 :def query_wigle(wifi_dictionary, out_csv, api_key):

print("[+] Querying Wigle.net through Python API for {} "

"APs".format(len(wifi_dictionary)))

for mac in wifi_dictionary:

wigle_results = query_mac_addr(mac, api_key)

def query_mac_addr(mac_addr, api_key):

query_url = "https://api.wigle.net/api/v2/network/search?" \

"onlymine = false&freenet = false&paynet = false" \ "&netid = {}".format(mac_addr)

req = requests.get(query_url, auth = (api_key[0], api_key[1]))

return req.json()

实际上WIGLE API调用每天都有一个限制,如果该限制超过那么它必须显示如下错误;try:

if wigle_results["resultCount"] == 0:

wifi_dictionary[mac]["Wigle"]["results"] = []

continue

else:

wifi_dictionary[mac]["Wigle"] = wigle_results

except KeyError:

if wigle_results["error"] == "too many queries today":

print("[-] Wigle daily query limit exceeded")

wifi_dictionary[mac]["Wigle"]["results"] = []

continue

else:

print("[-] Other error encountered for " "address {}: {}".format(mac,

wigle_results['error']))

wifi_dictionary[mac]["Wigle"]["results"] = []

continue

prep_output(out_csv, wifi_dictionary)

现在,我们将使用prep_output()将字典展平为易于写入的块和减号的方法;def prep_output(output, data):

csv_data = {}

google_map = https://www.google.com/maps/search/

现在,访问我们收集的所有数据,以便远至如下:for x, mac in enumerate(data):

for y, ts in enumerate(data[mac]["Timestamps"]):

for z, result in enumerate(data[mac]["Wigle"]["results"]):

shortres = data[mac]["Wigle"]["results"][z]

g_map_url = "{}{},{}".format(google_map, shortres["trilat"],shortres["trilong"])

现在,我们可以像在本章前面的脚本中那样使用write_csv()函数在CSV文件中编写输出.

相关新手教程:

python10086查询系统_Python数字移动设备取证相关推荐

  1. python10086查询系统_Python获取移动性能指标

    最近两天在研究移动性能这块,这个的用处非常大,比如说在做性能测试的时候用top 或者 dstat 1的时候获取到的性能指标是非常实用的,即时获取的指标评估和分析系统瓶颈. 再就是在自动化中调用性能指标 ...

  2. python成绩查询系统_python成绩查询

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 学了点python后,看到各种爬虫教程,原本想做个统计平均学分绩的小爬虫. 当真 ...

  3. python成绩查询系统_Python爬虫实战:登录教务系统查成绩

    本文记录我用Python登录教务系统查询成绩的过程.手动输入验证码,简单获取成绩页面.后续将可能更新自动识别验证码登录查询 前期准备 本爬虫用到了Python的Requests库和BeautifulS ...

  4. python 数据库查询系统_python查询数据库操作系统

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  5. python数据库查询系统_Python MySQL 查询数据(select from)

    1.从表中查询数据(Select From) 要从MySQL中的表中进行选择,请使用"SELECT"语句: 例如: 从"customers"表中选择所有记录,并 ...

  6. python课设题目日历查询系统_Python实例课程17——生成日历

    代码实现 #======================================================#功能:生成日历#作者:python小哥#时间:2020-4-8#微信公众号:D ...

  7. python 日历查询系统_python 日历

    上章总结了python中time模块的使用,这次总结日历模块 calendar >>> import calendar >>> cal = calendar.mon ...

  8. python数据分析学生成绩查询系统_python数据分析-学生成绩分析

    python数据分析-学生成绩分析 python数据分析-学生成绩分析 目标:分析学生成绩的影响因素 1.导入原始数据,以及需要用到的库 import pandas as pd import nump ...

  9. python地铁查询系统_Python实现属于自己的公交地铁线路图

    Python实现属于自己的公交地铁线路图,本文主要讲解的就是用Python计算公交线路图的功能,即输入起始点和结束点,即能够得出公交的线路. 先说下数据的来源,直接网上爬取,也可以直接略过此点,直接下 ...

最新文章

  1. 1071svm函数 r语言_如何利用R语言中的rpart函数建立决策树模型
  2. 织梦dedecms绿色高端生活家具装饰公司网站模板
  3. Java架构-每秒上千订单场景下的分布式锁高并发优化实践!
  4. 《Arduino家居安全系统构建实战》——1.1 家居安全的基础设施
  5. 【c++ | 谭浩翔】第三章练习
  6. access 英语什么意思_Access数据库集成教程二:创建查询
  7. 专业能力与行业价值 IBM在华的商业人工智能实践
  8. 配置Tomcat 域名解析 tomcat/conf server.xml
  9. C++封装Mysql数据库
  10. Taro框架中开发H5使用微信分享
  11. Python学习之Turtle库
  12. 网页抽奖程序(年会,开幕式等)
  13. comsol显示电场计算结果_comsol电磁场仿真案例
  14. RS232串口线接法与线芯引脚定义
  15. 国外问卷调查好做吗?
  16. 剑指 Offer 42. 连续子数组的最大和java
  17. 某公司员工的工资计算方法如下:一周内工作时间不超过40小时,按正常工作时间计酬;超出40小时的工作时间部分,按正常工作时间报酬的1.5倍计酬。员工按进公司时间分为新职工和老职工,进公司不少于5年的员工
  18. 计算机组策略主要功能,组策略概述
  19. 苹果微信浏览器html缓存图片吗,h5清理微信浏览器网页缓存
  20. 简单搭建钓鱼Wifi信号获取用户手机号

热门文章

  1. ipad使用的PDF书籍没有目录怎么办?
  2. matlab传感器避障小车,激光雷达避障小车的制作
  3. 浅谈技术管理之日式管理的殊途同归
  4. 伺服电机编码器为什么要调零或校正
  5. PMP——第3章 项目经理的角色
  6. 如何在Abaqus中用扫掠的方法画六面体网格
  7. 通达信资金净流入公式_主力净流入(副){51.63%/5655}
  8. bitcoin源码分析
  9. Nginx 上搭建PHP站 更改目录出现的错误:File not found、403 forbidden (13: Permission denied)
  10. 走出“大唐” 穆穆-movno1 第一财经周刊