|
沙发
楼主 |
发表于 2023-12-31 22:19:51
|
只看该作者
后来换了个方法,实现了要求的功能:
将SHELLOCE写入USER32.DLL的领空,函数头插入JMP后,使用中断门提权,触发用去驱动在0环中写入的一个函数,利用0环ESP偏移算出3环的ESP,然后再计算参数所在的位置,将其传给DBGPRINT输出。总算在2023年最后做出这个项目了。
3环部分************************************************************************************************************************
#include <Windows.h>
#include <stdio.h>
#include <WINIOCTL.H>
//获取值
#define GETVALUE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
//验证并修改页表
#define CHANGEVALUE CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_ANY_ACCESS)
//在内核空间分配内存
#define ALLOCATE CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_ANY_ACCESS)
//查找内存区域
#define LOOKUPMEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS)
//将0环HOOK函数修改页属性后传给三环
#define GETFUNCADDR CTL_CODE(FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED,FILE_ANY_ACCESS)
//修改IDT表
#define CHANGEIDTENTRY CTL_CODE(FILE_DEVICE_UNKNOWN,0x806,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define SYMBOLLINKNAME L"\\\\.\\SymbolLinkName"
#define SHELLCODESIZE 0x100
#define PARAMSIZE 0x40
#define GATESIZE 0x40
DWORD g_dwMsgAddr = 0;
DWORD g_dwParamAddr = 0;
HANDLE g_hDevice = NULL;
BYTE OrgCode[5] = {0x8b,0xff,0x55,0x8b,0xec};
BYTE ShellCode_Begin[5] = {0};
BYTE ShellCode_End[] = {
0x60, //pushad
0x9c, //pushfd
//InterruptGate
0xcd,0x20, //int 0x20
0x9d, //popfd
0x61, //popad
//OrgShellCode
0x8b,0xff, //mov edi,edi
0x55, //push ebp
0x8b,0xec, //mov ebp,esp
//Jump Return
0xe9,0x00,0x00,0x00,0x00, //待修改
};
BYTE ShellCode_Int[] = {
0x60, //pushfd
0x9C, //pushfd
0x8B,0x44,0x24,0x30, //mov eax,dword ptr [esp+0x30]
0x8B,0x58,0x34, //mov ebx,dword ptr [eax+0x34]
0x53, //push ebx
0x8B,0x44,0x24,0x34, //mov eax,dword ptr [esp+0x34]
0x8B,0x58,0x30, //mov ebx,dword ptr [eax+0x20]
0x53, //push ebx
0x8B,0x44,0x24,0x38, //mov eax,dword ptr [esp+0x38]
0x8B,0x58,0x2c, //mov ebx,dword ptr [eax+0x2C]
0x53, //push ebx
0x8B,0x44,0x24,0x3C, //mov eax,dword ptr [esp+0x3C]
0x8B,0x58,0x28, //mov ebx,dword ptr [eax+0x28]
0x53, //push ebx
0xB8,0xE0,0x18,0xC2,0xBA, //mov eax,0xBAC218E0 //待修改
0xFF,0xD0, //call eax
0x9D, //popfd
0x61, //popad
0xCF, //iretd
0x90,0x90,0x90,0x90
};
//修改ShellCode中指定位置的值
VOID ChangeShellCode(PBYTE ShellCode, DWORD dwSize, PBYTE pbSource);
//修正函数地址
VOID FixFuncAddr(PDWORD pdwFuncAddr);
//检查并修正线性地址的页属性
BOOL VerfyPage(HANDLE hDevice, DWORD dwLinnerAddr);
//循环输出指定内存地址的值
DWORD WINAPI ThreadProc(LPVOID lpParameter);
//利用驱动在Dll空间存放ShellCode_End
BOOL StoreShellEndInDll(IN HANDLE hDevice, IN DWORD dwStartAddr, OUT PDWORD pdwStoreAddr);
//利用驱动在Dll空间存放IntGate函数
BOOL StoreIntGateInDll(IN HANDLE hDevice, IN DWORD dwStartAddr, OUT PDWORD pdwStoreAddr);
//利用驱动将ShellCode_Begin覆盖函数头
BOOL ReWriteFuncHeaderWithShellCodeBegin(IN HANDLE hDevice, IN DWORD dwStartAddr, IN DWORD dwDestAddr);
//利用驱动在内核空间存放Parameter
BOOL StoreParameterInKernel(HANDLE hDevice);
//中断门
void __declspec(naked) IntGate()
{
__asm
{
//int 3
pushad //0x60,
pushfd //0x9C,
mov eax,dword ptr [esp+0x30] //0x8B,0x44,0x24,0x30,
mov ebx,dword ptr [eax+0x34] //0x8B,0x58,0x34,
push ebx //0x53,
mov eax,dword ptr [esp+0x34] //0x8B,0x44,0x24,0x34,
mov ebx,dword ptr [eax+0x30] //0x8B,0x58,0x30,
push ebx //0x53,
mov eax,dword ptr [esp+0x38] //0x8B,0x44,0x24,0x38,
mov ebx,dword ptr [eax+0x2c] //0x8B,0x58,0x2c,
push ebx //0x53,
mov eax,dword ptr [esp+0x3c] //0x8B,0x44,0x24,0x3C,
mov ebx,dword ptr [eax+0x28] //0x8B,0x58,0x28,
push ebx //0x53,
mov eax,0xBAC79A10 //0xB8,0xE0,0x18,0xC2,0xBA,
call eax //0xFF,0xD0,
popfd //0x9D,
popad //0x61,
iretd //0xCF
}
}
int main()
{
DWORD dwMsgwAddr = 0;
DWORD dwMyMsgwAddr = 0;
DWORD dwIntGateAddr = 0;
DWORD dwReturnLength = 0;
DWORD dwPTE = 0;
DWORD dwPteAddr = 0;
//获取MessageBoxW地址
printf("\n获取MessageBoxW地址\n");
PBYTE pbMsgBoxW = (PBYTE)MessageBoxW;
printf("MessageBoxW's First Byte Is 0x%.2x\n",*pbMsgBoxW);
dwMsgwAddr = (DWORD)pbMsgBoxW;
g_dwMsgAddr = dwMsgwAddr;
printf("MessageBoxW地址:0x%.8X\n", dwMsgwAddr);
//查看MessageBoxW前5个字节
printf("\n查看MessageBoxW前5个字节:");
for (DWORD i = 0; i < sizeof(ShellCode_Begin); i++)
{
printf("0x%.2x ", pbMsgBoxW[i]);
}
printf("\n");
//创建设备连接
printf("\n创建设备连接\n");
HANDLE hDevice = CreateFileW(SYMBOLLINKNAME,GENERIC_ALL,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
printf("Create Device Failed, ErrCode Is %d\n",GetLastError());
system("pause");
return -1;
}
printf("Create Device Success\n");
g_hDevice = hDevice;
//检查MessageBoxW的页属性
printf("\n检查MessageBoxW地址(0x%.8X)的页属性\n",dwMsgwAddr);
if (!VerfyPage(hDevice,dwMsgwAddr))
{
CloseHandle(hDevice);
system("pause");
return -1;
}
//*****************************************ShellCode_Int****************************************************************
if (!StoreIntGateInDll(hDevice,dwMsgwAddr,&dwIntGateAddr))
{
printf("\nStoreIntGateInDll失败,错误代码:%d\n",GetLastError());
CloseHandle(hDevice);
system("pause");
return -1;
}
printf("ShellCode_Int存放地址:0x%.8X\n",dwIntGateAddr);
//*****************************************ShellCode_End****************************************************************
if (!StoreShellEndInDll(hDevice,dwIntGateAddr + GATESIZE,&dwMyMsgwAddr))
{
printf("\nStoreShellEndInDll失败,错误代码:%d\n",GetLastError());
CloseHandle(hDevice);
system("pause");
return -1;
}
printf("ShellCode_End存放地址:0x%.8X\n",dwMyMsgwAddr);
//*****************************************ShellCode_Begin***************************************************************
if (!ReWriteFuncHeaderWithShellCodeBegin(hDevice,dwMsgwAddr,dwMyMsgwAddr))
{
printf("\nReWriteFuncHeaderWithShellCodeBegin失败,错误代码:%d\n",GetLastError());
CloseHandle(hDevice);
system("pause");
return -1;
}
//测试MessageBoxW
printf("\n测试MessageBoxW,按任意键开始\n");
getchar();
MessageBoxW(NULL,L"Hello",L"Caption",MB_OKCANCEL);
//收尾
printf("\n恢复原ShellCode\n");
system("pause");
printf("\n检查注入ShellCode_Int函数起始地址(0x%.8X)的页属性\n",dwIntGateAddr);
if (!VerfyPage(hDevice,dwIntGateAddr))
{
CloseHandle(hDevice);
system("pause");
return -1;
}
printf("恢复注入ShellCode_Int处硬编码\n");
memset((LPVOID)dwIntGateAddr,0,GATESIZE);
printf("\n检查MessageBoxW函数起始地址(0x%.8X)的页属性\n",dwMsgwAddr);
if (!VerfyPage(hDevice,dwMsgwAddr))
{
CloseHandle(hDevice);
system("pause");
return -1;
}
printf("恢复MessageBoxW函数起始处硬编码\n");
memcpy((LPVOID)dwMsgwAddr,OrgCode,sizeof(OrgCode));
printf("\n检查注入ShellCode_End函数起始地址(0x%.8X)的页属性\n",dwMyMsgwAddr);
if (!VerfyPage(hDevice,dwMyMsgwAddr))
{
CloseHandle(hDevice);
system("pause");
return -1;
}
printf("恢复注入ShellCode_End处硬编码\n");
memset((LPVOID)dwMyMsgwAddr,0,SHELLCODESIZE);
CloseHandle(hDevice);
printf("\n设备句柄已关闭\n\n");
system("pause");
return 0;
}
//修改ShellCode中指定位置的值
VOID ChangeShellCode(PBYTE ShellCode, DWORD dwSize, PBYTE pbSource)
{
printf("修改前的ShellCode:");
for (DWORD i = 0; i < dwSize; i++)
{
printf("0x%.2x ", ShellCode[i]);
ShellCode[i] = pbSource[i];
}
printf("\n修改后的ShellCode:");
for (i = 0; i < dwSize; i++)
{
printf("0x%.2x ", ShellCode[i]);
}
printf("\n");
}
//修正函数地址
VOID FixFuncAddr(PDWORD pdwFuncAddr)
{
printf("修正前,函数地址:0x%.8X\n", *pdwFuncAddr);
if (*(PBYTE)(*pdwFuncAddr) == 0xe9)
{
*pdwFuncAddr = *pdwFuncAddr + 5 + *(PDWORD)(*pdwFuncAddr + 1);
}
printf("修正后,函数地址:0x%.8X\n", *pdwFuncAddr);
}
//检查并修正线性地址的页属性
BOOL VerfyPage(HANDLE hDevice, DWORD dwLinnerAddr)
{
DWORD dwPDE = 0;
DWORD dwPTE = 0;
DWORD arrPage[2] = {0};
DWORD dwReturnLength = 0;
if (!DeviceIoControl(hDevice,CHANGEVALUE,&dwLinnerAddr,sizeof(dwLinnerAddr),arrPage,sizeof(arrPage),&dwReturnLength,NULL))
{
printf("DeviceIoControl CHANGEVALUE Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
dwPDE = arrPage[0];
dwPTE = arrPage[1];
printf("DeviceIoControl ALLOCATE Success!\nPDE:0x%.8X,PTE:0x%.8X\n",dwPDE,dwPTE);
return TRUE;
}
//利用驱动在Dll空间存放ShellCode_End
BOOL StoreShellEndInDll(IN HANDLE hDevice, IN DWORD dwStartAddr, OUT PDWORD pdwStoreAddr)
{
printf("\nStoreShellEndInDll\n");
DWORD dwReturnLength = 0;
DWORD arrIO[2] = {0};
arrIO[0] = dwStartAddr;
arrIO[1] = SHELLCODESIZE;
//在DLL空间找到存放ShellCode_End的地址
printf("\n在DLL空间找到存放ShellCode_End的地址\n");
if (!DeviceIoControl(hDevice,LOOKUPMEMORY,arrIO,sizeof(arrIO),pdwStoreAddr,sizeof(DWORD),&dwReturnLength,NULL))
{
printf("DeviceIoControl LOOKUPMEMORY Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
DWORD dwMyMsgwAddr = *pdwStoreAddr;
printf("DeviceIoControl LOOKUPMEMORY Success!\nShellCode_End存放的地址:0x%.8X,ReturnLength Is %d\n",dwMyMsgwAddr,dwReturnLength);
//**************************MessageBoxW函数参数**************************
//StoreParameterInDll(hDevice);
//********************************跳回地址*******************************
//修正跳回地址
printf("\n修正跳回地址:0x%.8x\n",g_dwMsgAddr + 5);
//跳转地址 = 当前地址 + 5 + E9参数
//E9参数 = 跳转地址 - 当前地址 - 5
DWORD dwBackAddr = g_dwMsgAddr + 5 - (DWORD)(dwMyMsgwAddr + 0xb) - 5;
printf("E9参数:0x%.8X\n", dwBackAddr);
ChangeShellCode((PBYTE)(ShellCode_End + 0xc), 4, (PBYTE)(&dwBackAddr));
//在Dll空间写入ShellCode_End
printf("\n检查存放ShellCode_End地址(0x%.8X)的页属性\n",dwMyMsgwAddr);
if (!VerfyPage(hDevice,dwMyMsgwAddr))
{
return FALSE;
}
printf("\n在Dll空间写入ShellCode_End\n");
__try
{
memcpy((LPVOID)dwMyMsgwAddr, (LPVOID)ShellCode_End, sizeof(ShellCode_End));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("写入ShellCode_End失败,错误代码:%d\n",GetLastError());
return FALSE;
}
printf("ShellCode_End Success\n");
return TRUE;
}
//利用驱动在内核空间存放Parameter
BOOL StoreParameterInKernel(IN HANDLE hDevice)
{
printf("\nStoreParameterInKernel\n");
//在内核空间分配内存,用于存放传入MessageBoxW的4个参数
printf("在内核空间分配内存,用于存放传入MessageBoxW的4个参数\n");
DWORD dwReturnLength = 0;
DWORD dwAllocateSize = PARAMSIZE;
DWORD dwParamAddr = 0;
DWORD arrParamAddr[4] = {0};
if (!DeviceIoControl(hDevice,ALLOCATE,&dwAllocateSize,sizeof(dwAllocateSize),&dwParamAddr,sizeof(dwParamAddr),&dwReturnLength,NULL))
{
printf("DeviceIoControl ALLOCATE Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
printf("DeviceIoControl ALLOCATE Success!\nParameter's Store Address Is 0x%.8X,ReturnLength Is %d\n",dwParamAddr,dwReturnLength);
g_dwParamAddr = dwParamAddr;
//分4个部分存放
printf("\n存放参数的地址分别为:\n");
for (int i = 0; i < 4; i++)
{
arrParamAddr[i] = dwParamAddr + i * 4;
printf("0x%.8X ",arrParamAddr[i]);
}
printf("\n");
//检查存放参数处的页属性
printf("\n检查存放参数地址(0x%.8X)的页属性\n",dwParamAddr);
if (!VerfyPage(hDevice,dwParamAddr))
{
return FALSE;
}
//分4个部分修改ShellCode_End
ChangeShellCode((PBYTE)(ShellCode_End + 0x07),4,(PBYTE)(&arrParamAddr[0]));
ChangeShellCode((PBYTE)(ShellCode_End + 0x10),4,(PBYTE)(&arrParamAddr[1]));
ChangeShellCode((PBYTE)(ShellCode_End + 0x19),4,(PBYTE)(&arrParamAddr[2]));
ChangeShellCode((PBYTE)(ShellCode_End + 0x22),4,(PBYTE)(&arrParamAddr[3]));
return TRUE;
}
//利用驱动将ShellCode_Begin覆盖函数头
BOOL ReWriteFuncHeaderWithShellCodeBegin(IN HANDLE hDevice, IN DWORD dwStartAddr, IN DWORD dwDestAddr)
{
printf("\nReWriteFuncHeaderWithShellCodeBegin\n");
//E9参数 = 目标地址 - 当前地址 - 5
printf("\n修正ShellCode_Begin\n");
DWORD dwJumpAddr = dwDestAddr - dwStartAddr - 5;
printf("ShellCode_Begin:0x%.8X\n", (DWORD)ShellCode_Begin);
printf("ShellCode_End:0x%.8X\n", (DWORD)ShellCode_End);
printf("E9参数:0x%.8X\n", dwJumpAddr);
//修正ShellCode_Begin
ShellCode_Begin[0] = 0xe9;
ChangeShellCode((PBYTE)(ShellCode_Begin + 1), 4, (PBYTE)(&dwJumpAddr));
//在Dll空间写入ShellCode_Begin
printf("\n检查存放ShellCode_Begin地址(0x%.8X)的页属性\n",dwStartAddr);
if (!VerfyPage(hDevice,dwStartAddr))
{
return FALSE;
}
printf("\n在Dll空间写入ShellCode_Begin\n");
__try
{
memcpy((LPVOID)dwStartAddr, (LPVOID)ShellCode_Begin, sizeof(ShellCode_Begin));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("写入ShellCode_Begin失败,错误代码:%d\n",GetLastError());
return FALSE;
}
printf("ShellCode_Begin Success\n");
return TRUE;
}
//利用驱动在Dll空间存放IntGate函数
BOOL StoreIntGateInDll(IN HANDLE hDevice, IN DWORD dwStartAddr, OUT PDWORD pdwStoreAddr)
{
printf("\nStoreIntGateInDll\n");
DWORD dwReturnLength = 0;
DWORD arrIO[2] = {0};
arrIO[0] = dwStartAddr;
arrIO[1] = GATESIZE;
//在DLL空间找到存放ShellCode_Int的地址
printf("\n在DLL空间找到存放ShellCode_Int的地址\n");
if (!DeviceIoControl(hDevice,LOOKUPMEMORY,arrIO,sizeof(arrIO),pdwStoreAddr,sizeof(DWORD),&dwReturnLength,NULL))
{
printf("DeviceIoControl LOOKUPMEMORY Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
DWORD dwIntGateAddr = *pdwStoreAddr;
printf("DeviceIoControl LOOKUPMEMORY Success!\nShellCode_Int存放的地址:0x%.8X,ReturnLength Is %d\n",dwIntGateAddr,dwReturnLength);
//获取0环HOOK函数地址
printf("\n获取0环HOOK函数的地址\n");
DWORD dwHookFuncAddr = 0;
if (!DeviceIoControl(hDevice,GETFUNCADDR,NULL,0,&dwHookFuncAddr,sizeof(dwHookFuncAddr),&dwReturnLength,NULL))
{
printf("DeviceIoControl GETFUNCADDR Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
printf("DeviceIoControl GETFUNCADDR Success!\nHOOK函数的地址:0x%.8X,ReturnLength Is %d\n",dwHookFuncAddr,dwReturnLength);
printf("读取HOOK函数首地址的值:0x%X\n",*(PDWORD)dwHookFuncAddr);
//*************************************构建中断门***************************************
printf("\n构建中断门\n");
ULONGLONG ullIntGateEntry = 0;
if (!DeviceIoControl(hDevice,CHANGEIDTENTRY,&dwIntGateAddr,sizeof(dwIntGateAddr),&ullIntGateEntry,sizeof(ullIntGateEntry),&dwReturnLength,NULL))
{
printf("DeviceIoControl GETFUNCADDR Failed, ErrCode Is %d\n",GetLastError());
return FALSE;
}
printf("DeviceIoControl GETFUNCADDR Success!\n添加的IDT项:0x%.16I64X,ReturnLength Is %d\n",ullIntGateEntry,dwReturnLength);
//修正ShellCode_Int中赋给EAX的0环函数(HookMsg)的地址
printf("mov eax,0x%.8X\n", dwHookFuncAddr);
ChangeShellCode((PBYTE)(ShellCode_Int + 0x23), 4, (PBYTE)(&dwHookFuncAddr));
//在Dll空间写入ShellCode_Int
printf("\n检查存放ShellCode_Int地址(0x%.8X)的页属性\n",dwIntGateAddr);
if (!VerfyPage(hDevice,dwIntGateAddr))
{
return FALSE;
}
printf("\n在Dll空间写入ShellCode_Int\n");
__try
{
memcpy((LPVOID)dwIntGateAddr, (LPVOID)ShellCode_Int, sizeof(ShellCode_Int));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("写入ShellCode_Int失败,错误代码:%d\n",GetLastError());
return FALSE;
}
printf("ShellCode_Int Success\n");
return TRUE;
}
0环部分************************************************************************************************************************
#include <ntifs.h>
//获取值
#define GETVALUE CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
//修正线性地址的页属性
#define CHANGEVALUE CTL_CODE(FILE_DEVICE_UNKNOWN,0x802,METHOD_BUFFERED,FILE_ANY_ACCESS)
//在内核空间分配内存
#define ALLOCATE CTL_CODE(FILE_DEVICE_UNKNOWN,0x803,METHOD_BUFFERED,FILE_ANY_ACCESS)
//查找内存区域
#define LOOKUPMEMORY CTL_CODE(FILE_DEVICE_UNKNOWN,0x804,METHOD_BUFFERED,FILE_ANY_ACCESS)
//将0环HOOK函数修改页属性后传给三环
#define GETFUNCADDR CTL_CODE(FILE_DEVICE_UNKNOWN,0x805,METHOD_BUFFERED,FILE_ANY_ACCESS)
//修改IDT表
#define CHANGEIDTENTRY CTL_CODE(FILE_DEVICE_UNKNOWN,0x806,METHOD_BUFFERED,FILE_ANY_ACCESS)
//将在多处引用,所以作为宏全局声明,避免多次输入
#define DEVICENAME L"\\Device\\MyDevice"
#define SYMBOLLINKNAME L"\\??\\SymbolLinkName"
//PDRIVER_OBJECT
PDRIVER_OBJECT g_pDriver = NULL;
//HOOK函数地址
ULONG g_ulHookFuncAddr = 0;
//IDT寄存器
typedef struct _IDT
{
ULONG ulIdtR;
USHORT usIdtL;
}IDT;
//驱动停止函数
VOID DriverUnload(PDRIVER_OBJECT pDriver);
//派遣函数:Create
NTSTATUS DispatchCreateFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp);
//派遣函数:Close
NTSTATUS DispatchCloseFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp);
//派遣函数:DeviceControl
NTSTATUS DispatchDeviceControlFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp);
//检查并修改线性地址的页属性
BOOLEAN CheckPageAttribute(IN ULONG ulMemAddr,OUT PULONG plPDE,OUT PULONG plPTE);
//三环调用的HOOK函数
VOID __stdcall HookMsg(ULONG hWnd, ULONG lpText, ULONG lpCaption, ULONG uType);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegPath)
{
NTSTATUS status;
ULONG ulRet = 0;
PDEVICE_OBJECT pDeviceObj;
UNICODE_STRING DeviceName;
UNICODE_STRING SymbolLinkName;
g_pDriver = pDriver;
//设置设备名称
RtlInitUnicodeString(&DeviceName,DEVICENAME);
//设置符号链接名称
RtlInitUnicodeString(&SymbolLinkName,SYMBOLLINKNAME);
//创建设备对象
status = IoCreateDevice(pDriver,0,&DeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pDeviceObj);
if (status != STATUS_SUCCESS)
{
DbgPrint("创建设备对象失败\r\n");
//If a driver's call to IoCreateDevice returns an error, the driver should release any resources that it allocated for that device.
IoDeleteDevice(pDeviceObj);
return status;
}
//设置交互方式
pDeviceObj->Flags |= DO_BUFFERED_IO;
//创建符号链接
status = IoCreateSymbolicLink(&SymbolLinkName,&DeviceName);
if (status != STATUS_SUCCESS)
{
DbgPrint("创建符号链接失败\r\n");
return STATUS_UNSUCCESSFUL;
}
//确定HOOK函数地址
g_ulHookFuncAddr = (ULONG)HookMsg;
DbgPrint("g_ulHookFuncAddr:0x%.8X\r\n",g_ulHookFuncAddr);
//设置派遣函数
pDriver->MajorFunction[IRP_MJ_CREATE] = DispatchCreateFunc;
pDriver->MajorFunction[IRP_MJ_CLOSE] = DispatchCloseFunc;
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControlFunc;
pDriver->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
//驱动停止函数
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
//删除符号链接
UNICODE_STRING SymbolLinkName;
RtlInitUnicodeString(&SymbolLinkName,SYMBOLLINKNAME);
IoDeleteSymbolicLink(&SymbolLinkName);
//删除设备
//This member is automatically updated when the driver calls IoCreateDevice successfully.
//A driver can use this member and the NextDevice member of DEVICE_OBJECT to step through a list of all the device objects that the driver created.
IoDeleteDevice(pDriver->DeviceObject);
DbgPrint("驱动已停止\r\n");
}
//派遣函数:Create
NTSTATUS DispatchCreateFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
DbgPrint("Create Dispatch Function Success\r\n");
//将IRP中的状态置为成功
pIrp->IoStatus.Status = status;
//返还的字节数
pIrp->IoStatus.Information = 0;//Information 的类型是 ULONG_PTR,即 unsinged long
//结束IRP请求
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
//派遣函数:Close
NTSTATUS DispatchCloseFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp)
{
NTSTATUS status = STATUS_SUCCESS;
DbgPrint("Close Dispatch Function Success\r\n");
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return status;
}
//派遣函数:DeviceControl
NTSTATUS DispatchDeviceControlFunc(PDEVICE_OBJECT pDeviceObj, PIRP pIrp)
{
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
PIO_STACK_LOCATION pIrpStack;
ULONG ulRead = 0;
ULONG ulWrite = 0;
//从三环传入的ShellCode_End大小
ULONG ulBufferSize = 0;
//ZeroMemoryBuffer
PUCHAR pcZeroBuffer = NULL;
//存放ShellCode_End的地址
PUCHAR pcShellBuffer = NULL;
//页属性:PDE & PTE
ULONG arrPage[2] = {0};
//判断结果
ULONG ulRet = 0;
//IDT寄存器
IDT stIdt = {0};
//需要在IDT中添加的函数地址
ULONGLONG ullIntGateEntry = 0;
//从三环传入的控制码
ULONG IoControlCode;
//从三环传入的数据长度
ULONG IoInLength;
//向三环输出的数据长度
ULONG IoOutLength;
//向三环实际输出的数据长度
ULONG RealOutLength;
//与三环传输的缓冲区(输入、输出是同一个缓冲区)
PVOID pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
DbgPrint("DeviceControl Dispatch Function Success\r\n");
//接收来自三环的数据(IRP)
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
//接收控制码
IoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
//接收传入数据长度
IoInLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
//输出数据长度
IoOutLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
//确定交互数据的缓冲区
pIoBuffer = pIrp->AssociatedIrp.SystemBuffer;
//分析收到的控制码
switch (IoControlCode)
{
case GETVALUE:
{
DbgPrint("\r\nGETVALUE\r\n");
//DbgBreakPoint();
//读取缓冲区
RtlCopyMemory(&ulRead,pIoBuffer,sizeof(ulRead));
DbgPrint("需要查找的内存地址:0x%.8X\r\n",ulRead);
//写入缓冲区,发数据给三环
ulWrite = *(PULONG)ulRead;
DbgPrint("0x%.8X地址的值:0x%X\r\n",ulRead,ulWrite);
RtlCopyMemory(pIoBuffer,&ulWrite,sizeof(ulWrite));
//设置返还数据的长度
RealOutLength = sizeof(ulWrite);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
case CHANGEVALUE:
{
DbgPrint("\r\nCHANGEVALUE\r\n");
//DbgBreakPoint();
//读取缓冲区
RtlCopyMemory(&ulRead,pIoBuffer,sizeof(ulRead));
DbgPrint("需要修改的内存地址:0x%.8X\r\n",ulRead);
//查看并修正线性地址的页属性
if (!CheckPageAttribute(ulRead,&arrPage[0],&arrPage[1]))
{
DbgPrint("线性地址无效\r\n");
//设置返还数据的长度
RealOutLength = 0;
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_UNSUCCESSFUL;
break;
}
DbgPrint("0x%.8X地址最终的页属性:\r\nPDE:0x%.8X,PTE:0x%.8X\r\n",ulRead,arrPage[0],arrPage[1]);
//写入缓冲区,发数据给三环
RtlCopyMemory(pIoBuffer,arrPage,sizeof(arrPage));
//设置返还数据的长度
RealOutLength = sizeof(arrPage);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
case ALLOCATE:
{
DbgPrint("\r\nALLOCATE\r\n");
//DbgBreakPoint();
//读取缓冲区
RtlCopyMemory(&ulRead,pIoBuffer,sizeof(ulRead));
DbgPrint("从三环传入的待开辟内存大小:0x%xr\n",ulRead);
//在高2G开辟内存空间
pcZeroBuffer = (PUCHAR)ExAllocatePool(NonPagedPool,ulBufferSize);
if (pcZeroBuffer == NULL)
{
DbgPrint("ExAllocatePool失败\r\n");
status = STATUS_UNSUCCESSFUL;
break;
}
ulWrite = (ULONG)pcZeroBuffer;
DbgPrint("ExAllocatePool成功,地址为:0x%.8X\r\n",ulWrite);
RtlFillMemory(pcZeroBuffer,ulRead,0);
//查看并修正线性地址的属性
if (!CheckPageAttribute(ulWrite,&arrPage[0],&arrPage[1]))
{
DbgPrint("线性地址无效\r\n");
//设置返还数据的长度
RealOutLength = 0;
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_UNSUCCESSFUL;
break;
}
DbgPrint("0x%.8X地址最终的页属性:\r\nPDE:0x%.8X,PTE:0x%.8X\r\n",ulWrite,arrPage[0],arrPage[1]);
//将内存地址写入缓冲区,发数据给三环
RtlCopyMemory(pIoBuffer,&ulWrite,sizeof(ulWrite));
//设置返还数据的长度
RealOutLength = sizeof(ulWrite);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
case LOOKUPMEMORY:
{
DbgPrint("\r\nLOOKUPMEMORY\r\n");
//DbgBreakPoint();
//读取缓冲区
RtlCopyMemory(&ulRead,pIoBuffer,sizeof(ulRead));
DbgPrint("从三环传入的遍历内存起始地址:0x%.8X\r\n",ulRead);
//从三环传入的ShellCode_End大小
RtlCopyMemory(&ulBufferSize,(PVOID)((ULONG)pIoBuffer + 4),sizeof(ulBufferSize));
DbgPrint("从三环传入的待开辟内存大小:0x%x\r\n",ulBufferSize);
//创建ZeroBuffer用于比较
pcZeroBuffer = (PUCHAR)ExAllocatePool(NonPagedPool,ulBufferSize);
if (pcZeroBuffer == NULL)
{
DbgPrint("ExAllocatePool失败\r\n");
status = STATUS_UNSUCCESSFUL;
break;
}
RtlFillMemory(pcZeroBuffer,ulBufferSize,0);
//遍历查找符合条件的内存区域
pcShellBuffer = (PUCHAR)ulRead;
while (TRUE)
{
ulRet = RtlCompareMemory(pcShellBuffer,pcZeroBuffer,ulBufferSize);
if (ulRet == ulBufferSize)
{
DbgPrint("已开辟0x%x大小的内存区域,地址:0x%.8X\r\n",ulBufferSize,(ULONG)pcShellBuffer);
break;
}
pcShellBuffer += 4;
}
//写入缓冲区,发数据给三环
ulWrite = (ULONG)pcShellBuffer;
DbgPrint("可写入ShellCode的地址:0x%.8X\r\n",ulWrite);
RtlCopyMemory(pIoBuffer,&ulWrite,sizeof(ulWrite));
//设置返还数据的长度
RealOutLength = sizeof(ulWrite);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
case GETFUNCADDR:
{
DbgPrint("\r\nGETFUNCADDR\r\n");
//获取HOOK函数的地址
ulWrite = (ULONG)HookMsg;
DbgPrint("HookMsg函数的地址:0x%.8X\r\n",ulWrite);
//将函数的页属性设置为用户级:US = 1
if (!CheckPageAttribute(ulWrite,&arrPage[0],&arrPage[1]))
{
DbgPrint("线性地址无效\r\n");
//设置返还数据的长度
RealOutLength = 0;
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_UNSUCCESSFUL;
break;
}
DbgPrint("0x%.8X地址最终的页属性:\r\nPDE:0x%.8X,PTE:0x%.8X\r\n",ulWrite,arrPage[0],arrPage[1]);
//将函数地址传给三环
RtlCopyMemory(pIoBuffer,&ulWrite,sizeof(ulWrite));
//设置返还数据的长度
RealOutLength = sizeof(ulWrite);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
case CHANGEIDTENTRY:
{
DbgPrint("\r\nCHANGEIDTENTRY\r\n");
//读取缓冲区
RtlCopyMemory(&ulRead,pIoBuffer,sizeof(ulRead));
DbgPrint("需要提权的函数地址:0x%.8X\r\n",ulRead);
//将函数地址转换为IDT项
ullIntGateEntry = (((ULONGLONG)ulRead >> 16) << 48) + 0xee0000080000 + (ulRead & 0xffff);
DbgPrint("即将添加的IDT项:%.16X\r\n",ullIntGateEntry);
//获取IDT地址
__asm sidt stIdt;
DbgPrint("IDT基址:0x%.8X,IDT长度:0x%x\n",stIdt.ulIdtR,stIdt.usIdtL);
//修改指定IDT项
RtlCopyMemory((PVOID)0x8003f500,&ullIntGateEntry,8);
DbgPrint("已修改IDT项(8003f500): %.16I64X\r\n",*(PULONGLONG)0x8003f500);
//写入缓冲区,发数据给三环
RtlCopyMemory(pIoBuffer,&ullIntGateEntry,sizeof(ullIntGateEntry));
//设置返还数据的长度
RealOutLength = sizeof(ullIntGateEntry);
pIrp->IoStatus.Information = RealOutLength;
DbgPrint("OutputLength Is %d\r\n",RealOutLength);
status = STATUS_SUCCESS;
break;
}
default:
DbgPrint("Switch Exception\r\n");
break;
}
pIrp->IoStatus.Status = status;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//检查并修改线性地址的页属性
BOOLEAN CheckPageAttribute(IN ULONG ulMemAddr,OUT PULONG plPDE,OUT PULONG plPTE)
{
ULONG ulPDE = 0;
ULONG ulPTE = 0;
ULONG ulPdeAddr = 0xc0600000 + ((ulMemAddr >> 0x12) & 0x003ff8);
ULONG ulPteAddr = 0xc0000000 + ((ulMemAddr >> 0x09) & 0x7ffff8);
DbgPrint("\r\n检查线性地址(0x%.8X)的页属性\r\n",ulMemAddr);
//查看PDE属性
ulPDE = *(PULONG)ulPdeAddr;
DbgPrint("PDE:0x%.8X\r\n",ulPDE);
//P位
if ((ulPDE & 0x1) != 0x1)
{
DbgPrint("PDE的P位为0,地址无效\r\n");
return FALSE;
}
else
{
//RW、US位
if ((ulPDE & 0x7) != 0x7)
{
ulPDE = (ulPDE & 0xfffffff8) + 0x7;
*(PULONG)ulPdeAddr = ulPDE;
DbgPrint("已修改PDE的RW、US位,PDE:0x%.8X\r\n",ulPDE);
}
//PS位
if (((ulPDE & 0x80) >> 0x7) == 0x1)
{
DbgPrint("PDE的PS位为1,大页,检查终止\r\n");
*plPDE = ulPDE;
*plPTE = -1;
return TRUE;
}
else
{
//小页,检查PTE
ulPTE = *(PULONG)ulPteAddr;
//P位
if ((ulPTE & 0x1) != 0x1)
{
DbgPrint("PTE的P位为0,地址无效\r\n");
return FALSE;
}
else
{
//RW、US位
if ((ulPTE & 0x7) != 0x7)
{
ulPTE = (ulPTE & 0xfffffff8) + 0x7;
*(PULONG)ulPteAddr = ulPTE;
DbgPrint("已修改PTE的RW、US位,PTE:0x%.8X\r\n",ulPTE);
}
else
{
DbgPrint("无需修改\r\n");
}
*plPDE = ulPDE;
*plPTE = ulPTE;
return TRUE;
}
}
}
}
//三环调用的HOOK函数
VOID __stdcall HookMsg(ULONG hWnd, ULONG lpText, ULONG lpCaption, ULONG uType)
{
__asm pushfd
DbgPrint("3环调用0环函数成功!!!\r\n");
DbgPrint("MessageBoxW(hWnd:0x%x, lpText:0x%x, lpCaption:0x%x, uType:0x%x)\n", hWnd, lpText, lpCaption, uType);
__asm popfd
return;
}
唯一的遗憾是还是没弄懂一楼的问题,看看学到后面能否明白吧 |
|