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