自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android下通過hook技術(shù)實(shí)現(xiàn)透明加解密保障數(shù)據(jù)安全

安全 數(shù)據(jù)安全
對(duì)于用戶在Android移動(dòng)設(shè)備商保存重要的隱私文件,通常采用一些加密保存的軟件。但在手機(jī)上實(shí)現(xiàn)隱私空間的軟件鱗次櫛比,但是問題在于打開文件都需要使用該隱私空間,將加密文件解密到臨時(shí)文件,然后再選擇應(yīng)用程序打開文件。

 一、前言

對(duì)于用戶在Android移動(dòng)設(shè)備商保存重要的隱私文件,通常采用一些加密保存的軟件。但在手機(jī)上實(shí)現(xiàn)隱私空間的軟件鱗次櫛比,但是問題在于打開文件都需要使用該隱私空間,將加密文件解密到臨時(shí)文件,然后再選擇應(yīng)用程序打開文件。這將導(dǎo)致用戶重要文件在設(shè)備上明文的存在,存在泄漏的風(fēng)險(xiǎn)。

而且根據(jù)筆者的調(diào)研,對(duì)于360隱私空間,應(yīng)用程序?qū)εR時(shí)文件修改后不能再逆向加密回密文,導(dǎo)致加密操作只能一次進(jìn)行。LBE隱私空間,相對(duì)較好,但其臨時(shí)文件存在生命周期過長(zhǎng)。

因此筆者通過現(xiàn)有知識(shí)討論一種采用hook技術(shù)實(shí)現(xiàn)的透明加解密方法,不需要在設(shè)備上生成臨時(shí)文件,從而保護(hù)用戶重要隱私。

二、技術(shù)要點(diǎn)

由于Android是基于linux內(nèi)核的開源系統(tǒng),根據(jù)語(yǔ)言環(huán)境不同可以分為Java層、Native C層、Linux Kernel層。Java層的安全是使用Java語(yǔ)言開發(fā),基于SDK,能實(shí)現(xiàn)的功能相對(duì)簡(jiǎn)單。Linux Kernel層安全,需要從源碼做起,編譯自己的系統(tǒng),通用性不強(qiáng)。因此在Native C層,通過JNI開發(fā),可以使用linux提供的函數(shù)實(shí)現(xiàn)更多的功能。

在hook API方面與linux的hook類似使用ptrace 函數(shù)與plt表實(shí)現(xiàn),還可以采用Inline hook的方式實(shí)現(xiàn),但是不是很穩(wěn)定,操作難度大。其本質(zhì)都是劫持函數(shù)調(diào)用。

但是由于處于Linux用戶態(tài),每個(gè)進(jìn)程都有自己獨(dú)立的進(jìn)程空間,所以必須先注入到所要hook的進(jìn)程空間,修改其內(nèi)存中的進(jìn)程代碼,替換其中過程表的符號(hào)地址,因此其生存空間是所注入的進(jìn)程,只能對(duì)某一進(jìn)程進(jìn)行HOOK。

Ptrace函數(shù)是調(diào)試程序所用,功能強(qiáng)大,不僅可以附加某一進(jìn)程(PTRACE_ATTACH),而且可以任意修改目標(biāo)進(jìn)程的內(nèi)存空間(PTRACE_PEEKDATA,讀內(nèi)存。PTRACE_POKEDATA,寫內(nèi)存),甚至是寄存器(PTRACE_SETREGS,PTRACE_GETREGS)

基本流程是利用寄存器指令中斷:

① PTRACE_ATTACH,綁定目標(biāo)進(jìn)程。

② PTRACE_GETREGS,獲取目標(biāo)進(jìn)程寄存器狀態(tài),并保存。

③ PTRACE_PEEKDATA與PTRACE_POKEDATA配合,保存原代碼,寫入要注入的代碼到當(dāng)前運(yùn)行位置。

④ PTRACE_SETREGS,恢復(fù)寄存器狀態(tài),并繼續(xù)執(zhí)行,這是注入的代碼開始在目標(biāo)進(jìn)程內(nèi)執(zhí)行,注入代碼完成HOOK,過程與Windows下相似。

