二、驅動

来源:https://www.cnblogs.com/derek1184405959/archive/2022/08/10/16570808.html
-Advertisement-
Play Games

二、驅動 2.1.hello world 1.創建項目 2.刪除Driver Files裡面的helloworld.inf文件 3.右鍵屬性 Inf2Cat->General->Run Inf2Cat 改成否 Driver Settings->General->Traget OS VERSION和T ...


二、驅動

2.1.hello world

1.創建項目

2.刪除Driver Files裡面的helloworld.inf文件

3.右鍵屬性

Inf2Cat->General->Run Inf2Cat 改成否
Driver Settings->General->Traget OS VERSION和Target Platform改成對一個的平臺
C/C++ -->常規->警告等級改為3,將警告視為錯誤改成否
C/C++ -->代碼生成-->Spectre Mitigation改為Disabled

4.helloworld.c

#include <ntifs.h>

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("卸載驅動\r\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	pDriver->DriverUnload = DriverUnload;
	DbgPrint("載入驅動\r\n");
	DbgPrint("註冊表路勁:%wZ\r\n",pReg);

	return STATUS_SUCCESS;
}

2.2.驅動基礎

1.字元串函數

1.RtiInitString初始化多位元組ascii
2.RtiInitUnicodestring初始化寬字元
3.RtlFreeUnicodeString釋放uncode字元串
4.RtlStringCbPrintfA格式化輸出記得引用#include <ntstrsafe.h
5.RtiCoipareunicodestring字特串比較

2.申請記憶體

ExAllocatePool   #申請記憶體
ExFreePool		 #釋放記憶體

3.創建線程

PsCreateSystemThread    #創建線程

2.3.鏈表

LIST_ENTRY

typedef struct _LIST_ENTRY {
   struct _LIST_ENTRY *Flink;
   struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY, *RESTRICTED_POINTER PRLIST_ENTRY;

節點

 struct MYNODE{
	LIST_ENTRY ListEntry;
	int data;
 };

操作

InitializeListHead  初始化鏈表頭 
IsListEmpty			判斷鏈表是否為空 
InsertHeadList		從鏈表頭部插入節點 
InsertTailList		從鏈表尾部插入節點 
RemoveHeadList		從鏈表頭部刪除節點 
RemoveTailList		從鏈表尾部刪除節點

二叉樹

#include <ntifs.h>


typedef struct _AAA 
{
	int id;
	int y;
	int x;
}AAA,*PAAA;

RTL_GENERIC_TABLE gTABLE = {0};

RTL_GENERIC_COMPARE_RESULTS NTAPI GenericCmp(
	_In_ struct _RTL_GENERIC_TABLE *Table,
	_In_ PVOID FirstStruct,
	_In_ PVOID SecondStruct
)
{
	PAAA  a1 = (PAAA)FirstStruct;
	PAAA  a2 = (PAAA)SecondStruct;
	if (a1->id == a2->id)
	{
		return GenericEqual;
	}

	if (a1->id > a2->id) return GenericGreaterThan;
	return GenericLessThan;
	
}

PVOID NTAPI GenericAllocate(
	_In_ struct _RTL_GENERIC_TABLE *Table,
	_In_ CLONG ByteSize
)
{
	return ExAllocatePool(NonPagedPool, ByteSize);
}

VOID NTAPI GenericFree(
	_In_ struct _RTL_GENERIC_TABLE *Table,
	_In_ __drv_freesMem(Mem) _Post_invalid_ PVOID Buffer
)
{
	ExFreePool(Buffer);
}

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	
	AAA aaa = { 1,2,3 };
	AAA aaa1 = { 2,4,5 };
	AAA aaa2 = { 3,6,7 };
	AAA aaa3 = {4,8,9};

	//初始化二叉樹
	RtlInitializeGenericTable(&gTABLE, GenericCmp, GenericAllocate, GenericFree, NULL);

	
	BOOLEAN newE = FALSE;
	//插入
	RtlInsertElementGenericTable(&gTABLE, &aaa, sizeof(AAA), &newE);
	RtlInsertElementGenericTable(&gTABLE, &aaa1, sizeof(AAA), &newE);
	RtlInsertElementGenericTable(&gTABLE, &aaa2, sizeof(AAA), &newE);
	RtlInsertElementGenericTable(&gTABLE, &aaa3, sizeof(AAA), &newE);

	AAA node = {3,0,0};

	//查找
	AAA * xxx = RtlLookupElementGenericTable(&gTABLE, &node);

	//獲取元素個數
	int number = RtlNumberGenericTableElements(&gTABLE);

	AAA *RestartKey = NULL;
	AAA* xx = 0;

	//判斷樹是否空
	if (!RtlIsGenericTableEmpty(&gTABLE))
	{
		//遍歷
		for (xx = RtlEnumerateGenericTableWithoutSplaying(&gTABLE, &RestartKey);
			xx != NULL;
			xx = RtlEnumerateGenericTableWithoutSplaying(&gTABLE, &RestartKey))
		{
			DbgPrintEx(77, 0, "%x\r\n", xx->id);
		}
	}
	
	//刪除
	RtlDeleteElementGenericTable(&gTABLE, &node);

	node.id = 3;
	xxx = RtlLookupElementGenericTable(&gTABLE, &node);

	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

2.4.驅動斷鏈

斷鏈自身

#include <ntifs.h>

typedef struct _KLDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	ULONG exp;
	ULONG un;
	ULONG NonPagedDebugInfo;
	ULONG DllBase;
	ULONG EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT __Undefined5;
	ULONG  __Undefined6;
	ULONG  CheckSum;
	ULONG  TimeDateStamp;
} KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;


