鱼C论坛

 找回密码
 立即注册

[原创] 早前学完<<郁金香过驱动保护>>做的一些笔记!

热度 4已有 2017 次阅读2013-6-27 22:47

高手直接飘过吧- -!!!

▲ C/C++ Project Option最终设置如下:
/nologo /Gz /MLd /W2 /WX /Z7 /Od /D WIN32=100 /D _X86_=1 /D WINVER=0x501 /D DBG=1 /Fo"ddk_check/" /Fd"ddk_check/" /FD /c

▲ Link Project Options最终设置如下:
Wdm.lib ntoskrnl.lib /nologo /base:"0x10000" /stack:0x400000,0x1000 /entry:"DriverEntry" /subsystem:console /incremental:no /pdb:"ddk_check/event.pdb" /debug /machine:I386 /nodefaultlib /out:"ddk_check/event.sys" /subsystem:native /driver /SECTION:INIT,D /RELEASE /IGNORE:4078

▲ Windows API 分为三类 分别是USER函数,GDI函数,和KERNEL函数
USER函数(user32.dll):这类函数管理窗口,菜单,对话框和控件
GDI函数(gdi32.dll):这类函数在物理设备上执行绘图操作 -Shadow SSDT-Dwin32k.sys
KERNEL函数(kernel32.dll):这类函数管理非GUI资源,例如,进程,线程,文件,和同步服务等.
ntkrnlpa.exe+ntkrnlpa.lib

▲ 内核 ntkrnlpa.ZwOpenProcess---SSDT--ntkrnlpa.NtOpenProcess--
用户空间中的Zw***和Nt***的实现都是一样的,比如ntdll!ZwOpenProcess和ntdll!NtOpenProcess的入口都是0x7C92D5FE,ntdll!ZwOpenFile和ntdll!NtOpenFile的入口都是0f7C92D59E。内核空间中的Zw函数,是Nt函数的一个Stup,只是mov系统调用号到eax中,转而直接调用(注意,没有像ntdll!ZwOpenProcess)nt!KiSystemService去从SSDT中找到相应号码的函数再调用之,真正的实现都在Nt***函数中

▲ WinDbg符号文件路径: windbg符号路径设置: srv*D:\WINDDK\symbols*http://msdl.microsoft.com/download/symbols

▲ WinDbg 快捷键
G :运行
U :汇编
F10 :步过
F8,F11:步入
shift+F11:跳出,返回到上层CALL执行
F5:运行
bp:下断点 int 3 ,CC断点
bl 显示断点列表
bc 清除指定断点
bd 禁用指定断点
be 启用指定断点

▲ WinDbg dd的使用
dd 函数名/地址
eg:
dd KeServiceDescriptorTable

dd poi[函数名/地址]+偏移
0x表示16进制数,0n表示10进制数 l表示列出(list)后面加个数,每个地址占4个字节所以要*4,poi就是读取[地址]里的内容
eg:
dd poi[KeServiceDescriptorTable]+0xa*4 l 1
dd poi[KeServiceDescriptorTable]+0n31*4 l 1

▲ SSDT结构
SSDT的全称是System Services Descriptor Table,系统服务描述符表 在ntoskrnl.exe导出KeServiceDescriptorTable这个表
typedef struct ServiceDescriptorTable
{
PVOID ServiceTableBase; //System Service Dispatch Table 的基地址
PVOID ServiceCounterTable;//包含着 SSDT 中每个服务被调用次数的计数器。这个计数器一般由sysenter 更新。
unsigned int NumberOfServices;//由 ServiceTableBase 描述的服务的数目。
PVOID ParamTableBase; //包含每个系统服务参数字节数表的基地址-系统服务参数表
}

▲ 汇编imul,shr(右移),shl(左移)
imul eax,eax,4 //相当于eax=eax*4
shl eax,3 //相当于eax=eax*2^3
shr eax,3 //相当于eax=eax/2^3

▲ MmGetSystemRoutineAddress 读出原始地址
PVOID
MmGetSystemRoutineAddress(
IN PUNICODE_STRING SystemRoutineName
);