⑤ 在HOOK完成后,注入的代碼執(zhí)行int3被ptrace捕獲,目標(biāo)進(jìn)程再次暫停執(zhí)行。

⑥ PTRACE_GETREGS,再次保存寄存器。

⑦ PTRACE_PEEKDATA與PTRACE_POKEDATA配合還原代碼。

⑧ PTRACE_SETREGS,恢復(fù)寄存器,目標(biāo)進(jìn)程繼續(xù)執(zhí)行。

⑨ PTRACE_DETACH,撤銷綁定目標(biāo)進(jìn)程。

參考LBE實(shí)現(xiàn)原理和看雪上關(guān)于Hook Ioctl的文章都基本上按照這種流程實(shí)現(xiàn)HOOK。

在明白hook工作機(jī)制后,對(duì)于實(shí)現(xiàn)Android上的透明加解密需要找到open和close函數(shù)的符號(hào)存在哪個(gè)動(dòng)態(tài)鏈接庫(kù)中,hook該應(yīng)用程序的這個(gè)動(dòng)態(tài)鏈接庫(kù),在open操作進(jìn)行的時(shí)候,將密文文件分塊解密到內(nèi)存中,并將該內(nèi)存中的文件標(biāo)識(shí)符返回。在close操作進(jìn)行的時(shí)候?qū)?nèi)存中的明文加密到本地密文存儲(chǔ)。

三、關(guān)鍵流程

1、閱讀Android代碼查找打開文件和關(guān)閉文件過程。這是我們實(shí)現(xiàn)透明加解密的關(guān)鍵。

參考http://blog.chinaunix.net/uid-26926660-id-3326678.html的方式

可以發(fā)現(xiàn)讀取文件流的函數(shù)最終通過JNI方式的read函數(shù)實(shí)現(xiàn),同樣打開文件的操作最終都?xì)w結(jié)于open函數(shù)。

而實(shí)現(xiàn)Java代碼的JNI支持的動(dòng)態(tài)庫(kù)是nativehelper.so因此我們需要hook的動(dòng)態(tài)庫(kù)即nativehelper.so。

注:在Android早期版本即android2.3、Android4.0上open和close符號(hào)在nativehelper.so中,該文件有140k大小。而在android4.1版本以上,谷歌重寫了android原生庫(kù)的實(shí)現(xiàn),nativehelper.so被拆分,筆者在4.0平臺(tái)進(jìn)行的開發(fā)并沒有閱讀尋找4.1版本之上的。

2、進(jìn)行進(jìn)程注入和ELF節(jié)替換

進(jìn)程注入就是將一段代碼拷貝到目標(biāo)進(jìn)程,然后讓目標(biāo)進(jìn)程執(zhí)行這段代碼的技術(shù)。由于這樣的代碼構(gòu)造起來比較復(fù)雜,所以實(shí)際情況下,只將很少的代碼注入到目標(biāo)進(jìn)程,而將真正做事的代碼放到一個(gè)共享庫(kù)中,即.so文件。被注入的那段代碼只負(fù)責(zé)加載這個(gè).so,并執(zhí)行里面的函數(shù)。由于.so中的函數(shù)是在目標(biāo)進(jìn)程中執(zhí)行的,所以在.so中的函數(shù)可以修改目標(biāo)進(jìn)程空間的任何內(nèi)存,當(dāng)然也可以加鉤子,從而達(dá)到改變目標(biāo)進(jìn)程工作機(jī)制的目的。

當(dāng)然不是任何進(jìn)程都有權(quán)限執(zhí)行注入操作的。Android平臺(tái)上的進(jìn)程注入是基于ptrace()的,要調(diào)用ptrace()需要有root權(quán)限。目前市面上的主流安全軟件也都是基于進(jìn)程注入來管理和控制其他應(yīng)用進(jìn)程的。這也就是為什么這些安全軟件需要獲得root權(quán)限的原因。

關(guān)于如何.so注入的實(shí)現(xiàn),可以參考看雪論壇的上的一個(gè)注入庫(kù)LibInject 和洗大師的一個(gè)開源項(xiàng)目Android Injector Library。