NTKERNELAPI NTSTATUS ObReferenceObjectByName(
	__in PUNICODE_STRING ObjectName,
	__in ULONG Attributes,
	__in_opt PACCESS_STATE AccessState,
	__in_opt ACCESS_MASK DesiredAccess,
	__in POBJECT_TYPE ObjectType,
	__in KPROCESSOR_MODE AccessMode,
	__inout_opt PVOID ParseContext,
	__out PVOID *Object
);

extern POBJECT_TYPE* IoDriverObjectType;

void DriverHide(PWCH objName)
{
	LARGE_INTEGER in = {0};
	in.QuadPart = -10000 * 5000; //等待5s
	KeDelayExecutionThread(KernelMode,FALSE,&in);

	UNICODE_STRING driverName = { 0 };
	RtlInitUnicodeString(&driverName, objName);
	PDRIVER_OBJECT httpDriver = NULL;
	NTSTATUS status = ObReferenceObjectByName(&driverName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, httpDriver);
	if (NT_SUCCESS(status))
	{
		PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)httpDriver->DriverSection;
		DbgPrintEx(77,0,"[db]: driver name = %wZ\r\n",&ldr->FullDllName);
		RemoveEntryList(&ldr->InLoadOrderLinks);
		httpDriver->DriverInit = NULL;
		httpDriver->DriverSection = NULL;
		ObDereferenceObject(httpDriver);
	}
	return ;
}


VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("卸載驅動\r\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	HANDLE hThread = NULL;
	NTSTATUS status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, DriverHide, L"\\driver\\1.duanlian");
	if (NT_SUCCESS(status))
	{
		NtClose(hThread);
	}
    
	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
	
}

斷鏈PCHunter32aq.sys

#include <ntifs.h>

//當系統載入一個驅動時,會為這個驅動建立一個_KLDR_DATA_TABLE_ENTRY結構體,
//DRIVER_OBJECT結構體的DriverSection成員指向這個結構體
//所有驅動的結構體通過InLoadOrderLinks成員鏈接起來
typedef struct _KLDR_DATA_TABLE_ENTRY {
	LIST_ENTRY InLoadOrderLinks;
	LIST_ENTRY exp;
	ULONG un;
	ULONG NonPagedDebugInfo;
	ULONG DllBase;
	ULONG EntryPoint;
	ULONG SizeOfImage;
	UNICODE_STRING FullDllName;
	UNICODE_STRING BaseDllName;
	ULONG Flags;
	USHORT LoadCount;
	USHORT __Undefined5;
	ULONG  __Undefined6;
	ULONG  CheckSum;
	ULONG  TimeDateStamp;
} KLDR_DATA_TABLE_ENTRY, * PKLDR_DATA_TABLE_ENTRY;

//根據驅動名字得到驅動對象
NTKERNELAPI NTSTATUS ObReferenceObjectByName(
	__in PUNICODE_STRING ObjectName,
	__in ULONG Attributes,
	__in_opt PACCESS_STATE AccessState,// 訪問許可權可以寫0 寫0完全訪問不受控制FILE_ALL_ACCESS,
	__in_opt ACCESS_MASK DesiredAccess,
	__in POBJECT_TYPE ObjectType,//對象類型
	__in KPROCESSOR_MODE AccessMode, //內核模式 有三種模式 enum 類型
	__inout_opt PVOID ParseContext,
	__out PVOID* Object     //輸出對象 我們要得到的驅動對象
);

extern POBJECT_TYPE* IoDriverObjectType;

void DriverHide(PWCH objName)
{
	LARGE_INTEGER in = { 0 };
	in.QuadPart = -10000 * 5000;
	KeDelayExecutionThread(KernelMode, FALSE, &in);  //線程等待5s

	//初始化驅動名字
	UNICODE_STRING driverName = { 0 };
	RtlInitUnicodeString(&driverName, objName);

	//根據驅動名字得到驅動對象
	PDRIVER_OBJECT httpDriver = NULL;  //驅動對象
	NTSTATUS status = ObReferenceObjectByName(&driverName, FILE_ALL_ACCESS, 0, 0, *IoDriverObjectType, KernelMode, NULL, &httpDriver);

	if (NT_SUCCESS(status))
	{
		PKLDR_DATA_TABLE_ENTRY ldr = (PKLDR_DATA_TABLE_ENTRY)httpDriver->DriverSection;
		DbgPrintEx(77, 0, "[db]: driver name = %wZ\r\n", &ldr->FullDllName);
		//斷鏈之前把PCHunter32aq的DriverSetion指向隨便一個位置,隱藏驅動的信息
		httpDriver->DriverSection = ldr->InLoadOrderLinks.Flink;
		//斷鏈
		RemoveEntryList(&ldr->InLoadOrderLinks);
		httpDriver->DriverInit = NULL;
		//刪除引用計數
		ObDereferenceObject(httpDriver);
	}
	return ;
}


VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	DbgPrint("卸載驅動\r\n");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	HANDLE hThread = NULL;
	//創建系統線程
	NTSTATUS status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, DriverHide, L"\\driver\\PCHunter32aq");
	if (NT_SUCCESS(status))
	{
		NtClose(hThread);
	}

	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
	
}

2.5.驅動通信

2.5.1.IRP_MJ_DEVICE_CONTROL

驅動main.c

#include <ntifs.h>

#define DEVICE_NAME L"\\Device\\tongxin"//設備名
#define SYM_NAME    L"\\??\\tongxin"

#define CODE_CTR_INDEX 0x800   //為設備定義一個唯一標識功能號
#define TEST CTL_CODE(FILE_DEVICE_UNKNOWN,CODE_CTR_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)   //控制代碼


NTSTATUS DefDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;//通知R3,派發已成功
	IoCompleteRequest(Irp, 0);//調用方已完成所有I/O請求處理操作,並將給定的 IRP 返回給 I/O 管理器

	return STATUS_SUCCESS;
}


