內核態進程管理器Intercessor和實現細節

內核態進程管理器Intercessor和實現細節

1087人閱讀 評論(0) 收藏 舉報
標 題: 【原創】內核態進程管理器Intercessor和實現細節
作 者: greatcsk
時 間: 2007-09-05,20:20
鏈 接: http://bbs.pediy.com/showthread.php?t=51157

BLOG原文:http://www.csksoft.net/blog/post/Intercessor_taskmgr.html
相關文件:

已經修改下載地址
下載地址:http://www.csksoft.net/Intercessor_report_src_bin.rar
由於文件太大,無法作爲附件提供,抱歉




原理和核心驅動代碼下載:ftp://FTP_Visitor:[email protected]/Public/Products/APP/Intercessor_report_src_bin.rar
---------------------------------------------------------------------------------------------
上學期windows高級操作系統作的大作業,主要對於枚舉進程採用直接掃描EPROCESS的辦法,也用到了Hook SSDT技術。所以有一定參考價值,同時工具本身也有其實用價值。

先介紹基本情況:
軟件畫面:
http://www.csksoft.net/BlogData/pic/intercessor_main.png
下表列出了本軟件中已實現的功能:
  • 顯示進程模塊 ?
  • CPU使用率統計 ?
  • 內核進程描述 ?
  • 內核態下實現進程的監控 ?
  • 禁止系統運行某個可執行文件
  • 進程創建或者退出自動刷新進程列表 ?
  • 強制進程結束,通過直接調用NtTerminateProcess實現
  • 防止自身非法關閉或調試 ?
  • 搜索隱藏進程,可以探測多種隱藏技術
  • 顯示進程EPROCESS地址
  • 顯示當前進程內存與虛擬內存
  • 顯示與設置進程優先級別
  • 顯示當前進程的版本信息以及詳細屬性
  • 藍色突出顯示隱藏進程



下面是簡要的一些原理分析,對於具體的描述,參見原理和核心驅動代碼下載給出的文檔,裏面有我當時寫的報告,那個比較詳細
當然其中很多技術不是我創造的,所以先向各位前輩們致謝!

直接內存搜索枚舉內存的原理和實現
在5.x的內核中,進程的EPROCESS往往存放於MmSystemRangeStart至System所屬EPROCESS地址之間。
其中MmSystemRangeStart是一個內核導出的常量,在32位標準內存模式下,他的值爲0x80000000,而在PAE模式的系統中, 這個值爲0xC0000000。對於System所屬EPROCESS地址,可以通過驅動加載時PsGetCurrentProcess()獲取,因爲驅 動的加載任務是在system進程中完成的。
在上述區間的具體取值確定下來後,接着就是要確定是否某一塊內存片斷是一個有效的EPROCESS結構。
在此首先需要確定EPROCESS在當前系統的表示。可以使用WinDbg的如下命令獲取:
lkd>dt _eprocess

下面摘錄winXP環境中EPROCESS的定義片斷 :
nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x06c ProcessLock : _EX_PUSH_LOCK
+0x070 CreateTime : _LARGE_INTEGER
+0x078 ExitTime : _LARGE_INTEGER
+0x080 RundownProtect : _EX_RUNDOWN_REF
+0x084 UniqueProcessId : Ptr32 Void
+0x088 ActiveProcessLinks : _LIST_ENTRY
+0x090 QuotaUsage : [3] Uint4B
+0x09c QuotaPeak : [3] Uint4B
//…
結構片斷:EPROCESS的定義

這個結構在WinXP中的大小是0x25C,可以從上面的代碼片斷中看出,許多信息,比如創建等都可以直接在這個結構體中獲取。
爲了驗證一個EPROCESS是否合法,需要考慮下面幾個字段的數據:
+0x078 ExitTime : _LARGE_INTEGER
+0x1b0 Peb : Ptr32 _PEB