筆者對(duì)這種兩種方式都有實(shí)驗(yàn),對(duì)于Libinject,就是向目標(biāo)進(jìn)程中注入libhook.so,首先調(diào)用ptrace()函數(shù),掛起該進(jìn)程。然后遍歷進(jìn)程加載的libc.so,通過dlopen和dlsym函數(shù)修改arm寄存器的值,然后壓入?yún)?shù),so路徑,并將之前找到的dlopen地址壓入寄存器,直接操作blx,就可以讓目標(biāo)進(jìn)程調(diào)用dlopen加載我們的so,同理dlsym調(diào)用我們的so里的函數(shù)。

注入完成后,會(huì)調(diào)用libhook.so庫(kù)中的hook_entry()函數(shù),該函數(shù)實(shí)現(xiàn)加載hook函數(shù)實(shí)現(xiàn)的動(dòng)態(tài)庫(kù),并對(duì)libnativehelper.so的got表和plt表的遍歷和修改。修改為自己編寫的實(shí)現(xiàn)open函數(shù)和close函數(shù)的動(dòng)態(tài)庫(kù)中的符號(hào)地址。因此需要注入兩個(gè)庫(kù),因?yàn)閘ibhook.so在執(zhí)行完后需要detach目標(biāo)進(jìn)程,從而釋放,而具體操作的動(dòng)態(tài)庫(kù)需要常駐內(nèi)存。實(shí)現(xiàn)常駐內(nèi)存需要在hook_entry()函數(shù)中顯式加載動(dòng)態(tài)庫(kù)。

以上注入以后的過程都由自己編程實(shí)現(xiàn),能夠加深對(duì)ELF格式理解。

而采用Android Injector Library則相對(duì)簡(jiǎn)單,在調(diào)用可執(zhí)行程序的主函數(shù)中實(shí)現(xiàn)即可:

這個(gè)文件編譯生成注入入口和符號(hào)表替換邏輯。

* 1、在該函數(shù)中加載libhook.so通過其中的do_hook函數(shù)返回原來的open和close地址以及要替換的新的open和close函數(shù)地址

* 2、然后靜態(tài)打開libnativehelper動(dòng)態(tài)庫(kù),讀取其結(jié)構(gòu)遍歷節(jié)表,找到全局符號(hào)表(GOT表),該表存儲(chǔ)了外部依賴符號(hào)的地址

* 3、遍歷GOT表找到原先的open函數(shù)和close函數(shù)地址,分別替換為新的open函數(shù)和新的close函數(shù)即可

 

圖片1

 

3、在學(xué)習(xí)這一過程中,需要了解linux的ELF格式,以下是學(xué)習(xí)ELF的筆記:參見《程序員的自我修養(yǎng)》如果熟悉則可跳過。

 

圖片2
圖片3

 

ehdr->e_shstrndx索引指向shstrtab的節(jié),可以用來索引節(jié)頭的字符串名稱描述。shstrtab表(Section Header String Table)保存段表中用到的字符串,最常見的就是段名、

常用的段名	說明
.rodata1	Read Only Data,這種段里存放的是只讀數(shù)據(jù),比如字符串常量、全局const變量。跟”.rodata”一樣
.comment	存放的是編譯器版本信息
.debug	        調(diào)試信息
.dynamic	動(dòng)態(tài)鏈接信息
.hash	        符號(hào)哈希表
.line	        調(diào)試時(shí)的行號(hào)表
.note	        額外的編譯器信息。比如程序的公司名、發(fā)布版本號(hào)等
.strtab	        String Table.字符串表
.symtab	        Symbol Table.符號(hào)表
.shstrtab	Section String Table.段名表
.plt  .got	動(dòng)態(tài)鏈接的跳轉(zhuǎn)表和全局入口表
.init   .fini	程序初始化與終結(jié)代碼段

符號(hào)節(jié),遍歷節(jié)頭時(shí)候。判斷每一個(gè)節(jié)的類型是不是SHT_SYMTAB或SHT_DYNSYM,那么對(duì)應(yīng)的節(jié)就是符號(hào)節(jié)。符號(hào)節(jié)存放的是一張符號(hào)表,符號(hào)表也是一個(gè)連續(xù)存儲(chǔ)的結(jié)構(gòu)數(shù)組.