NTSTATUS Dispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
    //返回一個指向IO_STACK_LOCATION結構的指針
	PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
	//DbgBreakPoint();
    //判斷類型是不是這個IRP_MJ_DEVICE_CONTROL
	if (ioStack->MajorFunction == IRP_MJ_DEVICE_CONTROL)
	{

		int size = ioStack->Parameters.DeviceIoControl.InputBufferLength;
		int OutputBufferLength = ioStack->Parameters.DeviceIoControl.OutputBufferLength;  
		ULONG IoControlCode = ioStack->Parameters.DeviceIoControl.IoControlCode;  //控制碼

		switch (IoControlCode)//判斷控制代碼
		{
		case TEST:
		{
			int* x = (int*)Irp->AssociatedIrp.SystemBuffer;   //獲取R3傳過來的參數
			int y = 500;
			DbgPrint("[db]:-------%x----------\r\n", *x);
			memcpy(Irp->AssociatedIrp.SystemBuffer,&y,4);     //寫數據也是在這個緩衝區
			Irp->IoStatus.Information = OutputBufferLength;
		}
		break;
		}
	}
	Irp->IoStatus.Status = STATUS_SUCCESS;//設置成功
	IoCompleteRequest(Irp, 0);
	return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	UNICODE_STRING symName = { 0 };
	RtlInitUnicodeString(&symName, SYM_NAME);
	IoDeleteSymbolicLink(&symName);               //刪除符號鏈接
	IoDeleteDevice(pDriver->DeviceObject);        //刪除設備
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	UNICODE_STRING unName = { 0 };
	RtlInitUnicodeString(&unName, DEVICE_NAME);   //初始化設備名

	UNICODE_STRING symName = { 0 };
	RtlInitUnicodeString(&symName, SYM_NAME);     //初始化符號名

	PDEVICE_OBJECT pDevice = NULL;

	//創建一個驅動設備使用的設備對象
	NTSTATUS status = IoCreateDevice(
		pDriver,                           //DriverObject,指向調用者的驅動程式對象的指針
		0,                                //指定要為設備對象的設備擴展分配的驅動程式確定的位元組數
		&unName,                          // 命名設備對象
		FILE_DEVICE_UNKNOWN,              //指定設備類型的值
		FILE_DEVICE_SECURE_OPEN,         //提供有關驅動程式設備的附加信息
		FALSE,                          //指定設備對象是否代表獨占設備
		&pDevice                        //指向變數的指針,該變數接收指向新創建的DEVICE_OBJECT結構的指針
	);


	if (!NT_SUCCESS(status))
	{
		DbgPrint("[db]:%x\r\n", status);
		//DbgPrintEx(77, 0, "");
		return status;
	}

	//設備名和用戶的可見名之間創建符號鏈接
	status = IoCreateSymbolicLink(&symName, &unName);


	if (!NT_SUCCESS(status))
	{
		IoDeleteDevice(pDevice);
		DbgPrint("[db]:%x\r\n", status);
		return status;
	}

	pDevice->Flags &= ~DO_DEVICE_INITIALIZING;  //xp系統才需要幹掉這個位,win7以上系統不需要
	pDevice->Flags |= DO_BUFFERED_IO;

	pDriver->MajorFunction[IRP_MJ_CREATE] = DefDispatch;   //設置回調函數
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DefDispatch;
	pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch;

	pDriver->DriverUnload = DriverUnload;
	return status;
}

r3.cpp

#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>

#define SYM_NAME    "\\\\.\\tongxin"   //符號名

#define CODE_CTR_INDEX 0x800   //為設備定義一個唯一標識功能號
#define TEST CTL_CODE(FILE_DEVICE_UNKNOWN,CODE_CTR_INDEX,METHOD_BUFFERED,FILE_ANY_ACCESS)   //控制代碼

int main()
{
	HANDLE hDevice = CreateFileA(
		SYM_NAME,								 //要創建或打開的文件或設備的名稱
		GENERIC_READ | GENERIC_WRITE,			//許可權
		FILE_SHARE_READ | FILE_SHARE_WRITE,    //請求的文件或設備的共用模式
		NULL, 
		OPEN_EXISTING,                         //對存在或不存在的文件或設備採取的操作。
		FILE_ATTRIBUTE_NORMAL,				  //文件或設備屬性和標誌,FILE_ATTRIBUTE_NORMAL是文件最常見的預設值。
		NULL
	);

	int x = 100;
	int y = 0;
	DWORD p = 0;

	BOOL  b = DeviceIoControl(
		hDevice,				//要在其上執行操作的設備的句柄
		TEST,				   //操作的控制代碼
		&x,					  //指向包含執行操作所需數據的輸入緩衝區的指針
		4,                   //輸入緩衝區的大小
		&y,                 //指向輸出緩衝區的指針
		4,                 //輸出緩衝區的大小
		&p,                //一個指向變數的指針
		NULL
	);     


	CloseHandle(hDevice);
	printf("%d\r\n", y);
	system("pause");
	return 0;
}

測試

先運行驅動,然後運行r3程式,可以看到y值改為500

2.5.2.IRP_MJ_READ

驅動main.c

#include <ntifs.h>

#define DEVICE_NAME L"\\Device\\tongxin"
#define SYM_NAME    L"\\??\\tongxin"


NTSTATUS DefDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, 0);

	return STATUS_SUCCESS;
}