中,ExitTime記錄了該進程的退出時間。對於正在運行的進程,該項屬性將永遠爲0。Peb指向進程環境塊的指針,在所有EPROCESS中,該數據區的高16位應該相同。
除了這2項判斷依據外,還可以根據包裝EPROCESS的OBJECT_HEADER結構來作出判斷。OBJECT_HEADER結構的定義如下:
nt!_OBJECT_HEADER
+0x000 PointerCount : Int4B
+0x004 HandleCount : Int4B
+0x004 NextToFree : Ptr32 Void
+0x008 Type : Ptr32 _OBJECT_TYPE
+0x00c NameInfoOffset : UChar
+0x00d HandleInfoOffset : UChar
+0x00e QuotaInfoOffset : UChar
+0x00f Flags : UChar
+0x010 ObjectCreateInfo : Ptr32 _OBJECT_CREATE_INFORMATION
+0x010 QuotaBlockCharged : Ptr32 Void
+0x014 SecurityDescriptor : Ptr32 Void
+0x018 Body : _QUAD
結構定義:OBJECT_HEADER
這個結構表示了一個內核對象,他出現於任何內核對象結構的頭部,也包括了EPROCESS頭部。其中我們感興趣的數據域是:
+0x008 Type : Ptr32 _OBJECT_TYPE

該指針指向了一個標示對象類別的結構體,所有EPROCESS結構外層的OBJECT_HEADER結構中,這項屬性值應該相同。

通過上述分析,通過搜索內存枚舉進程的流程如下:
1) 從MmSystemRangeStart至SYSTEM進程EPROCESS地址依次搜索
2) 將當前地址賦值給一個EPROCESS對象,將其中相關的數據域加以驗證
3) 如果是合法EPROCESS,則將其地址填入結果,同時控制搜索從當前位置+sizeof(EPROCESS)開始
4) 繼續下一次循環

以上方法還需要做的處理是:
? 獲取一個標準的PEB指針,作爲對照
? 獲取一個標準的OBJECT_TYPE指針,作爲對照
? 由於MmSystemRangeStart開始的內存並非連續的未分頁內存,也就是說其地址空間並不是連續的,因而直接循環掃描將出現缺頁錯誤,導致系統藍屏崩潰。

由於目前system的eprocess地址是已知的,很自然的想法便是通過system eprocess中的數據作爲對照數據。其中,OBJECT_TYPE指針的確可以如此獲取,然後對於PEB指針,在system eprocess中卻爲空值。
解決辦法是通過eprocess中的ActiveProcessLinks數據域得到由system eprocess指向的第一個eprocess地址,然後獲取其中的PEB數據。
對於第三個問題,解決辦法是通過查找頁表方式,嘗試對當前虛擬地址查找其對應的PGDE和PTE表,如果找到,則表示該內存地址有效。如果無效,則跳過一定的長度搜索。
對於標準的內存模式,PGDE和PTE如下圖所示:
PDE_1.gif
圖:標準內存模式下頁表分佈

圖中的Page Directory表存放於虛擬地址0xc0300000處,而每個Page Table緊跟於Page Directory表後存儲。因而可以通過上述佈局查找頁表。
然而對於PAE模式,頁表的表示方式以及存儲方位均不同於標準模式,因而需要用其他方法獲取,具體見下一節。
在解決上述問題後,進程枚舉便可以工作了,但通過該算法僅能獲得除了SYSTEM和IDLE外的進程,對於PID爲0和4(win2000中爲8)的這2個核心進程,需要用其他方法獲取。
對於SYSTEM進程,上文給出獲取方法,而Idle Process進程需要用下面給出的辦法:

獲取Idle Process的EPROCESS地址
在5.x內核虛擬地址0xFFDFF000位置存放的稱爲Processor Control Region(KPCR)的結構,通過WinDbg獲取他的結構描述爲:
nt!_KPCR
+0x000 NtTib : _NT_TIB
+0x01c SelfPcr : Ptr32 _KPCR
+0x020 Prcb : Ptr32 _KPRCB
+0x024 Irql : UChar
+0x028 IRR : Uint4B
+0x02c IrrActive : Uint4B
+0x030 IDR : Uint4B
………
結構片段:KPCR

其中,Prcb指向的KPRCB結構片段如下:
nt!_KPRCB
+0x000 MinorVersion : Uint2B
+0x002 MajorVersion : Uint2B
+0x004 CurrentThread : Ptr32 _KTHREAD
+0x008 NextThread : Ptr32 _KTHREAD
+0x00c IdleThread : Ptr32 _KTHREAD
+0x010 Number : Char
+0x011 Reserved : Char
………
結構片段:KPRCB

其中的CurrentThread指向了Idle Process線程的地址。分析KTHREAD結構,如下數據域是我們感興趣的:
+0x034 ApcState : _KAPC_STATE

他指向了KAPC_STATE結構,分析該結構,發現其中有如下數據域:
+0x010 Process : Ptr32 _KPROCESS

