古詩詞大全網 - 藝術簽名 - 驅動器的安裝和反轉

驅動器的安裝和反轉

對於壹個經常寫程序的人來說,寫驅動並不是壹件困難的事情。因為網上有很多現成的。

代碼,實現某個功能,直接Ctrl+C和Ctrl+V就可以解決問題。但是寫了驅動能加嗎?

載入內核是另壹回事,能不能存在別人硬盤上又是另壹回事。

因為很多殺毒軟件(尤其是像360這種沒有技術含量的)直接刪除後綴為sys的文件,

我甚至沒有機會打電話給NtLoadDriver。對於壹般的軟件,給出壹個語句來解釋解決方案。

別管解決方案了。但是對於惡意程序,妳無法給出壹個說法。所以許多惡意軟件作者找到了另壹種方法。

用大公司寫的,數字簽名的驅動幹壞事。

有人說,大公司做的驅動怎麽能用來幹壞事呢?其實這很好理解。

很多安全或者系統優化軟件,甚至是與系統無關的軟件(比如迅雷)都自帶驅動。

這些驅動器都是通用的。Q_lai_a_qu網友在博客中說:“ComputerZ.sys……...沒什麽。

反向是魯大師的驅動,發現這個驅動功能齊全,沒有經過調用者驗證!可以讀寫Msr。

寄存器,還可以用in和out指令讀寫端口,char/short/long數據長度齊全!"。這是

個人認為,請自行猜測可信度。先說壹個比較可信的例子:曾經有壹個病毒用了360。

antirk.dll刪除文件的殺毒軟件(請自己谷歌“360 antirk.dll”,妳會有驚喜。

AntiRK.dll不是司機,但也是非法使用)。破壞殺毒軟件的病毒是小兒科。

其實用壹些驅動也可以破壞硬件!最近在筆記本裏折騰硬件,“友協”上的網友給我推的。

推薦幾個軟件:SetFSB,ThrottleStop,NvFlash,WinFlash。他們正在修改CPU外部頻率,設置

設置CPU倍頻(CPU電壓可調)、讀寫圖形BIOS和讀寫主板BIOS的軟件。用壹句話概括他們的特點,

就是都支持NT x86/x64,驅動都有正式的數字簽名(尤其是最後兩個,分別有英偉達和華碩的數字簽名)。

最重要的是,他們的驅動程序沒有花花殼蓋,調用方也沒有經過驗證。

如果利用這些驅動和壹點逆向知識,就可以做出壹個破壞性的病毒(以下摘自我的紫水

水晶編程論壇帖子):

1.SetFSB可以調整處理器的外部頻率。如果直接把外接頻率調到600MHz,電腦會瞬間黑屏,可能是

會損壞CPU或主板;

2.ThrottleStop可以調整CPU的倍頻(如果CPU沒有鎖定倍頻),如果直接把倍頻調整到31,

電腦會瞬間黑屏,可能會損壞CPU或主板;ThrottleStop還可以調整CPU的核心電壓,如果

把CPU的核心電壓調到3V可以直接燒CPU甚至主板;

3.NvFlash、WinFlash等軟件可以直接讀寫BIOS(顯卡BIOS和主板BIOS),我們可以把

BIOS寫全零;

4.如果妳是病毒,先寫壞顯卡BIOS和主板BIOS,再通過調電壓燒顯卡和CPU。

(可能和主板壹起損壞);

解決辦法

可見,不驗證來電司機的危害是很大的。我最近被學院委任為

需要驅動程序的軟件(該驅動程序將被數字簽名)。為了防止上述悲劇發生,我決定正式下筆。

開車前,解決如何防止自己的司機被惡意利用。我以前在amethyst編程論壇上問過這個問題。

網友對這個問題的回答各種各樣,但大概可以分為三類:第壹類是信息驗證,比如應用程序。

按順序給司機發消息,驗證是“自己人”;第二類是外殼保護,比如添加到驅動和應用中。