NTSTATUS ReadDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
	DbgBreakPoint();
	PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
	LARGE_INTEGER ByteOffset = ioStack->Parameters.Read.ByteOffset;
	int Length = ioStack->Parameters.Read.Length;
	int* xxx = Irp->AssociatedIrp.SystemBuffer;
	*xxx = 100;
	Irp->IoStatus.Information = Length;
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, 0);
	return STATUS_SUCCESS;
}

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	UNICODE_STRING symName = { 0 };
	RtlInitUnicodeString(&symName, SYM_NAME);
	IoDeleteSymbolicLink(&symName);
	IoDeleteDevice(pDriver->DeviceObject);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	UNICODE_STRING unName = { 0 };
	RtlInitUnicodeString(&unName, DEVICE_NAME);

	UNICODE_STRING symName = { 0 };
	RtlInitUnicodeString(&symName, SYM_NAME);

	PDEVICE_OBJECT pDevice = NULL;

	NTSTATUS status = IoCreateDevice(pDriver, 0, &unName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);

	if (!NT_SUCCESS(status))
	{
		DbgPrint("[db]:%x\r\n", status);

		return status;
	}

	status = IoCreateSymbolicLink(&symName, &unName);


	if (!NT_SUCCESS(status))
	{
		IoDeleteDevice(pDevice);
		DbgPrint("[db]:%x\r\n", status);
		return status;
	}

	pDevice->Flags &= ~DO_DEVICE_INITIALIZING;
	pDevice->Flags |= DO_BUFFERED_IO;

	pDriver->MajorFunction[IRP_MJ_CREATE] = DefDispatch;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DefDispatch;
	pDriver->MajorFunction[IRP_MJ_READ] = ReadDispatch;

	pDriver->DriverUnload = DriverUnload;
	return status;
}

r3.cpp

#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>

#define SYM_NAME    "\\\\.\\tongxin"

int main()
{
	HANDLE hDevice = CreateFileA(SYM_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	int x = 500;
	DWORD p = 0;

	ReadFile(hDevice, &x, 4, &p, NULL); 

	CloseHandle(hDevice);
	printf("%d\r\n", x);
	system("pause");
	return 0;
}

測試

先運行驅動,然後運行r3程式,可以看到x值改為500

2.6.通信封裝

驅動main.c

#include <ntifs.h>
#include <Windowsx.h>

#define DEVICE_NAME L"\\Device\\tongxinfz"
#define SYM_NAME    L"\\??\\tongxinfz"

#define _COMM_ID	0x12345678//設定一個ID進行對比

typedef struct _CommPackage
{
	ULONG64 id;
	ULONG64 code;
	ULONG64 inData;
	ULONG64 inLen;
	ULONG64 outData;
	ULONG64 outLen;
}CommPackage, * PCommPackage;//自己創建一個包,用於通信

typedef NTSTATUS(NTAPI* CommCallback)(PCommPackage package);//定義了一個結構體指針

CommCallback gCommCallback = NULL;//創建一個新的結構體

typedef struct _Test
{
	int x;
}Test, * PTest;

typedef enum _CMD//枚舉
{
	TEST = 0,
}CMD;

VOID DriverDestoryComm(PDRIVER_OBJECT  pDriver)
{
	UNICODE_STRING symName = { 0 };
	RtlInitUnicodeString(&symName, SYM_NAME);
	IoDeleteSymbolicLink(&symName);
	if (pDriver->DeviceObject) IoDeleteDevice(pDriver->DeviceObject);
}//銷毀符號鏈接和設備鏈接	

NTSTATUS DefDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
	Irp->IoStatus.Status = STATUS_SUCCESS;
	IoCompleteRequest(Irp, 0);
	return STATUS_SUCCESS;
}

NTSTATUS WriteDispatch(DEVICE_OBJECT* DeviceObject, IRP* Irp)
{
	DbgBreakPoint();
	PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);//返回一個指向IO_STACK_LOCATION結構的指針
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	int Length = ioStack->Parameters.Write.Length;//要寫入的數據長度
	if (Length == sizeof(CommPackage) && gCommCallback)//判斷這個包是否存在
	{
		PCommPackage package = Irp->AssociatedIrp.SystemBuffer;
		if (package->id == _COMM_ID)//對比ID是不是一樣的
			if (MmIsAddressValid(package)) status = gCommCallback(package);
	}

	Irp->IoStatus.Information = 0;
	Irp->IoStatus.Status = status;//完成寫入
	IoCompleteRequest(Irp, 0);
	return status;
}

