1. 程式人生 > >Android安全/安全技術--21--基礎檔案格式解析

Android安全/安全技術--21--基礎檔案格式解析

4-1、so檔案格式解析

1、ELF檔案格式

Android中的so檔案就是ELF檔案,瞭解so檔案首先需要了解ELF檔案的格式,使用工具為readelf,常用命令如下:

1、檢視so檔案的頭部資訊

readelf -h xxx.so            //如:libhello.so等

2、檢視so檔案的節(Section)頭的資訊

readelf -S xxx.so            //如:libhello.so等

3、檢視so檔案的程式段頭資訊(Program)

readelf -l xxx.so            //如:libhello.so等

4、檢視so檔案的全部內容

readelf -a xxx.so            //如:libhello.so等

2、解析ELF檔案

1、定義ELF檔案中各個結構體的內容,需要閱讀原始碼中elf.h檔案,路徑如下:

\external\kernel-headers\original\asm-x86\elf.h

在看elf.h檔案中定義的資料結構時,記得每個欄位佔用的位元組數的可以了。

解析ELF檔案的頭部資訊

ELF頭部資訊資料結構中常用的幾個重要欄位:

e_phoff:是程式頭內容在整個檔案的偏移值,可以用這個偏移值來定位程式頭的開始位置,用於解析程式頭資訊。 e_shoff:是段頭內容在這個檔案的偏移值,可以用這個偏移值來定位段頭的開始位置,用於解析段頭資訊。 e_phnum:是程式頭的個數。 e_shnum:是段頭的個數。 e_shstrndx:是String段在整個段列表中的索引值,用於後面定位String段的位置。

3、解析段頭資訊,大致同上

4、解析程式頭資訊,大致同上

4-2、AndroidManifest.xml檔案格式解析

1、解析頭部資訊

任何一個檔案都有頭部資訊,頭部資訊一般都有固定格式頭部資訊還有以下這些欄位資訊:

檔案魔數(Magic Number):四個位元組
檔案大小(File Size):四個位元組

2、解析String Chunk

String Chunk主要用於存放AndroidManifest檔案中所有的字串資訊。

ChunkType:StringChunk的型別,固定四個位元組:0X001C0001
ChunkSize:StringChunk的大小,四個位元組
StringCount:StringChunk中字串的個數,四個位元組
StyleCount:StringChunk中樣式個數,四個位元組,一直是0X00000000
Unknown:區域位置,四個位元組,在解析過程中,這裡需要略過四個位元組
StringPoolOffset:字串池的偏移值,四個位元組,這個偏移值是相對與StringChunk的頭部位置
StylePoolOffset:樣式池的偏移值,四個位元組,這裡沒有Style,這個欄位可以忽略
StringOffsets:每個字串的偏移值,它的大小應該是StringCount*4個位元組
StyleOffsets:每個樣式的偏移值,它的大小應該是StyleCount*4個位元組

3、解析Resourceld Chunk

Resourceld Chunk主要是用來存放AndroidManifest中用到的系統屬性值對應的資源ID。

ChunkType:Resourceld Chunk的型別,固定四個位元組:0X00080108
ChunkSize:Resourceld Chunk的大小,四個位元組
Resourcelds:Resourceld的內容,這裡大小是Resourceld Chunk大小除以4,減去頭部的大小8個位元組(ChunkType和ChunkSize)

4、解析Start Namespace Chunk

這個Chunk主要包含一個AndroidManifest檔案中的命令空間的內容

ChunkType:Chunk的型別,固定四個位元組:0X00100100
ChunkSize:Chunk的大小,四個位元組
LineNumber:在AndroidManifest檔案中的行號,四個位元組
Unknown:未知區域,四個位元組
Prefix:名稱空間的字首,比如:android
Uri:名稱空間的URI

5、解析Start Tag Chunk

這個Chunk主要是存放AndroidManifest中的標籤資訊,是最核心、最複雜的內容

ChunkType:Chunk的型別,固定四個位元組:0X00100102
ChunkSize:Chunk的大小
LineNumber:在AndroidManifest檔案中的行號,四個位元組
Unkonwn:未知區域,四個位元組
NamespaceUri:該標籤用到的名稱空間的URI,四個位元組
Name:標籤名稱,四個位元組
Flags:標籤的型別,四個位元組,比如是開始標籤還是結束標籤等
AttributeCount:標籤包含的屬性個數,四個位元組
ClassAttribute:標籤包含的類屬性,四個位元組
Attributes:屬性內容,每個屬性是一個大小為5位元組的Entry陣列

4-3、resource.arsc檔案格式解析

1、頭部資訊

Resources.arsc檔案格式是由一系列的Chunk構成,每一個Chunk均包含ResChunk_header,用來描述這個Chunk的基本資訊。