在極其堅硬的外殼上,通信部分被VMP加密(類似於XueTr的做法);其他人提出混合應用、合成

第壹類和第二類相結合的做法。

這三個想法似乎都不錯,但我認為它們都不對。第壹種:別人只需要把所有的驅動都反過來就可以了。

的;第二種:雖然VMP保護和保護殼使破解變得困難,但並沒有使破解成為不可能。和

我不喜歡VMP和保護殼會降低程序執行的效率。最糟糕的是,殺毒軟件增加了壹個外殼(甚至)

甚至包括UPX和VMP在內的項目都被報道中毒,這是得不償失的。所以我想出了第三個主意:檢查呼叫者的

特色。如果是,執行函數語句,否則不執行。如何核對來電者的簽名?很多人都想

使用CRC32或MD5。不是不能用他們,而是我有自己的想法。我的想法來自

設計了壹套驗證算法,其規則如下:

1.獲取呼叫者的電子流程

2.通過調用者的EPROCESS獲取調用者的文件路徑。

3.獲取調用者文件的所有內容,並將其放入字節數組緩沖區。

4.依次加減buff中的所有元素(fb1+fb2-fb3...)才能得到y1。

5.依次異或buff中的所有元素(0 XOR fb1 XOR fb2 XOR fb3...)來獲得y2。

將y1和y2與計算值進行比較。如果都壹樣,執行功能代碼;如果它們不壹樣,它們就不壹樣。

執行功能代碼

用PsGetCurrentProcess()直接獲取調用者的EPROCESS,獲取調用者的文件路徑。

路徑比較麻煩,可以用我之前從高手那裏買的代碼(已經封裝成函數方便調用):

//根據e process獲取進程的完整路徑。

VOID getfullpathbyprocess(ULONG e process,PCHAR ProcessImageName)

{

ULONG對象;

PFILE _ OBJECT FileObject

UNICODE_STRING文件路徑;

UNICODE _ STRING DosName

字符串重排;

FileObject = NULL

文件路徑。Buffer = NULL

文件路徑。長度= 0;

* process imagename = 0;

//e process-& gt;section object(offset _ section object)

if(MmIsAddressValid((PULONG)(e process+offset _ section object)))

{

object =(*(PULONG)(e process+offset _ section object));

//KD print(("[GetProcessFileName]section object:0x % x \ n ",object));

if(MmIsAddressValid((PULONG)((ULONG)object+0x 014)))

{

object = *(PULONG)((ULONG)object+0x 014);

//KD print(("[GetProcessFileName]Segment:0x % x \ n ",object));

if(MmIsAddressValid((PULONG)((ULONG)object+0x 0)))

{

object = *(PULONG)((ULONG _ PTR)object+0x 0);

//KD print(("[GetProcessFileName]

ControlAera :0x%x\n ",object));

if(MmIsAddressValid((PULONG)((ULONG)object+0x 024)))

{

object = *(PULONG)((ULONG)object+0x 024);

if(NtBuildNumber & gt;= 6000)object =((ULONG)object & amp;

0x fffffff 8);

//KD print(("[GetProcessFileName]

FilePointer :0x%x\n ",object));

}

其他

返回;

}

其他

返回;

}

其他

返回;

}

其他

返回;

FileObject=(PFILE_OBJECT)對象;

文件路徑。buffer = ExAllocatePool(page pool,0x 200);

文件路徑。MaximumLength = 0x200

//KD print(("[GetProcessFileName]

文件指針:%wZ\n ",& amp文件指針-& gt;文件名));

ObReferenceObjectByPointer((PV oid)file object,0,NULL,kernel mode);

RtlVolumeDeviceToDosName(file object-& gt;設備對象。dos name);

RtlCopyUnicodeString(& amp;文件路徑。dos name);

rtlapendunicodestringtostring(& amp;文件路徑。file object-& gt;文件名);

ObDereferenceObject(file object);

rtlunicodestringtansigning(& amp;分配和分配。FilePath,TRUE);

如果(正在註冊。長度& gt= 216 )

{

memcpy(ProcessImageName,AnsiString。緩沖區,0x 100 u);

*(process imagename+215)= 0;

}

其他

{

memcpy(ProcessImageName,AnsiString。緩沖,分配。長度);

ProcessImageName[AnsiString。長度]= 0;

}

rtlfreeansigning(& amp;ansi ssing);

ExFreePool(DosName。緩沖);

ExFreePool(文件路徑。緩沖);

}