NTSTATUS NTAPI Dispatch(PCommPackage package)
{
	NTSTATUS status = STATUS_UNSUCCESSFUL;
	switch (package->code)//再來根據編號選擇執行不同的指令
	{
	case TEST:
	{
		PTest t = (PTest)package->inData;
		t->x = 200;
		DbgPrintEx(77, 0, "[db]:%d\r\n", t->x);//觀察是否成功寫入
		status = STATUS_SUCCESS;
	}
	break;
	}

	return status;
}

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	DriverDestoryComm(pDriver);
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg) {
	UNICODE_STRING unName = { 0 };
	UNICODE_STRING symName = { 0 };

	RtlInitUnicodeString(&unName, DEVICE_NAME);
	RtlInitUnicodeString(&symName, SYM_NAME);

	PDEVICE_OBJECT pDevice = NULL;

	NTSTATUS status = IoCreateDevice(pDriver, 0, &unName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevice);

	if (!NT_SUCCESS(status)) {
		KdPrintEx((77, 0, "[db]:%x\r\n", status));
		return status;
	}

	status = IoCreateSymbolicLink(&symName, &unName);

	if (!NT_SUCCESS(status)) {
		IoDeleteDevice(pDevice);
		KdPrintEx((77, 0, "[db]:%x\r\n", status));
	}

	pDevice->Flags &= ~DO_DEVICE_INITIALIZING;
	pDevice->Flags |= DO_BUFFERED_IO;

	pDriver->MajorFunction[IRP_MJ_CREATE] = DefDispatch;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = DefDispatch;
	pDriver->MajorFunction[IRP_MJ_WRITE] = WriteDispatch;//與之前的過程相仿

	if (NT_SUCCESS(status))
	{
		gCommCallback = Dispatch;
	}

	pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

r3.cpp

#include "stdio.h"
#include <Windows.h>

HANDLE ghDevice;
#define SYM_NAME    L"\\??\\tongxinfz"
typedef struct _CommPackage
{
	ULONG64 id;
	ULONG64 code;
	ULONG64 inData;
	ULONG64 inLen;
	ULONG64 outData;
	ULONG64 outLen;
}CommPackage, * PCommPackage;
#define _COMM_ID	0x12345678

typedef struct _Test
{
	int x;
}Test, * PTest;

typedef enum _CMD
{
	TEST = 0,
}CMD;

int main()
{

	Test x1 = { 0 };
	x1.x = 100;

	ghDevice = CreateFileW(SYM_NAME, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (ghDevice == NULL || ghDevice == INVALID_HANDLE_VALUE)
	{
		ghDevice = NULL;
		return 0;
	}

	CommPackage packag;
	packag.code = TEST;
	packag.inData = (ULONG64)&x1;
	packag.inLen = (ULONG64)4;
	packag.outData = (ULONG64)NULL;
	packag.outLen = (ULONG64)NULL;
	DWORD pro = NULL;
	packag.id = _COMM_ID;//構造結構體

	WriteFile(ghDevice, &packag, sizeof(CommPackage), &pro, NULL);
	printf("%d\r\n", x1.x);
	system("pause");
	return 0;
}

2.7.記憶體載入

Build.cpp


#include <stdlib.h>
#include <stdio.h>
#include <memory.h>

int main(int argc, char* args[], char** env)
{
	if (argc < 2)
	{
		printf("參數不對\r\n");
		printf("舉個例子:build.exe dll路徑\r\n");
		return 0;
	}

	char* dllpath = args[1];
	FILE* file = NULL;
	fopen_s(&file, dllpath, "rb");

	if (!file)
	{
		printf("文件不存在\r\n");
		return 0;
	}

	//求文件大小
	fseek(file, 0, SEEK_END);
	unsigned int len = ftell(file);

	//繞回到頭部文件流指針
	rewind(file);

	unsigned char* filebuffer = (unsigned char*)malloc(len);
	memset(filebuffer, 0, len);

	fread_s(filebuffer, len, len, 1, file);

	fclose(file);

	//創建一個文件 寫入我們的硬編碼
	if (argc == 2)
	{
		fopen_s(&file, "dll.h", "wb");
	}
	else
	{
		fopen_s(&file, args[2], "wb");
	}

	if (file == NULL)
	{
		free(filebuffer);
		return 0;
	}

	fputs("#pragma once\n", file);

	fprintf_s(file, "unsigned char sysData[%d] = 	{\n", len);
	fprintf_s(file, "\t");
	for (int i = 0; i < len; i++)
	{
		filebuffer[i] ^= 0xcd;
		filebuffer[i] ^= 0xd8;
		fprintf_s(file, "0x%02X, ", filebuffer[i]);
		if ((i + 1) % 30 == 0)
		{
			fprintf_s(file, "\r\n\t");
		}


	}

	fprintf_s(file, "\r\n};");
	fclose(file);

	free(filebuffer);

	return 0;
}

Test/Main.c

#include <ntifs.h>


VOID DriverUnload(PDRIVER_OBJECT pDriver)
{

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	DbgPrintEx(77, 0, "----------11111111111111111111111111---------------\r\n");
	//pDriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;
}

PeLoad/tools.h

#pragma once
#include <ntifs.h>

typedef enum _SYSTEM_INFORMATION_CLASS {
	SystemBasicInformation,
	SystemProcessorInformation,             // obsolete...delete
	SystemPerformanceInformation,
	SystemTimeOfDayInformation,
	SystemPathInformation,
	SystemProcessInformation,
	SystemCallCountInformation,
	SystemDeviceInformation,
	SystemProcessorPerformanceInformation,
	SystemFlagsInformation,
	SystemCallTimeInformation,
	SystemModuleInformation,
	SystemLocksInformation,
	SystemStackTraceInformation,
	SystemPagedPoolInformation,
	SystemNonPagedPoolInformation,
	SystemHandleInformation,
	SystemObjectInformation,
	SystemPageFileInformation,
	SystemVdmInstemulInformation,
	SystemVdmBopInformation,
	SystemFileCacheInformation,
	SystemPoolTagInformation,
	SystemInterruptInformation,
	SystemDpcBehaviorInformation,
	SystemFullMemoryInformation,
	SystemLoadGdiDriverInformation,
	SystemUnloadGdiDriverInformation,
	SystemTimeAdjustmentInformation,
	SystemSummaryMemoryInformation,
	SystemMirrorMemoryInformation,
	SystemPerformanceTraceInformation,
	SystemObsolete0,
	SystemExceptionInformation,
	SystemCrashDumpStateInformation,
	SystemKernelDebuggerInformation,
	SystemContextSwitchInformation,
	SystemRegistryQuotaInformation,
	SystemExtendServiceTableInformation,
	SystemPrioritySeperation,
	SystemVerifierAddDriverInformation,
	SystemVerifierRemoveDriverInformation,
	SystemProcessorIdleInformation,
	SystemLegacyDriverInformation,
	SystemCurrentTimeZoneInformation,
	SystemLookasideInformation,
	SystemTimeSlipNotification,
	SystemSessionCreate,
	SystemSessionDetach,
	SystemSessionInformation,
	SystemRangeStartInformation,
	SystemVerifierInformation,
	SystemVerifierThunkExtend,
	SystemSessionProcessInformation,
	SystemLoadGdiDriverInSystemSpace,
	SystemNumaProcessorMap,
	SystemPrefetcherInformation,
	SystemExtendedProcessInformation,
	SystemRecommendedSharedDataAlignment,
	SystemComPlusPackage,
	SystemNumaAvailableMemory,
	SystemProcessorPowerInformation,
	SystemEmulationBasicInformation,
	SystemEmulationProcessorInformation,
	SystemExtendedHandleInformation,
	SystemLostDelayedWriteInformation,
	SystemBigPoolInformation,
	SystemSessionPoolTagInformation,
	SystemSessionMappedViewInformation,
	SystemHotpatchInformation,
	SystemObjectSecurityMode,
	SystemWatchdogTimerHandler,
	SystemWatchdogTimerInformation,
	SystemLogicalProcessorInformation,
	SystemWow64SharedInformation,
	SystemRegisterFirmwareTableInformationHandler,
	SystemFirmwareTableInformation,
	SystemModuleInformationEx,
	SystemVerifierTriageInformation,
	SystemSuperfetchInformation,
	SystemMemoryListInformation,
	SystemFileCacheInformationEx,
	MaxSystemInfoClass  // MaxSystemInfoClass should always be the last enum
} SYSTEM_INFORMATION_CLASS;

typedef struct _RTL_PROCESS_MODULE_INFORMATION {
	HANDLE Section;                 // Not filled in
	PVOID MappedBase;
	PVOID ImageBase;
	ULONG ImageSize;
	ULONG Flags;
	USHORT LoadOrderIndex;
	USHORT InitOrderIndex;
	USHORT LoadCount;
	USHORT OffsetToFileName;
	UCHAR  FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;

typedef struct _RTL_PROCESS_MODULES {
	ULONG NumberOfModules;
	RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;


NTSTATUS ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass,
	void* SystemInformation, ULONG SystemInformationLength, ULONG* ReturnLength);

PIMAGE_NT_HEADERS RtlImageNtHeader(void* Base);



ULONG_PTR QueryModule(PUCHAR moduleName, ULONG_PTR* moduleSize);

PeLoad/tool.c

#include "tools.h"



ULONG_PTR QueryModule(PUCHAR moduleName, ULONG_PTR* moduleSize)
{
	if (moduleName == NULL) return 0;

	RTL_PROCESS_MODULES rtlMoudles = { 0 };
	PRTL_PROCESS_MODULES SystemMoudles = &rtlMoudles;
	BOOLEAN isAllocate = FALSE;
	//測量長度
	ULONG* retLen = 0;
	NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, SystemMoudles, sizeof(RTL_PROCESS_MODULES), &retLen);

	//分配實際長度記憶體
	if (status == STATUS_INFO_LENGTH_MISMATCH)
	{
		SystemMoudles = ExAllocatePool(PagedPool, retLen + sizeof(RTL_PROCESS_MODULES));
		if (!SystemMoudles) return 0;

		memset(SystemMoudles, 0, retLen + sizeof(RTL_PROCESS_MODULES));

		status = ZwQuerySystemInformation(SystemModuleInformation, SystemMoudles, retLen + sizeof(RTL_PROCESS_MODULES), &retLen);

		if (!NT_SUCCESS(status))
		{
			ExFreePool(SystemMoudles);
			return 0;
		}

		isAllocate = TRUE;
	}

	PUCHAR kernelModuleName = NULL;
	ULONG_PTR moudleBase = 0;

	do
	{


		if (_stricmp(moduleName, "ntoskrnl.exe") == 0 || _stricmp(moduleName, "ntkrnlpa.exe") == 0)
		{
			PRTL_PROCESS_MODULE_INFORMATION moudleInfo = &SystemMoudles->Modules[0];
			moudleBase = moudleInfo->ImageBase;
			if (moduleSize) *moduleSize = moudleInfo->ImageSize;

			break;
		}


		kernelModuleName = ExAllocatePool(PagedPool, strlen(moduleName) + 1);
		memset(kernelModuleName, 0, strlen(moduleName) + 1);
		memcpy(kernelModuleName, moduleName, strlen(moduleName));
		_strupr(kernelModuleName);


		for (int i = 0; i < SystemMoudles->NumberOfModules; i++)
		{
			PRTL_PROCESS_MODULE_INFORMATION moudleInfo = &SystemMoudles->Modules[i];

			PUCHAR pathName = _strupr(moudleInfo->FullPathName);
			DbgPrintEx(77, 0, "baseName = %s,fullPath = %s\r\n",
				moudleInfo->FullPathName + moudleInfo->OffsetToFileName, moudleInfo->FullPathName);


			if (strstr(pathName, kernelModuleName))
			{
				moudleBase = moudleInfo->ImageBase;
				if (moduleSize) *moduleSize = moudleInfo->ImageSize;
				break;
			}

		}

	} while (0);


	if (kernelModuleName)
	{
		ExFreePool(kernelModuleName);
	}

	if (isAllocate)
	{
		ExFreePool(SystemMoudles);
	}

	return moudleBase;
}

PeLoad/Loader.h

#pragma once
#include <ntifs.h>

BOOLEAN UpdataIAT(char* imageBuffer);

BOOLEAN LoadDriver(PUCHAR fileBuffer);

PeLoad/Loader.c

#include "Loader.h"
#include <ntimage.h>
#include "tools.h"



typedef NTSTATUS(NTAPI* DriverEntryProc)(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg);

typedef struct _IMAGE_RELOC
{
	UINT16	Offset : 12;		// 低12位---偏移
	UINT16	Type : 4;			// 高4位---類型
} IMAGE_RELOC, * PIMAGE_RELOC;

PUCHAR FileToImage(char* fileBuffer)
{
	if (!fileBuffer) return NULL;

	PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)fileBuffer;
	PIMAGE_NT_HEADERS pNts = (PIMAGE_NT_HEADERS)(fileBuffer + pDos->e_lfanew);

	//創建imageBuffer
	ULONG sizeofImage = pNts->OptionalHeader.SizeOfImage;
	PUCHAR imageBuffer = ExAllocatePool(NonPagedPool, sizeofImage);
	memset(imageBuffer, 0, sizeofImage);

	//複製PE頭
	memcpy(imageBuffer, fileBuffer, pNts->OptionalHeader.SizeOfHeaders);

	ULONG NumberOfSections = pNts->FileHeader.NumberOfSections;

	PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNts);

	//拉伸PE 結構
	for (ULONG i = 0; i < NumberOfSections; i++)
	{
		memcpy(imageBuffer + pSection->VirtualAddress, fileBuffer + pSection->PointerToRawData, pSection->SizeOfRawData);
		pSection++;
	}

	return imageBuffer;
}