▲ JMP结构
typedef struct _JMPCODE{
BYTE E9;
ULONG JMPADDR;
}JMPCODE;
计算方式是写入的地址:jmp_addr=old_addr-cur_addr-5

▲ 去掉页面保护,让cr0 第16位 置0 (即二进制第17个数) 才能进行写内核代码
使用时候加上:cli是关中断,防止有些硬件中断对程序的干扰
sti是开中断,允许硬件中断
0000 0000 0000 0001 0000 0000 0000 0000 cr0
& 1111 1111 1111 1110 1111 1111 1111 1111 FFFEFFFFh
0000 0000 0000 0000 0000 0000 0000 0000
__asm//去掉页面保护
{
cli
mov eax,cr0
and eax,not 10000h
mov cr0,eax
}
//在这里可以写入内核代码
__asm
{
mov eax,cr0
or eax,10000h
mov cr0,eax
sti
}

▲ Nt式驱动安装
A、OpenSCManager
B、CreateService
C、OpenService
D、StartService
E、CloseServiceHandle

▲ Nt式驱动卸载
A.OpenSCManager
B.OpenService
C.ControlService
D.DeleteService

▲ cpp文件编译需要在头文件处设置
好处:可以在代码中使用class,随意在哪处都可以定义变量,多了一些数据类型等等.
#pragma once
#ifdef __cplusplus
extern "C"
{
#endif
#include <NTDDK.h> //这里包含需要用C方式编译的头文件
#ifdef __cplusplus
}
#endif

▲ 应用程序与驱动交互访问(缓冲模式)
原理:
A、用户层传入数据-EXE部分代码
B、驱动层接收数据并处理-SYS部分代码
C、驱动层返回数据至用户层
D、用户层获得处理结果

代码实现:
//用户层
A.DeviceIoControl
B.CTL_CODE宏
#define add_code CTL_CODE(\
FILE_DEVICE_UNKNOWN, \ //DeviceType
0x800, \ // Function 0x800-0xfff 2048-4095
METHOD_BUFFERED, \ //Method
FILE_ANY_ACCESS) //Acess
//驱动层
C.当用户层调用了DeviceIoControl时就会产生一个IRP_MJ_DEVICE_CONTROL 事件传送到相应的驱动设备

//所以在驱动部分 必须先注册一个 IRP_MJ_DEVICE_CONTROL IRP处理函数
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = myDriver_DeviceIOControl;
//在这个回调函数里 可以通过 pIrp来获取 用户层EXE 传进来的参数
NTSTATUS myDriver_DeviceIOControl(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
//由pIrp得到输入缓冲区指针
//由pIrp得到输出缓冲区大小
//得到IOCTL码
//取得传入参数
//处理相送数据
//回传数据 SSDT hook
// C、驱动层回传数据给用户层
//完成IRP处理
//结束IRP请求
return status;
}

▲ 应用程序与驱动交互访问(直接模式)
原理:
A、用户层传入数据EXE部分代码
B、驱动层接收数据并处理SYS部分代码
C、驱动层返回数据至用户层
D、用户层获得处理结果
E、预编译指令#pragma #ifndef #endif
#define add_code CTL_CODE(
FILE_DEVICE_UNKNOWN,
0x800,
METHOD_IN_DIRECT,
FILE_ANY_ACCESS)
Method是指定数据传递的模式 有这几个值:
METHOD_BUFFERED //使用缓冲区方式操作 0
METHOD_IN_DIRECT //直接写方式 1 需要读权限
METHOD_OUT_DIRECT //直接读方式 2 既需要读权限又需要写权限 使用上面两种模式会输出数据缓冲区提供一个MDL
METHOD_NEITHER //其它方式 3

//获取 PIrp->MdlAddres 然后通过MmGetSystemAddressForMdlSafe将这段内存映身到内核模式下 供直接访问
int* OutBuffer =(int *)MmGetSystemAddressForMdlSafe(PIrp->MdlAddres, NormalPagePriority);

▲ 应用程序与驱动交互访问(其他模式)
#define add_code CTL_CODE(
FILE_DEVICE_UNKNOWN,
0x800,
METHOD_NEITHER,
FILE_ANY_ACCESS)

