一、c++
驅動代碼中C和C++代碼區別
A、函數調用約定
B、C和C++編譯方式
C、用C++方式編譯驅動
D、C代碼升級至C++
E、優化21課的代碼函數
本課主要是作着兩個工做:"D、C代碼升級至C++"、"E、優化21課的代碼"測試
【180】把 第21課 的代碼複製過來優化
【275】通常是經過改後綴名指針
【315】mini_ddk.c 更名爲 mini_ddk.cpp,使得 默認以c++的編譯方式來編譯。理論上是這樣的。code
【360】入口函數(DriverEntry)這裏,理論上要以 C 的標準方式來編譯對象
如今 使用 繼承開發環境來編譯 可能感受不出來,它一樣是能夠編譯的。【440】可是,使用 DDK來編譯的話 就會發現 它有錯誤繼承
【490】修改 source文件:mini_ddk.c 改成 mini_ddk.cpp教程
【525】此時編譯報錯ip
【640】
「
*.c
當文件後綴名爲*.c時 編譯器將會用C編譯器方式編譯
*.cpp
當文件後綴名爲*.cpp時 編譯器將會用C++編譯器方式編譯
區別:
解決辦法
在須要用到C方式編譯的函數前加extern "C"
須要用C方式編譯的頭文件作以下修改
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h> //這裏包含須要用C方式編譯的頭文件
#ifdef __cplusplus
}
#endif
」
【810】再次編譯,仍是有報錯,可是 錯誤少了。頭文件的錯誤提示 沒有了
「
1>errors in directory g:\驅動教程\024_驅動代碼中c和c++代碼區別\mini_ddk
1>mini_ddk.obj : error LNK2001: unresolved external symbol "struct _ServiceDescriptorTable * KeServiceDescriptorTable" (?KeServiceDescriptorTable@@3PAU_ServiceDescriptorTable@@A)
1>bufferoverflowk.lib(gs_support.obj) : error LNK2019: unresolved external symbol _DriverEntry@8 referenced in function _GsDriverEntry@8
1>sys\i386\ddk_helloworld.sys : error LNK1120: 2 unresolved externals
」
【1160】
「
_DriverEntry@8 //要求格式
?DriverEntry@@YGJPAU_DRIVER_OBJECT@@PAU_UNICODE_STRING@@@Z ?
實例 修改21課的代碼 升級到C++編譯模式
A、爲入口函數 添加Extern "C"
B、修改Source文件
C、修改21課的BUG
」
【1220】
(1)、「extern PServiceDescriptorTable KeServiceDescriptorTable;」
改成「extern "C" extern PServiceDescriptorTable KeServiceDescriptorTable;」
(2)、【1250】「NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B)」
改成「extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B)」
【1300】這是 連接錯誤(非 編譯錯誤),【1325】在生成目標文件時 並無出錯
【1390】看 編譯生成的目標文件(ZC: 貌似這裏是 未加「extern "C"」時的 .obj文件)
【1425】DriverEntry 被替代成了 「?DriverEntry@@YGJPAU_DRIVER_OBJECT@@PAU_UNICODE_STRING@@@Z...」
【1490】而 錯誤提示裏面 要求的是 symbol是這個「_DriverEntry@8」
【1585】再次編譯
【1605】從新打開 mini_ddk.obj
【1660】查找 "DriverEntry"
【1675】這個時候咱們看到,加「extern "C"」以後,生成的替代函數就是 「_DriverEntry@8」
【1750】此時的提示 也看到 編譯成功了
【1765】集成環境裏面編譯,報錯了
【1805】它把「extern "C"」識別成了錯誤。這時一個經典錯誤:vs2003-->項目 --> mini_ddk屬性 --> 配置屬性 --> C/C++ --> 高級 --> 「編譯爲」,如今的值爲 「編譯爲C代碼(/TC)」,這裏要 修改 選成 「默認」 或者 「編譯爲C++代碼(/TP)」。【1920】「默認」 的話,它就是經過 文件的後綴名 來判斷它所要編譯的方式。
【1975】改過以後,vs2003再來編譯,就OK了
【2050】第21課 寫的代碼裏面有一個bug
【2100】卸載例程 DDK_Unload裏面,【2140】須要加一個判斷,它是否進行了HOOK,加上一個標識
【2375】不加這個判斷的話,若是沒有 hook的話,在卸載驅動時,會藍屏
【2420】用 以前沒有加 ishook的那個驅動(DDK_HelloWorld.sys),到虛擬機中 測試一下
【2490】驅動載入的時候正常,【2495】卸載的時候 就藍屏了
【2520】vs2003保存一下,從新用DDK編譯
【2723】放到 虛擬機中 測試一下
【2790】加載 和 卸載 都OK
「
bool ishook = false;
NTSTATUS DriverEntry(PDRIVER_OBJECT _pDrvierObject, PUNICODE_STRING B)
{
ULONG cur, old, ulOffset;
JMPCODE JmpCode;
cur = GetNt_CurAddr() ;
old = GetNt_OldAddr();
if (cur != old)
{
// hook
ishook = true;
// 【2040】保存 前5個字節
pcur = (PJMPCODE)(cur); // 【2500】初始化指針
oldCode.E9 = pcur->E9; // 【2205】1字節
oldCode.JMPADDR = pcur->JMPADDR; // 【2210】4字節
ulOffset = old - (cur + 5);
JmpCode.E9 = 0xE9;
JmpCode.JMPADDR = ulOffset;
KdPrint(("要寫入的地址 : 0x%08X", JmpCode.JMPADDR));
__asm // 去掉頁面保護
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
pcur->E9 = 0xE9;
pcur->JMPADDR = JmpCode.JMPADDR; // 【1790】要跳轉到的地址
__asm // 恢復頁保護
{
mov eax,cr0
or eax,10000h //or eax,not 0FFFEFFFFh
mov cr0,eax
sti // 【1145】恢復中斷
}
KdPrint(("NtOpenProcess被Hook了"));
}
else
KdPrint(("NtOpenProcess沒有被Hook"));
_pDrvierObject->DriverUnload = DDK_Unload;
return 1;
}
VOID DDK_Unload(IN PDRIVER_OBJECT _pDrvierObject)
{
PDEVICE_OBJECT pDev; // 用來取得要刪除的設備對象
UNICODE_STRING symLinkName;
// unhook
if (ishook)
{
__asm // 去掉頁面保護
{
cli
mov eax,cr0
and eax,not 10000h //and eax,0FFFEFFFFh
mov cr0,eax
}
pcur->E9 = oldCode.E9;
pcur->JMPADDR = oldCode.JMPADDR;
__asm // 恢復頁保護
{
mov eax,cr0
or eax,10000h //or eax,not 0FFFEFFFFh
mov cr0,eax
sti // 【1145】恢復中斷
}
} // end unhook
pDev = _pDrvierObject->DeviceObject;
IoDeleteDevice(pDev); // 刪除設備
// 取得符號連接的名字
RtlInitUnicodeString(&symLinkName, L"\\??\\yjx888");
IoDeleteSymbolicLink(&symLinkName);
KdPrint(("驅動成功被卸載...OK----------"));
}
」
二、
extern "C" __declspec(naked) __stdcall test(int a, int b)