//獲取到 LoadLibraryExW
ULONG64 ExportTableFuncByName(char* pData, char* funcName)
{
	PIMAGE_DOS_HEADER pHead = (PIMAGE_DOS_HEADER)pData;
	PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pData + pHead->e_lfanew);
	int numberRvaAndSize = pNt->OptionalHeader.NumberOfRvaAndSizes;
	PIMAGE_DATA_DIRECTORY pDir = (PIMAGE_DATA_DIRECTORY)&pNt->OptionalHeader.DataDirectory[0];

	PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(pData + pDir->VirtualAddress);

	ULONG64 funcAddr = 0;
	for (int i = 0; i < pExport->NumberOfNames; i++)
	{
		int* funcAddress = pData + pExport->AddressOfFunctions;
		int* names = pData + pExport->AddressOfNames;
		short* fh = pData + pExport->AddressOfNameOrdinals;
		int index = -1;
		char* name = pData + names[i];

		if (strcmp(name, funcName) == 0)
		{
			index = fh[i];
		}



		if (index != -1)
		{
			funcAddr = pData + funcAddress[index];
			break;
		}


	}

	if (!funcAddr)
	{
		KdPrint(("沒有找到函數%s\r\n", funcName));

	}
	else
	{
		KdPrint(("找到函數%s addr %p\r\n", funcName, funcAddr));
	}


	return funcAddr;
}

