python逆向入門教程
1、開發(fā)環(huán)境
我們在Windows 10上開始python逆向之旅,首先開始搭建開發(fā)環(huán)境,python解釋器使用最新的3.6.1,IDE使用PyCharm社區(qū)版2017.1.3,下載地址如下所示,下載完成后直接雙擊安裝包安裝即可,隨后設(shè)置PyCharm的Project Interpreter為剛才安裝的Python解釋器就可以了。
【Python】https://www.python.org/downloads/
【PyCharm】http://www.jetbrains.com/pycharm/download/#section=windows
2、ctypes
首先介紹一下ctypes,它是一個用于Python的外部函數(shù)庫,提供了與C語言兼容的數(shù)據(jù)類型,允許調(diào)用動態(tài)鏈接庫或共享庫中的函數(shù),還可以包裝這些庫。下面是ctypes中的數(shù)據(jù)類型與C語言、Python中的數(shù)據(jù)類型的對應(yīng)關(guān)系。
ctypes中的數(shù)據(jù)類型全部通過class來實現(xiàn),在Python中加載C庫涉及如下幾個類。
- class ctypes.CDLL 加載共享庫,使用標準C函數(shù)調(diào)用慣例即cdecl,返回類型為int。
- class ctypes.OleDLL 加載共享庫,只用于Windows平臺,使用stdcall函數(shù)調(diào)用慣例,返回類型為HRESULT。
- class ctypes.WinDLL 加載共享庫,只用于Windows平臺,使用stdcall函數(shù)調(diào)用慣例,返回類型為int。
- class ctypes.PyDLL 類似于CDLL,與前面三個不同的是,在函數(shù)調(diào)用期間不會釋放GIL,Global Interpreter Lock。
- class ctypes.LibraryLoader(dlltype) dlltype為CDLL、OleDLL、WinDLL、PyDLL,這個類有一個加載共享庫的函數(shù)LoadLibrary。
加載C庫更簡單的方法是使用如下幾個預(yù)先創(chuàng)建的類實例。
ctypes.cdll ctypes.oledll ctypes.windll ctypes.pydll ctypes.pythonapi
上面提到了函數(shù)調(diào)用慣例cdecl和stdcall,cdecl的意思是函數(shù)的參數(shù)從右往左依次壓入棧內(nèi),函數(shù)的調(diào)用者在函數(shù)執(zhí)行完成之后負責(zé)函數(shù)的平衡,常用于X86架構(gòu)的C語言里,返回值存儲在EAX寄存器中,從匯編代碼的角度來看,函數(shù)參數(shù)從右往左依次壓棧,然后調(diào)用函數(shù),最后修改棧指針ESP為原來的位置。stdcall,參數(shù)傳遞的順序也是從右到左,不過棧的平衡處理由函數(shù)自己完成,而不是調(diào)用者,返回值同樣存儲在EAX中,也就是說,函數(shù)參數(shù)壓棧、函數(shù)調(diào)用之后沒有像cdecl一樣的棧指針ESP移動。
下面的例子在Python中調(diào)用C的printf函數(shù),printf屬于“C:\Windows\System32\msvcrt.dll”,也就是Linux上的“l(fā)ibc.so”。
from ctypes import * msvcrt = cdll.msvcrt message = b"Hello World\n" msvcrt.printf(b"Message is %s", message)
上面的代碼輸出“Message is Hello World”。另外,ctypes還允許在Python中定義結(jié)構(gòu)和聯(lián)合等其它高級功能,詳細介紹請參考https://docs.python.org/3.6/library/ctypes.html?highlight=ctypes#。
3、調(diào)試原理
使用調(diào)試器,能夠?qū)Τ绦蜻M行動態(tài)跟蹤和分析,特別是涉及到exploit、fuzzer和病毒分析的時候,動態(tài)分析程序的能力就顯得非常重要了。調(diào)試程序時,如果可以獲得源代碼,調(diào)試起來就容易一些,也就是透明的白盒測試,如果沒有源代碼,也就是黑盒測試,想要得到理想的結(jié)果,那就必須擁有高超的逆向技術(shù)和逆向工具的幫助。黑盒測試包括用戶模式與內(nèi)核模式兩種情況,兩者有不同的權(quán)限。
CPU的寄存器能夠?qū)ι倭康臄?shù)據(jù)進行快速的存取訪問,在X86指令集里,一個CPU有八個通用寄存器:EAX、EDX、ECX、ESI、EDI、EBP、ESP和EBX,以及其它的寄存器,下面逐個介紹。
EAX:累加寄存器,除了用于存儲函數(shù)的返回值外也用于執(zhí)行計算的操作,許多優(yōu)化的X86指令集都專門設(shè)計了針對EAX寄存器的讀寫和計算指令。
EDX:數(shù)據(jù)寄存器,本質(zhì)上是EAX寄存器的延伸,輔助EAX寄存器完成更多復(fù)雜的計算操作。
ECX:計數(shù)寄存器,用于循環(huán)操作,計算是向下而不是向上的,由大減到小。
ESI:Source Index,源操作數(shù)指針,存儲著輸入的數(shù)據(jù)流的位置,用于讀,高效地處理循環(huán)操作的數(shù)據(jù)。
EDI:Destination Index,目的操作數(shù)指針,存儲了計算結(jié)果存儲的位置,用于寫,高效地處理循環(huán)操作的數(shù)據(jù)。
ESP:Stack Pointer,棧指針,負責(zé)函數(shù)的調(diào)用和棧的操作,函數(shù)調(diào)用時壓棧參數(shù)和返回地址,指向棧頂即返回地址。
EBP:Base Pointer,基指針,負責(zé)函數(shù)的調(diào)用和棧的操作,函數(shù)調(diào)用時壓棧參數(shù)和返回地址,指向棧底。
EBX:唯一一個沒有特殊用途的寄存器,作為額外的數(shù)據(jù)存儲器。
EIP:Instruction Pointer,指令指針,總是指向馬上要執(zhí)行的指令。
熟悉調(diào)試器的朋友們都知道斷點,斷點其實就是一個調(diào)試事件,其它事件如經(jīng)典的段錯誤(Segment Fault)等。斷點包括軟件斷點、硬件斷點和內(nèi)存斷點,用于暫停被執(zhí)行程序。
軟件斷點:一個單字節(jié)的指令,將控制權(quán)轉(zhuǎn)移給調(diào)試器的斷點處理函數(shù)。匯編指令是CPU執(zhí)行的指令的高級表示方法,如下面的匯編指令MOV EAX, EBX,告訴CPU把存儲在EBX寄存器里的東西放到EAX寄存器,然而CPU并不明白這個匯編指令,必須轉(zhuǎn)化為能夠讓CPU識別的操作碼8BC3,假設(shè)這一操作發(fā)生在地址0x44332211,為了在這個地址設(shè)置斷點,暫停CPU,需要從2個字節(jié)的操作碼8BC3中換出一個單字節(jié)的操作碼,這個單字節(jié)的操作碼也就是3號中斷指令,INT3,一條能讓CPU暫停的指令,對應(yīng)的操作碼為0xCC,具體如下面的代碼片段所示。當調(diào)試器被告知在目標地址設(shè)置一個斷點時,它首先讀取目標地址的第一個字節(jié)的操作碼然后保存起來,同時把地址存儲在內(nèi)部的中斷列表中,接著,調(diào)試器把3號中斷指令對應(yīng)的操作碼0xCC寫到剛才的地址,當CPU執(zhí)行到替換后的操作碼的時候,CPU暫停,并觸發(fā)一個INT3事件,此時調(diào)試器就能捕捉到這個事件,然后調(diào)試器通過EIP判斷這個中斷地址是否是我們設(shè)置的斷點,如果是,就把對應(yīng)的操作碼寫回以恢復(fù)程序的正常運行。軟件斷點包括一次性斷點和持續(xù)性斷點,前者生效一次,后者一直生效,不生效后將其從中斷列表移除。需要注意的是,當我們改變了被調(diào)試程序的內(nèi)存數(shù)據(jù)時,同時改變了運行時軟件的CRC即循環(huán)冗余代碼校驗和,CRC是一種校驗數(shù)據(jù)是否被改變的機制,廣泛應(yīng)用于文件、內(nèi)存、文本、網(wǎng)絡(luò)數(shù)據(jù)包等任何想監(jiān)視數(shù)據(jù)的地方,它將一定范圍內(nèi)的數(shù)據(jù)進行hash計算,然后將hash值同此前的hash值進行比較,判斷數(shù)據(jù)是否改變,為了在這種特殊的情況下也能調(diào)試程序,就要使用下面介紹的硬件斷點了。
地址: 操作碼 匯編指令 0x44332211: 8BC3 MOV EAX, EBX 0x44332211: CCC3 MOV EAX, EBX
硬件斷點:在小塊區(qū)域內(nèi)設(shè)置斷點,屬于CPU級別,使用了DR0到DR7共八個特殊的調(diào)試寄存器,這些寄存器專門用于管理硬件斷點。DR0到DR3存儲硬件斷點地址,意味著同一時間內(nèi)最多只能有4個硬件斷點,DR4和DR5保留,DR6是狀態(tài)寄存器,說明被斷點觸發(fā)的調(diào)試事件的類型,DR7是開關(guān)寄存器,同時也存儲了斷點的不同類型,包括指令執(zhí)行時中斷、數(shù)據(jù)可以寫入時中斷、有數(shù)據(jù)讀或者寫但不執(zhí)行時中斷。硬件斷點使用1號中斷指令I(lǐng)NT1,負責(zé)硬件中斷和步進事件。硬件斷點的特點是同一時間只能設(shè)置四個斷點,而且斷點起作用的區(qū)域只有四個字節(jié),如果想要跟蹤一大塊內(nèi)存數(shù)據(jù),請使用下面介紹的內(nèi)存斷點。
內(nèi)存斷點:用于大塊區(qū)域,不是真正的斷點,而是改變了內(nèi)存中某個塊或者頁的權(quán)限。一個內(nèi)存頁是操作系統(tǒng)處理的最小的內(nèi)存單位,一個內(nèi)存頁被申請成功后,就擁有了一個權(quán)限集,如可執(zhí)行頁、可讀頁、可寫頁,這些決定了內(nèi)存該如何被訪問,任何對保護頁的訪問都會引發(fā)異常,之后頁面恢復(fù)訪問前的狀態(tài)。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python redis操作實例分析【連接、管道、發(fā)布和訂閱等】
這篇文章主要介紹了Python redis操作,結(jié)合實例形式分析了Python redis的連接、管道、發(fā)布和訂閱等相關(guān)概念、原理及操作技巧,需要的朋友可以參考下2019-05-05python庫umap有效地揭示高維數(shù)據(jù)的結(jié)構(gòu)和模式初探
這篇文章主要介紹了python庫umap有效地揭示高維數(shù)據(jù)的結(jié)構(gòu)和模式初探,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01Django-celery-beat動態(tài)添加周期性任務(wù)實現(xiàn)過程解析
這篇文章主要介紹了Django-celery-beat動態(tài)添加周期性任務(wù)實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11PyCharm提示No Python Interpreter的正確解決辦法
剛學(xué)Python時,拿到一個Python項目,想用pycharm打開運行卻報錯了,這篇文章主要給大家介紹了關(guān)于PyCharm提示No Python Interpreter的正確解決辦法,需要的朋友可以參考下2023-10-10Python樹莓派學(xué)習(xí)筆記之UDP傳輸視頻幀操作詳解
這篇文章主要介紹了Python樹莓派學(xué)習(xí)筆記之UDP傳輸視頻幀操作,結(jié)合實例形式詳細分析了Python樹莓派編程中使用UDP協(xié)議進行視頻幀傳輸?shù)南嚓P(guān)操作技巧與注意事項,需要的朋友可以參考下2019-11-11DjangoWeb使用Datatable進行后端分頁的實現(xiàn)
這篇文章主要介紹了DjangoWeb使用Datatable進行后端分頁的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05