type:當前Chunk的型別
headerSize:當前Chunk的頭部大小
size:當前Chunk的大小

2、資源索引表的頭部資訊

Resources.arsc檔案的第一個結構是資源索引表頭部,其結構描述了Resources.arsc檔案的大小和資源包數量。

header:就是標準的Chunk頭部資訊格式
packageCount:被編譯的資源包的個數

3、資源項的值字串資源池

緊跟頭部的是資源項的值字串資源池,該字串資源池包含了所有在資源包裡面定義的資源項的值字串。

header:標準的Chunk頭部資訊結構
stringCount:字串的個數
styleCount:字串樣式的個數
flags:字串的屬性,可取值包括0x000、0x001、0x100和它們的組合值
stringStart:字串內容塊相對於其頭部的距離
stylesStart:字串樣式塊相對於其頭部的距離

4、Package資料塊

接著資源項的值字串資源池後面的部分就是Package資料塊,這個資料塊記錄編譯包的元資料。

header:Chunk的頭部資訊資料結構
id:包的ID,等於Package ID,一般使用者包為0x7f,系統資源包為0x01
name:包名
typeString:型別字串資源池相對頭部的偏移
lastPublicType:最後一個匯出的Public型別字串在型別字串資源池中的索引
keyStrings:資源項名稱字串相對頭部的偏移
lastPublicKey:最後一個匯出的Public資源項名稱字串在資源項名稱字串資源池中的索引

5、型別規範資料塊

型別規範資料塊用來描述資源項的配置差異性。

header:Chunk的頭部資訊結構
id:標識資源的Type ID
res0:保留,始終為0
res1:保留,始終為0
entryCount:等於本型別的資源項個數,指名稱相同的資源項的個數

6、資源型別項資料塊

用來描述資源項的具體資訊,如此就可以知道每一個資源項的名稱、值和配置等資訊。

header:Chunk的頭部資訊結構
id:標識資源的Type ID
res0:保留,始終為0
res1:保留,始終為0
entryCount:等於本型別的資源項個數,指名稱相同的資源項的個數
entriesStart:等於資源項資料塊相對頭部的偏移值
resConfig:指向一個ResTable_config,用來描述配置資訊、地區、語言、解析度等。

ResTable_type後接著是一個大小為entryCount的uint32_t陣列,每一個數組元素都用於描述一個資源型別項資料塊的偏移位置。緊跟在這個偏移陣列後面的是一個大小為entryCount的ResTable_entry陣列,每一個數組元素都用來描述一個資源項的具體資訊。

ResTable_entry根據flags的不同,後面跟的資料也不相同:

flags為1:ResTable_entry是ResTable_map_entry,ResTable_map_entry繼承自ResTable_entry,而ResTable_map_entry其後跟著count個ResTable_map型別的陣列。 flags為0:則ResTable_entry其後跟隨的是一個Res_value,描述一個普通資源的值。

4-4、dex檔案格式解析

dex檔案格式如下:

檔案頭 header 檔案頭
索引區 string_ids 字串的索引
type_ids 型別的索引
proto_ids 方法原型的索引
field_ids 域的索引
method_ids 方法的索引
資料區 class_defs 類的定義區
data 資料區
link_data 連結資料區

上我寫的文件截圖: 在這裡插入圖片描述

1、頭部資訊header結構

dex檔案裡的header除了描述.dex檔案的資訊外,還有檔案裡其它各個區域的索引。header對應為結構體型別,邏輯上的描述用結構體header_item來理解它。

檔案頭摘要:

偏移值 大小 說明
0x0 8 幻數(magic number):”dex\n009\0”
0x8 4 校驗和
0xC 20 SHA-1 Signature
0x20 4 檔案長度(位元組)
0x24 4 頭長度(始終為0x5C)
0x28 8 填充(預留空間)
0x30 4 字元列表中的字元值
0x34 4 字元列表的絕對位移值
0x38 4 字元相關空間
0x3C 4 類專案中的類的數量
0x40 4 類專案的絕對位移值
0x44 4 欄位列表中的欄位數量
0x48 4 欄位列表的絕對位移值
0x4C 4 方法列表中的方法數量
0x50 4 方法列表的絕對位移值
0x54 4 類定義列表中的類定義數量
0x58 4 類定義列表的絕對位移值