BOOLEAN UpdataRelocation(char* imageBuffer)
{
	PIMAGE_NT_HEADERS pNts = RtlImageNtHeader(imageBuffer);
	if (!pNts) return FALSE;

	PIMAGE_DATA_DIRECTORY iRelocation = &pNts->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];

	PIMAGE_BASE_RELOCATION pBase = (PIMAGE_BASE_RELOCATION)(imageBuffer + iRelocation->VirtualAddress);

	while (pBase->SizeOfBlock && pBase->VirtualAddress)
	{

		PIMAGE_RELOC RelocationBlock = (PIMAGE_RELOC)((PUCHAR)pBase + sizeof(IMAGE_BASE_RELOCATION));

		UINT32	NumberOfRelocations = (pBase->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(IMAGE_RELOC);

		for (int i = 0; i < NumberOfRelocations; i++)
		{
			if (RelocationBlock[i].Type == IMAGE_REL_BASED_DIR64)
			{

				// 64 位
				PUINT64	Address = (PUINT64)((PUINT8)imageBuffer + pBase->VirtualAddress + RelocationBlock[i].Offset);
				UINT64	Delta = *Address - pNts->OptionalHeader.ImageBase + (PUINT8)imageBuffer;
				*Address = Delta;
			}
			else if (RelocationBlock[i].Type == IMAGE_REL_BASED_HIGHLOW)
			{

				PUINT32	Address = (PUINT32)((PUINT8)imageBuffer + pBase->VirtualAddress + (RelocationBlock[i].Offset));
				UINT32	Delta = *Address - pNts->OptionalHeader.ImageBase + (PUINT8)imageBuffer;
				*Address = Delta;
			}
		}

		pBase = (PIMAGE_BASE_RELOCATION)((PUCHAR)pBase + pBase->SizeOfBlock);
	}

	return TRUE;

}

BOOLEAN UpdataIAT(char* imageBuffer)
{
	if (!imageBuffer) return FALSE;

	PIMAGE_NT_HEADERS pNts = RtlImageNtHeader(imageBuffer);
	if (!pNts) return FALSE;

	PIMAGE_DATA_DIRECTORY pimportDir = &pNts->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
	PIMAGE_IMPORT_DESCRIPTOR import = (PIMAGE_IMPORT_DESCRIPTOR)(imageBuffer + pimportDir->VirtualAddress);

	BOOLEAN isSuccess = TRUE;

	for (; import->Name; import++)
	{
		PUCHAR libName = (imageBuffer + import->Name);
		ULONG_PTR base = QueryModule(libName, NULL);
		if (!base)
		{
			isSuccess = FALSE;
			break;
		}

		PIMAGE_THUNK_DATA pThuckName = (PIMAGE_THUNK_DATA)(imageBuffer + import->OriginalFirstThunk);
		PIMAGE_THUNK_DATA pThuckFunc = (PIMAGE_THUNK_DATA)(imageBuffer + import->FirstThunk);

		for (; pThuckName->u1.ForwarderString; ++pThuckName, ++pThuckFunc)
		{
			PIMAGE_IMPORT_BY_NAME FuncName = (PIMAGE_IMPORT_BY_NAME)(imageBuffer + pThuckName->u1.AddressOfData);

			ULONG_PTR func = ExportTableFuncByName((char*)base, FuncName->Name);
			if (func)
			{
				pThuckFunc->u1.Function = (ULONG_PTR)func;
			}
			else
			{
				isSuccess = FALSE;
				break;
			}
		}

		if (!isSuccess) break;

	}

	return isSuccess;
}

