二、驅動

来源: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
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...
  • 目錄前言PostgreSql安裝測試額外Nuget安裝Person.cs模擬運行Navicate連postgresql解決方案Garnet為什麼要選擇Garnet而不是RedisRedis不再開源Windows版的Redis是由微軟維護的Windows Redis版本老舊,後續可能不再更新Garne ...
  • C#TMS系統代碼-聯表報表學習 領導被裁了之後很快就有人上任了,幾乎是無縫銜接,很難讓我不想到這早就決定好了。我的職責沒有任何變化。感受下來這個系統封裝程度很高,我只要會調用方法就行。這個系統交付之後不會有太多問題,更多應該是做小需求,有大的開發任務應該也是第二期的事,嗯?怎麼感覺我變成運維了?而 ...
  • 我在隨筆《EAV模型(實體-屬性-值)的設計和低代碼的處理方案(1)》中介紹了一些基本的EAV模型設計知識和基於Winform場景下低代碼(或者說無代碼)的一些實現思路,在本篇隨筆中,我們來分析一下這種針對通用業務,且只需定義就能構建業務模塊存儲和界面的解決方案,其中的數據查詢處理的操作。 ...
  • 對某個遠程伺服器啟用和設置NTP服務(Windows系統) 打開註冊表 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer 將 Enabled 的值設置為 1,這將啟用NTP伺服器功 ...
  • title: Django信號與擴展:深入理解與實踐 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 後端開發 tags: Django 信號 松耦合 觀察者 擴展 安全 性能 第一部分:Django信號基礎 Djan ...
  • 使用xadmin2遇到的問題&解決 環境配置: 使用的模塊版本: 關聯的包 Django 3.2.15 mysqlclient 2.2.4 xadmin 2.0.1 django-crispy-forms >= 1.6.0 django-import-export >= 0.5.1 django-r ...
  • 今天我打算整點兒不一樣的內容,通過之前學習的TransformerMap和LazyMap鏈,想搞點不一樣的,所以我關註了另外一條鏈DefaultedMap鏈,主要調用鏈為: 調用鏈詳細描述: ObjectInputStream.readObject() DefaultedMap.readObject ...
  • 後端應用級開發者該如何擁抱 AI GC?就是在這樣的一個大的浪潮下,我們的傳統的應用級開發者。我們該如何選擇職業或者是如何去快速轉型,跟上這樣的一個行業的一個浪潮? 0 AI金字塔模型 越往上它的整個難度就是職業機會也好,或者說是整個的這個運作也好,它的難度會越大,然後越往下機會就會越多,所以這是一 ...
  • @Autowired是Spring框架提供的註解,@Resource是Java EE 5規範提供的註解。 @Autowired預設按照類型自動裝配,而@Resource預設按照名稱自動裝配。 @Autowired支持@Qualifier註解來指定裝配哪一個具有相同類型的bean,而@Resourc... ...