在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > android平臺arm指令學習和調(diào)試

            android平臺arm指令學習和調(diào)試

            作者: 時間:2016-11-09 來源:網(wǎng)絡 收藏
            */

            一、Ndk下內(nèi)聯(lián)匯編

            跟vc下一樣,ndk編譯環(huán)境下也能使用內(nèi)聯(lián)匯編,如下:

            本文引用地址:http://www.biyoush.com/article/201611/317575.htm

            include

            intmy_thumb(intdummy)

            {

            __asm__(

            “movr0,#1tn”

            “movr1,#2tn”

            “addr0,r0,r1tn”

            “bxlr”

            );

            }

            intmain()

            {

            intn=my_thumb(12);

            printf(“result:%08x”,n);

            return0;

            }

            再看看使用標簽的例子:

            #include

            intmy_thumb(intdummy)

            {

            __asm(

            “movr0,#0x1tn”

            “ldrr0,__starttn”

            “adrr0,__starttn”

            “ldrr0,=__starttn”

            “__start:tn”

            “noptn”

            );

            }

            intmain()

            {

            intn=my_thumb(12);

            printf(“result:%08x”,n);

            return0;

            }

            二、編譯

            創(chuàng)建android.mk文件,然后使用ndk-build進行編譯

            1)編譯一個可執(zhí)行程序,Android.mk文件的內(nèi)容如下:

            LOCAL_PATH:=$(callmy-dir)

            include$(CLEAR_VARS)

            LOCAL_MODULE:=helloa

            LOCAL_SRC_FILES:=testHello.c

            include$(BUILD_EXECUTABLE)

            2)編譯一個so,android.mk文件內(nèi)容如下:

            LOCAL_PATH:=$(callmy-dir)

            include$(CLEAR_VARS)

            LOCAL_MODULE:=testJniSo

            LOCAL_SRC_FILES:=testJniSo.c

            include$(BUILD_SHARED_LIBRARY)

            3)必須有一個jni目錄,目錄結(jié)構(gòu):

            4)這樣之后,就可以在cmd窗口中,切換到代碼目錄,使用ndk-build命令進行編譯。

            三、調(diào)試可執(zhí)行程序

            1)Push編譯好的elf到樣機中

            2)使用gdbserver啟動該文件

            “/data/local/gdbserver:12345/data/local/helloa”

            3)adbforwardtcp:12345tcp:12345

            4)啟動gdb

            5)Targetremote127.0.0.1:12345

            6)Ni是單步,setdisassemble-nexton下一句指令顯示反匯編,使用setarmforce-modearm或者setarmforce-modethumb讓gdb切換thumb和arm代碼顯示。

            7)Display/i$pc顯示當前的代碼

            8)Continue就是windbg的f5,od的f9

            9)Infobreakpoints顯示斷點,而delete刪除斷點disable禁用斷點

            10)Disas0xAAAA,+20(20字節(jié)的數(shù)據(jù))顯示反匯編

            11)調(diào)試比較



            Gdbarm和ida反匯編比較:

            四、調(diào)試so

            以愛加密為例,進行調(diào)試,范例是看雪求助帖給出的,鏈接如下:

            http://bbs.pediy.com/showthread.php?t=184375

            調(diào)試方法

            1)So中實現(xiàn)的方法,程序跑起來再附加的話,該方法可能已經(jīng)執(zhí)行完??囱┥辖o出方法步驟較多,應用和底層都調(diào)試,有點復雜如下:

            我試出來的方法,對so文件進行修改,讓其在入口處直接調(diào)用它本身。需要注意的是,必須在so的入口函數(shù)處修改,如果在內(nèi)部調(diào)用函數(shù)修改,app會自動退出。

            2)gdb的調(diào)試,使用ndk下自帶的gdbserver和gdb進行調(diào)試

            3)將修改的so導入到手機該應用的lib目錄下,覆蓋之前的so文件。然后運行app,出現(xiàn)只有邊界的黑框。Gdbserver附加,使用set命令,將bl調(diào)用自身的命令改回去,則可以進行正常調(diào)試了。

            4)模塊基地址的獲取cat/proc/pid/maps找到

            5)Dump內(nèi)存的命令式dumpbinarymemoryc:xxxstartAdendAd

            6)小細節(jié)要注意的是:.init_proc的地址是0x31cb9,ida直接點過去,是一堆數(shù)據(jù),摁c無法轉(zhuǎn)成代碼

            因為arm指令和thumb指令是2字節(jié)或者4字節(jié)對齊的,所以,改地址加1應該是真正的地址。將該地址修改為調(diào)用自身,然后gdb附加,成功斷下來,然后輸入“ir$lr”查看返回值,如下

            該地址恰巧是在linker模塊中,

            此處的在linker中的代碼如下:

            7)至于為什么系統(tǒng)的linker會調(diào)用.init_proc,不得而知。該so的oep為空,沒有section表,但是有dynamicsection表。自己寫一個so,并沒有函數(shù)“init_proc”的導出,需要再研究下elf文件格式。

            自解碼

            本身的so是經(jīng)過加密的,解密的代碼是在.init_proc+1的位置,字節(jié)碼的代碼較長,部分代碼如下:

            1)windows下逃避斷點的方法,就是利用“codeshadow”的方式,在申請內(nèi)存,然后將代碼拷貝到指定的申請的空間上執(zhí)行,這樣,直接斷原代碼是斷不到的。但是,直接搜索二進制就可以找到這樣的鏡像代碼。

            如下,之前應該運行的代碼:

            拷貝到其它地方執(zhí)行的代碼:

            2)計算指定函數(shù)的匯編指令長度:代碼要進行拷貝執(zhí)行,必須計算拷貝代碼的長度。愛加密計算拷貝代碼的長度方式是通過call來計算的。函數(shù)實現(xiàn)的排布如下:

            __asmcalltargetFunc

            xxxxxx

            xxxxxx

            xxxxxx

            xxxxxx

            xxxxxx

            xxxxxx

            VoidtargetFunc

            而call的指令是:

            00f0是指令opcode,c0與跳轉(zhuǎn)的距離有關,計算公式是(targetAddr–curAddr)/2–2=opdataLen。那么知道c0就知道中間xxx代碼的長度了。

            3)愛加密處理的數(shù)據(jù)有三塊,第一塊未知,第二塊是壓縮過的指令數(shù)據(jù),第三塊是需要拷貝到堆上的代碼,這三塊數(shù)據(jù)總長度為0x29e3c,使用mmap2進行申請映射內(nèi)存,如下:

            然后將三塊數(shù)據(jù)拷貝到映射的內(nèi)存上,

            在此之后,數(shù)據(jù)內(nèi)存排布:

            AAAAAAAAA

            BBBBBBBBBB

            CCCCCCCCCC

            愛加密還原代碼前,處理了三塊數(shù)據(jù),如上。其中,“AAAAAAAAAA”數(shù)據(jù)是一組未使用過的數(shù)據(jù),具體功能未知,長度為0x6b0;“BBBBBBBBBB”代表的是lzma壓縮過的數(shù)據(jù);“CCCCCCCCCC”代表的是拷貝函數(shù)的數(shù)據(jù)(一共拷貝三個函數(shù)的代碼)。

            4)修改lr,然后刷新cache,返回到mmap2得到的堆上的函數(shù)進行執(zhí)行

            OAD:510A4010 01 1C MOVS R1, R0 ; r0 0x4fb83e3c
            LOAD:510A4012 10 1C MOVS R0, R2 ; r2 0x4fb83bd8
            LOAD:510A4014 BE 46 MOV LR, R7 ; r7 0x4fb83d91
            LOAD:510A4014 ; 這里對lr寄存器進行修改
            LOAD:510A4016 C3 E7 B libexec___ARM_NR_cacheflush

            5)再次調(diào)用mmap2,抹掉最初的“AA”、“BB”和“CC”三塊數(shù)據(jù),這樣,之前執(zhí)行的代碼和數(shù)據(jù)將都被清零。這三塊數(shù)據(jù)就被搬運到第一次調(diào)用mmap2得到的地址上,數(shù)據(jù)在內(nèi)存重新做了排布。

            6)解壓數(shù)據(jù):將數(shù)據(jù)解壓到第二次調(diào)用mmap2清零的地址上,偏移為0x6b0。數(shù)據(jù)的解壓使用的是lzma算法,解壓的代碼:

            上圖中,r4指向的lzma的解壓函數(shù),r0是待解壓的數(shù)據(jù),r1是待解壓的長度,r2是解壓到的地址,r3上是保存解壓到的地址空間的長度的地址。Lzma的具體實現(xiàn):

            7)修正指定數(shù)據(jù):解壓完的數(shù)據(jù)并不是最終的代碼,還需要進行修正。修正代碼如下:

            修正的方法是:解壓后的數(shù)據(jù)從末端開始往前,每四字節(jié)為單位,如果這四字的最高個字節(jié)是低四位是0xb,則進行移位修復。(這種方法很像pe殼中解密代碼后,對0xe8、0xe9、0xff25等的修復)修復代碼如下:

            8)修改內(nèi)存屬性,代碼就完全解密,并可以運行了。

            解密前的導出函數(shù)代碼如下:

            顯然上圖中的代碼沒法運行,解碼后的代碼如下:

            解碼后的代碼分析

            解密后的代碼上邊已經(jīng)給出,r0傳遞的就是jnienv虛表指針,gdb中顯示相關api在libicuil8n.so模塊中,如下:

            1)動態(tài)注冊接口:解密后的代碼主要是動態(tài)注冊用于java調(diào)用的接口,如下:

            2)load的實現(xiàn)

            3)run方法的實現(xiàn)

            gdb調(diào)試的問題:

            1)Gdb在遇到bxpc;nop指令,從thumb指令切換到arm指令時,會出錯,調(diào)試無法繼續(xù)進行。解決方法:

            http://sourceware-org.1504.n7.nabble.com/Fix-ARM-stepping-over-Thumb-mode-quot-bx-pc-quot-or-quot-blx-pc-quot-td69213.html)

            2)gdb遇到如下的拷貝指令也會退出調(diào)試,解決方法是跳過這段代碼的位置下斷點。

            LOAD:510A3F88 loc_510A3F88 ; CODE XREF: libexec_memcopy+1Ej
            LOAD:510A3F88 DC 13 B1 E8 LDMIA R1!, {R2-R4,R6-R9,R12}
            LOAD:510A3F8C 01 50 55 E2 SUBS R5, R5, #1 ; 這里r5不斷的減少
            LOAD:510A3F90 DC 13 A0 E8 STMIA R0!, {R2-R4,R6-R9,R12}
            LOAD:510A3F94 FB FF FF 1A BNE loc_510A3F88
            LOAD:510A3F98 D4 03 BD E8 LDMFD SP!, {R2,R4,R6-R9}



            評論


            技術專區(qū)

            關閉