VOID UpdateCookie(char* imageBuffer)
{
	//DbgBreakPoint();
	if (!imageBuffer) return FALSE;

	PIMAGE_NT_HEADERS pNts = RtlImageNtHeader(imageBuffer);
	if (!pNts) return FALSE;

	PIMAGE_DATA_DIRECTORY pConfigDir = &pNts->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG];

	PIMAGE_LOAD_CONFIG_DIRECTORY config = (PIMAGE_LOAD_CONFIG_DIRECTORY)(pConfigDir->VirtualAddress + imageBuffer);

	*(PULONG)(config->SecurityCookie) += 10;

}

BOOLEAN LoadDriver(PUCHAR fileBuffer)
{
	PUCHAR imageBase = FileToImage(fileBuffer);
	if (!imageBase) return FALSE;

	BOOLEAN isSuccess = FALSE;

	do
	{
		isSuccess = UpdataRelocation(imageBase);
		if (!isSuccess) break;

		isSuccess = UpdataIAT(imageBase);
		if (!isSuccess) break;

		//修複cookie
		UpdateCookie(imageBase);

		//call 入口點
		PIMAGE_NT_HEADERS pNts = RtlImageNtHeader(imageBase);

		ULONG_PTR entry = pNts->OptionalHeader.AddressOfEntryPoint;
		DriverEntryProc EntryPointFunc = (DriverEntryProc)(imageBase + entry);
		NTSTATUS status = EntryPointFunc(NULL, NULL);
		if (!NT_SUCCESS(status))
		{
			isSuccess = FALSE;
			break;
		}


		//清空PE頭
		memset(imageBase, 0, PAGE_SIZE);

	} while (0);



	if (!isSuccess)
	{
		ExFreePool(imageBase);

	}

	return isSuccess;
}

PeLoad/DriverMain.c

#include <ntifs.h>
#include "tools.h"
#include "Loader.h"
#include "dll.h"

VOID DriverUnload(PDRIVER_OBJECT pDriver)
{

}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING pReg)
{
	ULONG dwImageSize = sizeof(sysData);
	unsigned char* pMemory = (unsigned char*)ExAllocatePool(NonPagedPool, dwImageSize);
	memcpy(pMemory, sysData, dwImageSize);
	for (ULONG i = 0; i < dwImageSize; i++)
	{
		pMemory[i] ^= 0xDE;
		pMemory[i] ^= 0x73;
	}
	QueryModule(" ", NULL);
	DbgBreakPoint();
	LoadDriver(pMemory);
	ExFreePool(pMemory);
	pDriver->DriverUnload = DriverUnload;
	return STATUS_UNSUCCESSFUL;
}

encode.bat

set "projectpath=%cd%"
cd ../
set "preProjectpath=%cd%"
cd %projectpath%
set "SignFullPath=%preProjectpath%/Debug/Test.sys"
Build.exe %SignFullPath%
作者:zhang_derek 出處:http://www.cnblogs.com/derek1184405959/ github:https://github.com/derek-zhang123
個性簽名:其實人跟樹一樣,越是嚮往高處的陽光,它的根就越要伸向黑暗的地底。

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前兩天一個鄰居發出了靈魂質問:“為什麼我買的180平和你的169平看上去一樣大?” “因為咱倆的套內面積都是138平......” 我們去看房子,比較不同樓盤的價格,看的都是單價,可這個單價,卻是用(總價 ÷ 建築面積)計算的。而我們實際買到手裡的,是套內面積。 套內面積 = 使用面積+牆體厚度+陽 ...
  • 線程本地存儲 · 語雀 (yuque.com) 線程本地存儲提供了線程記憶體儲變數的能力,這些變數是線程私有的。 線程本地存儲一般用在跨類、跨方法的傳遞一些值。 線程本地存儲也是解決特定場景下線程安全問題的思路之一(每個線程都訪問本線程自己的變數)。 Java 語言提供了線程本地存儲,ThreadLo ...
  • 在大部分涉及到資料庫操作的項目裡面,事務控制、事務處理都是一個無法迴避的問題。這裡我們一起探討下關於事務控制相關的一些內容。 ...
  • 來源: blog.csdn.net/fumitzuki/article/details/81630048 volatile關鍵字是由JVM提供的最輕量級同步機制。與被濫用的synchronized不同,我們並不習慣使用它。想要正確且完全的理解它並不容易。 Part1Java記憶體模型 Java記憶體模型 ...
  • 多商戶商城系統,也稱為B2B2C(BBC)平臺電商模式多商家商城系統。可以快速幫助企業搭建類似拼多多/京東/天貓/淘寶的綜合商城。 多商戶商城系統支持商家入駐加盟,同時滿足平臺自營、旗艦店等多種經營方式。平臺可以通過收取商家入駐費,訂單交易服務費,提現手續費,簡訊通道費等多手段方式,實現整體盈利。 ...
  • [演算法1-排序](.NET源碼學習)& LINQ & Lambda 說起排序演算法,在日常實際開發中我們基本不在意這些事情,有API不用不是沒事找事嘛。但必要的基礎還是需要瞭解掌握。 排序的目的是為了讓無序的數據,變得“有序”。此處的有序指的是,滿足當前使用需求的順序,除了自帶的API,我們還可以自定 ...
  • 作為一個沒有系統學習過依賴註入的開發者而言,如果直接在一個使用依賴註入的框架下進行開發,往往對於依賴註入的存在是沒有明顯的察覺,通過代碼追根溯源你都會看不出對象是從哪裡創建的。但這並不影響你進行開發的工作,你可以參照現有代碼的使用形式,將需要使用的對象加入到構造函數的參數列表上,你就可以使用對象,調 ...
  • PDF/X-1a是一種PDF文件規範標準,在製作、使用PDF以及印刷時所需要遵循的技術條件,屬於PDF/X-1標準下的一個子標準。 PDF/X-1標準有由CGATS於1999年制定的PDF/X-1:1999,由ISO於2001年制的PDF/X-1:2001、PDF/X-1a:2001以及PDF/X- ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...