編程過程中用到的變量和函數(shù)都可以稱之為符號(hào),一個(gè)ELF文件中并不只有一個(gè)符號(hào)節(jié),通常是兩個(gè),一個(gè)為”.dynsym”的動(dòng)態(tài)節(jié)類型為SHT_DYNSYM,所有引入的外部符號(hào)在這里有所體現(xiàn),另一個(gè)為SHT_SYMTAB,名字為“.symtab”保存了所有有用符號(hào)信息。

Symbol Table 符號(hào)表保存了一個(gè)程序在定位和重定位時(shí)需要的定義和引用的信息。一個(gè)符號(hào)表索引是相應(yīng)的下標(biāo)。符號(hào)表的存在意義是體現(xiàn)在多個(gè)目標(biāo)文件進(jìn)行鏈接的時(shí)候,在鏈接中,目標(biāo)文件之間相互拼合實(shí)際上是目標(biāo)文件之間對(duì)地址的引用,即對(duì)函數(shù)和變量的地址的引用,而函數(shù)和變量可以統(tǒng)稱為符號(hào)(Symbol),函數(shù)名或變量名就是符號(hào)名(Symbol Name)。我們可以將符號(hào)看作是是鏈接中的粘合劑,整個(gè)鏈接過程就是基于符號(hào)才能夠正確完成。在符號(hào)表”.symtab“中,其也是像段表的結(jié)構(gòu)一樣,是一個(gè)數(shù)組,每個(gè)數(shù)組元素是一個(gè)固定的結(jié)構(gòu)來保存符號(hào)的相關(guān)信息,比如符號(hào)名(不是字符串,而是該符號(hào)名在字符串表的下標(biāo))、符號(hào)對(duì)應(yīng)的值(可能是段中的偏移,也可能是符號(hào)的虛擬地址)、符號(hào)大小(數(shù)據(jù)類型的大小)等等。符號(hào)表中記錄的一般是全局符號(hào),比如全局變量、全局函數(shù)等等。

目標(biāo)文件的符號(hào)表包含定位或重定位程序符號(hào)定義和引用時(shí)所需要的信息。符號(hào)表入口結(jié)構(gòu)定義如下:

typedef struct{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
Unsigned char st_info;
Unsigned char st_other;
Elf32_Half st_shndx;
}Elf32_Sym;

其中st_name包含指向符號(hào)表字符串表(strtab)中的索引,從而可以獲得符號(hào)名。St_value指出符號(hào)的值,可能是一個(gè)絕對(duì)值、地址等。St_size指出符號(hào)相關(guān)的內(nèi)存大小,比如一個(gè)數(shù)據(jù)結(jié)構(gòu)包含的字節(jié)數(shù)等。St_info規(guī)定了符號(hào)的類型和綁定屬性,指出這個(gè)符號(hào)是一個(gè)數(shù)據(jù)名、函數(shù)名、section名還是源文件名;并且指出該符號(hào)的綁定屬性是local、global還是weak。

GOT表和PLT表

GOT(Global Offset Table)表中每一項(xiàng)都是本運(yùn)行模塊要引用的一個(gè)全局變量或函數(shù)的地址。可以用GOT表來間接引用全局變量、函數(shù),也可以把GOT表的首地址作為一個(gè)基 準(zhǔn),用相對(duì)于該基準(zhǔn)的偏移量來引用靜態(tài)變量、靜態(tài)函數(shù)。由于加載器不會(huì)把運(yùn)行模塊加載到固定地址,在不同進(jìn)程的地址空間中,各運(yùn)行模塊的絕對(duì)地址、相對(duì)位 置都不同。這種不同反映到GOT表上,就是每個(gè)進(jìn)程的每個(gè)運(yùn)行模塊都有獨(dú)立的GOT表,所以進(jìn)程間不能共享GOT表。

 

圖片4

 

動(dòng)態(tài)鏈接機(jī)制