异常处理:
VOID ProbeForRead( __in PVOID Address, __in SIZE_T Length, __in ULONG Alignment);//检测是否可读
VOID ProbeForWrite( __inout PVOID Address, __in SIZE_T Length, __in ULONG Alignment);//检测是否可写

__try
{
//1 得到输入缓冲首地址
int *InputBuffer=(int*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
ProbeForRead(InputBuffer,cbin,sizeof(int));
.....
//2 得到输出缓冲首地址
int *OutputBuffer=(int*)pIrp->UserBuffer;
ProbeForWrite(OutputBuffer,cbout,sizeof(int));
}

__except(EXCEPTION_EXECUTE_HANDLER)
{
KdPrint(("指定内存不可读 或者 不可写 ,将继续执行后边代码 \n"));
}

▲ 内存管理相关内核API
Destination目标地址 Source源地址
1.RtlCopyMemory//复制内存
2.RtlCopyBytes//功能与RtlCopyMemory一样,都是调用方法memcpy
3.RtlMoveMemory//功能与RtlCopyMemory类似,区别是重叠内存
4.RtlZeroMemory //清零内存块,清零长度为Length
5.RtlFillMemory//为字符fill填充Destination 填充长度为Length
6.RtlEqualMemory//比较内存,相同返回一个无符号数值,不同返回0
7.RtlCompareMemory//与RtlEqualMemory类似,返回值不同
8.ExAllocatePool//类似C++的new C的malloc
PVOID ExAllocatePool(
__in POOL_TYPE PoolType,
__in SIZE_T NumberOfBytes);
9.ExFreePool//类似C++的delete C的free
VOID ExFreePool( __in PVOID P);

typedef enum _POOL_TYPE {
NonPagedPool = 0, //不分页
PagedPool = 1, //分页
NonPagedPoolMustSucceed = 2, //指定分配 非分页内存,要求必须成功。
DontUseThisType = 3, //未指定,留给系统使用
NonPagedPoolCacheAligned = 4,//非分页内存,要求内存边界对齐。
PagedPoolCacheAligned = 5,//分页内存,要求内存边界对齐。
NonPagedPoolCacheAlignedMustS = 6 //指定分配 非分页内存,要求内存边界对齐,要求必须成功。
} POOL_TYPE;

▲ 关于内核操作字符串的API
UNICODE_STRING//占2个字节
ANSI_STRING//占1个字节
RtlFreeAnsiString//销毁字符串
RtlFreeUnicodeString
RtlCopyUnicodeString//复制字符串
RtlEqualUnicodeString//比较两个Unicode字符串是否相同
RtlUpcaseUnicodeString//第三个参数设置为假 到大写
RtlUnicodeStringToInteger//字符串转整数型
RtlIntegerToUnicodeString//整数型转字符串 第二个参数为进制
RtlUnicodeStringToAnsiString//两种格式字符串相互转换
RtlAnsiStringToUnicodeString

▲ Shadow SSDT表
KeServiceDescriptorTable 导出的是SSDT表
在XP环境下(Hook时不能在入口函数DriverEntry 进行,必须在其他函数里!)
Shadow SSDT 与 SSDT的偏移
Shadow SSDT=KeServiceDescriptorTable-0x40+0x10
即Shadow SSDT=KeServiceDescriptorTable-0x30

▲ typedef 返回类型(*新类型)(参数表)
如typedef BOOL (__stdcall *PNtUserDestroyWindow)(HWND hwnd);
其中__stdcall表示参数从右向左压入堆栈
定义PNtUserDestroyWindow NtUserDestroyWindow;
NtUserDestroyWindow=(PNtUserDestroyWindow)Real_NtUserDestroyWindow_Addr;

路过

雷人
1

握手
2

鲜花

鸡蛋

刚表态过的朋友 (3 人)

发表评论 评论 (1 个评论)

回复 无名侠 2014-3-6 20:56
哈哈,给力!!我在研究内核与R3通信的新方法,比如开一个R3可以访问的中断,用eax做索引,推介楼主看一下寒江独钓

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-16 14:12

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部