magic:頭區域的起始8位元組是magic number。最後n035\0是換行回車符和Null值,用於防止破壞magic number的數值 Checksum:除magic number以外的其他檔案的校驗和值,使用了adler32演算法。因為是小端序儲存的,所以是0x07784031 Signature:除magic number、校驗和之外的其他檔案的SHA-1演算法識別標誌,用於識別固有檔案 file_size:檔案大小。因使用了小端序,所以是0x6100 Header_size:頭大小,始終為0x70 endian_tag:小端序標籤。值為0x12345678,表示資料使用小端序方式儲存 link_size:Link節區大小。非靜態連線時會設定為“0” link_off:從檔案起始到連線會話的位移值。如果link_size是0,它也會被設定為0。如果不是0,位移值應該是link_data節區的位移值

2、string_ids資料結構

string_ids區索引了dex檔案所有的字串,這個區裡的元素格式為string_ids_item。以_ids結尾的各個段裡放置的都是對應資料的偏移地址,只是為一個索引,所以才會在dex檔案佈局裡把這些區歸類為“索引區”。

LEB128格式:是基於一個位元組的一種不定長的編碼方式,若第一個位元組的最高位為1,則表示還需要下一個位元組來描述,直至最後一個位元組最高位為0。將LEB128編碼的數字轉換為可讀數字的規則是:除去每個位元組的第7位(左邊最高位),將每個位元組剩餘的7個位拼接在一起,即為要實際使用的數字。

3、type_ids資料結構

type_ids資料結構中存放的資料主要是描述dex中所有的型別,比如類型別、基本型別等資訊。type_ids區索引了dex檔案裡的所有資料型別,包括class型別、陣列型別、基本型別。本區域裡的元素格式為:type_ids_item。

4、proto_ids資料結構

該資料結構裡的元素為proto_id_item。其中引數如下:

shorty_idx:它的值是一個string_ids的index號,最終是一個簡短的字串描述,用來說明該method原型。
return_type_idx:它的值是一個type_ids的index號,表示該method原型的返回值型別。
parameters_off:字尾off是offset,指向method原型的引數列表type_list,若method沒有引數,則值為0。

5、field_ids資料結構

field_ids區裡面存放的是dex檔案引用的所有的field。這個區的元素格式是field_id_item。

class_idx:表示本field所屬的class型別,class_idx的值是type_ids的一個index,並且必須指向一個class型別。
type_idx:表示本field的型別,它的值也是type_ids的一個index
name_idx:表示本field的名稱,它的值是string_ids的一個index

6、method_ids資料結構

method_ids是索引區的最後一個條目,它索引了dex檔案裡的所有method。method_ids的元素格式是method_id_item。

class_idx:表示該method所屬的class型別,class_idx的值是type_ids的一個index,並且必須指向一個class型別。
name_idx:表示該method的名稱,它的值是string_ids的一個index。
proto_idx:描述該method的原型,指向proto_ids的一個index。

7、class_defs資料結構

1、class_def_item:class_defs區域裡存放著class的定義,並且部分資料指向了data區域裡面。

偏移值 大小 說明
0x0 4 類索引
0x4 4 訪問插口
0x8 4 超級類的索引
0xC 4 介面專案的絕對位移
0x10 4 靜態欄位專案的絕對位移
0x14 4 例項欄位專案的絕對位移0x18 4 非虛擬方法專案的絕對位移
0x1C 4 虛擬方法專案的絕對位移

class_idx:描述具體的class型別,值是type_ids的一個index access_flags:描述class的訪問型別,諸如public、final、static等 superclass_idx:描述supperclass的型別,值的形式跟class_idx一樣 interfaces_off:值為偏移地址,指向class的interfaces,被指向的資料結構為type_list。class若沒有interfaces,值為0 source_file_idx:表示原始碼檔案的資訊,值是string_ids的一個index annotions_off:值是一個偏移地址,指向的內容是該class的註釋,位置在data區,格式為:annotations_directory_item,若沒有此項內容,值為0 class_data_off:值是一個偏移地址,指向的內容是該class的使用到的資料,位置在data區,格式為class_data_item,若沒有此項內容,值為0 static_value_off:值是一個偏移地址,指向data區裡的一個列表,格式為encoded_array_item,若沒有此項內容,值為0

2、class_def_item => class_data_item

class_data_off指向data區裡的class_data_item結構,class_data_item裡存放著本class使用到的各種資料。

3、class_def_item => class_data_item => code_item

如何走到這一步:

1、一個dex檔案被分成了9個區,其中一個索引區叫做class_defs,索引了dex裡面用到的class,以及對這個class的描述。

2、class_defs區,其實是class_def_item結構,描述了諸如名稱、superclass、access flag、interface等。

3、class_data_item結構,描述class裡使用到的static field、interface field、direct_method、virtual_method的數目和描述。

4、encoded_method結構,描述了某個method和method型別,access flags和一個指向code_item的偏移地址,裡面存放的是該method的具體實現。

5、code_item,該結構裡描述著某個method的具體實現。