這是一個指向KPROCESS的指針,回顧前面給出的EPROCESS定義,發現這個結構就出現在EPROCESS的頭部,也就是說,Process指向了Idle Process的EPROCESS指針。
因而,只需要更具上述過程找到KAPC_STATE. Process的數據便獲取了Idle Process的EPROCESS指針。

對PAE環境的支持
在本軟件開發初期調試階段,發現直接內存掃描EPROCESS等方法無法在雙核機器上工作,後來得知windows自動爲雙核機器開啓了PAE(Physical Address Extension)模式。
對於開啓時PAE模式的系統,內核模塊將不再是以前的ntoskrnl.exe,而是ntkrpamp.exe或者其他。因而許多內核符號地址以及數據結構存放地址均有變化。
對於開啓了PAE模式的系統,其頁表爲如下結構:
PDE_2.gif
圖:PAE模式的頁表結構

同時頁表的存放地址變爲0xc0600000,對於上述的虛擬內存有效性檢測,需要作出修改才能適應PAE模式。
然而在本軟件中,採用了內核提供的MmIsAddressValid函數來判斷頁表。這樣可以直接避免PAE模式帶來的差異,也降低了程序的複雜程度。

防護進程非法關閉的實現
在執行進程的銷燬中,NtTerminateProcess函數起到了決定性作用。因而最直觀的想法就是對該函數進行Hook。同時判斷是否爲需要保護的進程,如果是則強制函數返回。
但是,NtTerminateProcess並沒有在5.x的內核中導出。因而直接獲取其入口地址進行inline hook的難度較大,且極容易受 到諸如內核補丁等的干擾。這裏採用的辦法是使用修改SSDT表中NtTerminateProcess入口的地址實現對該函數的Hook。
對於SSDT表,在內核中的導出符號爲:KeServiceDescriptorTable
其結構定義如下:
struct ServiceDescriptorEntry {
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase;
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}

其中ServiceTableBase爲一個指向對應系統調用號處理函數的數組。因而,我們需要作的就是首先獲取NtTerminateProcess的系統調用號,然後修改上述數組,將入口地址修改爲我們的Hook替換函數。
對於NtTerminateProcess的系統調用號,可以通過它的wrap函數ZwTerminateProcess進行分析:
; NTSTATUS __stdcall ZwTerminateProcess(HANDLE ProcessHandle,NTSTATUS ExitStatus)
public _ZwTerminateProcess@8
_ZwTerminateProcess@8 proc near

ProcessHandle= dword ptr 4
ExitStatus= dword ptr 8

mov eax, 101h
lea edx, [esp+ProcessHandle]
pushf
push 8
call _KiSystemService
retn 8

其中第一行mov eax,101h是我們感興趣的,101h這個值就是NtTerminateProcess的系統服務號。而ZwTerminateProcess是一個系統導出的符號。
通過分析規律,其他Zw開頭的wrap函數均以mov eax, i32 的形式開始,因而可以通過如下宏獲取任意Wrap函數對應目標函數的系統服務號:
#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)

今後的Hook操作便是對KeServiceDescriptorTable. ServiceTableBase[]進行查表和修改。

然而,即使在內核態,也無法直接對KeServiceDescriptorTable的數據進行修改,原因就是內核爲了保證SSDT被非法修改,已將 該段內存設爲了只讀模式。解決辦法是通過將該段內存映射到一段可寫入地址範圍。下面代碼通過創建MDL區段實現了該功能:
g_pmdlSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!g_pmdlSystemCall)
return;
MmBuildMdlForNonPagedPool(g_pmdlSystemCall);

今後,只需要對g_pmdlSystemCall指向的地址進行寫入操作即可。

接下來需要製作用於替換NtTerminateProcess的Hook函數,已知NtTerminateProcess的原形如下:
NTSTATUS NtTerminateProcess(
IN HANDLE ProcessHandle OPTIONAL,
IN NTSTATUS ExitStatus
);

其中ProcessHandle爲需要關閉進程的對象句柄,可以通過ObReferenceObjectByHandle()將該句柄對應EPROCESS地址獲取。因而,用以保護目標進程被惡意關閉的Hook替換函數如下:
NTSTATUS
NTAPI
NewNtTerminateProcess(
IN HANDLE ProcessHandle OPTIONAL,
IN NTSTATUS ExitStatus
)
{
PEPROCESS process_to_kill;
if (ObReferenceObjectByHandle(ProcessHandle,GENERIC_READ,NULL,KernelMode,
&process_to_kill,0) == STATUS_SUCCESS){

if ( PEPROCESS2PROTECTED== process_to_kill &&
PsGetCurrentProcess() != process_to_kill) return STATUS_ACCESS_DENIED;
}
return Old_ZwTerminateProcess(ProcessHandle,ExitStatus);

}
其中,PEPROCESS2PROTECTED爲預先設置的需要保護的進程EPROCESS地址,它可以在主程序啓動初期通過IoDeviceControl函數傳送至驅動程序

經過上述步驟以後,可以保護進程被非法關閉,效果圖如下:

然而,目前仍舊可以通過附加調試器並強行終止進程調試的手段達到關閉進程的目的。原因在於附加調試進程使用了NtOpenProcess函數,因而爲了進行較全面的保護,還需要Hook NtOpenProcess函數。拒絕一切對需要保護進程的開啓操作。
但此舉導致無法對本軟件開啓XP帶來的主題界面,因而在沒有特殊需要情況下,開啓調試保護的驅動程序沒有工作。
在進行了調試保護後,當嘗試使用調試器附加進程時,將報錯。下面是OllyIce嘗試附加本軟件時的錯誤信息:


強制結束進程的實現
由上述分析可知,強制結束進程的關鍵在於使用NtTerminateProcess函數。然後同樣可以通過Hook該函數達到防止被關閉的目的。其中Hook手段有SSDT hook和inline hook。
爲了防止第三方進程採用同樣的手段避免自身被非法關閉,可以採用下面2類辦法:
a) 恢復SSDT函數入口或恢復inline hook修改過的函數入口代碼
b) 直接調用未導出的PspTerminateProcess函數

其中,第一種做法較爲常見,而第二類做法操作難度較大,主要是因爲PspTerminateProcess爲非導出的符號,而且目前關於該函數使用的相關資料幾乎爲零。通過IDA pro5對內核進行反工程可以看到該函數的彙編代碼,摘錄部分片段如下:
PAGE:00555772 ; __stdcall PspTerminateProcess(x, x)
PAGE:00555772 arg_0 = dword ptr 8
PAGE:00555772 arg_4 = dword ptr 0Ch
PAGE:00555772
PAGE:00555772 mov edi, edi
PAGE:00555774 push ebp
PAGE:00555775 mov ebp, esp
PAGE:00555777 push esi
PAGE:00555778 mov eax, large fs:124h
PAGE:0055577E mov esi, [ebp+arg_0]
PAGE:00555781 cmp esi, [eax+44h]
PAGE:00555784 jnz short loc_55578D
PAGE:00555786 mov eax, 0C000000Dh
PAGE:0055578B jmp short loc_5557E7
PAGE:0055578D loc_55578D: ; CODE XREF: PspTerminateProcess(x,x)+12j
PAGE:0055578D push edi
PAGE:0055578E lea edi, [esi+248h]
PAGE:00555794 test byte ptr [edi+1], 20h
代碼:PspTerminateProcess函數片斷

可以猜測其參數與NtTerminateProcess相似,然而直接調用具有下面幾點風險:
a) NtTerminateProcess未被導出,難以有效定位
b) NtTerminateProcess是內部函數,直接用其銷燬進程會導致系統不穩定

因而,爲了保證本軟件的穩定性,在本次實現中沒有考慮第二種做法。然後對於大部分情況,本軟件強制結束進程能力十分有效。

用戶態讀寫物理內存的實現
爲了精簡內核程序的設計,本軟件將大部分進程操作功能在用戶態程序加以實現。這裏便需要用戶態程序具有物理內存的讀寫能力。
對於讀寫物理內存,可以通過設置內核目錄樹中/Device/PhysicalMemory對象ACL權限,將寫入權限附加去該對象,並使用NtOpenSection打開。這部分內容已比較成熟,可以找到許多相關文章。
接下來的問題是如何將虛擬內存轉化爲物理內存。由於大部分的內存讀取是在內核地址空間中的,因而有一種較爲簡單的映射模式:
if (vAddress < 0x80000000L || vAddress >= 0xA0000000L) {
add.QuadPart = (ULONGLONG) vAddress & 0xFFFF000;
} else {
add.QuadPart = (ULONGLONG) vAddress & 0x1FFFF000;
}
add.QuadPart = add.QuadPart + (ULONGLONG) (vAddress & 0xFFF);
代碼:將內核地址轉化爲物理地址的經驗代碼

上述代碼可以很有效的轉化在未分頁區段的內核內存。然而在本次試驗中,時常出現EPROCESS存在於分頁內存的情況,因而上述方法未必有效。
解決辦法有下面2種
a) 模擬內核查找頁表的模式完成函書轉化
b) 通過Callgate技術從ring3動態提權至ring0,調用內核函數MmGetPhysicalAddress完成內存轉化。

在本軟件代碼中,均實現了2種方式的功能,然而考慮到Callgate的不穩定因素,最終只採用第一種方案。下面將分別介紹。
對於模擬內核查找頁表,上文已經介紹過利用該項技術實現了有效地址的判斷。對於用戶態實現,大致算法相同,唯一需要解決的問題是頁表存放地址0xC0300000這是一內核態虛擬地址,同樣需要作物理內存轉化。這樣一來似乎陷入了循環。
不過實際情況是5.x內核對於頁表的存放地點一般是固定的,如下是未開啓PAE模式中各內核的頁表存放的物理地址:
內核版本 頁表物理地址
win2k 0x30000
XP 0x39000
2003 0x39000

獲取了頁表物理地址後,通過NtMapViewOfSection函數即可將該部分物理內存映射至本地程序地址空間進行操作。

對於使用Callgate調用MmGetPhysicalAddress的方法,首先需要遍歷GDT表找到空白項用於存放CALLGATE。
x86指令體系中可以用如下指令獲取GDT表地址,同時它支持ring3級別程序的調用:
_asm sgdt gGdt_addr;

CALLGATE是一個特殊的GDT表項,他用於實現ring3程序直接調用高級別程序代碼運行。這樣爲Ring3程序的動態提權提供了可能。
本軟件中函數InstallCallgate實現了CallGate代碼的設置,該函數從GDT表末尾開始搜索沒有使用的GDT表項,然後設置需要調用的CALLGATE信息:
CgDesc->offset_0_15 = (WORD) (Function & 0xFFFF);
CgDesc->selector = 0x8;
CgDesc->param_count = 0;
CgDesc->some_bits = 0;
CgDesc->type = 0xC; // 32-bits callgate junior
CgDesc->app_system = 0; // A system segment
CgDesc->dpl = 3; // Ring 3 code can call
CgDesc->present = 1;
CgDesc->offset_16_31 = (WORD) (Function >> 16);
pGATMap->Desc = CgDesc;
代碼:InstallCallgate設置callgate片段

其中type字段的設置表明了此項GDT表爲Callgate,而Callgate函數的高低16位分別被設置到offset_0_15與offset_16_31數據域中。
設置完Callgate後,需要定義Callgate函數,由於該函數不支持傳統的函數調用規範,也不希望編譯器加入其它無用代碼,需要在函數申明前 加上__declspec(naked)編譯指令。同時由於希望Callgate函數使用同程序相同的地址空間,也就是不希望在執行CallGate時發 生進程調度,可以在CallGate中調用CLI指令暫時關閉中斷。
爲了方便,我們編寫了下面宏負責CallGate函數的申明:
//CALL GATE STUB
#define DefineRing0Stub(func) /
__declspec(naked) void func() { /
__asm { /
__asm pushad /
__asm pushf /
__asm cli /
}

#define EndDefineRing0Stub() /
_asm { /
__asm popf /
__asm popad /
__asm retf /
} /
}

接下來的任務就是在Callgate中調用內核API MmGetPhysicalAddress。其代碼如下:
DefineRing0Stub(cgNewGetPhysicalAddress)
CurMap.pAddress = MmGetPhysicalAddress(CurMap.pAddress);
EndDefineRing0Stub()

這裏還需要解決2個問題:
第一是MmGetPhysicalAddress函數入口地址的獲取,由於該函數由ntoskrnl.exe模塊導出,無法通過靜態導入表綁定入口地 址。解決辦法是強行用LoadLibrary加載ntoskrnl.exe模塊,然後使用GetProcAddress獲取該函數在用戶進程中的映射地 址,接着通過ZwQuerySystemInformation查詢ntoskrnl.exe的基址,從而將函數 MmGetPhysicalAddress入後地址換算的真正的內核地址。
具體代碼如下:
static inline DWORD GetKFuncAddr(LPCSTR funcName)
{
DWORD ans = NULL;
if (g_hKMODULE) {
ans = ((DWORD) g_kernel_base - (DWORD)g_hKMODULE +
(DWORD) GetProcAddress(g_hKMODULE, funcName));
}
return ans;
}

