Windows PE导出表编程3(暴力覆盖导出函数)
今天要嘗試的導(dǎo)出表相關(guān)編程內(nèi)容是:覆蓋函數(shù)地址部分的指令代碼。
這種覆蓋技術(shù),是將AddressOfFunctions指向的地址空間指令字節(jié)碼實(shí)施覆蓋,這種技術(shù)又繁衍出兩種:
暴力覆蓋,即將所有的代碼全部替換為新代碼。新代碼可能含有原來代碼的全部功能,也可能不包含原有代碼功能。
完美覆蓋,通過構(gòu)造指令,實(shí)施新代碼與源代碼的共存和無遺漏運(yùn)行。因?yàn)橥昝栏采w涉及代碼的重定位,相對復(fù)雜一些,今天嘗試暴力覆蓋。目標(biāo)是我自己寫了一個(gè)dll導(dǎo)出一個(gè)加法函數(shù),然后我要用另一個(gè)自定義函數(shù)替換這個(gè)函數(shù),讓他直接返回0。
1.首先定義測試用的dll,以及測試用的exe。
?
?
?
2.找到要替換的函數(shù)的FOA,這里面是指找到_Add函數(shù),思路是先通過PE頭找到導(dǎo)出表,信息,根據(jù)導(dǎo)出表信息(RVA)計(jì)算FOA從而找到導(dǎo)出表在文件中的位置,然后分析導(dǎo)出表結(jié)構(gòu),找到導(dǎo)出函數(shù)列表地址(RVA),計(jì)算FOA,在計(jì)算的導(dǎo)出表地址處找到導(dǎo)出函數(shù)地址(ROA),計(jì)算FOA,這樣就算是找到了函數(shù)的代碼段了。細(xì)節(jié)如下如:
上圖是找到了導(dǎo)出函數(shù)列表地址24A8.
導(dǎo)出函數(shù)列表地址24A8轉(zhuǎn)成FOA是12A8,在這里找到了導(dǎo)出函數(shù)地址1010,然后繼續(xù)轉(zhuǎn)成FOA位410?,?so?410就是該導(dǎo)出函數(shù)實(shí)現(xiàn)的代碼段了。
3.接下來的事就是把自己寫好的新功能函數(shù)的機(jī)器碼拷貝到上面的代碼段就行了,獲取機(jī)器碼也有個(gè)方法,就是先自己用C++寫好,然后調(diào)試看反匯編,在內(nèi)存里直接把翻譯好的機(jī)器碼整個(gè)(整個(gè)函數(shù))拿出來就行了。
這樣得到的直接返回一個(gè)0的函數(shù)的機(jī)器碼是:55?8b?ec?33?c0?5d?c3
4.替換2找到的代碼段位置,也是替換到5d?c3,剩余的不夠的位置用90(NOP)補(bǔ)齊。
5.保存文件之后再繼續(xù)測試一發(fā),發(fā)現(xiàn)不管給_Add()函數(shù)傳什么都會(huì)直接返回0的。
去看此時(shí)加載的D.dll的Add函數(shù)再次確認(rèn)下函數(shù)代碼對應(yīng)機(jī)器碼已經(jīng)被修改,同時(shí)反匯編代碼的匯編解釋也是錯(cuò)的。
最后提示一點(diǎn)就是這個(gè)姿勢需要注意一點(diǎn)就是堆棧平衡問題,上面的測試其實(shí)都是基于C++dll調(diào)用的,默認(rèn)是調(diào)用者負(fù)責(zé)釋放參數(shù)堆棧:
? ? 而有的時(shí)候需要在函數(shù)里面去把這個(gè)函數(shù)的堆棧平衡了,這個(gè)地方要注意一下。還有就是覆蓋的時(shí)候最好是把內(nèi)容少的覆蓋到內(nèi)容多的函數(shù)里,不然的話可能會(huì)破壞掉其他的函數(shù),如果你覺得我只要這個(gè)覆蓋的函數(shù)的功能就行了,別的破壞就破壞了,這樣還是不行,因?yàn)檫@個(gè)函數(shù)的實(shí)現(xiàn)有可能依賴于里面自己實(shí)現(xiàn)的其他函數(shù)的支持。
總結(jié)
以上是生活随笔為你收集整理的Windows PE导出表编程3(暴力覆盖导出函数)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows PE导出表编程2(重组导
- 下一篇: Windows PE导出表编程4(重构导