這篇主要講解如何解析Manifest.mbdb文件。
使用二進制工具打開這個文件,文件的頭6個字節是固定的,相當於是文件的一種標識
后面的內容是一個一個的項,可以使用一個循環來讀取文件,一個一個解析。
這里有一個概念要先說一下,就是域,域是用來定位一個文件在手機上的全路徑。比如上圖的 AppDomain-cairot,這個域就表示文件在手機上的目錄為 /var/mobile/Applications/,不同的域對應的手機的目錄是不一樣的,下面給出所有域和目錄的一個對應關系,下面是自己的一段代碼, 看懂這段代碼就知道域和路徑的關系了。
if (item.Domain == "WirelessDomain")
{
item.PathOnPhone.Format("/var/wireless/%s", item.Path);
}
else if (item.Domain == "ManagedPreferencesDomain")
{
item.PathOnPhone.Format("/var/Managed Preferences/%s", item.Path);
}
else if (item.Domain == "MediaDomain")
{
item.PathOnPhone.Format("/var/mobile/%s", item.Path);
}
else if (item.Domain == "SystemPreferencesDomain")
{
item.PathOnPhone.Format("/var/preferences/%s", item.Path);
}
else if (item.Domain == "CameraRollDomain")
{
item.PathOnPhone.Format("/var/mobile/%s", item.Path);
}
else if (item.Domain == "RootDomain")
{
item.PathOnPhone.Format("/var/root/%s", item.Path);
}
else if (item.Domain == "MobileDeviceDomain")
{
item.PathOnPhone.Format("/var/MobileDevice/%s", item.Path);
}
else if (item.Domain == "KeychainDomain")
{
item.PathOnPhone.Format("/var/Keychains/%s", item.Path);
}
else if (item.Domain == "HomeDomain")
{
item.PathOnPhone.Format("/var/mobile/%s", item.Path);
}
else if (item.Domain == "DatabaseDomain")
{
item.PathOnPhone.Format("/var/db/%s", item.Path);
}
else if (item.Domain.Find("AppDomain-") == 0)
{
CAtlStringA strTmp(item.Domain);
strTmp.Replace("AppDomain-", "");
item.PathOnPhone.Format("/var/mobile/Applications/%s/%s",strTmp , item.Path);
}
1) 獲取域。 頭6個字節之后的2個字節,標識域的長度,但是2字節的內容並不是直接標識長度,看下面的代碼。先讀出一個字節,然后再讀出一個字節,進行運算之后得出的一個長度。下圖就是 AppDomain-cairot
std::string CBackupMbdb::ReadNextStringBy2bytesLen(CBinaryReader& reader)
{
std::string strResult;
byte num = reader.ReadByte();
byte num2 = reader.ReadByte();
if ((num == 0xff) && (num2 == 0xff))
{
return strResult;
}
int num3 = (num * 0x100) + num2;
strResult = reader.ReadString(num3);
return strResult;
}
2) 之后就是手機上路徑。這個路徑和域組合之后就可以得出文件在iphone 上的全路徑了。第一個圖中的item.path 就是這個路徑,item.Domain 就是域。 根據上面的代碼就可以組合出全路徑了。這個路徑獲取方法和域是一樣的。先讀取文件的2個字節,然后根據這兩個字節的大小讀取內容。從上圖看先讀的兩個為0000,所以路徑就是空字符串。
3)鏈接路徑。這個我也不是很清楚,貌似像是windows 的快捷方式一樣,會指向一個其他的路徑。反正我沒用上這個東西。 讀取的方式和前面一樣
4) 緊接着數據的一段哈希。先讀出2個字節,然后根據這兩個字節計算出一個大小,進行一些判斷之后把16 進制的數據轉換成字符串。
std::string CBackupMbdb::smethod10(CBinaryReader& reader)
{
std::string strResult ;
byte num = reader.ReadByte();
byte num2 = reader.ReadByte();
if ((num == 0xff) && (num2 == 0xff))
{
return strResult;
}
int num6 = (num * 0x100) + num2;
CAutoVectorPtr<byte> pBuffer;
pBuffer.Allocate(num6);
reader.Read(pBuffer.m_p,num6);
int index = 0;
index = 0;
while (index < num6)
{
if ((pBuffer.m_p[index] < 0x20) || (pBuffer.m_p[index] >= 0x80))
{
break;
}
index++;
}
if (index == num6)
{
strResult = bytes_to_hex_string(pBuffer.m_p,num6);
}
return strResult;
}
5) 第五個內容的讀取方法和第四個一樣,但是所有的讀出來的都是空字符串。
6) 讀出固定的40個字節,這40個字節里面包含的信息很多,不過大部分都是不需要的,只有一個字段是重要的,這個字段會影響后面的文件讀取。
CAutoVectorPtr<byte> pRecordInfo;
pRecordInfo.Allocate(40);
reader.Read(pRecordInfo.m_p,40);
//0x27 也就是最后的位置保存了這個項的屬性個數,要用這個數字循環讀出屬性來。
itemInfo.PropertyCount = pRecordInfo[0x27];
for (int i=0;i<itemInfo.PropertyCount;i++)
{
CAtlStringA key = ReadNextStringBy2bytesLen(reader).c_str();
CAtlStringA value = smethod10(reader).c_str();
itemInfo.Properties[key] = value;
}
7) 根據第一步和第二步得出來的域和路徑計算SHA1值,這個哈希值也就是本地的路徑。
std::string strHash1Src;
if (itemInfo.Path.IsEmpty())
{
strHash1Src = itemInfo.Domain;
}
else
{
strHash1Src = itemInfo.Domain + "-" + itemInfo.Path;
}
std::string strTmp;
CAppUtilis::EncrypBySHA1(strHash1Src,strTmp);
然后一直循環讀取文件,直到文件讀完就可以解析出所有的文件路徑了
轉讓Android,IOS 手機助手各種技術資料,文檔,以及源碼,有需要的可以聯系我QQ: 2506314894