用 Python 调查移动设备的 iTunes 备份
在 2011 年 4 月,安全研究人员和前苹果员工公开了 iPhone 和 Ipad IOS 操作
系统的一个隐私问题。一个重要的调查之后发现 IOS 系统事实上跟踪和记录设
备的 GPS 坐标并存储在手机的 consolidated.db 数据库中。在这个数据库中一
个名为 Cell-Location 的表包含了收集的手机的 GPS 坐标。该设备通过综合了最
近的手机信号发射塔来确定定位信息为用户提供更好的服务。然而,安全人员
提出,该收据可能会被恶意的使用,用来跟踪 iPhone/Ipad 用户的完整活动路
线。此外,使用备份和存储移动设备的信息到电脑上也记录了这些信息。虽然
定位记录信息已经从苹果系统中移出了,但发现数据的过程任然还在。在本节
中,我们将重复这一过程,从 iPhone 设备中提取备份信息。具体来说,我们将
使用 Python 脚本从 IOS 备份中提取所有的文本消息。
当用户对 iPhone 或者 iPad 设备进行备份时,它将文件存储到机器的特殊目录。
对于 Windows 系统,iTunes 程序存储移动设备备份目录在 C:\Documents and
Settings\<USERNAME>\Application
Data\AppleComputer\MobileSync\Backup 下,在 Mac OS X 系统上储存目录在
/Users/<USERNAME>/Library/Application Support/MobileSync/Backup/。
iTunes 程序备份移动设备存储所有的移动设备到这些目录下。让我们来探究我
的 iPhone 最近的备份文件。
investigator$ ls
68b16471ed678a3a470949963678d47b7a415be3
68c96ac7d7f02c20e30ba2acc8d91c42f7d2f77f
68b16471ed678a3a470949963678d47b7a415be3
68d321993fe03f7fe6754f5f4ba15a9893fe38db
69005cb27b4af77b149382d1669ee34b30780c99
693a31889800047f02c64b0a744e68d2a2cff267
6957b494a71f191934601d08ea579b889f417af9
698b7961028238a63d02592940088f232d23267e
6a2330120539895328d6e84d5575cf44a082c62d
<..SNIPPED..>
为了获得关于每个文件更多的信息,我们将使用 UNIX 命令 file 来提取每个文件
的文件类型。这个命令使用文件头的字节信息类确认文件类型。这为我们提供
了更多的信息,我们看到移动备份目录包含了一些 sqlite3 数据库,JPEG 图像,
原始数据和 ASCII 文本文件。
investigator$ file *
68b16471ed678a3a470949963678d47b7a415be3: data
68c96ac7d7f02c20e30ba2acc8d91c42f7d2f77f: SQLite 3.x database
68b16471ed678a3a470949963678d47b7a415be3: JPEG image data
68d321993fe03f7fe6754f5f4ba15a9893fe38db: JPEG image data
69005cb27b4af77b149382d1669ee34b30780c99: JPEG image data
693a31889800047f02c64b0a744e68d2a2cff267: SQLite 3.x
database
6957b494a71f191934601d08ea579b889f417af9: SQLite 3.x
database
698b7961028238a63d02592940088f232d23267e: JPEG image data
6a2330120539895328d6e84d5575cf44a082c62d: ASCII English
text
<..SNIPPED..>
file 命令让我们知道一些文件包含 SQLite 数据库并对灭个数据库的内容有少量
的描述。我们将使用 Python 脚本快速的快速的枚举在移动备份目录下找到的每
一个数据库的所有的表。注意我们将再次在我们的 Python 脚本中使用
sqlite3。我们的脚本列出工作目录的内容然后尝试连接每一个数据库。对于那
些成功的连接,脚本将执行命令:SELECT tbl_name FROM sqlite_master
WHERE type==‘table’。,每一个 SQLite 数据库维护了一个
sqlite_master 的表包含了数据库的总体结构,说明了数据库的总体架构。上面
的命令允许我们列举数据库模式。
import os
import sqlite3
def printTables(iphoneDB):
try:
conn = sqlite3.connect(iphoneDB)
c = conn.cursor()
c.execute('SELECT tbl_name FROM sqlite_master WHERE
type==\"table\";')
print("\n[*] Database: "+iphoneDB)
for row in c:
print("[-] Table: "+str(row))
except:
pass
finally:
conn.close()
dirList = os.listdir(os.getcwd())
for fileName in dirList:
printTables(fileName)
运行我们的脚本,我们列举了移动备份目录里的所有的数据库模式。当脚本找
到多个数据库,我们将整理输出我们关心的特定的数据库。注意文件名为
d0d7e5fb2ce288813306e4d4636395e047a3d28 包含了一个 SQLite 数据库里面
有一个名为 messages 的表。该数据库包含了存储在 iPhone 备份中的文本消息
列表。
investigator$ python listTables.py
<..SNIPPED...>
[*] Database: 3939d33868ebfe3743089954bf0e7f3a3a1604fd
[-] Table: (u'ItemTable',)
[*] Database: d0d7e5fb2ce288813306e4d4636395e047a3d28
[-] Table: (u'_SqliteDatabaseProperties',)
[-] Table: (u'message',)
[-] Table: (u'sqlite_sequence',)
[-] Table: (u'msg_group',)
[-] Table: (u'group_member',)
[-] Table: (u'msg_pieces',)
[-] Table: (u'madrid_attachment',)
[-] Table: (u'madrid_chat',)
[*] Database: 3de971e20008baa84ec3b2e70fc171ca24eb4f58
[-] Table: (u'ZFILE',)
[-] Table: (u'Z_1LABELS',)
<..SNIPPED..>
虽然现在我们知道 SQLite 数据库文件
d0d7e5fb2ce288813306e4d4636395e047a3d28 包含了文本消息,我们想要能
够自动的对不同的备份进行调查。为了执行这个,我们编写了一个简单的函数
名为 isMessageTable(),这个函数将连接数据库并枚举数据库模式信息。如果
文件包含名为 messages 的表,则返回 True,否则函数返回 False。现在我们有
能力快速扫描目录下的上千个文件并确认包含 messages 表的特定数据库。
def isMessageTable(iphoneDB):
try:
conn = sqlite3.connect(iphoneDB)
c = conn.cursor()
c.execute('SELECT tbl_name FROM sqlite_master WHERE
type==\"table\";')
for row in c:
if 'message' in str(row):
return True
except:
return False
现在,我们可以定位文本消息数据库了,我们希望可以打印包含在数据库中的
内容,如时间,地址,文本消息。为此,我们连接数据库并执行以下命令:
‘select datetime(date,\‘unixepoch\’), address, text from message WHERE
address>0;’我们可以打印查询结果到屏幕上。注意,我们将使用一些异常处
理,如果 isMessageTable()返回的数据库不是我们需要的文本信息数据库,它
将不包含数据,地址,和文本的列。如果我们去错了数据库,我们将允许脚本
捕获异常并继续执行,直到找到正确的数据库。
def printMessage(msgDB):
try:
conn = sqlite3.connect(msgDB)
c = conn.cursor()
c.execute('select datetime(date,\'unixepoch\'),address, text
from message WHERE address>0;')
for row in c:
date = str(row[0])
addr = str(row[1])
text = row[2]
print('\n[+] Date: '+date+', Addr: '+addr + ' Message: ' +
text)
except:
pass
包装这些函数在一起,我们可以构建最终的脚本。我们将添加一个选项解析来
执行 iPhone 备份的目录。接下来,我们将列出该目录的内容并测试每一个文件
直到找到文本信息数据库。一旦我们找到这个文件,我们可以打印数据库的内
容在屏幕上。
# coding=UTF-8
import os
import sqlite3
import optparse
def isMessageTable(iphoneDB):
try:
conn = sqlite3.connect(iphoneDB)
c = conn.cursor()
c.execute('SELECT tbl_name FROM sqlite_master WHERE
type==\"table\";')
for row in c:
if 'message' in str(row):
return True
except:
return False
def printMessage(msgDB):
try:
conn = sqlite3.connect(msgDB)
c = conn.cursor()
c.execute('select datetime(date,\'unixepoch\'),address, text from
message WHERE address>0;')
for row in c:
date = str(row[0])
addr = str(row[1])
text = row[2]
print('\n[+] Date: '+date+', Addr: '+addr + ' Message: ' + text)
except:
pass
def main():
parser = optparse.OptionParser("usagerog -p <iPhone Backup
Directory> ")
parser.add_option('-p', dest='pathName',
type='string',help='specify skype profile path')
(options, args) = parser.parse_args()
pathName = options.pathName
if pathName == None:
print parser.usage
exit(0)
else:
dirList = os.listdir(pathName)
for fileName in dirList:
iphoneDB = os.path.join(pathName, fileName)
if isMessageTable(iphoneDB):
try:
print('\n[*] --- Found Messages ---')
printMessage(iphoneDB)
except:
pass
if __name__ == '__main__':
main()
对 iPhone 备份目录运行这个脚本,我们可以看到一些存储在 iPhone 备份中的
最近的文本消息。
investigator$ python iphoneMessages.py -p ∼/Library/Application\
Support/MobileSync/Backup/192fd8d130aa644ea1c644aedbe2370
8221146a8/
[*] --- Found Messages ---
[+] Date: 2011-12-25 03:03:56, Addr: 55555554333 Message:
Happy
holidays, brother.
[+] Date: 2011-12-27 00:03:55, Addr: 55555553274 Message: You
didnt
respond to my message, are you still working on the book?
[+] Date: 2011-12-27 00:47:59, Addr: 55555553947 Message: Quick
question, should I delete mobile device backups on iTunes?
<..SNIPPED..>