原理:

用ZwQuerySystemInformation 功能号为11(SystemModuleInformation)  得到所有系统模块的地址 遍历搜索得到ntos模块的基地址

读Ntos模块到System进程空间中

在ntos中找到函数真正地址

将地址转换为ssdt的索引

//X64版本
#include "ResumeSSDTHook.h" #define SEC_IMAGE 0x1000000 PVOID __NtosModuleBaseAddress = NULL;
ULONG64 __NtosModuleLength = ;
PVOID __SSDTAddress = ;
ULONG32 __NtOpenProcessIndex = ; NTSTATUS
DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegisterPath)
{
PDEVICE_OBJECT DeviceObject;
NTSTATUS Status;
int i = ;
char FunctionName[] = "NtOpenProcess";
char ModuleName[] = "ntoskrnl.exe"; UNICODE_STRING DeviceName;
UNICODE_STRING LinkName; RtlInitUnicodeString(&DeviceName,DEVICE_NAME);
RtlInitUnicodeString(&LinkName,LINK_NAME); //创建设备对象; Status = IoCreateDevice(DriverObject,,
&DeviceName,FILE_DEVICE_UNKNOWN,,FALSE,&DeviceObject);
if (!NT_SUCCESS(Status))
{
return Status;
} Status = IoCreateSymbolicLink(&LinkName,&DeviceName); for (i = ; i<IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DriverObject->MajorFunction[i] = DefaultPassThrough;
} DriverObject->DriverUnload = UnloadDriver;
//得Ntos
if (GetSystemMoudleInfoBySystemModuleName(ModuleName,
&__NtosModuleBaseAddress, &__NtosModuleLength) == FALSE)
{
return Status;
} DbgPrint("Win7 Ntos模块地址:%p\r\n", __NtosModuleBaseAddress);
DbgPrint("Win7 Ntos模块大小:%x\r\n", __NtosModuleLength);
//得ssdt
if (GetSSDTAddress(&__SSDTAddress) == FALSE)
{
return Status;
}
DbgPrint("Win7 SSDT地址:%p\r\n", __SSDTAddress);
//得需要hook的函数的索引
if (GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(FunctionName,
&__NtOpenProcessIndex) == FALSE)
{
return STATUS_UNSUCCESSFUL;
}
DbgPrint("Win7 __NtOpenProcessIndex地址:%d\r\n", __NtOpenProcessIndex); //
if (ResumeSSDT(__SSDTAddress, __NtosModuleBaseAddress, __NtOpenProcessIndex, ) == TRUE)
{
DbgPrint("恢复成功\r\n");
} #ifdef WIN64
DbgPrint("WIN64: ResumeSSDTHook IS RUNNING!!!");
#else
DbgPrint("WIN32: ResumeSSDTHook SIS RUNNING!!!"); #endif return STATUS_SUCCESS;
} NTSTATUS
DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = ;
IoCompleteRequest(Irp,IO_NO_INCREMENT); return STATUS_SUCCESS;
} VOID
UnloadDriver(PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING LinkName;
PDEVICE_OBJECT NextDeviceObject = NULL;
PDEVICE_OBJECT CurrentDeviceObject = NULL;
RtlInitUnicodeString(&LinkName,LINK_NAME); IoDeleteSymbolicLink(&LinkName);
CurrentDeviceObject = DriverObject->DeviceObject;
while (CurrentDeviceObject != NULL)
{ NextDeviceObject = CurrentDeviceObject->NextDevice;
IoDeleteDevice(CurrentDeviceObject);
CurrentDeviceObject = NextDeviceObject;
} DbgPrint("ResumeSSDTHook IS STOPPED!!!");
} BOOLEAN GetSystemMoudleInfoBySystemModuleName(char* ModuleName,
PVOID* ModuleBase, ULONG64* ModuleLength)
{
int i = ;
NTSTATUS Status = STATUS_SUCCESS;
PVOID BufferData = NULL;
ULONG ReturnLength = ;
//功能号为11,先获取所需的缓冲区大小 得大小
Status = ZwQuerySystemInformation(SystemModuleInformation, NULL, , &ReturnLength); //SSDT
if (Status != STATUS_INFO_LENGTH_MISMATCH) //没有内存
{
return FALSE;
} //申请内存
BufferData = ExAllocatePool(PagedPool, ReturnLength); //PagedPool(数据段 置换到磁盘) NonPagedPool(代码段 不置换到磁盘) if (BufferData == NULL)
{
return FALSE;
} //再次调用 得数据
Status = ZwQuerySystemInformation(SystemModuleInformation, BufferData, ReturnLength, &ReturnLength);
if (!NT_SUCCESS(Status))
{
ExFreePool(BufferData);
return FALSE;
} for (i = ; i < ((PSYSTEM_MODULES_INFO)BufferData)->NumberOfModules; i++)
{
if (strstr(((PSYSTEM_MODULES_INFO)BufferData)->Modules[i].ModuleFullPathData,
ModuleName) != NULL) //Ntoskernel.exe
{
*ModuleBase = ((PSYSTEM_MODULES_INFO)BufferData)->Modules[i].ModuleBase;
*ModuleLength = ((PSYSTEM_MODULES_INFO)BufferData)->Modules[i].ModuleLength; if (BufferData != NULL)
{
ExFreePool(BufferData);
BufferData = NULL;
}
return TRUE;
}
}
if (BufferData != NULL)
{
ExFreePool(BufferData);
BufferData = NULL;
} return FALSE;
} BOOLEAN ResumeSSDT(ULONG64 SSDTAddress, ULONG64 ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount)
{
int i = ;
PUINT8 RVAOfSSDT = ;
WCHAR FileFullPathData[] = L"\\SystemRoot\\System32\\ntoskrnl.exe";
PIMAGE_DOS_HEADER DosHeader = NULL;
PIMAGE_NT_HEADERS NtHeader = NULL;
PIMAGE_OPTIONAL_HEADER OptionalHeader = NULL;
PIMAGE_SECTION_HEADER SectionHeader = NULL;
PVOID PresupporseImageBase = ; //优先加载地址
PVOID BaseOfSSDTInFile = ; //文件基地址
PVOID v1 = ; //函数真正地址
ULONG32 v2 = ; //SSDT[Offset]
char v3;
CHAR Bits[] = { }; PVOID BufferData = NULL;
//获得SSDT与ntos模块基地址RVA
RVAOfSSDT = ((PUINT8)(((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0)) - (PUINT8)ModuleBase; //读Ntos模块到System进程空间中 (FileAlign)
if (ReadingFileInRing0Space(FileFullPathData, &BufferData) == FALSE)
{
return FALSE;
} DosHeader = (PIMAGE_DOS_HEADER)BufferData;
NtHeader = (PIMAGE_NT_HEADERS)(DosHeader->e_lfanew + (PUINT8)BufferData);
OptionalHeader = &(NtHeader->OptionalHeader);
PresupporseImageBase = OptionalHeader->ImageBase; //优先加载的地址 SectionHeader = (PIMAGE_SECTION_HEADER)((PUINT8)NtHeader + sizeof(IMAGE_NT_HEADERS)); for (i = ; i<NtHeader->FileHeader.NumberOfSections; i++)
{
if (RVAOfSSDT >= SectionHeader[i].VirtualAddress && RVAOfSSDT <
(SectionHeader[i].VirtualAddress + SectionHeader[i].SizeOfRawData))
{
//SSDT的文件偏移
BaseOfSSDTInFile = (PVOID)((PUINT8)BufferData + (RVAOfSSDT - (PUINT8)(SectionHeader[i].VirtualAddress)) + SectionHeader[i].PointerToRawData);
break;
}
} //NtOpenProcess 文件中ssdt索引对应的函数地址 - 模块加载基地址 + ntos模块的基地址
v1 = (PUINT8)(((PULONG64)BaseOfSSDTInFile)[SSDTFunctionIndex]) - (PUINT8)PresupporseImageBase + (PUINT8)ModuleBase;
//偏移
v1 = (PUINT8)v1 - (PUINT8)(((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0);
v1 = (ULONG32)v1 << ; //处理参数个数
if (ParameterCount>)
{
ParameterCount = ParameterCount - ;
}
else
{
ParameterCount = ;
} //处理低四位,填写参数个数 如果一个函数的参数为5 那么dwTemp的低4位就是 0001 如果参数是6 就是0002 因为 6要减4
#define SETBIT(x,y) x|=(1<<y) //将X的第Y位置1
#define CLRBIT(x,y) x&=~(1<<y) //将X的第Y位清0
#define GETBIT(x,y) (x & (1 << y)) //取X的第Y位,返回0或非0 memcpy(&v3, &v1, );
for (i = ; i<; i++) //一个16进制 4个二进制 0000
{
Bits[i] = GETBIT(ParameterCount, i);
if (Bits[i])
{
SETBIT(v3, i);
}
else
{
CLRBIT(v3, i);
}
}
memcpy(&v1, &v3, ); //获得真实的数据了 //获得当前的数据
v2 = ((PULONG32)(((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0))[SSDTFunctionIndex];
if (v1 != v2)
{
WPOFF();
((PULONG32)(((PSERVER_SERVICE_DESCRIPTOR_TABLE)SSDTAddress)->Unknow0))[SSDTFunctionIndex] = (ULONG32)v1;
WPON();
} if (BufferData != NULL)
{
ExFreePool(BufferData);
BufferData = NULL;
}
return TRUE;
} VOID WPOFF()
{
_disable();
__writecr0(__readcr0() & (~(0x10000))); }
VOID WPON()
{
__writecr0(__readcr0() ^ 0x10000);
_enable();
} BOOLEAN GetSSDTAddress(ULONG64* SSDTAddress)
{
//kd> rdmsr c0000082
PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
PUCHAR EndSearchAddress = StartSearchAddress + PAGE_SIZE;
PUCHAR i = NULL;
UCHAR v1 = , v2 = , v3 = ;
INT64 Offset = ; //002320c7
ULONG64 VariableAddress = ;
*SSDTAddress = NULL;
for (i = StartSearchAddress; i < EndSearchAddress; i++)
{
if (MmIsAddressValid(i) && MmIsAddressValid(i + ) && MmIsAddressValid(i + ))
{
v1 = *i;
v2 = *(i + );
v3 = *(i + );
if (v1 == 0x4c && v2 == 0x8d && v3 == 0x15)
{
memcpy(&Offset, i + , );
*SSDTAddress = Offset + (ULONG64)i + ;
break;
}
}
}
//如果是Win32 导出表 搜索 KeServiceDescriptorTable
if (*SSDTAddress == NULL)
{
return FALSE;
} return TRUE;
}
BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(CHAR* FunctionName, ULONG32* SSDTFunctionIndex)
{
ULONG i;
BOOLEAN IsOk = FALSE;
WCHAR FileFullPath[] = L"\\SystemRoot\\System32\\ntdll.dll"; //C:\Windows\
SIZE_T MappingViewSize = ;
PVOID MappingBaseAddress = NULL;
PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
PIMAGE_NT_HEADERS NtHeader = NULL;
UINT32* AddressOfFunctions = NULL;
UINT32* AddressOfNames = NULL;
UINT16* AddressOfNameOrdinals = NULL;
CHAR* v1 = NULL;
ULONG32 FunctionOrdinal = ;
PVOID FunctionAddress = ;
ULONG32 Offset_SSDTFunctionIndex = ;
//将Ntdll.dll映射 当前的空间中 *SSDTFunctionIndex = -;
IsOk = MappingPEFileInRing0Space(FileFullPath, &MappingBaseAddress, &MappingViewSize);
if (IsOk == FALSE)
{
return FALSE;
}
else
{
__try {
NtHeader = RtlImageNtHeader(MappingBaseAddress); //extern
if (NtHeader && NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress)
{
ImageExportDirectory = (IMAGE_EXPORT_DIRECTORY*)((UINT8*)MappingBaseAddress +
NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); AddressOfFunctions = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfFunctions);
AddressOfNames = (UINT32*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNames);
AddressOfNameOrdinals = (UINT16*)((UINT8*)MappingBaseAddress + ImageExportDirectory->AddressOfNameOrdinals);
for (i = ; i < ImageExportDirectory->NumberOfNames; i++)
{
v1 = (char*)((ULONG64)MappingBaseAddress + AddressOfNames[i]); //获得函数名称
if (_stricmp(FunctionName, v1) == )
{
FunctionOrdinal = AddressOfNameOrdinals[i];
FunctionAddress = (PVOID)((UINT8*)MappingBaseAddress + AddressOfFunctions[FunctionOrdinal]); *SSDTFunctionIndex = *(ULONG32*)((UINT8*)FunctionAddress + Offset_SSDTFunctionIndex);
break;
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
;
}
} ZwUnmapViewOfSection(NtCurrentProcess(), MappingBaseAddress); //解除映射 if (*SSDTFunctionIndex == -)
{
return FALSE;
} return TRUE;
}
BOOLEAN MappingPEFileInRing0Space(WCHAR* FileFullPath, PVOID* MappingBaseAddress, PSIZE_T MappingViewSize)
{ NTSTATUS Status;
UNICODE_STRING v1;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle = NULL;
HANDLE SectionHandle = NULL; if (!FileFullPath &&MmIsAddressValid(FileFullPath))
{
return FALSE;
} if (!MappingBaseAddress&&MmIsAddressValid(MappingBaseAddress))
{
return FALSE;
} RtlInitUnicodeString(&v1, FileFullPath);
InitializeObjectAttributes(&ObjectAttributes,
&v1,
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
NULL,
NULL
); //获得文件句柄
Status = IoCreateFile(&FileHandle,
GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes, //文件绝对路径
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
,
CreateFileTypeNone,
NULL,
IO_NO_PARAMETER_CHECKING
);
if (!NT_SUCCESS(Status))
{
return FALSE;
} ObjectAttributes.ObjectName = NULL;
Status = ZwCreateSection(&SectionHandle,
SECTION_QUERY | SECTION_MAP_READ,
&ObjectAttributes,
NULL,
PAGE_WRITECOPY,
SEC_IMAGE, //内存对齐 0x1000
FileHandle
);
ZwClose(FileHandle);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
Status = ZwMapViewOfSection(SectionHandle,
NtCurrentProcess(), //映射到当前进程的内存空间中
MappingBaseAddress,
,
,
,
MappingViewSize,
ViewUnmap,
,
PAGE_WRITECOPY
);
ZwClose(SectionHandle);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
return TRUE;
}
BOOLEAN ReadingFileInRing0Space(WCHAR* FileFullPathData, PVOID* BufferData)
{ NTSTATUS Status;
LARGE_INTEGER ReturnLength = { , };
UNICODE_STRING v1;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandle;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION v2 = { };
if (FileFullPathData == NULL&&*BufferData != NULL)
{
return FALSE;
} RtlInitUnicodeString(&v1, FileFullPathData);
InitializeObjectAttributes(&ObjectAttributes, &v1, OBJ_CASE_INSENSITIVE, NULL, NULL); //获取文件句柄
Status = ZwCreateFile(&FileHandle,
SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
);
if (!NT_SUCCESS(Status))
{
return FALSE;
} //计算文件长度 Status = ZwQueryInformationFile(FileHandle,
&IoStatusBlock,
&v2,
sizeof(FILE_STANDARD_INFORMATION),
FileStandardInformation);
if (!NT_SUCCESS(Status))
{
ZwClose(FileHandle);
return FALSE;
} //动态申请内存
*BufferData = ExAllocatePool(PagedPool, v2.EndOfFile.LowPart);
if (*BufferData == NULL)
{
ZwClose(FileHandle);
return FALSE;
} //读取文件到内存 Status = ZwReadFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
*BufferData,
v2.EndOfFile.LowPart,
&ReturnLength,
NULL); if (!NT_SUCCESS(Status))
{
ExFreePool(*BufferData);
ZwClose(FileHandle);
return FALSE;
}
ZwClose(FileHandle); return TRUE;
}
#include <ntifs.h>
#include <ntimage.h>
#ifndef CXX_ResumeSSDTHook_H
#define CXX_ResumeSSDTHook_H #define DEVICE_NAME L"\\Device\\ResumeSSDTHookDevice"
#define LINK_NAME L"\\??\\ResumeSSDTHookLink"
#define SystemModuleInformation 0xB typedef struct SYSTEM_MODULE_INFO
{
UINT32 Unknow0[];
UINT64 ModuleBase;
UINT32 ModuleLength;
UINT32 Flags;
UINT64 Unknow1;
char ModuleFullPathData[];
} SYSTEM_MODULE_INFO, *PSYSTEM_MODULE_INFO; typedef struct _SYSTEM_MODULES_INFO
{
UINT32 NumberOfModules;
SYSTEM_MODULE_INFO Modules[];
}SYSTEM_MODULES_INFO, *PSYSTEM_MODULES_INFO; typedef struct _SERVER_SERVICE_DESCRIPTOR_TABLE_
{
PVOID Unknow0;
PVOID Unknow1;
PVOID Unknow2;
PVOID Unknow3;
}SERVER_SERVICE_DESCRIPTOR_TABLE, *PSERVER_SERVICE_DESCRIPTOR_TABLE; extern
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(PVOID BaseAddress); extern
NTSTATUS
ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength); VOID
UnloadDriver(PDRIVER_OBJECT DriverObject); BOOLEAN GetSystemMoudleInfoBySystemModuleName(char * ModuleName, PVOID * ModuleBase, ULONG64 * ModuleLength); BOOLEAN ResumeSSDT(ULONG64 SSDTAddress, ULONG64 ModuleBase, ULONG32 SSDTFunctionIndex, ULONG32 ParameterCount); VOID WPOFF(); VOID WPON(); BOOLEAN GetSSDTAddress(ULONG64 * SSDTAddress); BOOLEAN GetSSDTFunctionIndexFromNtdllExportTableByFunctionName(CHAR * FunctionName, ULONG32 * SSDTFunctionIndex); BOOLEAN MappingPEFileInRing0Space(WCHAR * FileFullPath, PVOID * MappingBaseAddress, PSIZE_T MappingViewSize); BOOLEAN ReadingFileInRing0Space(WCHAR * FileFullPathData, PVOID * BufferData); NTSTATUS
DefaultPassThrough(PDEVICE_OBJECT DeviceObject,PIRP Irp); #endif

ring0 恢复SSDTHook的更多相关文章

  1. ring0 关于SSDTHook使用的绕过页面写保护的原理与实现

    原博:http://www.cnblogs.com/hongfei/archive/2013/06/18/3142162.html 为了安全起见,Windows XP及其以后的系统将一些重要的内存页设 ...

  2. ring0 SSDTHook

    SSDT 的全称是 System Services Descriptor Table,系统服务描述符表.这个表就是一个把 Ring3 的 Win32 API 和 Ring0 的内核 API 联系起来. ...

  3. ring0 SSDTHook 实现x64/x86

    #include "HookSSDT.h" #include <ntimage.h> #define SEC_IMAGE 0x001000000 ULONG32 __N ...

  4. SSDTHook实例--编写稳定的Hook过滤函数

    解说怎样写Hook过滤函数,比方NewZwOpenProcess.打开进程. 非常多游戏保护都会对这个函数进行Hook. 因为我们没有游戏保护的代码,无法得知游戏公司是怎样编写这个过滤函数. 我看到非 ...

  5. ring0 与 ring3 层之间的交互

    在进行Windows的ring0层开发时,必不可免的要与 ring3 层进行交互.进行数据间的相互传输.可用的方法有DeviceIoCntrol,ReadFile.我平常都是用的DeviceIoCon ...

  6. RING0到RING3

    在前一篇文章里面,我们将了CPU保护模式中的几种特权RING0,RING1,RING2,RING3!操作系统通常运行在RING0,应用程序通常运行在RING3. CPU如何从RING0到RING3 先 ...

  7. 64位内核开发第十二讲,进程监视,ring3跟ring0事件同步.

    一丶同步与互斥详解,以及实现一个进程监视软件. 1.用于线程同步的 KEVENT 事件很简单分别分为 事件状态. 以及事件类别. 事件状态: 有信号 Signaled 无信号 Non-signaled ...

  8. X86驱动:恢复SSDT内核钩子

    SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用 ...

  9. Hook集合----SSDTHook(x86 Win7)

    最近在学习Ring0层Hook的一些知识点,很久就写完SSDTHook的代码了,但是一直没有整理成笔记,最近有时间也就整理整理. 介绍: SSDTHook 实质是利用Ntoskrnl.exe 中全局导 ...

随机推荐

  1. shopNC开发手册

    链接:   https://wenku.baidu.com/view/b9232d24dd3383c4bb4cd2c9.html https://wenku.baidu.com/view/ff1566 ...

  2. follow Up — 20181101

    406. Minimum Size Subarray Sum public class Solution { /** * @param nums: an array of integers * @pa ...

  3. Macbook使用Gitlab配置SSH Key

    git是分布式代码管理工具,远程代码管理是基于ssh的,代码上传大搜gitlab或者github代码仓储时,需要进行ssh配置. 把本地代码上传到服务器时需要加密处理,git中公钥(id_rsa.pu ...

  4. PIE SDK与Matlab结合说明文档

    1.功能简介 Matlab是三大数学软件之一,它在数学类科技应用软件中在数值计算方面首屈一指.Matlab可以进行矩阵运算.绘制函数和数据.实现算法.创建用户界面.连接其他编程语言的程序等,主要应用于 ...

  5. Transform 引起的 z-index "失效"

    重新学习CSS后的第三天,学习制作阴影的过程中,发现的问题:设置了box-shadow后展现的阴影: 添加transform:rotate(10deg);后的效果: 查看CodePen例子:阴影效果 ...

  6. stream4

    import java.util.Comparator; import java.util.function.BinaryOperator; public class BinaryOperatorTe ...

  7. GCD - Extreme(欧拉函数变形)

    题目链接:https://vjudge.net/problem/UVA-11426 题目大意: 给出整数n∈[2,4000000],求解∑gcd(i,j),其中(i,j)满足1≤i<j≤n. 的 ...

  8. ExcelHelper office 导出

    要是服务器上没有装着excel 可以用c#导出excel表吗 2009-08-10 17:36 风之成 | 分类:办公软件 | 浏览2279次 租用的空间 服务器上没有装着office excel,可 ...

  9. 求大神帮忙解决一下c#winfrom bindingNavigatorPositionItem加载直接跳转问题

    c# winfrom bindingNavigatorPositionItem控件问题加载直接跳转到相对应的行的问题

  10. CssClass初步语法了解

    首先 创建Css有三种方法  这里面就不一一介绍了,主要说第二种 创建第二种Css样式表  要在标签<title><title>标签下面写 如: <style type= ...