首先回顧一下Linux平臺(tái)上,一個(gè)模塊甲需要調(diào)用另外一個(gè)模塊乙中的函數(shù)時(shí)的動(dòng)態(tài)鏈接機(jī)制:

1、模塊甲在編譯期間,將要引用的模塊乙的名字與函數(shù)名寫入自身的符號(hào)表。

2、運(yùn)行期模塊甲調(diào)用時(shí),調(diào)用流程是從調(diào)用代碼到PLT表到GOT表再跳入模塊乙。

而如何保證模塊甲的代碼能從其PLT/GOT跳到正確的模塊乙入口,這就是鏈接器做的事情。

標(biāo)準(zhǔn)Linux鏈接器是ld.so,支持懶綁定,也就是說,模塊甲在編譯期間生成的調(diào)用模塊乙的原始代碼,流程是從調(diào)用代碼到PLT表到鏈接器。運(yùn)行期第一次調(diào)模塊乙時(shí),首先進(jìn)入鏈接器,鏈接器根據(jù)調(diào)用信息加載模塊乙搜尋其符號(hào)并將找到的函數(shù)地址填入GOT表,之后的后續(xù)調(diào)用流程就直接走PLT/GOT表了。這種機(jī)制能減少加載時(shí)的開銷,為L(zhǎng)inux發(fā)行版等采用。

Android雖然內(nèi)核基于Linux,但其動(dòng)態(tài)鏈接機(jī)制卻不是ld.so而是自帶的linker,不支持懶綁定。也就是說,上述模塊甲乙如果在Android平臺(tái)上,則是模塊甲加載時(shí),linker就會(huì)根據(jù)模塊甲中的.rel.plt表和字符串表中的內(nèi)容加載模塊乙并搜索其所需函數(shù)地址并預(yù)先填入GOT表。之后調(diào)用流程每次都直接走PLT/GOT表,不再進(jìn)linker,PLT表中也省去了跳至linker的代碼,這種流程和“勤勞”綁定類似,倒是為攔截提供了一點(diǎn)方便。如果攔截懶綁定的入口時(shí)模塊乙還沒加載地址也沒找到,攔截就沒法進(jìn)行了。

要攔截模塊甲對(duì)乙的調(diào)用,一般思路是通過ptrace遠(yuǎn)程注入并加載一新攔截模塊至模塊甲,并搜索模塊甲的GOT表,找到對(duì)模塊乙的調(diào)用地址,改成新模塊內(nèi)的某函數(shù)地址,然后新模塊內(nèi)的這個(gè)函數(shù)在進(jìn)行了自己的處理后,再跳到模塊乙中。

Android和Linux的鏈接器不同導(dǎo)致了內(nèi)存布局的差異,也導(dǎo)致了網(wǎng)上流行的Linux注入與HOOK的方法行不通。網(wǎng)上的方法是通過ptrace注入后,搜索dynamic的section中的PLTGOT區(qū),去里頭取link_map以遍歷此進(jìn)程所加載的模塊來搜索需要hook的函數(shù)地址。但Android上,dynamic的section的PLTGOT區(qū)前幾項(xiàng)都是空的,沒有l(wèi)ink_map這個(gè)數(shù)據(jù)結(jié)構(gòu),只能通過分析/proc/ /maps來遍歷模塊。

4、閱讀代碼中的注意事項(xiàng)

在Android Injector Library閱讀過程中有幾個(gè)需要注意的地方。

1)利用捕捉SIGSEGV的無(wú)效內(nèi)存引用或者段錯(cuò)誤的異常信號(hào)來執(zhí)行ptrace。

2)ptrace(PTRACE_PEEKTEXT, pid, addr, data)

描述:從內(nèi)存地址中讀取一個(gè)字節(jié),pid表示被跟蹤的子進(jìn)程,內(nèi)存地址由addr給出,data為用戶變量地址用于返回讀到的數(shù)據(jù)。

在Linux(i386)中用戶代碼段與用戶數(shù)據(jù)段重合所以讀取代碼段和數(shù)據(jù)段數(shù)據(jù)處理是一樣的。

3)linker 主要用于實(shí)現(xiàn)共享庫(kù)的加載與鏈接。它支持應(yīng)用程序?qū)?kù)函數(shù)的隱式和顯式調(diào)用。查找/system/bin/linker中加載的libdl.so,加載位置固定,定義了dlopen,dlcose,dlsym,dlerror。

4)有下列代碼理解,即dynsym和symtab的關(guān)系

 

圖片5

 

5)在代碼中有關(guān)于dynsym符號(hào)讀取順序的錯(cuò)誤。但是不影響使用。使用androidSDK下的工具readelf

 

圖片6

 

5、需要編寫自己的open函數(shù)和close函數(shù)實(shí)現(xiàn)加解密操作

該過程使用Android 平臺(tái)下的openssl EVP編程,該過程的難度不大。

關(guān)鍵點(diǎn)一是在于使用密鑰空間構(gòu)造。推薦密鑰空間使用數(shù)組。使用char*字符串即使在字符串最后存在’’也會(huì)由于內(nèi)存中的其他內(nèi)容影響密鑰初始化,出現(xiàn)意想不到的問題。

關(guān)鍵點(diǎn)二在close時(shí),參數(shù)只有文件描述符,可以通過下述代碼獲得文件名。

 

圖片7

 

關(guān)鍵點(diǎn)三在于使用Openssl進(jìn)行對(duì)稱加解密時(shí)會(huì)填充到相應(yīng)的塊大小,需要手動(dòng)剝離這些填充??梢圆捎脟?guó)際通用填充方式構(gòu)造填充,或者自主構(gòu)造密文文件頭記錄填充大小。

http://en.wikipedia.org/wiki/Padding_(cryptography)

6、記得在Makefile文件中加入

LOCAL_LDLIBS+=-L$(SYSROOT)/usr/lib -llog

LOCAL_LDLIBS+=-L$(SYSROOT)/usr/lib -lcrypto

LOCAL_LDLIBS+=-L$(SYSROOT)/usr/lib -lssl

7、需要再進(jìn)行密鑰管理模塊的開發(fā),該過程不再描述。

四、總結(jié)

該種方案能夠?qū)崿F(xiàn)在android平臺(tái)上的透明加解密。不足之處在于需要使用root權(quán)限,提前捕捉用戶程序啟動(dòng),對(duì)其進(jìn)行hook。在移動(dòng)設(shè)備上效率是瓶頸,而且文件不宜過大。對(duì)docxlspdfppttxt等文本、jpg等圖片支持較好,其他格式的文件筆者沒有進(jìn)行測(cè)試。

責(zé)任編輯:藍(lán)雨淚 來源: 網(wǎng)絡(luò)攻防實(shí)驗(yàn)室
相關(guān)推薦

2010-09-17 20:33:03

2009-03-25 16:28:46

個(gè)人信息數(shù)據(jù)泄露防護(hù)DLP

2012-12-03 10:59:30

2020-12-13 09:40:11

物聯(lián)網(wǎng)物聯(lián)網(wǎng)安全加密方法

2020-10-20 10:23:52

物聯(lián)網(wǎng)安全智慧城市

2022-11-18 18:36:24

2022-01-26 07:25:09

PythonRSA加解密

2021-05-10 15:00:36

數(shù)據(jù)資產(chǎn)技術(shù)大數(shù)據(jù)

2022-03-22 22:49:57

大數(shù)據(jù)信息安全安全

2021-11-18 23:10:38

數(shù)據(jù)庫(kù)安全網(wǎng)絡(luò)安全

2023-03-30 08:11:52

Spring加解密連接池

2017-03-06 14:44:49

Androidhook技術(shù)

2018-05-09 10:48:58

Android加密密碼學(xué)

2018-02-07 15:25:41

2011-09-10 20:52:27

數(shù)據(jù)中心數(shù)據(jù)安全云技術(shù)云備份

2011-08-01 14:36:06

加密RSA

2025-03-10 07:49:13

2022-07-27 08:49:34

接口加密解密

2015-02-11 15:27:26

微信SDK

2024-09-27 15:24:15

Spring數(shù)據(jù)加解密
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)