IRP操作文件

[cpp]  view plain  copy
  1. #include <ntddk.h>  
  2.   
  3. #ifndef MAX_PATH  
  4. #define MAX_PATH          260  
  5. #endif  
  6.   
  7. NTSTATUS ObOpenObjectByPointer(PVOID Object,ULONG HandleAttributes,PACCESS_STATE PassedAccessState,ACCESS_MASK DesiredAccess,POBJECT_TYPE ObjectType,KPROCESSOR_MODE AccessMode,PHANDLE Handle);  
  8. NTSTATUS ObCreateObject(KPROCESSOR_MODE ProbeMode, POBJECT_TYPE ObjectType, POBJECT_ATTRIBUTES ObjectAttributes, KPROCESSOR_MODE OwnershipMode, PVOID ParseContext, ULONG ObjectBodySize, ULONG PagedPoolCharge, ULONG NonPagedPoolCharge, PVOID *Object);  
  9. NTSTATUS SeCreateAccessState(PACCESS_STATE AccessState, PVOID AuxData, ACCESS_MASK DesiredAccess, PGENERIC_MAPPING GenericMapping);  
  10.   
  11. typedef struct _AUX_ACCESS_DATA {  
  12.     PPRIVILEGE_SET PrivilegesUsed;  
  13.     GENERIC_MAPPING GenericMapping;  
  14.     ACCESS_MASK AccessesToAudit;  
  15.     ACCESS_MASK MaximumAuditMask;  
  16.     ULONG Unknown[256];  
  17. } AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;  
  18.   
  19. //获取设备对象  
  20. NTSTATUS GetDriveObject(PUNICODE_STRING pDriveName, PDEVICE_OBJECT *DeviceObject, PDEVICE_OBJECT *ReadDevice);  
  21.   
  22. //IRP删除文件  
  23. NTSTATUS IrpDeleteFileForce(PFILE_OBJECT pFileObject);  
  24.   
  25. //IRP删除文件  
  26. NTSTATUS IrpDeleteFileEx(PFILE_OBJECT pFileObject);  
  27.   
  28. //IRP删除文件  
  29. NTSTATUS IrpDeleteFile(PFILE_OBJECT pFileObject);  
  30.   
  31. //删除文件  
  32. NTSTATUS ZwDeleteFile(PFILE_OBJECT pFileObject);  
  33.   
  34. //复制文件  
  35. NTSTATUS CopyFileEx(PUNICODE_STRING lpExistingFileName, PUNICODE_STRING lpNewFileName);  
  36.   
  37. //IRP设置文件  
  38. NTSTATUS irpSetFileAttributes(PFILE_OBJECT pFileObject, PIO_STATUS_BLOCK  pIoStatusBlock,PVOID FileInformation,ULONG Length,FILE_INFORMATION_CLASS  FileInformationClass,BOOLEAN  ReplaceIfExists);  
  39.   
  40. //IRP打开文件  
  41. NTSTATUS IrpCreateFile(PUNICODE_STRING pFilePath, ACCESS_MASK DesiredAccess, PIO_STATUS_BLOCK pIoStatusBlock, PFILE_OBJECT *pFileObject);  
  42.   
  43. //IRP读取文件  
  44. NTSTATUS IrpReadFile(PFILE_OBJECT pFileObject, PLARGE_INTEGER pByteOffset, ULONG Length, PVOID pBuffer, PIO_STATUS_BLOCK pIoStatusBlock);  
  45.   
  46. //IRP写文件  
  47. NTSTATUS IrpFileWrite(PFILE_OBJECT pFileObject, PLARGE_INTEGER ByteOffset, ULONG Length, PVOID Buffer, PIO_STATUS_BLOCK pIoStatusBlock);  
  48.   
  49. //IRP关闭文件  
  50. NTSTATUS IrpClose(PFILE_OBJECT  pFileObject);  
  51.   
  52.   
  53. VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)  
  54. {  
  55.     return;  
  56. }  
  57.   
  58. NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)  
  59. {  
  60.     NTSTATUS status;  
  61.     DriverObject->DriverUnload = DriverUnload;  
  62.       
  63.     DbgBreakPoint();  
  64.   
  65.     UNICODE_STRING strFilePath;  
  66.     IO_STATUS_BLOCK IoStatusBlock = {0};  
  67.     PFILE_OBJECT pFileObject = NULL;  
  68.     RtlInitUnicodeString(&strFilePath, L"\\??\\c:\\MyDriver1.sys");  
  69.   
  70.   
  71.     //打开文件  
  72.     status=IrpCreateFile(&strFilePath, DELETE, &IoStatusBlock, &pFileObject);  
  73.     if (NT_SUCCESS(status))  
  74.     {  
  75.   
  76.         //删除文件  
  77.         //status=ZwDeleteFile(pFileObject);  
  78.         //status = IrpDeleteFile(pFileObject);  
  79.         //status=IrpDeleteFileForce(pFileObject);  
  80.         //KdPrint(("OK\n"));  
  81.         //status=IrpDeleteFileForce(pFileObject);  
  82.   
  83.         //关闭文件  
  84.         status=IrpClose(pFileObject);  
  85.     }  
  86.     return STATUS_SUCCESS;  
  87. }  
  88.   
  89.   
  90. //完成历程  
  91. NTSTATUS IoCompletionRoutineEx(PDEVICE_OBJECT  DeviceObject, PIRP  Irp, PVOID  Context)  
  92. {  
  93.   
  94.     *Irp->UserIosb = Irp->IoStatus;  
  95.     if (Irp->UserEvent)  
  96.         KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0);  
  97.   
  98.     if (Irp->MdlAddress)  
  99.     {  
  100.         IoFreeMdl(Irp->MdlAddress);  
  101.         Irp->MdlAddress = NULL;  
  102.     }  
  103.   
  104.     IoFreeIrp(Irp);  
  105.     return STATUS_MORE_PROCESSING_REQUIRED;  
  106.   
  107. }  
  108.   
  109. //IRP写文件  
  110. NTSTATUS IrpFileWrite(PFILE_OBJECT pFileObject, PLARGE_INTEGER ByteOffset, ULONG Length, PVOID Buffer, PIO_STATUS_BLOCK pIoStatusBlock)  
  111. {  
  112.     //定义变量  
  113.     NTSTATUS status;  
  114.     KEVENT event;  
  115.     PIRP irp;  
  116.     PIO_STACK_LOCATION irpSp;  
  117.     PDEVICE_OBJECT deviceObject;  
  118.   
  119.     //参数效验  
  120.     if (pIoStatusBlock == NULL || pFileObject == NULL || Length <= 0 || Buffer == NULL)return STATUS_INVALID_PARAMETER;  
  121.   
  122.     //参数效验  
  123.     if (ByteOffset == NULL)  
  124.     {  
  125.         if (!(pFileObject->Flags & FO_SYNCHRONOUS_IO))  
  126.             return STATUS_INVALID_PARAMETER;  
  127.         ByteOffset = &pFileObject->CurrentByteOffset;  
  128.     }  
  129.   
  130.     //获取原始设备对象  
  131.     deviceObject = IoGetRelatedDeviceObject(pFileObject);  
  132.     if (deviceObject == NULL || deviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  133.       
  134.   
  135.     //分配IRP  
  136.     irp = IoAllocateIrp(deviceObject->StackSize, FALSE);  
  137.     if (irp == NULL)return STATUS_INSUFFICIENT_RESOURCES;  
  138.   
  139.     //分配MDL缓冲区  
  140.     irp->MdlAddress = IoAllocateMdl(Buffer, Length, FALSE, FALSE, NULL);  
  141.     if (irp->MdlAddress == NULL)  
  142.     {  
  143.         IoFreeIrp(irp);  
  144.         return STATUS_INSUFFICIENT_RESOURCES;;  
  145.     }  
  146.     //更新MDL  
  147.     MmBuildMdlForNonPagedPool(irp->MdlAddress);  
  148.   
  149.     //设置变量  
  150.     irp->Flags = IRP_WRITE_OPERATION;            //IRP写操作  
  151.     irp->RequestorMode = KernelMode;  
  152.     irp->UserIosb = pIoStatusBlock;  
  153.     irp->UserEvent = &event;  
  154.     irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  155.     irp->Tail.Overlay.OriginalFileObject = pFileObject;  
  156.   
  157.     irpSp = IoGetNextIrpStackLocation(irp);  
  158.     irpSp->MajorFunction = IRP_MJ_WRITE;  
  159.     irpSp->MinorFunction = IRP_MN_NORMAL;  
  160.     irpSp->DeviceObject = deviceObject;  
  161.     irpSp->FileObject = pFileObject;  
  162.     irpSp->Parameters.Write.Length = Length;  
  163.     irpSp->Parameters.Write.ByteOffset = *ByteOffset;  
  164.   
  165.     KeInitializeEvent(&event, SynchronizationEvent, FALSE);  
  166.     IoSetCompletionRoutine(irp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  167.     status = IoCallDriver(deviceObject, irp);  
  168.     if (status == STATUS_PENDING)  
  169.         status = KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);  
  170.     status = pIoStatusBlock->Status;  
  171. #ifdef DBG  
  172.     KdPrint(("写入文件长度%d  文件状态%d\n", pIoStatusBlock->Information, pIoStatusBlock->Status));  
  173. #endif  
  174.   
  175.     return status;  
  176. }  
  177.   
  178.   
  179. //IRP删除文件  
  180. NTSTATUS IrpDeleteFileEx(PFILE_OBJECT pFileObject)  
  181. {  
  182.     //定义变量  
  183.     NTSTATUS                status;  
  184.     PIRP                    pIrp;  
  185.     PIO_STACK_LOCATION      irpSp;  
  186.     PDEVICE_OBJECT          DeviceObject;  
  187.     IO_STATUS_BLOCK         IoStatusBlock;  
  188.     KEVENT                  SycEvent;  
  189.     PSECTION_OBJECT_POINTERS        pSectionObjectPointer;  
  190.     FILE_DISPOSITION_INFORMATION    FileInformationDelete;  
  191.     static FILE_BASIC_INFORMATION   FileInformationAttribute;  
  192.   
  193.   
  194.     //参数效验  
  195.     if (pFileObject == NULL)return STATUS_INVALID_PARAMETER;  
  196.   
  197.     //设置文件属性  
  198.     memset(&FileInformationAttribute, 0, sizeof(FILE_BASIC_INFORMATION));  
  199.     FileInformationAttribute.FileAttributes = FILE_ATTRIBUTE_NORMAL;  
  200.     status = irpSetFileAttributes(pFileObject, &IoStatusBlock, &FileInformationAttribute, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, TRUE);  
  201.     if (!NT_SUCCESS(status))return status;  
  202.   
  203.   
  204.     //获取原始设备对象  
  205.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  206.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  207.   
  208.     // 创建IRP    
  209.     pIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);  
  210.     if (pIrp == NULL)  
  211.     {  
  212.         //ObDereferenceObject(pFileObject);  
  213.         return STATUS_UNSUCCESSFUL;  
  214.     }  
  215.   
  216.       
  217.     //初始化同步事件对象  
  218.     KeInitializeEvent(&SycEvent, SynchronizationEvent, FALSE);  
  219.   
  220.     //设置变量  
  221.     FileInformationDelete.DeleteFile = TRUE;  
  222.   
  223.     //初始化IRP    
  224.     pIrp->AssociatedIrp.SystemBuffer = &FileInformationDelete;  
  225.     pIrp->UserEvent = &SycEvent;  
  226.     pIrp->UserIosb = &IoStatusBlock;  
  227.     pIrp->Tail.Overlay.OriginalFileObject = pFileObject;  
  228.     pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  229.     pIrp->RequestorMode = KernelMode;  
  230.   
  231.     // 设置IRP堆栈    
  232.     irpSp = IoGetNextIrpStackLocation(pIrp);  
  233.     irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;  
  234.     irpSp->DeviceObject = DeviceObject;  
  235.     irpSp->FileObject = pFileObject;  
  236.     irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);  
  237.     irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;  
  238.     irpSp->Parameters.SetFile.FileObject = pFileObject;  
  239.   
  240.     // 设置完成例程    
  241.     IoSetCompletionRoutine(pIrp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  242.   
  243.     //如果没有这3行,就无法删除正在运行的文件    
  244.     pSectionObjectPointer = pFileObject->SectionObjectPointer;  
  245.     pSectionObjectPointer->ImageSectionObject = 0;  
  246.     pSectionObjectPointer->DataSectionObject = 0;  
  247.   
  248.     // 派发IRP    
  249.     status=IoCallDriver(DeviceObject, pIrp);  
  250.     if (status == STATUS_PENDING)  
  251.         KeWaitForSingleObject(&SycEvent, Executive, KernelMode, TRUE, NULL);  
  252.     status = IoStatusBlock.Status;  
  253.     // 递减引用计数    
  254.     //ObDereferenceObject(pFileObject);  
  255.   
  256.     return status;  
  257.   
  258. }  
  259.   
  260. //IRP删除文件  
  261. NTSTATUS IrpDeleteFileForce(PFILE_OBJECT pFileObject)  
  262. {  
  263.   
  264.     //定义变量  
  265.     NTSTATUS                status;  
  266.     PIRP                    pIrp;  
  267.     PIO_STACK_LOCATION      irpSp;  
  268.     PDEVICE_OBJECT          DeviceObject;  
  269.     IO_STATUS_BLOCK         IoStatusBlock;  
  270.     KEVENT                  SycEvent;  
  271.     PVOID pImageSectionObject = NULL;  
  272.     PVOID pDataSectionObject = NULL;  
  273.     PVOID pSharedCacheMap = NULL;  
  274.     PSECTION_OBJECT_POINTERS        pSectionObjectPointer;  
  275.     FILE_DISPOSITION_INFORMATION    FileInformationDelete;  
  276.     static FILE_BASIC_INFORMATION   FileInformationAttribute;  
  277.   
  278.   
  279.     //参数效验  
  280.     if (pFileObject == NULL)return STATUS_INVALID_PARAMETER;  
  281.   
  282.     //设置文件属性  
  283.     memset(&FileInformationAttribute, 0, sizeof(FILE_BASIC_INFORMATION));  
  284.     FileInformationAttribute.FileAttributes = FILE_ATTRIBUTE_NORMAL;  
  285.     status = irpSetFileAttributes(pFileObject, &IoStatusBlock, &FileInformationAttribute, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation, TRUE);  
  286.     if (!NT_SUCCESS(status))return status;  
  287.   
  288.   
  289.     //获取原始设备对象  
  290.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  291.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  292.   
  293.     // 创建IRP    
  294.     pIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);  
  295.     if (pIrp == NULL)return STATUS_UNSUCCESSFUL;  
  296.   
  297.     //初始化同步事件对象  
  298.     KeInitializeEvent(&SycEvent, SynchronizationEvent, FALSE);  
  299.   
  300.     //设置变量  
  301.     FileInformationDelete.DeleteFile = TRUE;  
  302.   
  303.     //初始化IRP    
  304.     pIrp->AssociatedIrp.SystemBuffer = &FileInformationDelete;  
  305.     pIrp->UserEvent = &SycEvent;  
  306.     pIrp->UserIosb = &IoStatusBlock;  
  307.     pIrp->Tail.Overlay.OriginalFileObject = pFileObject;  
  308.     pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  309.     pIrp->RequestorMode = KernelMode;  
  310.   
  311.     // 设置IRP堆栈    
  312.     irpSp = IoGetNextIrpStackLocation(pIrp);  
  313.     irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;  
  314.     irpSp->DeviceObject = DeviceObject;  
  315.     irpSp->FileObject = pFileObject;  
  316.     irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);  
  317.     irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;  
  318.     irpSp->Parameters.SetFile.FileObject = pFileObject;  
  319.   
  320.     // 设置完成例程    
  321.     IoSetCompletionRoutine(pIrp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  322.   
  323.   
  324.     //设置变量  
  325.     if (pFileObject->SectionObjectPointer)  
  326.     {  
  327.         //一个空值表明,可执行图像目前不在内存中  
  328.         //一个空值表示数据流当前不在内存中  
  329.         //空值的数据流是  
  330.         pImageSectionObject = pFileObject->SectionObjectPointer->ImageSectionObject;  
  331.         pDataSectionObject = pFileObject->SectionObjectPointer->DataSectionObject;  
  332.         pSharedCacheMap = pFileObject->SectionObjectPointer->SharedCacheMap;  
  333.   
  334.         pFileObject->SectionObjectPointer->ImageSectionObject = NULL;  
  335.         pFileObject->SectionObjectPointer->DataSectionObject = NULL;  
  336.         pFileObject->SectionObjectPointer->SharedCacheMap = NULL;  
  337.     }  
  338.       
  339.   
  340.     // 派发IRP    
  341.     status = IoCallDriver(DeviceObject, pIrp);  
  342.     if (status == STATUS_PENDING)  
  343.         KeWaitForSingleObject(&SycEvent, Executive, KernelMode, TRUE, NULL);  
  344.     status = IoStatusBlock.Status;  
  345.   
  346.     //还原变量  
  347.     if (pFileObject->SectionObjectPointer)  
  348.     {  
  349.         pFileObject->SectionObjectPointer->ImageSectionObject = pImageSectionObject;  
  350.         pFileObject->SectionObjectPointer->DataSectionObject = pDataSectionObject;  
  351.         pFileObject->SectionObjectPointer->SharedCacheMap = pSharedCacheMap;  
  352.     }  
  353.   
  354.     return status;  
  355. }  
  356.   
  357. //IRP删除文件  
  358. NTSTATUS IrpDeleteFile(PFILE_OBJECT pFileObject)  
  359. {  
  360.     //定义变量  
  361.     NTSTATUS           ntStatus = STATUS_SUCCESS;  
  362.     PDEVICE_OBJECT DeviceObject;  
  363.     PIRP                        pIrp;  
  364.     KEVENT                  SycEvent;  
  365.     FILE_DISPOSITION_INFORMATION    FileInformation;  
  366.     IO_STATUS_BLOCK                 ioStatus;  
  367.     PIO_STACK_LOCATION           irpSp;  
  368.   
  369.     //参数效验  
  370.     if (pFileObject == NULL)return STATUS_INVALID_PARAMETER;  
  371.   
  372.     //获取原始设备对象  
  373.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  374.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  375.   
  376.     //分配IRP  
  377.     pIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);  
  378.     if (pIrp == NULL)  
  379.     {  
  380.         //ObDereferenceObject(pFileObject);  
  381.         return ntStatus;  
  382.     }  
  383.   
  384.     // 初始化同步事件对象     
  385.     KeInitializeEvent(&SycEvent, SynchronizationEvent, FALSE);  
  386.   
  387.     //指示操作系统文件是否应在关闭该文件时删除该文件。将此成员设置为在关闭时删除该文件  
  388.     FileInformation.DeleteFile = TRUE;  
  389.   
  390.     // 初始化IRP     
  391.     pIrp->AssociatedIrp.SystemBuffer = &FileInformation;  
  392.     pIrp->UserEvent = &SycEvent;  
  393.     pIrp->UserIosb = &ioStatus;  
  394.     pIrp->Tail.Overlay.OriginalFileObject = pFileObject;  
  395.     pIrp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  396.     pIrp->RequestorMode = KernelMode;  
  397.   
  398.     // 设置IRP堆栈     
  399.     irpSp = IoGetNextIrpStackLocation(pIrp);  
  400.     irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;  
  401.     irpSp->DeviceObject = DeviceObject;  
  402.     irpSp->FileObject = pFileObject;  
  403.     irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);  
  404.     irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;  
  405.     irpSp->Parameters.SetFile.FileObject = pFileObject;  
  406.   
  407.     IoSetCompletionRoutine(pIrp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  408.   
  409.     // 派发IRP     
  410.     ntStatus = IoCallDriver(DeviceObject, pIrp);  
  411.     if (ntStatus == STATUS_PENDING)  
  412.         KeWaitForSingleObject(&SycEvent, Executive, KernelMode, TRUE, 0);  
  413.     ntStatus = ioStatus.Status;  
  414.   
  415.     return ntStatus;  
  416. }  
  417.   
  418. //删除文件  
  419. NTSTATUS ZwDeleteFile(PFILE_OBJECT pFileObject)  
  420. {  
  421.     //定义变量  
  422.     PDEVICE_OBJECT DeviceObject;  
  423.     HANDLE FileHandle;  
  424.     NTSTATUS ntStatus;  
  425.     IO_STATUS_BLOCK                 ioStatus;  
  426.     FILE_DISPOSITION_INFORMATION    FileInformation;  
  427.       
  428.     //参数效验  
  429.     if (pFileObject == NULL)return STATUS_INVALID_PARAMETER;  
  430.   
  431.     // 获取文件句柄     
  432.     ntStatus = ObOpenObjectByPointer(pFileObject,0,NULL,DELETE,*IoFileObjectType,KernelMode,&FileHandle);  
  433.     if (!NT_SUCCESS(ntStatus))return ntStatus;  
  434.     ObDereferenceObject(pFileObject);  
  435.   
  436.     FileInformation.DeleteFile = TRUE;  
  437.     ntStatus=ZwSetInformationFile(FileHandle, &ioStatus, &FileInformation, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation);  
  438.     return ntStatus;  
  439. }  
  440.   
  441. //IRP设置文件  
  442. NTSTATUS irpSetFileAttributes(PFILE_OBJECT pFileObject, PIO_STATUS_BLOCK  pIoStatusBlock, PVOID pFileInformation, ULONG FileInformationLength, FILE_INFORMATION_CLASS  FileInformationClass, BOOLEAN  ReplaceIfExists)  
  443. {  
  444.   
  445.     //定义变量  
  446.     NTSTATUS                        ntStatus = STATUS_SUCCESS;  
  447.     PDEVICE_OBJECT          DeviceObject;  
  448.     PIRP                                 Irp;  
  449.     KEVENT                           SycEvent;  
  450.     PIO_STACK_LOCATION      irpSp;  
  451.   
  452.     //参数效验  
  453.     if (pFileObject == NULL || pIoStatusBlock==NULL || pFileInformation ==NULL|| FileInformationLength <=0)return STATUS_INVALID_PARAMETER;  
  454.   
  455.     //获取原始设备对象  
  456.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  457.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  458.   
  459.     // 创建IRP     
  460.     Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);  
  461.     if (Irp == NULL)  
  462.     {  
  463.         //ObDereferenceObject(pFileObject);  
  464.         return STATUS_UNSUCCESSFUL;  
  465.     }  
  466.   
  467.     // 初始化同步事件对象     
  468.     KeInitializeEvent(&SycEvent, SynchronizationEvent, FALSE);  
  469.   
  470.   
  471.     // 初始化IRP     
  472.     Irp->AssociatedIrp.SystemBuffer = pFileInformation;                  //设置属性  
  473.     Irp->UserEvent = &SycEvent;  
  474.     Irp->UserIosb = pIoStatusBlock;  
  475.     Irp->Tail.Overlay.OriginalFileObject = pFileObject;  
  476.     Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  477.     Irp->RequestorMode = KernelMode;  
  478.   
  479.   
  480.     // 设置IRP堆栈信息     
  481.     irpSp = IoGetNextIrpStackLocation(Irp);  
  482.     irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;  
  483.     irpSp->DeviceObject = DeviceObject;  
  484.     irpSp->FileObject = pFileObject;  
  485.     irpSp->Parameters.SetFile.ReplaceIfExists = ReplaceIfExists;         //是否替换    
  486.     irpSp->Parameters.SetFile.Length = FileInformationLength;                //长度  
  487.     irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;   //类型  
  488.     irpSp->Parameters.SetFile.FileObject = pFileObject;  
  489.   
  490.   
  491.     IoSetCompletionRoutine(Irp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  492.     ntStatus=IoCallDriver(DeviceObject, Irp);  
  493.     if (ntStatus == STATUS_PENDING)  
  494.         KeWaitForSingleObject(&SycEvent, Executive, KernelMode, TRUE, NULL);  
  495.     ntStatus = pIoStatusBlock->Status;  
  496.     //ObDereferenceObject(pFileObject);  
  497.     return ntStatus;  
  498.   
  499. }  
  500.   
  501. //获取设备对象  
  502. NTSTATUS GetDriveObject(PUNICODE_STRING pDriveName, PDEVICE_OBJECT *DeviceObject, PDEVICE_OBJECT *ReadDevice)  
  503. {  
  504.   
  505.     //定义变量  
  506.     NTSTATUS status;  
  507.     OBJECT_ATTRIBUTES objectAttributes;  
  508.     HANDLE DeviceHandle = NULL;  
  509.     IO_STATUS_BLOCK ioStatus;  
  510.     PFILE_OBJECT pFileObject;  
  511.   
  512.     //参数效验  
  513.     if (pDriveName ==NULL||DeviceObject == NULL || ReadDevice == NULL)return STATUS_INVALID_PARAMETER;  
  514.   
  515.     //  \\??\\C:  
  516.     //打开设备  
  517.     InitializeObjectAttributes(&objectAttributes,pDriveName,OBJ_CASE_INSENSITIVE,NULL,NULL);  
  518.     status = IoCreateFile(&DeviceHandle,SYNCHRONIZE | FILE_ANY_ACCESS,&objectAttributes,&ioStatus,NULL,0,FILE_SHARE_READ | FILE_SHARE_WRITE,FILE_OPEN,FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,NULL,0,CreateFileTypeNone,NULL,IO_NO_PARAMETER_CHECKING);  
  519.     if (!NT_SUCCESS(status))return status;  
  520.   
  521.     //获取文件对象  
  522.     status = ObReferenceObjectByHandle(DeviceHandle,FILE_READ_DATA,*IoFileObjectType,KernelMode,&pFileObject,NULL);  
  523.     if (!NT_SUCCESS(status))  
  524.     {  
  525.         ZwClose(DeviceHandle);  
  526.         return status;  
  527.     }  
  528.   
  529.     //效验结果  
  530.     if (pFileObject->Vpb == 0 || pFileObject->Vpb->RealDevice == NULL)  
  531.     {  
  532.         ObDereferenceObject(pFileObject);  
  533.         ZwClose(DeviceHandle);  
  534.         return STATUS_UNSUCCESSFUL;  
  535.     }  
  536.   
  537.     //设置变量  
  538.     *DeviceObject = pFileObject->Vpb->DeviceObject;  
  539.     *ReadDevice = pFileObject->Vpb->RealDevice;  
  540.   
  541.     ObDereferenceObject(pFileObject);  
  542.     ZwClose(DeviceHandle);  
  543.   
  544.   
  545.     return STATUS_SUCCESS;  
  546. }  
  547.   
  548. //IRP打开文件  
  549. NTSTATUS IrpCreateFile(PUNICODE_STRING pFilePath, ACCESS_MASK DesiredAccess,PIO_STATUS_BLOCK pIoStatusBlock, PFILE_OBJECT *pFileObject)  
  550. {  
  551.     //定义变量  
  552.     NTSTATUS ntStatus;  
  553.     PIRP pIrp;  
  554.     KEVENT kEvent;  
  555.     static ACCESS_STATE AccessState;  
  556.     static AUX_ACCESS_DATA AuxData;  
  557.     OBJECT_ATTRIBUTES ObjectAttributes;  
  558.     PFILE_OBJECT  pNewFileObject;  
  559.     IO_SECURITY_CONTEXT SecurityContext;  
  560.     PIO_STACK_LOCATION IrpSp;  
  561.     PDEVICE_OBJECT pDeviceObject = NULL;  
  562.     PDEVICE_OBJECT pReadDevice = NULL;  
  563.     UNICODE_STRING DriveName;  
  564.     wchar_t* pFileNameBuf = NULL;  
  565.     static wchar_t szFilePath[MAX_PATH] = { 0 };  
  566.     #define SYMBOLICLINKLENG            6           //  \\??\\c:            \\windows\\notepad.exe  
  567.   
  568.   
  569.     //参数效验  
  570.     if (pFilePath==NULL||pIoStatusBlock==NULL||pFileObject==NULL || pFilePath->Length<= SYMBOLICLINKLENG)return STATUS_INVALID_PARAMETER;  
  571.   
  572.   
  573.     //pFilePath  \\??\\c:\\456\\123.sys  
  574.     RtlZeroMemory(szFilePath, sizeof(szFilePath));  
  575.     RtlCopyMemory(szFilePath, pFilePath->Buffer, (SYMBOLICLINKLENG + 1)*sizeof(wchar_t));  
  576.     RtlInitUnicodeString(&DriveName, szFilePath);  
  577.   
  578.   
  579.   
  580.     //获取设备对象  
  581.     ntStatus=GetDriveObject(&DriveName, &pDeviceObject, &pReadDevice);  
  582.     if (!NT_SUCCESS(ntStatus))return ntStatus;  
  583.   
  584.     RtlZeroMemory(szFilePath, sizeof(szFilePath));  
  585.     RtlCopyMemory(szFilePath, &pFilePath->Buffer[SYMBOLICLINKLENG], pFilePath->Length- SYMBOLICLINKLENG);  
  586.     RtlInitUnicodeString(&DriveName, szFilePath);  
  587.     pFileNameBuf= ExAllocatePool(NonPagedPool, DriveName.MaximumLength);  
  588.     if (pFileNameBuf == NULL)return STATUS_UNSUCCESSFUL;  
  589.     RtlZeroMemory(pFileNameBuf, DriveName.MaximumLength);  
  590.     RtlCopyMemory(pFileNameBuf, DriveName.Buffer, DriveName.Length);  
  591.       
  592.   
  593.     //参数效验  
  594.     if (pDeviceObject == NULL || pReadDevice == NULL || pDeviceObject->StackSize<=0)return STATUS_UNSUCCESSFUL;  
  595.   
  596.     InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 0, NULL);  
  597.     ntStatus = ObCreateObject(KernelMode, *IoFileObjectType, &ObjectAttributes, KernelMode, NULL, sizeof(FILE_OBJECT), 0, 0, &pNewFileObject);  
  598.     if (!NT_SUCCESS(ntStatus))return ntStatus;  
  599.   
  600.     pIrp = IoAllocateIrp(pDeviceObject->StackSize, FALSE);  
  601.     if (pIrp == NULL)  
  602.     {  
  603.         ObDereferenceObject(pNewFileObject);  
  604.         return STATUS_INSUFFICIENT_RESOURCES;  
  605.     }  
  606.   
  607.     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);  
  608.     RtlZeroMemory(pNewFileObject, sizeof(FILE_OBJECT));  
  609.     pNewFileObject->Type = IO_TYPE_FILE;  
  610.     pNewFileObject->Size = sizeof(FILE_OBJECT);  
  611.     pNewFileObject->DeviceObject = pReadDevice;  
  612.     pNewFileObject->Flags = FO_SYNCHRONOUS_IO;  
  613.     RtlInitUnicodeString(&pNewFileObject->FileName, pFileNameBuf);       //地址不能是局部变量地址  
  614.     KeInitializeEvent(&pNewFileObject->Lock, SynchronizationEvent, FALSE);  
  615.     KeInitializeEvent(&pNewFileObject->Event, NotificationEvent, FALSE);  
  616.   
  617.     ntStatus = SeCreateAccessState(&AccessState, &AuxData, FILE_ALL_ACCESS, IoGetFileObjectGenericMapping());  
  618.     if (!NT_SUCCESS(ntStatus))  
  619.     {  
  620.         IoFreeIrp(pIrp);  
  621.         ObDereferenceObject(pNewFileObject);  
  622.         return ntStatus;  
  623.     }  
  624.   
  625.   
  626.     SecurityContext.SecurityQos = NULL;  
  627.     SecurityContext.AccessState = &AccessState;       
  628.     SecurityContext.DesiredAccess = DesiredAccess; //FILE_ALL_ACCESS;       // DELETE  
  629.     SecurityContext.FullCreateOptions = 0;  
  630.   
  631.     pIrp->MdlAddress = NULL;  
  632.     pIrp->AssociatedIrp.SystemBuffer = NULL;  
  633.     pIrp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API;  
  634.     pIrp->RequestorMode = KernelMode;  
  635.     pIrp->UserIosb = pIoStatusBlock;  
  636.     pIrp->UserEvent = &kEvent;  
  637.     pIrp->PendingReturned = FALSE;  
  638.     pIrp->Cancel = FALSE;  
  639.     pIrp->CancelRoutine = NULL;  
  640.     pIrp->Tail.Overlay.Thread = PsGetCurrentThread();  
  641.     pIrp->Tail.Overlay.AuxiliaryBuffer = NULL;  
  642.     pIrp->Tail.Overlay.OriginalFileObject = pNewFileObject;  
  643.   
  644.     IrpSp = IoGetNextIrpStackLocation(pIrp);  
  645.     IrpSp->MajorFunction = IRP_MJ_CREATE;  
  646.     IrpSp->DeviceObject = pDeviceObject;  
  647.     IrpSp->FileObject = pNewFileObject;  
  648.     IrpSp->Parameters.Create.SecurityContext = &SecurityContext;  
  649.     IrpSp->Parameters.Create.Options = (FILE_OPEN_IF << 24) | 0;  
  650.     IrpSp->Parameters.Create.FileAttributes = (USHORT)FILE_ATTRIBUTE_NORMAL;  
  651.     IrpSp->Parameters.Create.ShareAccess = NULL; //(USHORT)FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;  
  652.     IrpSp->Parameters.Create.EaLength = 0;  
  653.   
  654.     IoSetCompletionRoutine(pIrp, IoCompletionRoutineEx, 0, TRUE, TRUE, TRUE);  
  655.     ntStatus = IoCallDriver(pDeviceObject, pIrp);  
  656.     if (ntStatus == STATUS_PENDING)  
  657.         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);  
  658.     ntStatus = pIoStatusBlock->Status;  
  659.   
  660.     if (!NT_SUCCESS(ntStatus))  
  661.     {  
  662.         pNewFileObject->DeviceObject = NULL;  
  663.         ObDereferenceObject(pNewFileObject);  
  664.     }  
  665.     else  
  666.     {  
  667.         //设置变量  
  668.         InterlockedIncrement(&pNewFileObject->DeviceObject->ReferenceCount);  
  669.         if (pNewFileObject->Vpb)  
  670.             InterlockedIncrement(&pNewFileObject->Vpb->ReferenceCount);  
  671.         *pFileObject = pNewFileObject;  
  672.   
  673.         //ObDereferenceObject(CreateFileObject);  
  674.     }  
  675.   
  676.     return ntStatus;  
  677. }  
  678.   
  679. //IRP读取文件  
  680. NTSTATUS IrpReadFile(PFILE_OBJECT pFileObject,PLARGE_INTEGER pByteOffset,ULONG Length,PVOID pBuffer,PIO_STATUS_BLOCK pIoStatusBlock)  
  681. {  
  682.     //定义变量  
  683.     PDEVICE_OBJECT DeviceObject;  
  684.     PIRP pirp;  
  685.     PIO_STACK_LOCATION irpSp;  
  686.     KEVENT event;  
  687.     NTSTATUS status;  
  688.   
  689.   
  690.     //参数效验  
  691.     if (pFileObject == NULL|| pByteOffset ==NULL || Length<=0 || pBuffer ==NULL|| pIoStatusBlock==NULL)return STATUS_INVALID_PARAMETER;  
  692.       
  693.     //获取原始设备对象  
  694.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  695.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  696.   
  697.     //分配IRP  
  698.     pirp = IoAllocateIrp(DeviceObject->StackSize, FALSE);  
  699.     if (pirp == NULL)return STATUS_INSUFFICIENT_RESOURCES;  
  700.   
  701.     //分配MDL  
  702.     pirp->MdlAddress = IoAllocateMdl(pBuffer, Length, FALSE, FALSE, NULL);  
  703.     if (pirp->MdlAddress == NULL)  
  704.     {  
  705.         IoFreeIrp(pirp);  
  706.         return STATUS_INSUFFICIENT_RESOURCES;;  
  707.     }  
  708.     //更新MDL  
  709.     MmBuildMdlForNonPagedPool(pirp->MdlAddress);  
  710.   
  711.     pirp->Flags = IRP_READ_OPERATION;  
  712.     pirp->RequestorMode = KernelMode;  
  713.     pirp->UserIosb = pIoStatusBlock;  
  714.     pirp->UserEvent = &event;  
  715.     pirp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();  
  716.     pirp->Tail.Overlay.OriginalFileObject = pFileObject;  
  717.   
  718.     irpSp = IoGetNextIrpStackLocation(pirp);  
  719.     irpSp->MajorFunction = IRP_MJ_READ;  
  720.     irpSp->MinorFunction = IRP_MN_NORMAL;  
  721.     irpSp->DeviceObject = DeviceObject;  
  722.     irpSp->FileObject = pFileObject;  
  723.     irpSp->Parameters.Read.Length = Length;  
  724.     irpSp->Parameters.Read.ByteOffset = *pByteOffset;  
  725.   
  726.     KeInitializeEvent(&event, SynchronizationEvent, FALSE);  
  727.     IoSetCompletionRoutine(pirp, IoCompletionRoutineEx, NULL, TRUE, TRUE, TRUE);  
  728.     status = IoCallDriver(DeviceObject, pirp);  
  729.     if (status == STATUS_PENDING)  
  730.         status = KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, NULL);  
  731.     status = pIoStatusBlock->Status;  
  732.     return status;  
  733. }  
  734.   
  735. //复制文件  
  736. NTSTATUS CopyFileEx(PUNICODE_STRING lpExistingFileName, PUNICODE_STRING lpNewFileName)  
  737. {  
  738.     //定义变量  
  739.     NTSTATUS Status = STATUS_UNSUCCESSFUL;  
  740.     OBJECT_ATTRIBUTES ObAttr = { 0 };  
  741.     HANDLE hFileSource = NULL;  
  742.     HANDLE hFileDest = NULL;  
  743.     IO_STATUS_BLOCK IoStatus = { 0 };  
  744.     char* pBuff = NULL;  
  745.     ULONG Leng = 0;  
  746.     LARGE_INTEGER Offset = { 0 };  
  747.   
  748.     //参数效验  
  749.     if (lpExistingFileName == NULL || lpExistingFileName->Length <= 0 || lpNewFileName == NULL || lpNewFileName->Length <= 0)return STATUS_INVALID_PARAMETER;  
  750.       
  751.   
  752.     do  
  753.     {  
  754.         pBuff = ExAllocatePool(PagedPool, PAGE_SIZE);  
  755.         if (pBuff == NULL)break;  
  756.   
  757.         InitializeObjectAttributes(&ObAttr, lpExistingFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);  
  758.         Status = ZwOpenFile(&hFileSource, FILE_READ_DATA, &ObAttr, &IoStatus, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT);  
  759.         if (!NT_SUCCESS(Status))  
  760.         {  
  761.             hFileDest = NULL;  
  762.             break;  
  763.         }  
  764.   
  765.         InitializeObjectAttributes(&ObAttr, lpNewFileName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);  
  766.         Status = ZwCreateFile(&hFileDest, GENERIC_WRITE, &ObAttr, &IoStatus, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);  
  767.         if (NT_SUCCESS(Status))  
  768.         {  
  769.             hFileDest = NULL;  
  770.             break;  
  771.         }  
  772.   
  773.         do  
  774.         {  
  775.             Status = ZwReadFile(hFileSource, NULL, NULL, NULL, &IoStatus, pBuff, PAGE_SIZE, &Offset, NULL);  
  776.             if (NT_ERROR(Status))  
  777.             {  
  778.                 if (STATUS_END_OF_FILE == Status)  
  779.                 {  
  780.                     Status = STATUS_SUCCESS;  
  781.                 }  
  782.                 break;  
  783.             }  
  784.             Leng = (ULONG)IoStatus.Information;  
  785.             Status = ZwWriteFile(hFileDest, NULL, NULL, NULL, &IoStatus, pBuff, Leng, &Offset, NULL);  
  786.             if (Leng != IoStatus.Information)  
  787.             {  
  788.                 Status = STATUS_UNSUCCESSFUL;  
  789.                 break;  
  790.             }  
  791.             Offset.QuadPart += IoStatus.Information;  
  792.         } while (NT_SUCCESS(Status));  
  793.   
  794.     } while (FALSE);  
  795.   
  796.   
  797.   
  798.     if (pBuff)  
  799.     {  
  800.         ExFreePool(pBuff);  
  801.         pBuff = NULL;  
  802.     }  
  803.   
  804.     if (hFileSource)  
  805.     {  
  806.         ZwClose(hFileSource);  
  807.         hFileSource = NULL;  
  808.     }  
  809.   
  810.     if (hFileDest)  
  811.     {  
  812.         ZwClose(hFileDest);  
  813.         hFileDest = NULL;  
  814.     }  
  815.   
  816.     return Status;  
  817. }  
  818.   
  819. //IRP关闭文件  
  820. NTSTATUS IrpClose(PFILE_OBJECT  pFileObject)  
  821. {  
  822.     //定义变量  
  823.     PDEVICE_OBJECT DeviceObject;  
  824.     NTSTATUS ntStatus;  
  825.     IO_STATUS_BLOCK  IoStatusBlock;  
  826.     PIRP pIrp;  
  827.     KEVENT kEvent;  
  828.     PIO_STACK_LOCATION IrpSp;  
  829.   
  830.     //参数效验  
  831.     if (pFileObject == NULL)return STATUS_INVALID_PARAMETER;  
  832.   
  833.     //获取原始设备对象  
  834.     DeviceObject = IoGetRelatedDeviceObject(pFileObject);  
  835.     if (DeviceObject == NULL || DeviceObject->StackSize <= 0)return STATUS_UNSUCCESSFUL;  
  836.   
  837.     //分配IRP  
  838.     pIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);  
  839.     if (pIrp == NULL)return STATUS_INSUFFICIENT_RESOURCES;  
  840.   
  841.   
  842.     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);  
  843.     pIrp->UserEvent = &kEvent;  
  844.     pIrp->UserIosb = &IoStatusBlock;  
  845.     pIrp->RequestorMode = KernelMode;  
  846.     pIrp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;  
  847.     pIrp->Tail.Overlay.Thread = PsGetCurrentThread();  
  848.     pIrp->Tail.Overlay.OriginalFileObject = pFileObject;  
  849.   
  850.     IrpSp = IoGetNextIrpStackLocation(pIrp);  
  851.     IrpSp->MajorFunction = IRP_MJ_CLEANUP;  
  852.     IrpSp->FileObject = pFileObject;  
  853.   
  854.     ntStatus = IoCallDriver(DeviceObject, pIrp);  
  855.     if (ntStatus == STATUS_PENDING)  
  856.         KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);  
  857.   
  858.     ntStatus = IoStatusBlock.Status;  
  859.     if (!NT_SUCCESS(ntStatus))  
  860.     {  
  861.         IoFreeIrp(pIrp);  
  862.         return ntStatus;  
  863.     }  
  864.   
  865.     KeClearEvent(&kEvent);  
  866.     IoReuseIrp(pIrp, STATUS_SUCCESS);  
  867.   
  868.     pIrp->UserEvent = &kEvent;  
  869.     pIrp->UserIosb = &IoStatusBlock;  
  870.     pIrp->Tail.Overlay.OriginalFileObject = pFileObject;  
  871.     pIrp->Tail.Overlay.Thread = PsGetCurrentThread();  
  872.     pIrp->AssociatedIrp.SystemBuffer = (PVOID)NULL;  
  873.     pIrp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;  
  874.   
  875.     IrpSp = IoGetNextIrpStackLocation(pIrp);  
  876.     IrpSp->MajorFunction = IRP_MJ_CLOSE;  
  877.     IrpSp->FileObject = pFileObject;  
  878.   
  879.     if (pFileObject->Vpb && !(pFileObject->Flags & FO_DIRECT_DEVICE_OPEN))  
  880.     {  
  881.         InterlockedDecrement(&pFileObject->Vpb->ReferenceCount);  
  882.         pFileObject->Flags |= FO_FILE_OPEN_CANCELLED;  
  883.     }  
  884.   
  885.     ntStatus = IoCallDriver(DeviceObject, pIrp);  
  886.     if (ntStatus == STATUS_PENDING)  
  887.         KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);  
  888.   
  889.     IoFreeIrp(pIrp);  
  890.   
  891.     ntStatus = IoStatusBlock.Status;  
  892.     return ntStatus;  
  893.   
  894. }  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值