android apk 防止反編譯技術第二篇-運行時修改Dalvik指令

來源:互聯網
上載者:User

標籤:

上一篇我們講了apk防止反編譯技術中的加殼技術,如果有不明白的可以查看我的上一篇部落格http://my.oschina.net/u/2323218/blog/393372。接下來我們將介紹另一種防止apk反編譯的技術-運行時修改位元組碼。這種方法是在工作中在實現app wrapping時,看到國外的一篇關於android 安全的介紹實現的並且獨創。下面我們來介紹一下這種方法。

       

我們知道apk產生後所有的java產生的class檔案都被dx命令整合成了一個classes.dex檔案,當apk運行時dalvik虛擬機器載入classes.dex檔案並且用dexopt命令進行進一步的最佳化成odex檔案。我們的方法就是在這個過程中修改dalvik指令來達到我們的目的。

 

一、dex檔案格式

dex的檔案格式通常有7個主要部分和資料區組成,格式如下:

 

header部分記錄了主要的資訊其他的部分只是索引,索引的內容存在data地區。

 

Header部分結構如下:

 

欄位名稱

位移值

長度

描述

magic

0x0

8

‘Magic‘值,即魔數欄位,格式如”dex/n035/0”,其中的035表示結構的版本。

checksum

0x8

4

校正碼。

signature

0xC

20

SHA-1簽名。

file_size

0x20

4

Dex檔案的總長度。

header_size

0x24

4

檔案頭長度,009版本=0x5C,035版本=0x70。

endian_tag

0x28

4

標識位元組順序的常量,根據這個常量可以判斷檔案是否交換了位元組順序,預設情況下=0x78563412。

link_size

0x2C

4

串連段的大小,如果為0就表示是靜態串連。

link_off

0x30

4

串連段的開始位置,從本檔案頭開始算起。如果串連段的大小為0,這裡也是0。

map_off

0x34

4

map資料基地址。

string_ids_size

0x38

4

字串列表的字串個數。

string_ids_off

0x3C

4

字串列表表基地址。

type_ids_size

0x40

4

類型列表裡類型個數。

type_ids_off

0x44

4

類型列表基地址。

proto_ids_size

0x48

4

原型列表裡原型個數。

proto_ids_off

0x4C

4

原型列表基地址。

field_ids_size

0x50

4

欄位列表裡欄位個數。

field_ids_off

0x54

4

欄位列表基地址。

method_ids_size

0x58

4

方法列表裡方法個數。

method_ids_off

0x5C

4

方法列表基地址。

class_defs_size

0x60

4

類定義類表中類的個數。

class_defs_off

0x64

4

類定義列表基地址。

data_size

0x68

4

資料區段的大小,必須以4位元組對齊。

data_off

0x6C

4

資料區段基地址

 

dex與class檔案相比的一個優勢,就是將所有的常量字串集統一管理起來了,這樣就可以減少冗餘,最終的dex檔案size也能變小一些。詳細的dex檔案介紹就不說了,有興趣的可以查看android 源碼dalvik/docs目錄下的dex-format.html檔案有詳細介紹。不過我記得在android4.0版本後就沒有了這個檔案。

根據上面的dex檔案的格式結構,dalvik虛擬機器運行dex檔案執行的位元組碼就存在method_ids地區裡面。我們查看dalvik虛擬機器源碼會有一個

        struct DexCode { 

        u2  registersSize; 

        u2  insSize; 

        u2  outsSize; 

        u2  triesSize; 

        u4  debugInfoOff;       /* file offset to debug info stream */ 

        u4  insnsSize;          /* size of the insns array, in u2 units */ 

        u2  insns[1]; 

        /* followed by optional u2 padding */ 

        /* followed by try_item[triesSize] */ 

        /* followed by uleb128 handlersSize */  

        /* followed by catch_handler_item[handlersSize] */ 

    }; 

這樣一個結構,這裡的insns數組存放的就是dalvik的位元組碼。我們只要定位到相關類方法的DexCode資料區段,即可通過修改insns數組,從而實現我們的目的。

 

二、odex檔案格式

 

        apk安裝或啟動時,會通過dexopt來將dex產生最佳化的odex檔案。過程是將apk中的classes.dex解壓後,用dexopt處理並儲存為/data/dalvik-cache/[email protected]@<package-name>[email protected]檔案。

 odex檔案結構如下:

從中我們發現dex檔案作為最佳化後的odex的一部分,我們只需要從odex中找出dex的部分即可以了。

 

三、方法實現

        要實現修改位元組碼,就需要先定位到想要修改得代碼的位置,這就需要先解析dex檔案。dex檔案的解析在dalvik源碼的dexDump.cpp給出了我們具體的實現,根據它的實現我們可以尋找我們需要的類及方法。具體實現步驟如下:

(1)    找到我們apk產生的odex檔案,獲得odex檔案在記憶體中的映射地址和大小。實現代碼如下:

?
1234567891011121314151617181920212223   void *base = NULL;   int module_size = 0;   char filename[512];   // simple test code  here!   for(int i=0; i<2; i++){          sprintf(filename,"/data/dalvik-cache/[email protected]@%s-%[email protected]""com.android.dex", i+1); base = get_module_base(-1, filename);//獲得odex檔案在記憶體中的映射地址   if(base != NULL){          break;   }   }  module_size = get_module_size(-1, filename); //獲得odex檔案大小

(2)    知道dex檔案在odex中的位移,以便解析dex檔案。代碼如下:

?
1234567891011 // search dex from odex   void *dexBase = searchDexStart(base);   if(checkDexMagic(dexBase) == false){          ALOGE("Error! invalid dex format at: %p", dexBase);          return;   }

 

(3)    找到dex位移以後就可以解析dex檔案,從而尋找我們要進行替換的方法所在的類,然後在該類中找到該方法並返回該方法對應的DexCode結構體。函數實現如下:

?
12345678910111213141516171819 static const DexCode *dexFindClassMethod(DexFile *dexFile, const char *clazz, const char *method) {     DexClassData* classData = dexFindClassData(dexFile, clazz);     if(classData == NULL) return NULL;     const DexCode* code = dexFindMethodInsns(dexFile, classData, method);     if(code != NULL) {         dumpDexCode(code);     }     return code; }

(4)    找到DexCode後就可以進行指令替換了。實現如下:

?
123456789101112131415161718192021222324252627 const DexCode  *code =     dexFindClassMethod(&gDexFile, "Lcom/android/dex/myclass;""setflagHidden"); const DexCode*code2 =  dexFindClassMethod(&gDexFile, "Lcom/android/dex/myclass;""setflag");     // remap!!!!     if(mprotect(base, module_size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0){     DexCode *pCode = (DexCode *)code2;     // Modify!     pCode->registersSize = code->registersSize;         for(u4 k=0; k<code->insnsSize; k++){                pCode->insns[k] = code->insns[k];         }       mprotect(base, module_size, PROT_READ | PROT_EXEC); }

注意:由於是在運行時修改的dalvik指令,這是進程的記憶體映射為唯讀,所以需要調用mprotect函數將唯讀改為讀寫才能進行指令的修改。

 

         根據上面的講述相信大家對運行時修改位元組碼的技術有了一定的瞭解,下一篇我們將講解另一種android apk防止反編譯技術,期待大家的捧場。如果對這篇講的技術有任何疑問及想要獲得這篇文章講的技術的工程源碼

    歡迎關注個人公眾平台:程式員互動聯盟(coder_online),掃一掃下方二維碼或搜尋號coder_online即可關注,我們可以線上交流。

android apk 防止反編譯技術第二篇-運行時修改Dalvik指令

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.