欧美性猛交黑人xxxx,成人毛片一区二区三区,久久综合九色综合精品,男的把j放进女人下面视频免费

用DLL控制Windows中進(jìn)程的方

  • 發(fā)布于:2022-02-14
  • 265 人圍觀
  在Microsoft Windows中,每個進(jìn)程都有它自己的私有地址空間。當(dāng)使用指針來引用內(nèi)存時,指針的值將引用你自己進(jìn)程的地址空間中的一個內(nèi)存地址。你的進(jìn)程不能創(chuàng)建一銎湟用屬于另一個進(jìn)程的內(nèi)存指針。因此,如果你的進(jìn)程存在一個錯誤,改寫了一個隨機(jī)地址系內(nèi)存,那么這個錯誤不會影響另一個進(jìn)程使用的內(nèi)存。Windows 98 在Windows 98下運行的各個進(jìn)程共享2 GB的地址空間,該地址空間從0x80000000至0xFFFFFFFF。只有內(nèi)存映像文件和統(tǒng)組件才能映射到這個區(qū)域。
  
  獨立的地址空間對于編程人員和用戶來說都是非常有利的。對于編程人員來說,系統(tǒng)更容易捕獲隨意的內(nèi)存讀取和寫入操作。對于用戶來說,操作系統(tǒng)將變得更加健壯,因個應(yīng)用程序無法破壞另一個進(jìn)程或操作系統(tǒng)的運行。當(dāng)然,操作系統(tǒng)的這個健壯特性是要凍代價的,因為要編寫能夠與其他進(jìn)程進(jìn)行通信,或者能夠?qū)ζ渌M(jìn)程進(jìn)行操作的應(yīng)用程序難得多。
  
  有些情況下,必須打破進(jìn)程的界限,訪問另一個進(jìn)程的地址空間,這些情況包括:
  
  當(dāng)你想要為另一個進(jìn)程創(chuàng)建的窗口建立子類時。
  當(dāng)你需要調(diào)試幫助時(例如,當(dāng)你需要確定另一個進(jìn)程正在使用哪個DLL時)。
  當(dāng)你想要掛接其他進(jìn)程時。
  
  這里將介紹兩種方法,可以用來將DLL插入到另一個進(jìn)程的地址空間中。一旦你的DLL進(jìn)入另一個進(jìn)程的地址空間,就可以對另一個進(jìn)程為所欲為。這一定會使你非常害怕,因此,究竟應(yīng)該怎樣做,要三思而后行。
  
  1 插入DLL:一個例子
  假設(shè)你想為由另一個進(jìn)程創(chuàng)建的窗口建立一個子類。你可能記得,建立子類就能夠改變窗口的行為特性。若要建立子類,只需要調(diào)用SetWindowLongPtr函數(shù),改變窗口的內(nèi)嬋中的窗口過程地址,指向一個新的(你自己的) WndProc。Platform SDK文檔說,應(yīng)用程蠆能為另一個進(jìn)程創(chuàng)建的窗口建立子類。這并不完全正確。為另一個進(jìn)程的窗口建立子類的關(guān)鍵問題與進(jìn)程地址空間的邊界有關(guān)。
  
  當(dāng)調(diào)用下面所示的SetWindowsLongPtr函數(shù),建立一個窗口的子類時,你告訴系統(tǒng),發(fā)送到或者顯示在hwnd設(shè)定的窗口中的所有消息都應(yīng)該送往MySubclassProc,而不是送往口的正常窗口過程:
  
  進(jìn)程A中代碼:
  EXE file:
  LRESUlT WndProc(HWND hend,UNIT uMsg,...){.....}
  USER32.DLL file
  LONG DispatchMessage(CONST MSG*msg)
  {
  LONG lRet;
  WNDPROC lpfnWndProc=
  (WNDPROC)GetWindowLongPtr(msg,hwnd,GWLP_WNDPROC
  );
  lRet=lpfnWndProc(msg.hwnd,msg.message,msg.wParam,mag.
  lParam);
  return lRet;
  }
  進(jìn)程B中:
  EXE file
  void Somefunc(void)
  {
  HWND hwnd=Findwindow("class A",NULL);
  SetWindowLongPtr(hwnd,GWLP_WNDPROC,MySubclassProc);
  }
  USER32.DLL file ......
  
  
  換句話說,當(dāng)系統(tǒng)需要將消息發(fā)送到指定窗口的WndProc時,要查看它的地址,然后直接調(diào)用WndProc。在本例中,系統(tǒng)發(fā)現(xiàn)MySubclassProc函數(shù)的地址與窗口相關(guān)聯(lián),因此就直接調(diào)用MySubclassProc函數(shù)。
  
  為另一個進(jìn)程創(chuàng)建的窗口建立子類時遇到的問題是,建立子類的過程位于另一個地址空間中。下面舉個例子,說明窗口過程是如何接受消息的。進(jìn)程A正在運行,并且已經(jīng)創(chuàng)建了一個窗口。文件User32.dll被映射到進(jìn)程A的地址空間中。
  
  對User32.dll文件的映射是為了接收和發(fā)送在進(jìn)程A中運行的任何線程創(chuàng)建的任何窗口中發(fā)送和顯示的消息。當(dāng)User32.dll的映像發(fā)現(xiàn)一個消息時,它首先要確定窗口的WndProc的地址,然后調(diào)用該地址,傳遞窗口的句柄、消息和wParam和lParam值。當(dāng)WndProc處理該消息后,User32.dll便循環(huán)運行,并等待另一個窗口消息被處理。
  
  進(jìn)程B中的線程試圖為進(jìn)程A中的線程創(chuàng)建的窗口建立子類現(xiàn)在假設(shè)你的進(jìn)程是進(jìn)程B,你想為進(jìn)程A中的線程創(chuàng)建的窗口建立子類。你在進(jìn)程B中的代碼必須首先確定你想要建立子類的窗口的句柄。這個操作使用的方法很多。上面的例子只是調(diào)用FindWindow函數(shù)來獲得需要的窗口。接著,進(jìn)程B中的線程調(diào)用SetWindowLongPtr函數(shù),試圖改變窗口的WndProc的地址。請注意我說的“試圖”二字。這個函數(shù)調(diào)用⒉進(jìn)行什么操作,它只是返回NULL。SetWindowLongPtr函數(shù)中的代碼要查看是否有一個進(jìn)程正在試圖改變另一個進(jìn)程創(chuàng)建的窗口的WndProc地址,然后將忽略這個函數(shù)的調(diào)用。
  
  如果SetWindowLongPtr函數(shù)能夠改變窗口的WndProc,那將出現(xiàn)什么情況呢?系統(tǒng)將把MySubclassProc的地址與特定的窗口關(guān)聯(lián)起來。然后,當(dāng)有一條消息被發(fā)送到這個窗口中時,進(jìn)程A中的User32代碼將檢索該消息,獲得MySubclassProc的地址,并試圖調(diào)用這個地址。但是,這時可能遇到一個大問題。MySubclassProc將位于進(jìn)程B的地址空間中,而進(jìn)程A是個活動進(jìn)程。顯然,如果User32想要調(diào)用該地址,它就要調(diào)用進(jìn)程A的地址空間中的一個地址,這就可能造成內(nèi)存訪問的違規(guī)。
  為了避免這個問題的產(chǎn)生,應(yīng)該讓系統(tǒng)知道M y S u b c l a s s P r o c是在進(jìn)程B的地址空間中,然后,在調(diào)用子類的過程之前,讓系統(tǒng)執(zhí)行一次上下文轉(zhuǎn)換。M i c r o s o f t沒有實現(xiàn)這個輔助函數(shù)功能,原因是:應(yīng)用程序很少需要為其他進(jìn)程的線程創(chuàng)建的窗口建立子類。大多數(shù)應(yīng)用程序只是為它們自己創(chuàng)建的窗口建立子類,Wi n d o w s的內(nèi)存結(jié)構(gòu)并不阻止這種創(chuàng)建操作。
  
  切換活動進(jìn)程需要占用許多C P U時間。
  
  進(jìn)程B中的線程必須執(zhí)行M y S u b c l a s s P r o c中的代碼。系統(tǒng)究竟應(yīng)該使用哪個線程呢?是現(xiàn)有的線程,還是新線程呢?
  
  U s e r 3 2 . d l l怎樣才能說明與窗口相關(guān)的地址是用于另一個進(jìn)程中的過程,還是用于同一個進(jìn)程中的過程呢?
  
  由于對這個問題的解決并沒有什么萬全之策,因此M i c r o s o f t決定不讓S e t Wi n d o w s L o n g P t r改變另一個進(jìn)程創(chuàng)建的窗口過程。不過仍然可以為另一個進(jìn)程創(chuàng)建的窗口建立子類—只需要用另一種方法來進(jìn)行這項操作。這并不是建立子類的問題,而是進(jìn)程的地址空間邊界的問題。如果能將你的子類過程的代碼放入進(jìn)程A的地址空間,就可以方便地調(diào)用S e t Wi n d o w L o n g P t r函數(shù),將進(jìn)程A的地址傳遞給M y S u b c l a s s P r o c函數(shù)。我將這個方法稱為將D L L“插入”進(jìn)程的地址空間。有若干種方法可以用來進(jìn)行這項操作。下面將逐個介紹它們
  
  2.通過掛鉤插入DLL
  可以使用掛鉤將D L L插入進(jìn)程的地址空間。為了使掛鉤能夠像它們在1 6位Wi n d o w s中那樣工作,M i c r o s o f t不得不設(shè)計了一種方法,使得D L L能夠插入另一個進(jìn)程的地址空間中。
  
  下面讓我們來看一個例子。進(jìn)程A(類似Microsoft Spy++的一個實用程序)安裝了一個掛鉤W N _ G E T M E S S A G E,以便查看系統(tǒng)中的各個窗口處理的消息。該掛鉤是通過調(diào)用下面的S e t Wi n d o w s H o o k E x函數(shù)來安裝的:
  
  第一個參數(shù)W H _ G E T M E S S A G E用于指明要安裝的掛鉤的類型。第二個參數(shù)G e t M s g P r o c用于指明窗口準(zhǔn)備處理一個消息時系統(tǒng)應(yīng)該調(diào)用的函數(shù)的地址(在你的刂房占渲校5三個參數(shù)h i n s t D l l用于指明包含G e t M s g P r o c函數(shù)的D L L。在Wi n d o w s中,D L L的h i n s t D l l的值用于標(biāo)識DLL被映射到的進(jìn)程的地址空間中的虛擬內(nèi)存地址。最后一個參數(shù)0用于指明要掛接的線程。
  
  對于一個線程來說,它可以調(diào)用S e t Wi n d o w s H o o k E x函數(shù),傳遞系統(tǒng)中的另一個線程的I D。通過為這個參數(shù)傳遞0,就告訴系統(tǒng)說,我們想要掛接系統(tǒng)中的所有G U I線程。
  
  現(xiàn)在讓我們來看一看將會發(fā)生什么情況:
  
  1) 進(jìn)程B中的一個線程準(zhǔn)備將一條消息發(fā)送到一個窗口。
  
  2) 系統(tǒng)查看該線程上是否已經(jīng)安裝了W H _ G E T M E S S A G E掛鉤。
  
  3) 系統(tǒng)查看包含G e t M s g P r o c函數(shù)的D L L是否被映射到進(jìn)程B的地址空間中。
  
  4) 如果該D L L尚未被映射,系統(tǒng)將強(qiáng)制該D L L映射到進(jìn)程B的地址空間,并且將進(jìn)程B中的D L L映像的自動跟蹤計數(shù)遞增1。
  
  5) 當(dāng)D L L的h i n s t D l l用于進(jìn)程B時,系統(tǒng)查看該函數(shù),并檢查該D L L的h i n s t D l l是否與它用于進(jìn)程A時所處的位置相同。
  
  如果兩個h i n s t D l l是在相同的位置上,那么G e t M s g P r o c函數(shù)的內(nèi)存地址在兩個進(jìn)程的地址空間中的位置也是相同的。在這種情況下,系統(tǒng)只需要調(diào)用進(jìn)程A的地址空間中的G e t M s g P r o c函數(shù)即可。
  
  如果h i n s t D l l的位置不同,那么系統(tǒng)必須確定進(jìn)程B的地址空間中G e t M s g P r o c函數(shù)的虛擬內(nèi)存地址。這個地址可以使用下面的公式來確定:
  
  將GetMsgProc A的地址減去hinstDll A的地址,就可以得到G e t M s g P r o c函數(shù)的地址位移(以字節(jié)為計量單位)。將這個位移與hinstDll B的地址相加,就得出G e t M s g P r o c函數(shù)在用于進(jìn)程B的地址空間中該D L L的映像時它的位置。
  
  6) 系統(tǒng)將進(jìn)程B中的D L L映像的自動跟蹤計數(shù)遞增1。
  
  7) 系統(tǒng)調(diào)用進(jìn)程B的地址空間中的G e t M s g P r o c函數(shù)。
  
  8) 當(dāng)G e t M s g P r o c函數(shù)返回時,系統(tǒng)將進(jìn)程B中的D L L映像的自動跟蹤計數(shù)遞減1。
  
  注意,當(dāng)系統(tǒng)插入或者映射包含掛鉤過濾器函數(shù)的D L L時,整個D L L均被映射,而只是掛鉤過濾器函數(shù)被映射。這意味著D L L中包含的任何一個函數(shù)或所有函數(shù)現(xiàn)在都存在,并且可以從進(jìn)程B的環(huán)境下運行的線程中調(diào)用。
  
  若要為另一個進(jìn)程中的線程創(chuàng)建的窗口建立子類,首先可以在創(chuàng)建該窗口的掛鉤上設(shè)置一個W H _ G E T M E S S A G E掛鉤,然后,當(dāng)G e t M s g P r o c函數(shù)被調(diào)用時,調(diào)用S e t Wi n d o w L o n g P t r函數(shù) 來建立窗口的子類。當(dāng)然,子類的過程必須與G e t M s g P r o c函數(shù)位于同一個D LL中。
  
  與插入D L L的注冊表方法不同,這個方法允許你在另一個進(jìn)程的地址空間中不再需要DL L時刪除該D L L的映像,方法是調(diào)用下面的函數(shù):
  
  當(dāng)一個線程調(diào)用U n h o o k Wi n d o w s H o o k E x函數(shù)時,系統(tǒng)將遍歷它必須將D L L插入到的各個進(jìn)程的內(nèi)部列表,并且對D L L的自動跟蹤計數(shù)進(jìn)行遞減。當(dāng)自動跟蹤計數(shù)時,D L L就自動從進(jìn)程的地址空間中被刪除。應(yīng)該記得,就在系統(tǒng)調(diào)用G e t M s g P r o c前,它對D L L的自動跟蹤計數(shù)進(jìn)行了遞增(見上面的第6個步驟)。
  
  該自動跟蹤計數(shù)沒有遞增,那么當(dāng)進(jìn)程B的線程試圖執(zhí)行G e t M s g P r o c函數(shù)中的代朧,系統(tǒng)中運行的另一個線程就可以調(diào)用U n l o o k Wi n d o w s H o o k E x函數(shù)。
  
  這一切意味著不能撤消該窗口的子類并且立即撤消該掛鉤。該掛鉤必須在該子類的壽命期內(nèi)保持有效狀態(tài)。
  
  3.使用遠(yuǎn)程線程插入DLL
  插入D L L的另一個方法是使用遠(yuǎn)程線程。這種方法具有更大的靈活性。它要求你懂得若干個Wi n d o w s特性、如進(jìn)程、線程、線程同步、虛擬內(nèi)存管理、D L L和U n i c o d e等(如果對這些特性不清楚,請參閱本書中的有關(guān)章節(jié))。Wi n d o w s的大多數(shù)函數(shù)市斫討歡宰己進(jìn)行操作。
  
  這是很好的一個特性,因為它能夠防止一個進(jìn)程破壞另一個進(jìn)程的運行。但是,有些函數(shù)卻允許一個進(jìn)程對另一個進(jìn)程進(jìn)行操作。這些函數(shù)大部分最初是為調(diào)試程序和其他工具杓的。不過任何函數(shù)都可以調(diào)用這些函數(shù)。
  
  這個D L L插入方法基本上要求目標(biāo)進(jìn)程中的線程調(diào)用L o a d L i b r a r y函數(shù)來載必要的D L L。
  
  由于除了自己進(jìn)程中的線程外,我們無法方便地控制其他進(jìn)程中的線程,因此這種解決方案要求我們在目標(biāo)進(jìn)程中創(chuàng)建一個新線程。由于是自己創(chuàng)建這個線程,因此我們能夠控?fù)鋱?zhí)行什么代碼。幸好,Wi n d o w s提供了一個稱為C r e a t e R e m o t e T h r e a d的函數(shù),使我們能夠非常容易地在另一個進(jìn)程中創(chuàng)建線程:
  
  C r e a t e R e m o t e T h r e a d與C r e a t e T h r e a d很相似,差別在于它增加了一個參數(shù)h P r o c e s s。該參數(shù)指明擁有新創(chuàng)建線程的進(jìn)程。參數(shù)p f n S t a r t A d d r指明線程函數(shù)的內(nèi)存地址。當(dāng)然,該內(nèi)存地址與遠(yuǎn)程進(jìn)程是相關(guān)的。線程函數(shù)的代碼不能位于你自己進(jìn)程的地址空間中。
  
  Windows 98 在Windows 98中,C r e a t e R e m o t e T h r e a d函數(shù)不存在有用的實現(xiàn)代碼,它只是返回N U L L。調(diào)用G e t L a s t E r r o r函數(shù)將返回E R R O R _ C A L L _ N O T _ I M P L E M E N T E D(C r e a t e T h r e a d函數(shù)包含用于在調(diào)用進(jìn)程中創(chuàng)建線程的完整的實現(xiàn)代碼)。由于C r e a t e R e m o t e T h r e a d沒有實現(xiàn),因此,在Windows 98下,不能使用本方法來插入D L L。
  
  好了,現(xiàn)在你已經(jīng)知道如何在另一個進(jìn)程中創(chuàng)建線程了,但是,如何才能讓該線程加載我們的D L L呢?答案很簡單,那就是需要該線程調(diào)用L o a d L i b r a r y函數(shù)。
  
  我們將詳細(xì)步驟說明如下:
  1) 使用Vi r t u a l A l l o c E x函數(shù),分配遠(yuǎn)程進(jìn)程的地址空間中的內(nèi)存。
  
  2) 使用Wr i t e P r o c e s s M e m o r y函數(shù),將D L L的路徑名拷貝到第一個步驟中已經(jīng)分配的內(nèi)存中。
  
  3) 使用G e t P r o c A d d r e s s函數(shù),獲取L o a d L i b r a r y A或L o a dL i b r a t y W函數(shù)的實地址(在K e r n e l 3 2 . d l l中)。
  
  4) 使用C r e a t e R e m o t e T h r e a d函數(shù),在遠(yuǎn)程進(jìn)程中創(chuàng)建一個線程,它調(diào)用正確的L o a d L i b r a r y函數(shù),為它傳遞第一個步驟中分配的內(nèi)存的地址。這時, D L L已經(jīng)被插入遠(yuǎn)程進(jìn)程的地址空間中,同時D L L的D l l M a i n函數(shù)接收到一個D L L _ P R O C E S S _ AT TA C H通知,并且能夠執(zhí)行需要的代碼。當(dāng)D l l M a in函數(shù)返回時,遠(yuǎn)程線程
  
  從它對L o a d L i b r a r y的調(diào)用返回到B a s e T h r e a d S t a r t 函數(shù)(第6 章中已經(jīng)介紹。然后B a s e T h r e a d S t a r t調(diào)用E x i t T h r e a d,使遠(yuǎn)程線程終止運行。
  
  現(xiàn)在遠(yuǎn)程進(jìn)程擁有第一個街柚蟹峙淶哪詿嬋椋鳧 L L則仍然保留在它的地址空間中。
  
  若要將它刪除,需要在遠(yuǎn)程線程退出后執(zhí)行下面的步驟:
  
  5) 使用Vi r t u a l F r e e E x函數(shù),釋放第一個步驟中分配的內(nèi)存。
  
  6) 使用G e t P r o c A d d r e s s函數(shù),獲得F r e e L i b r a r y函數(shù)的實地址(在K e r n e l 3 2 . d l l中)。
  
  7) 使用C r e a t e R e m o t e T h r e a d函數(shù),在遠(yuǎn)程進(jìn)程中創(chuàng)建一個線程,它調(diào)用F r e e L i b r a r y函數(shù),傳遞遠(yuǎn)程D L L的H I N S TA N C E。
  
  這就是它的基本操作步驟。這種插入D L L的方法存在的唯一一個不足是, Windows 98并不支持這樣的函數(shù)。只能在Windows 2000上使用這種方法。
萬企互聯(lián)
標(biāo)簽: