YJX_Driver_024_驅動代碼中C和C++代碼區別

一、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)

相關文章
相關標籤/搜索