上述函數實現了獲取任意導出的內核函數地址的功能,其中g_hKMODULE爲通過LoadLibrary加載的ntoskrnl.exe的用戶態基 址。而ntoskrnl.exe內核基址由g_kernel_base給出,該變量可以通過程序中的函數:DWORD GetModuleBase (LPCSTR name)獲取。

在實現了虛擬地址到物理地址的轉化後,便很容易的實現了用戶態程序直接對內存的讀寫。

動態監視進程創建、銷燬的實現
對於監視進程的創建銷燬,本軟件使用了內核函數PsSetCreateProcessNotifyRoutine函數,他將進程創建、銷燬的信息回調給我們設置的函數。
然而關鍵問題在於如何實現內核態程序在收到消息後通知用戶程序。下面是幾種可行的方法:
a) 在用戶態設立單獨進程,以阻塞方式請求IoDeviceControl。而內核態函數以異步方式處理該請求,當有進程創建消息時,完成一個IRP請求。從而喚醒了用戶態線程。實現了消息通知。
b) 在用戶臺採用異步的文件讀寫請求,內核態使用發送KEvent消息實現消息通知
c) 又用戶態程序定期輪詢。

前2種方案的優點在於可以在進程創建或銷燬後立即通知用戶程序,從而得以立即刷新進程列表。但是實現異步IRP請求設計複雜,同時要避免線程鎖死等問題。
因而本軟件使用了第三種方法。考慮到軟件本身需要一固定頻率刷新進程信息,因而完全可以使用戶態程序佔有主導權。
具體實現方式是在內核程序中設立全局隊列,每當有新的進程創建/銷燬消息時,便往隊列中追加新的項目。當用戶程序讀取該隊列時,則將隊列清空。表示之前的進程監控情況已轉達給用戶程序。
同時爲了保護內核安全,全局隊列以20筆記錄爲限,如果記錄了超過20筆記錄仍沒有用戶程序讀取該隊列,則設置一個Dirty標誌,表示記錄溢出。並且停止消息的添加。在今後用戶程序讀取隊列時,發現Dirty標誌則強制刷新進程列表,防止有“影子”進程的存在。
經過實踐證明,該方法不但實踐簡單,同時也具有很高的效率。每秒一次的輪詢足夠給用戶以瞬時刷新進程列表的感覺。


參考文獻

Windows Internals,Fourth Edition

Undocumented Windows NT

Undocumented Windows.2000.SECRETS.A PROGRAMMERS.COOKBOOK

Playing with Windows /dev/(k)mem, By crazylord,
http://www.phrack.org/phrack/59/p59-0x10.txt

淺談NT下Ring3無驅進入Ring0的方法, By hopy,
http://bbs.pediy.com/showthread.php?threadid=37946

必備絕技——hook大法( 中 ), By Lvg,
http://bbs.pediy.com/showthread.php?threadid=42422

Do All In One EXE File Under Win32, By icelord,
www.xfocus.net/articles/200610/887.html

How PAE X86 Works.mht, Microsoft Tech Net,
http://technet2.microsoft.com/windowsserver/en/library/00284c8d-7a42-40f2-8a01-8de61dccd8c91033.mspx

內存與進程管理器, By greatdong,
https://www.xfocus.net/bbs/index.php?act=ST&f=2&t=58182

Ring0下搜索內存枚舉隱藏進程, By uty,
http://www.cnxhacker.net/Article/show/3412.html

Process Termination: Known Methods, By EP_X0FF,
http://forum.sysinternals.com/forum_posts.asp?TID=5865

Administrator用戶直接獲取SYSTEM權限, By scz,
www.nsfocus.net/index.php?act=magazine&do=view&mid=1900

獲得進程的EPROCESS, By MustBE
www.xfocus.net/articles/200406/706.html

獲取Windows 系統的內核變量, By於暘
www.nsfocus.net/index.php?act=magazine&do=view&mid=2248

一些常用內核變量的定位, By flyingkisser
http://forum.byr.cn/pc/index.php?id=flyingkisser&pno=7

Windows Template Library (WTL),
http://www.codeproject.com/wtl/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章