上面的代碼需要三個硬代碼,分別是NtBuildNumber(系統版本號)和EPROCESS。

SectionObject項和UniqueProcessId項的偏移量。我測試的操作系統是Windows 2003。因此

我在代碼中將其定義如下:

# define offset _ section object 0x 124

# define offset _ UniqueProcessId 0x 94

ULONG NtBuildNumber = 3790

獲取流程路徑後檢查簽名。因為流程已經說清楚了,所以直接給出代碼:

VOID CalcChar(puni code _ STRING logFileUnicodeString,LONG *XorChar,LONG

*AnSChar)

{

OBJECT_ATTRIBUTES對象屬性;

IO _ STATUS _ BLOCK iostatus

處理hfile

NTSTATUS ntStatus

文件_標準_信息;

普查爾·普弗;

ULONG i=0,y1=0,y2 = 0;

//初始化對象屬性

InitializeObjectAttributes(& amp;對象屬性,

logFileUnicodeString,

OBJ不區分大小寫,//區分大小寫。

空,

NULL);

//創建文件

ntStatus = ZwCreateFile(& amp;hfile,

GENERIC_READ

& amp對象屬性,

& ampiostatus,

空,

文件_屬性_正常,

文件共享讀取,

FILE_OPEN,//即使存在於這個文件中,也是創建的。

文件_同步_ IO _非警報,

空,

0 );

如果(!NT_SUCCESS(ntStatus))

{

dprintf("文件不存在!\ n ");

返回;

}

//讀取文件長度

ntStatus = ZwQueryInformationFile(hfile,

& ampiostatus,

& ampfsi,

sizeof(文件標準信息),

文件標準信息);

dprintf("程序想讀取%d字節\n ",fsi。endo ffile . quad part);

//為讀取的文件分配緩沖區

pBuffer =(PUCHAR)ExAllocatePool(paged pool,

(長)fsi。endo ffile . quad part);

//讀取文件

ZwReadFile(hfile,NULL,

空,空,

& ampiostatus,

p緩沖器,

(長)fsi。四部分,

NULL、NULL);

dprintf("程序確實讀取了%d字節\n ",iostatus。信息);

//XOR計算

for(I = 0;我& ltiostatus。信息;i++)

y1=y1^(long)(*(pbuffer+i));

* xor char = y 1;

//加減運算

for(I = 0;我& ltiostatus。信息;i++)

{

如果(i%2==0)

y2 = y2+(LONG)(*(p buffer+I));

其他

y2 = y2-(LONG)(*(p buffer+I));

}

* AnSChar = y2

//關閉文件句柄

zw close(hfile);

//釋放緩沖區

ex free pool(p buffer);

}

它將被稱為next。我們需要寫壹個函數VerifyCaller,這個函數裏有兩個值。

固化在驅動程序中的是合法調用者的兩個特征值。為了方便計算這兩個特征值,我特意寫了壹個

應用程序,核心代碼如下:

選項顯式

私有函數ReadFile(ByVal strFileName作為字符串,可選ByVal

lngStartPos As Long = 1,可選ByVallngFileSize As Long =-1)As Byte()

Dim FilNum As Long

FilNum = FreeFile

以#FilNum格式打開二進制文件的strFileName

如果lngFileSize = -1,則

ReDim ReadFile(LOF(FilNum)-lngStartPos)

其他

ReDim ReadFile(lngFileSize-1)

如果…就會結束

Get #FilNum,lngStartPos,ReadFile

關閉#FilNum

結束功能

