SSDT HOOK攔截遠執行緒的建立(下)

2021-07-07 02:58:06 字數 3603 閱讀 1488

第三部分:從程序控制代碼獲取資訊

在第二部分我們使用了乙個前提:可以通過程序控制代碼得到pid等資訊。

事實上這是可行的,這一部分我們就進行介紹。我這裡使用的是爐子大蝦的《api hook實現ring3的程序保護》一文中提到的方法。

爐子那篇文章裡講的很詳細,這裡只說下如何從程序控制代碼中獲取資訊吧,在ntdll中有個函式可以幫助我們:zw(nt)queryinformationprocess,下面是我在《the undocumented functions——microsoft windows nt/2000》一書中查到的原型宣告:

ntsysapi ntstatus ntapi ntqueryinformationprocess(

in handle processhandle,

in processinfoclass processinformationclass,

out pvoid processinformation,

in ulong processinformationlength,

out pulong returnlength );

第乙個引數輸入程序控制代碼,第三個引數輸出該控制代碼的相關資訊,至於是什麼資訊,就要看第二個引數的說明了。

第二個引數是個enum結構,很長,我數了一下,足有39個變數,所以這裡就不列出來浪費版面了,我們需要關心的是第乙個,即processbasicinformation,與它相關的結構體是process_basic_information,如下所示:

typedef struct

_process_basic_information process_basic_information;

這個結構的uniqueprocessid域可以給出我們想要的程序控制代碼資訊。不過有時候我們還想知道程序名,因為通過程序名可以更加直觀地獲得資訊。

我仔細看了一下processinfoclass這個列舉結構,發現第28個子域應該是代表程序路徑資訊:processimagefilename,但遺憾的是我找不到與之相對應的結構體定義(家裡沒法上網,又不會除錯,只好先放下以後再說)。

現在我們只好通過其他方法來得到通過控制代碼程序名資訊,我開始的思路是首先呼叫函式obreferenceobjectbyhandle通過控制代碼獲取到乙個指標,然後呼叫obquerynamestring獲取有關資訊,可惜沒測試成功,後來改用zwqueryobject還是沒測試成功,自己不會除錯又沒人可以給指點下,只好作罷。

既然我們不會從控制代碼直接得到程序名,但不要忘了現在我們已經可以從控制代碼得到程序的pid,通過pid再得到程序名還不簡單?

在ring3通過pid得到程序名還真簡單,我們隨便選一種方法先遍歷一下,然後比對一下pid,就能得到程序名了。不對,是連程序的完整路徑都可以得到。不過在ring0我還不會得到完整路徑,而且我也不想使用那種麻煩的方法來獲取程序名。

偶然在某篇文章(真忘了是哪篇-_-)見有人提到乙個函式pslookupprocessbyprocessid,到《the undocumented functions》中查到它的原型宣告如下所示:

ntsysapi ntstatus ntapi pslookupprocessbyprocessid(

in ulong processid,

out peprocess *peprocess );

可以看到它輸出了大名鼎鼎的peprocess結構,這個結構中正好包含有程序名的資訊(可惜不是完整路徑),就湊合著用吧。這個結構在相關偏移量在不同的系統上是不同的,這裡我參考了北極星2003大蝦的某篇文章,專門寫了乙個函式首先判斷系統,然後再動態返回相應的偏移量。

辛辛苦苦忙活了半天,總算可以通過控制代碼獲得程序的pid和程序名資訊了,如下面的**所示:

ulong                         lret;

pvoid pbuffer;

process_basic_information *pbi;

peprocess eprocess;

puchar imagefilepath;

ulong dwnameoffset;

pbuffer = exallocatepool(pagedpool, sizeof

(process_basic_information));

zwqueryinformationprocess(processhandle, processbasicinformation, pbuffer,

sizeof(process_basic_information), &lret);

pbi = (struct _process_basic_information *)pbuffer;

pslookupprocessbyprocessid(pbi->uniqueprocessid, &eprocess);

dwnameoffset =getplantformdependentinfo();

imagefilepath = (puchar)((lptstr)eprocess +dwnameoffset);

kdprint((

"[nokyo] 目標程序:%d -> %s

", pbi->uniqueprocessid, imagefilepath));

什麼,要看演示效果?笨吶,圖2不就是演示效果麼!!!

第四部分:動態獲取函式索引

文章寫到了這裡還不算完,在第一部分我們使用了硬編碼來確定zwcreatethread的索引號,但硬編碼的情況我們必須盡量避免,否則就很難保證通用性。

動態獲取zw*函式的索引號其實並不難,網上有關恢復ssdt的**鋪天蓋地,裡面都少不了這乙個功能。這裡我是從李馬的ssdtdump中提取出了關於獲取函式索引的**(控制台的,不需要驅動,它不能在驅動裡面直接用,需要自己修改),主要**如下所示:

void

enumssdt(in hmodule hntdll)}}

destroymodulelist( plist );

}

對函式**有不太理解的地方可以詳細參考《城裡城外看ssdt》一文,這段**我們同樣可以將其寫在驅動程式中以動態獲取函式的索引號。

上述**的演示結果如圖3所示:

到這裡本文就算結束了,**寫的很簡陋,關於如何向應用層程式傳送通知和資訊的方法就不再贅述了,關於deviceiocontrol的示例到處都是。本文還遺留了乙個問題,就是如何得到目標dll的路徑,也就是createremotethread函式的第五個引數lpparameter,這個問題就交給各位讀者解決了。

補充:      其實這篇文章的**並不完整,具體點就是在第二部分過濾的不夠詳細,因為多數程序在啟動的時候都需要其他程序建立主線程的,大多數是由explorer.exe等系統程序建立的,因此我們還需要通過判斷目標程序是否為空,這個可以參考爐子的文章。

但爐子的文章中使用的是硬編碼,而動態獲取某個值偏移量的方法我不會,所以我使用的是判斷目標程序的父程序方法,雖然不太保險,但總算解決了。

執行緒的建立

建立執行緒的幾種方法 1 createthread 執行緒執行函式必須是全域性的 使用方法 執行緒執行函式宣告 dword winapi threadproc lpvoid lpparam 建立執行緒 createthread null,0,threadproc,info i 0,dwthreadi...

執行緒的建立

執行緒在thread物件建立時開始啟動,傳遞給執行緒的函式執行結束時,執行緒也結束。執行緒thread建構函式 template explicit thread fn fx,args ax thread thread other noexcept thr other.thr thread opera...

執行緒的建立

執行緒的建立 1 使用createthread函式建立執行緒 handle createthread lpsecurity attributes lpsa,dword cbstack,lpthread start routine lpstartaddr,lpvoid lpvthreadparam,d...