海哥/火哥/周壑内核/麦洛科菲/科锐
麦洛科菲系统安全高级班
高质量C/C++编程指南
C语言中 “%z” 的使用;
//格式化描述符的安全性问题
//printf的安全性问题:栈上内存泄露,内存被修改(%n)
#include <stdio.h>
void MyPrint(char* buf)
{
printf("%s\n",buf);
printf(buf);
}
int main() {
MyPrint((char*)"hello");
printf("\n");
MyPrint((char*)"%x");
return 0;
}
main函数的问题
//先于main()执行
#include<stdio.h>
#include<windows.h>
int before_main1()
{
printf("before_main1()\n");
return 0;
}
int before_main2()
{
printf("before_main2()\n");
return 0;
}
int after_main()
{
printf("after_main()\n");
return 0;
}
typedef int func();
#pragma data_seg(".CRT$XIU")
static func* before1[] = { before_main1 };
#pragma data_seg(".CRT$XCU")
static func* before2[] = { before_main2 };
#pragma data_seg()
int main()
{
_onexit(after_main);
printf("helloworld\n");
return 0;
}
sizeof 和函数的区别:使用 sizeof 在编译阶段就能确定,使用函数需要在运行阶段才能确定
//结构体对齐、栈对齐
//为啥要对齐:CPU读取数据更快
//指定对齐大小:#pragma pack(1)
typedef struct x
{
char a;
long b;
char c;
double d;
}x;
typedef struct y
{
char a;
char c;
long b;
double d;
}y;
int main()
{
printf("%d\n", sizeof(x));
printf("%d\n", sizeof(y));
return 0;
}
虚拟内存地址(VA)=装载地址(ImageBase)+节偏移+文件偏移地址
相对虚拟地址(RVA)=VA-ImageBase
VOffset:VA节起始地址相对与ImageBase的偏移量
ROffset:PointerToRawData节起始地址对于文件起始位置的偏移量
thiscall是C++类成员函数缺省的调用约定,但它没有显示的声明形式。thiscall意味着:
参数入栈:参数从右向左入栈
this指针入栈:如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压栈后被压入堆栈。
堆栈恢复:对参数个数不定的,调用者清理堆栈,否则函数自己清理堆栈。
x64与x86的fastcall的区别:
1,比ecx(rcx),edx(rdx)寄存器多了2个r8,r9
2,参数入栈,会对齐到8个字节
3,函数的前4个参数存放到了rcx,rdx,r8,r9四个寄存器中,但在栈上也会预留4个空间
4,调用者来负责栈的平衡
//作业
1、计算一个整数的二进制中有多少个 1。如 10 的二进制为 1010,所以有 2 个 1。
2、请设计一个函数,把十进制的正整数转化为三十六进制字符串。三十六进制的规则为 “0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ”。比如:1=“0001”,10=“000A”,20=“000K”,35=“000Z”,36=“0010”;
3、判断一个平台是低位优先还是高位优先;
4、改变一个整数的存储方式 (0x12345678 0x78563412);
5、将一个字符串按照单词逆置,如”hello world” “world hello”;
6、将一个字符串,左旋 N 个字符。如左旋 3 个字符:”hello world” “lo worldhel”;
7、通过异或实现一个只带一个指针域的双向链表;
//1、计算一个整数的二进制中有多少个 1。如 10 的二进制为 1010,所以有 2 个 1。
//Brian Kernighan 算法
#include <stdio.h>
int countOnes(int num) {
int count = 0;
while (num) {
num &= (num - 1);
count++;
}
return count;
}
int main() {
int number;
printf("请输入一个整数: ");
scanf("%d", &number);
int result = countOnes(number);
printf("该整数的二进制表示中有 %d 个1\n", result);
return 0;
}
//2、请设计一个函数,把十进制的正整数转化为三十六进制字符串。
#include <stdio.h>
#include <string.h>
// 将十进制数转换为三十六进制字符串
void decimalToBase36(int decimal, char* result) {
const char base36Digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int index = 3;
result[4] = '\0';
while (decimal > 0 && index >= 0) {
result[index--] = base36Digits[decimal % 36];
decimal /= 36;
}
while (index >= 0) {
result[index--] = '0';
}
}
int main() {
int decimal;
char result[5];
printf("请输入一个十进制整数: ");
if (scanf("%d", &decimal) != 1) {
printf("输入错误,请输入一个有效的整数。\n");
return 1;
}
decimalToBase36(decimal, result);
printf("对应的4位定长三十六进制字符串为: %s\n", result);
return 0;
}
//3、判断一个平台是低位优先还是高位优先;
#include <stdio.h>
int isLittleEndian() {
int num = 1;
return *((char*)&num);
}
int main() {
if (isLittleEndian()) {
printf("The platform is little - endian.\n");
} else {
printf("The platform is big - endian.\n");
}
return 0;
}
//4、改变一个整数的存储方式 (0x12345678 0x78563412);
#include <stdio.h>
unsigned int reverseBytes(unsigned int num) {
return ((num & 0xFF000000) >> 24) | ((num & 0x00FF0000) >> 8) | ((num & 0x0000FF00) << 8) | ((num & 0x000000FF) << 24);
}
int main() {
unsigned int num1 = 0x12345678;
unsigned int num2 = 0x78563412;
printf("Before reversing: 0x%X\n", num1);
printf("After reversing: 0x%X\n", reverseBytes(num1));
printf("Before reversing: 0x%X\n", num2);
printf("After reversing: 0x%X\n", reverseBytes(num2));
return 0;
}
//5、将一个字符串按照单词逆置,如”hello world” “world hello”;
#include <stdio.h>
#include <string.h>
void reverseWords(char* str) {
int len = strlen(str);
char temp[len + 1];
int j = 0;
for (int i = len - 1; i >= 0; i--) {
if (str[i] =='') {
for (int k = i + 1; k <= len - 1 && str[k]!=''; k++) {
temp[j++] = str[k];
}
temp[j++] ='';
}
if (i == 0) {
for (int k = 0; k <= len - 1 && str[k]!=''; k++) {
temp[j++] = str[k];
}
}
}
temp[j] = '\0';
strcpy(str, temp);
}
int main() {
char str[] = "hello world";
reverseWords(str);
printf("%s\n", str);
return 0;
}
//6、将一个字符串,左旋 N 个字符。如左旋 3 个字符:”hello world” “lo worldhel”;
#include <stdio.h>
#include <string.h>
void leftRotate(char* str, int n) {
int len = strlen(str);
n = n % len;
char temp[n + 1];
strncpy(temp, str, n);
temp[n] = '\0';
for (int i = 0; i < len - n; i++) {
str[i] = str[i + n];
}
strcat(str, temp);
}
int main() {
char str[] = "hello world";
leftRotate(str, 3);
printf("%s\n", str);
return 0;
}
//7、通过异或实现一个只带一个指针域的双向链表;
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构
typedef struct XorNode {
int data;
struct XorNode* ptr;
} XorNode;
// 辅助函数:获取两个指针的异或
XorNode* Xor(XorNode* a, XorNode* b) {
return (XorNode*)((unsigned long)(a) ^ (unsigned long)(b));
}
// 创建新节点
XorNode* createNode(int data) {
XorNode* newNode = (XorNode*)malloc(sizeof(XorNode));
newNode->data = data;
newNode->ptr = NULL;
return newNode;
}
// 在头部插入节点
void insertAtHead(XorNode** head, int data) {
XorNode* newNode = createNode(data);
if (*head!= NULL) {
newNode->ptr = Xor(*head, NULL);
(*head)->ptr = Xor(Xor((*head)->ptr, NULL), newNode);
}
*head = newNode;
}
// 打印链表
void printList(XorNode* head) {
XorNode* prev = NULL;
XorNode* curr = head;
XorNode* next;
while (curr!= NULL) {
printf("%d ", curr->data);
next = Xor(prev, curr->ptr);
prev = curr;
curr = next;
}
printf("\n");
}
// 释放链表内存
void freeList(XorNode* head) {
XorNode* prev = NULL;
XorNode* curr = head;
XorNode* next;
while (curr!= NULL) {
next = Xor(prev, curr->ptr);
free(curr);
prev = curr;
curr = next;
}
}
int main() {
XorNode* head = NULL;
insertAtHead(&head, 1);
insertAtHead(&head, 2);
insertAtHead(&head, 3);
printList(head);
freeList(head);
return 0;
}
驱动框架
//框架
#include <ntddk.h>
#define DEVICE_NAME L"\\device\\ntmodeldrv"//设备名
#define LINK_NAME L"\\dosdevices\\ntmodeldrv"//符号链接
#define IOCTRL_BASE 0x800
#define MYIOCTRL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE+i, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define CTL_HELLO MYIOCTRL_CODE(0)
#define CTL_PRINT MYIOCTRL_CODE(1)
#define CTL_BYE MYIOCTRL_CODE(2)
NTSTATUS DispatchCommon(PDEVICE_OBJECT pObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchCreate(PDEVICE_OBJECT pObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchRead(PDEVICE_OBJECT pObject, PIRP pIrp)
{
PVOID pReadBuffer = NULL;
ULONG uReadLength = 0;
PIO_STACK_LOCATION pStack = NULL;
ULONG uMin = 0;
ULONG uHelloStr = 0;
uHelloStr = (wcslen(L"hello world") + 1) * sizeof(WCHAR);
//第一步,拿到缓存的地址和长度
//从头部拿缓存地址
pReadBuffer = pIrp->AssociatedIrp.SystemBuffer;
//从栈上拿缓存长度
pStack = IoGetCurrentIrpStackLocation(pIrp);
uReadLength = pStack->Parameters.Read.Length;
//第二步:读,写等操作
uMin = uReadLength > uHelloStr ? uHelloStr : uReadLength;
RtlCopyMemory(pReadBuffer, L"hello world", uMin);
//第三步,完成IRP
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = uMin;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchWrite(PDEVICE_OBJECT pObject, PIRP pIrp)
{
PVOID pWriteBuff = NULL;
ULONG uWriteLength = 0;
PIO_STACK_LOCATION pStack = NULL;
PVOID pBuffer = NULL;
pWriteBuff = pIrp->AssociatedIrp.SystemBuffer;
pStack = IoGetCurrentIrpStackLocation(pIrp);
uWriteLength = pStack->Parameters.Write.Length;
pBuffer = ExAllocatePoolWithTag(PagedPool, uWriteLength, 'TSET');
if (pBuffer == NULL)
{
pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
memset(pBuffer, 0, uWriteLength);
RtlCopyMemory(pBuffer, pWriteBuff, uWriteLength);
ExFreePool(pBuffer);
pBuffer = NULL;
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = uWriteLength;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchIoctrl(PDEVICE_OBJECT pObject, PIRP pIrp)
{
ULONG uIoctrlCode = 0;
PVOID pInputBuff = NULL;
PVOID pOutputBuff = NULL;
ULONG uInputLength = 0;
ULONG uOutputLength = 0;
PIO_STACK_LOCATION pStack = NULL;
pInputBuff = pOutputBuff = pIrp->AssociatedIrp.SystemBuffer;
pStack = IoGetCurrentIrpStackLocation(pIrp);
uInputLength = pStack->Parameters.DeviceIoControl.InputBufferLength;
uOutputLength = pStack->Parameters.DeviceIoControl.OutputBufferLength;
uIoctrlCode = pStack->Parameters.DeviceIoControl.IoControlCode;
switch (uIoctrlCode)
{
case CTL_HELLO:
DbgPrint("Hello iocontrol\n");
break;
case CTL_PRINT:
DbgPrint("%ws\n", pInputBuff);
break;
case CTL_BYE:
DbgPrint("Goodbye iocontrol\n");
break;
default:
DbgPrint("Unknown iocontrol\n");
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClean(PDEVICE_OBJECT pObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose(PDEVICE_OBJECT pObject, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING uLinkName = { 0 };
RtlInitUnicodeString(&uLinkName, LINK_NAME);
IoDeleteSymbolicLink(&uLinkName);
IoDeleteDevice(pDriverObject->DeviceObject);
DbgPrint("Driver unloaded\n");
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,
PUNICODE_STRING pRegPath)
{
UNICODE_STRING uDeviceName = { 0 };
UNICODE_STRING uLinkName = { 0 };
NTSTATUS ntStatus = 0;
PDEVICE_OBJECT pDeviceObject = NULL;
ULONG i = 0;
DbgPrint("Driver load begin\n");
RtlInitUnicodeString(&uDeviceName, DEVICE_NAME);
RtlInitUnicodeString(&uLinkName, LINK_NAME);
RtlInitUnicodeString(&uDeviceName,DEVICE_NAME);
RtlInitUnicodeString(&uLinkName,LINK_NAME);
IoCreateDevice(pDriverObject,0,&uDeviceName,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObject);
ntStatus = IoCreateDevice(pDriverObject,
0, &uDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);
if (!NT_SUCCESS(ntStatus))
{
DbgPrint("IoCreateDevice failed:%x", ntStatus);
return ntStatus;
}
//DO_BUFFERED_IO规定R3和R0之间read和write通信的方式:
//1,buffered io
//2,direct io
//3,neither io
pDeviceObject->Flags |= DO_BUFFERED_IO;
ntStatus = IoCreateSymbolicLink(&uLinkName, &uDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
DbgPrint("IoCreateSymbolicLink failed:%x\n", ntStatus);
return ntStatus;
}
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION + 1; i++)
{
pDriverObject->MajorFunction[i] = DispatchCommon;
}
pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
pDriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctrl;
pDriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchClean;
pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObject->DriverUnload = DriverUnload;
DbgPrint("Driver load ok!\n");
return STATUS_SUCCESS;
}
#include <windows.h>
#include <winsvc.h>
#include <conio.h>
#include <stdio.h>
#include <winioctl.h>
#define DRIVER_NAME "ntmodeldrv"
#define DRIVER_PATH ".\\ntmodeldrv.sys"
#define IOCTRL_BASE 0x800
#define MYIOCTRL_CODE(i) \
CTL_CODE(FILE_DEVICE_UNKNOWN, IOCTRL_BASE+i, METHOD_BUFFERED,FILE_ANY_ACCESS)
#define CTL_HELLO MYIOCTRL_CODE(0)
#define CTL_PRINT MYIOCTRL_CODE(1)
#define CTL_BYE MYIOCTRL_CODE(2)
//装载NT驱动程序
BOOL LoadDriver(char* lpszDriverName,char* lpszDriverPath)
{
//char szDriverImagePath[256] = "D:\\DriverTest\\ntmodelDrv.sys";
char szDriverImagePath[256] = {0};
//得到完整的驱动路径
GetFullPathName(lpszDriverPath, 256, szDriverImagePath, NULL);
BOOL bRet = FALSE;
SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
//打开服务控制管理器
hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( hServiceMgr == NULL )
{
//OpenSCManager失败
printf( "OpenSCManager() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
////OpenSCManager成功
printf( "OpenSCManager() ok ! \n" );
}
//创建驱动所对应的服务
hServiceDDK = CreateService( hServiceMgr,
lpszDriverName, //驱动程序的在注册表中的名字
lpszDriverName, // 注册表驱动程序的 DisplayName 值
SERVICE_ALL_ACCESS, // 加载驱动程序的访问权限
SERVICE_KERNEL_DRIVER,// 表示加载的服务是驱动程序
SERVICE_DEMAND_START, // 注册表驱动程序的 Start 值
SERVICE_ERROR_IGNORE, // 注册表驱动程序的 ErrorControl 值
szDriverImagePath, // 注册表驱动程序的 ImagePath 值
NULL, //GroupOrder HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GroupOrderList
NULL,
NULL,
NULL,
NULL);
DWORD dwRtn;
//判断服务是否失败
if( hServiceDDK == NULL )
{
dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS )
{
//由于其他原因创建服务失败
printf( "CrateService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
//服务创建失败,是由于服务已经创立过
printf( "CrateService() Failed Service is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" );
}
// 驱动程序已经加载,只需要打开
hServiceDDK = OpenService( hServiceMgr, lpszDriverName, SERVICE_ALL_ACCESS );
if( hServiceDDK == NULL )
{
//如果打开服务也失败,则意味错误
dwRtn = GetLastError();
printf( "OpenService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
printf( "OpenService() ok ! \n" );
}
}
else
{
printf( "CrateService() ok ! \n" );
}
//开启此项服务
bRet= StartService( hServiceDDK, NULL, NULL );
if( !bRet )
{
DWORD dwRtn = GetLastError();
if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_ALREADY_RUNNING )
{
printf( "StartService() Failed %d ! \n", dwRtn );
bRet = FALSE;
goto BeforeLeave;
}
else
{
if( dwRtn == ERROR_IO_PENDING )
{
//设备被挂住
printf( "StartService() Failed ERROR_IO_PENDING ! \n");
bRet = FALSE;
goto BeforeLeave;
}
else
{
//服务已经开启
printf( "StartService() Failed ERROR_SERVICE_ALREADY_RUNNING ! \n");
bRet = TRUE;
goto BeforeLeave;
}
}
}
bRet = TRUE;
//离开前关闭句柄
BeforeLeave:
if(hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if(hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
//卸载驱动程序
BOOL UnloadDriver( char * szSvrName )
{
BOOL bRet = FALSE;
SC_HANDLE hServiceMgr=NULL;//SCM管理器的句柄
SC_HANDLE hServiceDDK=NULL;//NT驱动程序的服务句柄
SERVICE_STATUS SvrSta;
//打开SCM管理器
hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
if( hServiceMgr == NULL )
{
//带开SCM管理器失败
printf( "OpenSCManager() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
//带开SCM管理器失败成功
printf( "OpenSCManager() ok ! \n" );
}
//打开驱动所对应的服务
hServiceDDK = OpenService( hServiceMgr, szSvrName, SERVICE_ALL_ACCESS );
if( hServiceDDK == NULL )
{
//打开驱动所对应的服务失败
printf( "OpenService() Failed %d ! \n", GetLastError() );
bRet = FALSE;
goto BeforeLeave;
}
else
{
printf( "OpenService() ok ! \n" );
}
//停止驱动程序,如果停止失败,只有重新启动才能,再动态加载。
if( !ControlService( hServiceDDK, SERVICE_CONTROL_STOP , &SvrSta ) )
{
printf( "ControlService() Failed %d !\n", GetLastError() );
}
else
{
//打开驱动所对应的失败
printf( "ControlService() ok !\n" );
}
//动态卸载驱动程序。
if( !DeleteService( hServiceDDK ) )
{
//卸载失败
printf( "DeleteSrevice() Failed %d !\n", GetLastError() );
}
else
{
//卸载成功
printf( "DelServer:deleteSrevice() ok !\n" );
}
bRet = TRUE;
BeforeLeave:
//离开前关闭打开的句柄
if(hServiceDDK)
{
CloseServiceHandle(hServiceDDK);
}
if(hServiceMgr)
{
CloseServiceHandle(hServiceMgr);
}
return bRet;
}
void TestDriver()
{
//测试驱动程序
HANDLE hDevice = CreateFile("\\\\.\\NTmodeldrv",
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if( hDevice != INVALID_HANDLE_VALUE )
{
printf( "Create Device ok ! \n" );
}
else
{
printf( "Create Device Failed %d ! \n", GetLastError() );
return;
}
CHAR bufRead[1024]={0};
WCHAR bufWrite[1024]=L"Hello, world";
DWORD dwRead = 0;
DWORD dwWrite = 0;
ReadFile(hDevice, bufRead, 1024, &dwRead, NULL);
printf("Read done!:%ws\n",bufRead);
printf("Please press any key to write\n");
getch();
WriteFile(hDevice, bufWrite, (wcslen(bufWrite)+1)*sizeof(WCHAR), &dwWrite, NULL);
printf("Write done!\n");
printf("Please press any key to deviceiocontrol\n");
getch();
CHAR bufInput[1024] ="Hello, world";
CHAR bufOutput[1024] = {0};
DWORD dwRet = 0;
WCHAR bufFileInput[1024] =L"c:\\docs\\hi.txt";
printf("Please press any key to send PRINT\n");
getch();
DeviceIoControl(hDevice,
CTL_PRINT,
bufFileInput,
sizeof(bufFileInput),
bufOutput,
sizeof(bufOutput),
&dwRet,
NULL);
printf("Please press any key to send HELLO\n");
getch();
DeviceIoControl(hDevice,
CTL_HELLO,
NULL,
0,
NULL,
0,
&dwRet,
NULL);
printf("Please press any key to send BYE\n");
getch();
DeviceIoControl(hDevice,
CTL_BYE,
NULL,
0,
NULL,
0,
&dwRet,
NULL);
printf("DeviceIoControl done!\n");
CloseHandle( hDevice );
}
int main(int argc, char* argv[])
{
//加载驱动
BOOL bRet = LoadDriver(DRIVER_NAME,DRIVER_PATH);
if (!bRet)
{
printf("LoadNTDriver error\n");
return 0;
}
//加载成功
printf( "press any key to create device!\n" );
getch();
TestDriver();
//这时候你可以通过注册表,或其他查看符号连接的软件验证。
printf( "press any key to stop service!\n" );
getch();
//卸载驱动
bRet = UnloadDriver(DRIVER_NAME);
if (!bRet)
{
printf("UnloadNTDriver error\n");
return 0;
}
return 0;
}
查看SSDT
查看shadowSSDT
反调试
//反反调试
反反调试的思路也就出来了。针对清零DebugPort来防止调试的方法,可以通过对DebugPort内存地址下内存断点:
ba w4 debugport_addr
这样一旦有程序代码在修改DebugPort,就会被断下,从而找到对应的清零DebugPort的反调试代码,然后对这部分代码进行patch(用机器码0x90(nop)或者0xC3(ret)取代),从而让它失去作用,当然有的程序会对代码进行校验,一旦发现代码被篡改,就会采取保护措施,比如抛出异常或者退出程序。
针对调用系统函数如KdDisableDebugger()来检测调试器存在从而禁止被调试的方法,可以在对应的这些函数的地址下断点,然后对相关的代码进行patch,然后使该函数判断失效。比如:
bp KdDisableDebugger、eb xxx
针对通过HOOK系统函数来防止进程被调试的方法,可以直接将这些系统函数的钩子直接恢复,可以通过内核驱动程序或者借助一些ARK工具(比如Pchunter)就可以直接检测和恢复这些函数钩子。
花指令
系统引导
//强删文件
#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "DelFile.h"
PDEVICE_OBJECT g_HookDevice;
NTSTATUS dfQuerySymbolicLink(
IN PUNICODE_STRING SymbolicLinkName,
OUT PUNICODE_STRING LinkTarget
)
{
OBJECT_ATTRIBUTES oa;
NTSTATUS status;
HANDLE handle;
InitializeObjectAttributes(
&oa,
SymbolicLinkName,
OBJ_CASE_INSENSITIVE,
0,
0);
status = ZwOpenSymbolicLinkObject(&handle, GENERIC_READ, &oa);
if (!NT_SUCCESS(status))
{
return status;
}
LinkTarget->MaximumLength = 1024*sizeof(WCHAR);
LinkTarget->Length = 0;
LinkTarget->Buffer = ExAllocatePoolWithTag(PagedPool, LinkTarget->MaximumLength, 'A0');
if (!LinkTarget->Buffer)
{
ZwClose(handle);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(LinkTarget->Buffer, LinkTarget->MaximumLength);
status = ZwQuerySymbolicLinkObject(handle, LinkTarget, NULL);
ZwClose(handle);
if (!NT_SUCCESS(status))
{
ExFreePool(LinkTarget->Buffer);
}
return status;
}
BOOLEAN dfCloseFileHandle(WCHAR *name)
{
NTSTATUS status;
PVOID buf = NULL;
PSYSTEM_HANDLE_INFORMATION pSysHandleInfo;
SYSTEM_HANDLE_TABLE_ENTRY_INFO handleTEI;
ULONG size = 1;
ULONG NumOfHandle = 0;
ULONG i;
CLIENT_ID cid;
HANDLE hHandle;
HANDLE hProcess;
HANDLE hDupObj;
HANDLE hFile;
HANDLE link_handle;
OBJECT_ATTRIBUTES oa;
ULONG FileType;
ULONG processID;
UNICODE_STRING uLinkName;
UNICODE_STRING uLink;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK IoStatus;
ULONG ulRet;
PVOID fileObject;
POBJECT_NAME_INFORMATION pObjName;
UNICODE_STRING delFileName = {0};
int length;
WCHAR wVolumeLetter[3];
WCHAR *pFilePath;
UNICODE_STRING uVolume;
UNICODE_STRING uFilePath;
UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"");
BOOLEAN bRet = FALSE;
for ( size = 1; ; size *= 2 )
{
if ( NULL == ( buf = ExAllocatePoolWithTag(NonPagedPool,size, 'FILE') ) )
{
DbgPrint(("alloc mem failed\n"));
goto Exit;
}
RtlZeroMemory( buf ,size );
status = ZwQuerySystemInformation( SystemHandleInformation, buf, size, NULL );
if ( !NT_SUCCESS( status ) )
{
if ( STATUS_INFO_LENGTH_MISMATCH == status )
{
ExFreePool( buf );
buf = NULL;
}
else
{
DbgPrint(( "ZwQuerySystemInformation() failed"));
goto Exit;
}
}
else
{
break;
}
}
pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)buf;
NumOfHandle = pSysHandleInfo->NumberOfHandles;
/* Get the volume character like C: */
//\??\c:\haha.doc-->\device\harddiskvolume3\haha.doc
wVolumeLetter[0] = name[4];
wVolumeLetter[1] = name[5];
wVolumeLetter[2] = 0;
uLinkName.Buffer = ExAllocatePoolWithTag(NonPagedPool, 256 + sizeof(ULONG), 'A1');
uLinkName.MaximumLength = 256;
RtlInitUnicodeString(&uVolume, wVolumeLetter);
RtlInitUnicodeString( &uLink, L"\\DosDevices\\");
RtlCopyUnicodeString(&uLinkName, &uLink);
status = RtlAppendUnicodeStringToString(&uLinkName, &uVolume);
if (!NT_SUCCESS(status))
{
KdPrint(("RtlAppendUnicodeStringToString() failed"));
return FALSE;
}
dfQuerySymbolicLink(&uLinkName, &delFileName);
RtlFreeUnicodeString(&uLinkName);
KdPrint(("delFileName:%wZ", &delFileName));
pFilePath = (WCHAR *) &name[6];
RtlInitUnicodeString( &uFilePath, pFilePath);
RtlAppendUnicodeStringToString(&delFileName, &uFilePath);
if (!NT_SUCCESS(status))
{
KdPrint(("RtlAppendUnicodeStringToString() failed"));
return FALSE;
}
KdPrint(("delFile:%wZ", &delFileName));
for(i = 0; i < NumOfHandle ;i++)
{
handleTEI = pSysHandleInfo->Handles[i];
if (handleTEI.ObjectTypeIndex != 25 && handleTEI.ObjectTypeIndex != 28)//28文件,25设备对象
continue;
processID = (ULONG) handleTEI.UniqueProcessId;
cid.UniqueProcess = (HANDLE)processID;
cid.UniqueThread = (HANDLE)0;
hHandle = (HANDLE)handleTEI.HandleValue;
InitializeObjectAttributes( &oa ,NULL ,0 ,NULL ,NULL );
status = ZwOpenProcess( &hProcess ,PROCESS_DUP_HANDLE ,&oa ,&cid );
if ( !NT_SUCCESS( status ) )
{
KdPrint(( "ZwOpenProcess:%d Fail ", processID));
continue;
}
status = ZwDuplicateObject( hProcess ,hHandle ,NtCurrentProcess() ,&hDupObj ,\
PROCESS_ALL_ACCESS ,0 ,DUPLICATE_SAME_ACCESS );
if ( !NT_SUCCESS( status ) )
{
DbgPrint(( "ZwDuplicateObject1 : Fail " ));
continue;
}
status = ObReferenceObjectByHandle(
hDupObj,
FILE_ANY_ACCESS,
0,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(status))
{
DbgPrint(( "ObReferenceObjectByHandle : Fail " ));
continue;
}
pObjName = (POBJECT_NAME_INFORMATION) ExAllocatePoolWithTag(NonPagedPool, \
sizeof (OBJECT_NAME_INFORMATION) + 1024 * sizeof (WCHAR), 'A1');
if (STATUS_SUCCESS != (status = ObQueryNameString(fileObject, pObjName, \
sizeof (OBJECT_NAME_INFORMATION) + 1024 * sizeof (WCHAR), &ulRet)))
{
ObDereferenceObject(fileObject);
continue;
}
if (RtlCompareUnicodeString(&pObjName->Name, &delFileName, TRUE) == 0)
{
ObDereferenceObject(fileObject);
ZwClose(hDupObj);
status = ZwDuplicateObject( hProcess ,hHandle ,NtCurrentProcess() ,&hDupObj ,\
PROCESS_ALL_ACCESS ,0 ,DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
if ( !NT_SUCCESS( status ) )
{
DbgPrint(( "ZwDuplicateObject2 : Fail " ));
//return FALSE;
}
else
{
ZwClose(hDupObj);
bRet = TRUE;
//return TRUE;
}
break;
}
ExFreePool(pObjName);
pObjName = NULL;
ObDereferenceObject(fileObject);
ZwClose( hDupObj );
ZwClose( hProcess );
}
Exit:
if (pObjName != NULL)
{
ExFreePool(pObjName);
pObjName = NULL;
}
if (delFileName.Buffer != NULL)
{
ExFreePool(delFileName.Buffer);
}
if ( buf != NULL )
{
ExFreePool( buf );
buf = NULL;
}
return(bRet);
}
NTSTATUS
dfOpenFile(WCHAR* name,PHANDLE phFileHandle, ACCESS_MASK access,ULONG share)
{
IO_STATUS_BLOCK iosb;
NTSTATUS stat;
OBJECT_ATTRIBUTES oba;
UNICODE_STRING nameus;
if(KeGetCurrentIrql()>PASSIVE_LEVEL){return 0;}
RtlInitUnicodeString(&nameus,name);
InitializeObjectAttributes(
&oba,
&nameus,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
0,
0);
stat=IoCreateFile(
phFileHandle,
access,
&oba,
&iosb,
0,
FILE_ATTRIBUTE_NORMAL,
share,
FILE_OPEN,
0,
NULL,
0,
0,
NULL,
IO_NO_PARAMETER_CHECKING);
return stat;
}
NTSTATUS
dfSkillSetFileCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
Irp->UserIosb->Status = Irp->IoStatus.Status;
Irp->UserIosb->Information = Irp->IoStatus.Information;
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN dfDelFile(WCHAR* name)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event;
FILE_DISPOSITION_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
PSECTION_OBJECT_POINTERS pSectionObjectPointer;
HANDLE handle;
ntStatus = dfOpenFile(name, &handle, FILE_READ_ATTRIBUTES|DELETE,FILE_SHARE_DELETE);
if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND ||
ntStatus == STATUS_OBJECT_PATH_NOT_FOUND )
{
KdPrint(("No such file"));
return FALSE;
}
else if (!NT_SUCCESS(ntStatus))
{
if (dfCloseFileHandle(name))//遍历全局句柄表,关闭独占打开的句柄
{
ntStatus = dfOpenFile(name, &handle, FILE_READ_ATTRIBUTES|DELETE,FILE_SHARE_DELETE);
if (!NT_SUCCESS(ntStatus))
return FALSE;
}
else
{
return FALSE;
}
}
ntStatus = ObReferenceObjectByHandle(handle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
DbgPrint("ObReferenceObjectByHandle()");
ZwClose(handle);
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
ZwClose(handle);
return FALSE;
}
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
FileInformation.DeleteFile = TRUE;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp);
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
dfSkillSetFileCompletion,
&event,
TRUE,
TRUE,
TRUE);
//删除正在运行中的exe所做的处理
pSectionObjectPointer = fileObject->SectionObjectPointer;
if(pSectionObjectPointer)
{
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
}
ntStatus = IoCallDriver(DeviceObject, Irp);
if (!NT_SUCCESS(ntStatus))
{
ObDereferenceObject(fileObject);
ZwClose(handle);
return FALSE;
}
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);
//IoFreeIrp(Irp);
ObDereferenceObject(fileObject);
ZwClose(handle);
return TRUE;
}
NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_OBJECT p_NextObj;
DbgPrint("OnUnload called\n");
p_NextObj = DriverObject->DeviceObject;
if (p_NextObj != NULL)
{
RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &deviceLinkUnicodeString );
IoDeleteDevice( DriverObject->DeviceObject );
}
return STATUS_SUCCESS;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer );
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer );
ntStatus = IoCreateDevice ( DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_SWAP,
0,
TRUE,
&g_HookDevice );
if(! NT_SUCCESS(ntStatus))
{
DbgPrint(("Failed to create device!\n"));
return ntStatus;
}
/* We test the DelFile() function here */
if (dfDelFile(L"\\??\\c:\\haha.doc"))
{
KdPrint(("Deleted"));
}
else
{
KdPrint(("Failed"));
}
if (dfDelFile(L"\\??\\c:\\filedelet.exe"))
{
KdPrint(("Deleted"));
}
else
{
KdPrint(("Failed"));
}
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString );
if(! NT_SUCCESS(ntStatus))
{
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("Failed to create symbolic link!\n");
return ntStatus;
}
DriverObject->DriverUnload = OnUnload;
return STATUS_SUCCESS;
}
IRQL 中断请求级别
线程
多线程
强杀进程
#include <ntddk.h>
#include <ntimage.h>
#include <ntdef.h>
#include "Ioctlcmd.h"
const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\KillProc";
const WCHAR deviceNameBuffer[] = L"\\Device\\KillProc";
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
IN ULONG SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL );
typedef unsigned long DWORD;
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation;
#define SystemModuleInformation 11
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
PDEVICE_OBJECT g_HookDevice;
NTSTATUS PsLookupProcessByProcessId(ULONG ProcessId,PEPROCESS *Process);
typedef NTSTATUS (*PSPTERPROC) ( PEPROCESS Process, NTSTATUS ExitStatus );
PSPTERPROC MyPspTerminateProcess = NULL ;
NTSTATUS OnUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
PDEVICE_OBJECT p_NextObj;
DbgPrint("OnUnload called\n");
p_NextObj = DriverObject->DeviceObject;
if (p_NextObj != NULL)
{
RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );
IoDeleteSymbolicLink( &deviceLinkUnicodeString );
IoDeleteDevice( DriverObject->DeviceObject );
}
return STATUS_SUCCESS;
}
NTSTATUS
DispatchControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
PVOID inputBuffer;
PVOID outputBuffer;
PVOID userBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntstatus;
unsigned int i;
unsigned total = 0;
ULONG count = 0;
HANDLE handle;
ULONG cnt;
PEPROCESS Eprocess = NULL;
DWORD pid;
ntstatus = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation (Irp);
inputBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBuffer = Irp->AssociatedIrp.SystemBuffer;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (irpStack->MajorFunction)
{
case IRP_MJ_CREATE:
break;
case IRP_MJ_SHUTDOWN:
break;
case IRP_MJ_CLOSE:
break;
case IRP_MJ_DEVICE_CONTROL:
if(IOCTL_TRANSFER_TYPE(ioControlCode) == METHOD_NEITHER)
{
outputBuffer = Irp->UserBuffer;
}
switch (ioControlCode )
{
case IOCTL_PROC_KILL:
if(MyPspTerminateProcess==NULL)
{
*(DWORD*)outputBuffer = -1;
Irp->IoStatus.Information = sizeof(DWORD);
}
else
{
pid = *(DWORD*)inputBuffer;
{
ntstatus = PsLookupProcessByProcessId(pid , &Eprocess);
if(!NT_SUCCESS(ntstatus))
{
DbgPrint("Failed to lookup process 0x%x, status %8.8x\n", pid , ntstatus);
*(DWORD*)outputBuffer = 1;
Irp->IoStatus.Information = sizeof(DWORD);
break;
}
DbgPrint("Lookup of process 0x%x, PEPROCESS at %8.8x\n", pid, Eprocess);
ntstatus = MyPspTerminateProcess(Eprocess, 0);
if(!NT_SUCCESS(ntstatus))
{
DbgPrint("Failed to terminate process 0x%x, status %8.8x\n", pid, ntstatus);
*(DWORD*)outputBuffer = 2;
Irp->IoStatus.Information = sizeof(DWORD);
break;
}
*(DWORD*)outputBuffer = 0;
Irp->IoStatus.Information = sizeof(DWORD);
DbgPrint("Process 0x%x terminated\n", pid);
}
}
break;
default:
break;
}
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return ntstatus;
}
NTSTATUS DispatchCreate (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
VOID DoFind(IN PVOID pContext)
{
NTSTATUS ret;
PSYSTEM_MODULE_INFORMATION module = NULL;
ULONG n=0;
void *buf = NULL;
ULONG ntosknlBase;
ULONG ntosknlEndAddr;
ULONG curAddr;
ULONG code1_sp3=0x8b55ff8b,code2_sp3=0xA16456EC,code3_sp3=0x00000124,code4_sp3=0x3B08758B;
ULONG i;
NtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)GetFunctionAddr(L"NtQuerySystemInformation");
if (!NtQuerySystemInformation)
{
DbgPrint("Find NtQuerySystemInformation faild!");
goto Ret;
}
ret=NtQuerySystemInformation(SystemModuleInformation,&n,0,&n);
if (NULL==( buf=ExAllocatePoolWithTag(NonPagedPool, n, 'DFSP')))
{
DbgPrint("ExAllocatePool() failed\n" );
goto Ret;
}
ret=NtQuerySystemInformation(SystemModuleInformation,buf,n,NULL);
if (!NT_SUCCESS(ret)) {
DbgPrint("NtQuerySystemInformation faild!");
goto Ret;
}
module=(PSYSTEM_MODULE_INFORMATION)((PULONG)buf+1);
ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
ntosknlBase=(ULONG)module->Base;
curAddr=ntosknlBase;
ExFreePool(buf);
for (i=curAddr;i<=ntosknlEndAddr;i++)
{
if (*((ULONG *)i)==code1_sp3)
{
if (*((ULONG *)(i+4))==code2_sp3)
{
if (*((ULONG *)(i+8))==code3_sp3)
{
if (*((ULONG *)(i+12))==code4_sp3)
{
MyPspTerminateProcess=(PSPTERPROC)i;
break;
}
}
}
}
}
Ret:
PsTerminateSystemThread(STATUS_SUCCESS);
}
VOID GetPspAddr()
{
HANDLE hThread;
PVOID objtowait=0;
NTSTATUS dwStatus =
PsCreateSystemThread(
&hThread,
0,
NULL,
(HANDLE)0,
NULL,
DoFind,
NULL
);
NTSTATUS st;
if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
{
st=KfRaiseIrql(PASSIVE_LEVEL);
}
if ((KeGetCurrentIrql())!=PASSIVE_LEVEL)
{
return;
}
ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&objtowait,
NULL
);
st=KeWaitForSingleObject(objtowait,Executive,KernelMode,FALSE,NULL); //NULL表示无限期等待.
return;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS rc;
RTL_OSVERSIONINFOW osvi;
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
RtlInitUnicodeString (&deviceNameUnicodeString,
deviceNameBuffer );
RtlInitUnicodeString (&deviceLinkUnicodeString,
deviceLinkBuffer );
ntStatus = IoCreateDevice ( DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_SWAP,
0,
TRUE,
&g_HookDevice );
if(! NT_SUCCESS(ntStatus))
{
DbgPrint(("Failed to create device!\n"));
return ntStatus;
}
ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
&deviceNameUnicodeString );
if(! NT_SUCCESS(ntStatus))
{
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("Failed to create symbolic link!\n");
return ntStatus;
}
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] =
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchControl;
DriverObject->DriverUnload = OnUnload;
GetPspAddr();
if(MyPspTerminateProcess == NULL)
{
DbgPrint("PspFunc Not Find!\n");
}
return STATUS_SUCCESS;
}
zw*、nt*系列函数区别
驱动加载监控
DLL链接
//反调试
1、TLS回调函数先于程序入口执行,调试器加载主程序的时候会在OEP处设置软件断点,通过TLS回调得到程序的OEP然后判断入口是否为int 3断点
2、IsDebuggerPresent()
3、通过SEH查询context里面的DRX寄存器是否为0
4、进程堆里另外一个标志,ForceFlags,他由一组标志组成,正常情况下,该值为0
5、HEAP_FREE_CHECKING_ENABLED
6、CheckRemoteDebuggerPresent()
7、OutputDebugString()
8、ZwYieldExecution()
//进程枚举
1、Ring3枚举进程:CreateToolhelp32Snapshot()+Process32First()+Process32Next()、ZwQuerySystemInformation(SystemProcessesAndThreadsInformation)、EnumWindows()
2、PspCidTable
3、PsLookupProcessByProcessId
//几个重要的内核结构体
//https://www.cnblogs.com/wf751620780/p/10588949.html
//https://www.cnblogs.com/Tempt/p/10185570.html
0: kd> dt nt!_KTRAP_FRAME
+0x000 DbgEbp : Uint4B
+0x004 DbgEip : Uint4B
+0x008 DbgArgMark : Uint4B
+0x00c DbgArgPointer : Uint4B
+0x010 TempSegCs : Uint2B
+0x012 Logging : UChar
+0x013 Reserved : UChar
+0x014 TempEsp : Uint4B
+0x018 Dr0 : Uint4B
+0x01c Dr1 : Uint4B
+0x020 Dr2 : Uint4B
+0x024 Dr3 : Uint4B
+0x028 Dr6 : Uint4B
+0x02c Dr7 : Uint4B
+0x030 SegGs : Uint4B
+0x034 SegEs : Uint4B
+0x038 SegDs : Uint4B
+0x03c Edx : Uint4B
+0x040 Ecx : Uint4B
+0x044 Eax : Uint4B
+0x048 PreviousPreviousMode : Uint4B
+0x04c ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD
+0x050 SegFs : Uint4B
+0x054 Edi : Uint4B
+0x058 Esi : Uint4B
+0x05c Ebx : Uint4B
+0x060 Ebp : Uint4B
+0x064 ErrCode : Uint4B
+0x068 Eip : Uint4B
+0x06c SegCs : Uint4B
+0x070 EFlags : Uint4B
+0x074 HardwareEsp : Uint4B
+0x078 HardwareSegSs : Uint4B
+0x07c V86Es : Uint4B
+0x080 V86Ds : Uint4B
+0x084 V86Fs : Uint4B
+0x088 V86Gs : Uint4B
0: kd> dt _EPROCESS
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x098 ProcessLock : _EX_PUSH_LOCK
+0x0a0 CreateTime : _LARGE_INTEGER
+0x0a8 ExitTime : _LARGE_INTEGER
+0x0b0 RundownProtect : _EX_RUNDOWN_REF
+0x0b4 UniqueProcessId : Ptr32 Void
+0x0b8 ActiveProcessLinks : _LIST_ENTRY
+0x0c0 ProcessQuotaUsage : [2] Uint4B
+0x0c8 ProcessQuotaPeak : [2] Uint4B
+0x0d0 CommitCharge : Uint4B
+0x0d4 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : Ptr32 _PS_CPU_QUOTA_BLOCK
+0x0dc PeakVirtualSize : Uint4B
+0x0e0 VirtualSize : Uint4B
+0x0e4 SessionProcessLinks : _LIST_ENTRY
+0x0ec DebugPort : Ptr32 Void
+0x0f0 ExceptionPortData : Ptr32 Void
+0x0f0 ExceptionPortValue : Uint4B
+0x0f0 ExceptionPortState : Pos 0, 3 Bits
+0x0f4 ObjectTable : Ptr32 _HANDLE_TABLE
+0x0f8 Token : _EX_FAST_REF
+0x0fc WorkingSetPage : Uint4B
+0x100 AddressCreationLock : _EX_PUSH_LOCK
+0x104 RotateInProgress : Ptr32 _ETHREAD
+0x108 ForkInProgress : Ptr32 _ETHREAD
+0x10c HardwareTrigger : Uint4B
+0x110 PhysicalVadRoot : Ptr32 _MM_AVL_TABLE
+0x114 CloneRoot : Ptr32 Void
+0x118 NumberOfPrivatePages : Uint4B
+0x11c NumberOfLockedPages : Uint4B
+0x120 Win32Process : Ptr32 Void
+0x124 Job : Ptr32 _EJOB
+0x128 SectionObject : Ptr32 Void
+0x12c SectionBaseAddress : Ptr32 Void
+0x130 Cookie : Uint4B
+0x134 Spare8 : Uint4B
+0x138 WorkingSetWatch : Ptr32 _PAGEFAULT_HISTORY
+0x13c Win32WindowStation : Ptr32 Void
+0x140 InheritedFromUniqueProcessId : Ptr32 Void
+0x144 LdtInformation : Ptr32 Void
+0x148 VdmObjects : Ptr32 Void
+0x14c ConsoleHostProcess : Uint4B
+0x150 DeviceMap : Ptr32 Void
+0x154 EtwDataSource : Ptr32 Void
+0x158 FreeTebHint : Ptr32 Void
+0x160 PageDirectoryPte : _HARDWARE_PTE
+0x160 Filler : Uint8B
+0x168 Session : Ptr32 Void
+0x16c ImageFileName : [15] UChar
+0x17b PriorityClass : UChar
+0x17c JobLinks : _LIST_ENTRY
+0x184 LockedPagesList : Ptr32 Void
+0x188 ThreadListHead : _LIST_ENTRY
+0x190 SecurityPort : Ptr32 Void
+0x194 PaeTop : Ptr32 Void
+0x198 ActiveThreads : Uint4B
+0x19c ImagePathHash : Uint4B
+0x1a0 DefaultHardErrorProcessing : Uint4B
+0x1a4 LastThreadExitStatus : Int4B
+0x1a8 Peb : Ptr32 _PEB
+0x1ac PrefetchTrace : _EX_FAST_REF
+0x1b0 ReadOperationCount : _LARGE_INTEGER
+0x1b8 WriteOperationCount : _LARGE_INTEGER
+0x1c0 OtherOperationCount : _LARGE_INTEGER
+0x1c8 ReadTransferCount : _LARGE_INTEGER
+0x1d0 WriteTransferCount : _LARGE_INTEGER
+0x1d8 OtherTransferCount : _LARGE_INTEGER
+0x1e0 CommitChargeLimit : Uint4B
+0x1e4 CommitChargePeak : Uint4B
+0x1e8 AweInfo : Ptr32 Void
+0x1ec SeAuditProcessCreationInfo : _SE_AUDIT_PROCESS_CREATION_INFO
+0x1f0 Vm : _MMSUPPORT
+0x25c MmProcessLinks : _LIST_ENTRY
+0x264 HighestUserAddress : Ptr32 Void
+0x268 ModifiedPageCount : Uint4B
+0x26c Flags2 : Uint4B
+0x26c JobNotReallyActive : Pos 0, 1 Bit
+0x26c AccountingFolded : Pos 1, 1 Bit
+0x26c NewProcessReported : Pos 2, 1 Bit
+0x26c ExitProcessReported : Pos 3, 1 Bit
+0x26c ReportCommitChanges : Pos 4, 1 Bit
+0x26c LastReportMemory : Pos 5, 1 Bit
+0x26c ReportPhysicalPageChanges : Pos 6, 1 Bit
+0x26c HandleTableRundown : Pos 7, 1 Bit
+0x26c NeedsHandleRundown : Pos 8, 1 Bit
+0x26c RefTraceEnabled : Pos 9, 1 Bit
+0x26c NumaAware : Pos 10, 1 Bit
+0x26c ProtectedProcess : Pos 11, 1 Bit
+0x26c DefaultPagePriority : Pos 12, 3 Bits
+0x26c PrimaryTokenFrozen : Pos 15, 1 Bit
+0x26c ProcessVerifierTarget : Pos 16, 1 Bit
+0x26c StackRandomizationDisabled : Pos 17, 1 Bit
+0x26c AffinityPermanent : Pos 18, 1 Bit
+0x26c AffinityUpdateEnable : Pos 19, 1 Bit
+0x26c PropagateNode : Pos 20, 1 Bit
+0x26c ExplicitAffinity : Pos 21, 1 Bit
+0x26c Spare1 : Pos 22, 1 Bit
+0x26c ForceRelocateImages : Pos 23, 1 Bit
+0x26c DisallowStrippedImages : Pos 24, 1 Bit
+0x26c LowVaAccessible : Pos 25, 1 Bit
+0x270 Flags : Uint4B
+0x270 CreateReported : Pos 0, 1 Bit
+0x270 NoDebugInherit : Pos 1, 1 Bit
+0x270 ProcessExiting : Pos 2, 1 Bit
+0x270 ProcessDelete : Pos 3, 1 Bit
+0x270 Wow64SplitPages : Pos 4, 1 Bit
+0x270 VmDeleted : Pos 5, 1 Bit
+0x270 OutswapEnabled : Pos 6, 1 Bit
+0x270 Outswapped : Pos 7, 1 Bit
+0x270 ForkFailed : Pos 8, 1 Bit
+0x270 Wow64VaSpace4Gb : Pos 9, 1 Bit
+0x270 AddressSpaceInitialized : Pos 10, 2 Bits
+0x270 SetTimerResolution : Pos 12, 1 Bit
+0x270 BreakOnTermination : Pos 13, 1 Bit
+0x270 DeprioritizeViews : Pos 14, 1 Bit
+0x270 WriteWatch : Pos 15, 1 Bit
+0x270 ProcessInSession : Pos 16, 1 Bit
+0x270 OverrideAddressSpace : Pos 17, 1 Bit
+0x270 HasAddressSpace : Pos 18, 1 Bit
+0x270 LaunchPrefetched : Pos 19, 1 Bit
+0x270 InjectInpageErrors : Pos 20, 1 Bit
+0x270 VmTopDown : Pos 21, 1 Bit
+0x270 ImageNotifyDone : Pos 22, 1 Bit
+0x270 PdeUpdateNeeded : Pos 23, 1 Bit
+0x270 VdmAllowed : Pos 24, 1 Bit
+0x270 CrossSessionCreate : Pos 25, 1 Bit
+0x270 ProcessInserted : Pos 26, 1 Bit
+0x270 DefaultIoPriority : Pos 27, 3 Bits
+0x270 ProcessSelfDelete : Pos 30, 1 Bit
+0x270 SetTimerResolutionLink : Pos 31, 1 Bit
+0x274 ExitStatus : Int4B
+0x278 VadRoot : _MM_AVL_TABLE
+0x298 AlpcContext : _ALPC_PROCESS_CONTEXT
+0x2a8 TimerResolutionLink : _LIST_ENTRY
+0x2b0 RequestedTimerResolution : Uint4B
+0x2b4 ActiveThreadsHighWatermark : Uint4B
+0x2b8 SmallestTimerResolution : Uint4B
+0x2bc TimerResolutionStackRecord : Ptr32 _PO_DIAG_STACK_RECORD
EPROCESS和ETHREAD都是双向链表组织管理,一个EPROCESS中包含一个KPROCESS,这个KPROCESS中指向一个ETHREAD结构,在ETHREAD中又包含一个KTHREAD结构
//结束线程
1、NtTerminateThread()
2、PspTerminateThreadByPointer()
3、Insert APC
保护模式
#include<ntifs.h>
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver,PUNICODE_STRING pReg)
{
pDriver->DriverUnload=DriverUnload;
return STATUS_SUCCESS;
}
CPU的两种架构:RISC(arm)、CISC(x86)
“几乎所有的冯·诺伊曼型计算机的CPU,其工作都可以分为5个阶段:取指令、指令译码、访存取数、执行指令、结果写回”
增量链接
//裸函数
void __declspec(naked) fn(){}
//以下很多内容选自“羽夏的博客”
相关主页:https://www.cnblogs.com/wingsummer
CPU的三个模式:实模式、保护模式(保护内存非法访问和特权指令的使用)、虚拟8086模式
段寄存器有这几个:ES、CS、SS、DS、FS、GS、LDTR、TR,它们各有自己特殊的用途。
Mov指令:MOV AX,ES,但只能读16位的可见部分;MOV DS,AX写段寄存器,写的是96位。
读写LDTR的指令为:SLDT/LLDT
读写TR的指令为:STR/LTR
//注意在学习保护模式的时候不要把操作系统的概念扯进去,还没到操作系统层面
GDT:全局描述符表
LDT:局部描述符表
寄存器GDTR(48位)存储了GDT表的位置和大小
r gdtr //读取GDT表地址
r gdtl //读取GDT表的大小
dq 8003f000 l30 //0x8003f000为GDT表的地址(0x30=48)
CPL:CPU当前的权限级别
DPL:如果你想访问我,你应该具备什么样的权限(CPL)
RPL:用什么权限去访问一个段
对于一致代码段,也称为共享段:
特权级高的程序不允许访问特权级低的数据:核心态不允许访问用户态的数据
特权级低的程序可以访问到特权级高的数据,但特权级不会改变:用户态还是用户态
对于非一致代码段:
只允许同级访问
绝对禁止不同级别的访问:核心态不是用户态,用户态也不是核心态
//代码段间跳转的执行流程
1、段选择子拆分
2、查表得到段描述符
3、权限检查
4、加载段描述符
5、代码执行
调用门执行流程如下所示:
指令格式:CALL CS:EIP (EIP是废弃的)
执行步骤:
1、根据CS的值查GDT表,找到对应的段描述符且该描述符是一个调用门。
2、在调用门描述符中存储另一个代码段的段选择子,将其加载到CS中。
3、选择子指向的段的Base + 偏移地址就是真正要执行的地址。
IDT表包含3种门描述符:任务门描述符、中断门描述符、陷阱门描述符
指令格式:INT N (N为中断门索引号)
执行步骤:
1、在没有权限切换时,会向堆栈顺次压入EFLAG、CS和EIP;如果有权限切换,会向堆栈顺次压入SS、ESP、EFLAG、CS和EIP。
2、CPU会索引到IDT表。后面的N表示查IDT表项的下标。对比调用门,中断门没有了RPL,故CPU只会校验CPL。
3、在中断门中,不能通过RETF返回,而应该通过IRET/IRETD指令返回。
总结:
1、CS的权限一旦改变,SS的权限也要随着改变,CS与SS的等级必须一样。
2、JMP FAR只能跳转到同级非一致代码段,但CALL FAR可以通过调用门提权,提升CPL的权限。
调用门总结:
1、当通过门,权限不变的时候,只会PUSH两个值:CS和返回地址,新的CS的值由调用门决定。
2、当通过门,权限改变的时候,会PUSH四个值:SS、ESP、CS和返回地址,新的CS的值由调用门决定,新的SS和ESP由TSS提供。
3、通过门调用时,要执行哪行代码由调用门决定,但使用RETF返回时,由堆栈中压入的值决定,这就是说,进门时只能按指定路线走,出门时可以FQ,即只要改变堆栈里面的值就可以想去哪去哪。
任务段(TSS,Task-state segment)
任务门的执行流程:
1、通过INT N的指令进行触发任务门
2、查IDT表,找到任务门描述符
3、通过任务门描述符,查GDT表,找到TSS段描述符
4、使用TSS段中的值修改TR寄存器
5、IRETD返回
驱动
普通程序 | 内核 |
---|---|
malloc | ExAllocatePoolWithTag |
memset | RtlFillMemory |
memcpy | RtlMoveMemory |
free | ExFreePool |
系统调用
并不是所有的API必须进0环的,可以在3环完全实现;比如Ntdll.dll导出的memcmp函数。
_KUSER_SHARED_DATA
SSDT的全称是System Services Descriptor Table,意为系统服务描述符表。在32位XP中,我们可以通过ETHREAD结构体加偏移的方式进行访问。在内核文件中,有一个变量是导出的:KeServiceDescriptorTable。通过它我们可以访问SSDT
进程与线程
每个windows进程在0环都有一个对应的结构体:EPROCESS; 每个Windows线程在0环都有一个对应的结构体ETHREAD;
KPCR中存储了CPU本身要用的一些重要数据:GDT、IDT以及线程相关的一些信息;
当线程进入0环时,FS:[0]指向KPCR,3环时FS:[0]指向 TEB;
每个CPU都有一个KPCR结构体,即一个核一个。
句柄表
句柄是给3环用的,而不是给内核用的;Windows所有涉及句柄的API,一旦到了真正函数实现的部分,就立刻使用ObReferenceObjectByHandle把它转化为真正的指向内核对象的指针
APC
同步