私有函數WriteFile(ByVal strFileName為字符串,bytData()為字節,

可選ByVal lngStartPos As Long =-1,可選ByVal OverWrite As Boolean =

真實)

出錯時轉到erx

Dim FilNum As Long

FilNum = FreeFile

If OverWrite = True並且Dir(strFileName)& lt;& gt”“那麽

殺死strFileName

如果…就會結束

以#FilNum格式打開二進制文件的strFileName

如果lngStartPos = -1,則

把#FilNum,LOF(FilNum) + 1,bytData

其他

將#FilNum,lngStartPos,bytData

如果…就會結束

關閉#FilNum

erx:

結束功能

私有子命令1_Click()

Dim buff()為字節,I為Long,y為Long,ub為Long

text1.text是文件名

buff = ReadFile(Text1。Text,1,-1)

ub = UBound(buff)

計算異或字符

y = 0

對於i = 0至ub

y = y異或緩沖器(I)

然後

文本2。Text = CLng(y)

多項活動

計算添加/子字符

y = 0

對於i = 0至ub

如果我模2 = 0,那麽

y = y + CLng(buff(i))

其他

y = y - CLng(buff(i))

如果…就會結束

然後

短信3。Text = CLng(y)

末端接頭

私有子窗體_Load()

我。Icon = LoadPicture(" ")

末端接頭

驅動程序中的VerifyCaller代碼如下:

長驗證呼叫者(無效)

{

PEPROCESS cur _ ep

char cur _ PP[260];

char * nt _ cur _ pp

ANSI _ STRING asCur _ pp

UNICODE _ STRING usCur _ pp

LONG xorc,ansc

cur _ EP = PsGetCurrentProcess();

getfullpathbyprocess((ULONG)cur _ EP,cur _ PP);

//添加\?在文件名之前。\

nt_cur_pp=cs("\\?\\ ",cur _ PP);

DbgPrint("%s ",nt _ cur _ PP);

rtlinitansigning(& amp;asCur_pp,nt _ cur _ PP);

rtlansistringunicodestring(& amp;us cur _ PP & amp;asCur_pp,TRUE);

DbgPrint("%wZ ",& ampus cur _ PP);

卡爾查爾(& ampus cur _ PP & amp;xorc & amp;ansc);

dbg print(" xor char:% LD;AnSChar: %ld ",xorc,ansc);

//這是合法程序預先計算好的特征碼,必須固化在驅動裏!

if(xorc = = 186 & amp;& ampansc==136176)

返回1;

其他

返回0;

}

在執行DispatchIoctl函數的每個函數之前,調用VerifyCaller()來檢查調用者:

開關(uIoControlCode)

{

案例IOCTL_VERIFY:

{

dbg print("[my driver]DispatchIoctl-IOCTL _ VERIFY ");

if(VerifyCaller()==1)

dbg print("[my driver]{ IOCTL _ VERIFY }函數代碼現在運行!");

其他

dbg print("[my driver]{ IOCTL _ VERIFY }您是非法調用者!");

狀態=狀態_成功;

打破;

}

//下面省略

}

試探性試驗

3.首先把合法調用者和非法調用者(用eXeScope隨便給合法調用者打補丁,

例如刪除程序的版本信息)並將驅動程序復制到虛擬機。

4.用合法的調用者加載驅動程序並執行它。

5.用非法調用者加載驅動程序並執行它。

6.在DbgView中比較以上兩者的輸出。

當呼叫者合法時:

當呼叫者是非法的:

寫在最後

寫完這篇文章,我必須重申,只有當司機攜帶正式的數字簽名,才能調用方的。

代碼是有用的。為什麽這麽說?因為其他人不能用正式的數字簽名修補驅動程序(壹次

當驅動是補丁的時候,簽名就會失效,就像壹個被打碎的女人,壹文不值。這個比喻雖然俗,但是很

合適)。沒有簽名驅動,就沒有使用價值。就算別人想用,扔司機就行了。

在IDA中,所有的代碼都出來了。