程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> WINDOWS黑客基礎(3):注入代碼

WINDOWS黑客基礎(3):注入代碼

編輯:C++入門知識

有使用過外掛的朋友應該知道,我們在玩游戲的時候,有很多輔助功能給你使用,比如吃藥,使用物品等功能,這個時候我們就是使用注入代碼的技術,簡單的來將就是我們讓另外一個進程去執行我們想讓它執行的代碼,這中間的關鍵函數是CreateRemoteThread



CreateRemoteThread的參數跟CreateThread的參數差不多,多出來的hProcess是我們要對其操作的進程HANDLE,在早期的WINDOWS版本CreateThread確實是使用CreateRemoteThread實現的,就是把hProcess傳入我們自己的進程HANDLE


CreateRemoteThread的功能就是在指定的進程創建一個線程,這個線程運行我們指定的函數,看起來很簡單,但是有一個問題,就是虛擬內存導致的問題

大家都知道,在WINDOWS下是使用虛擬內存來進行數據管理的,每個進程都有自己獨立的地址空間,假設進程A准備向進程B注入一段代碼,他要讓進程B執行他進程空間的函數InjectionCode(),這個函數在進程A的地址空間地址為0X3000

現在我們開始進行代碼注入,利用CreateRemoteThread我們告訴B進程,請執行虛擬內存地址為0X3000的代碼,這個時候B進程該干什麼呢??B進程收到這個命令後,他很聽話地創建了線程,然後乖乖得CALL了0X3000的內容,請注意,現在B進程CALL的是它自己內存空間內0X3000的代碼而不是A進程的,那麼現在B進程的0X3000是什麼內容??沒人知道,運氣好的話說不定真的有段代碼給你執行,運氣不好你自己也不知道會發生什麼事情,這就跟你進錯了學生公寓一樣,同樣號碼的房間,運氣好是校花的房間,運氣不好就是如花的房間

那麼我們怎麼才能讓進程去執行我們對應的代碼呢??我們只要在B進程內開辟一塊內存,然後把我們的代碼或者數據復制進去,再執行對應的代碼就可以了,我們需要用到這幾個函數:

*

這兩個函數跟我們平常用的函數都差不多,只是多了個進程的選項,大概步驟如下圖:

 

現在我們將實際操作一下:

下面是我們要注入的程序,在這之前,我們最好把基地址固定掉,這樣我們不會每次重新運行程序的時候函數的地址都會改變,在VS2008中,項目屬性->鏈接器->高級,把隨機基址和固定基址選擇默認值

 PrintMsg(  * main(

假設我們的PrintMsg的地址是0x401000,現在我們需要往這個進程裡面注入一段代碼,讓她可以自動調用PrintMsg這個函數

    *msg =    unsigned  PARAM_SIZE =    unsigned  EXE_SIZE =  
 
  InjectionCode(  *              mov eax,
       main(      HANDLE hProcess = OpenProcessByProcessNmae(     
      (hProcess ==          printf(                //一定要把函數的代碼和msg寫入要注入的進程,否則會發生位置錯誤(一般是崩潰)
     LPVOID RemoteExe =     LPVOID RemoteParam = 
     SIZE_T WriteCount =       ret =      ret = WriteProcessMemory(hProcess,RemoteParam,msg,PARAM_SIZE,&     ret = WriteProcessMemory(hProcess,RemoteExe,InjectionCode,,& 
     HANDLE hThread = CreateRemoteThread(hProcess,NULL,,(LPTHREAD_START_ROUTINE)RemoteExe,RemoteParam,  }

運行上面的程序,我們就可以在另外一個進程中創建一個線程,並且這個線程將會輸出該線程的ID以及我們要輸出的消息

上面的程序還有幾個要注意的:

1.資源競爭

由於是創建線程執行相應代碼所以肯定會有資源競爭的問題,以後要寫代碼一定要注意,在本例中我忽略了這個問題

2. 關於代碼的長度問題

在本例中,我們的代碼長度是0X13,但是要知道,匯編代碼的長度隨便懂一下就可能更改,可能因為一個指令,也可能因為一個參數,所以我們需要時刻注意這點,關於代碼長度怎麼測量,我是看了反匯編的代碼後計算的,這個方法比較准確,也可以大概估計下,只要能把代碼復制完整就可以,超出也沒關系,只要不超出申請的內存大小就可以

3.記得備份我們使用的寄存器

這個十分重要,一旦你更改了寄存器,如果沒有後面沒有恢復,可能會導致一系列錯誤,特別是ESP,EBP等重要的寄存器

3.注入代碼多次調用系統DLL中的函數

<<WINDOWS核心編程>>裡面說,系統的DLL都會加載到一個固定的地址,比如VirtualAllocEx,一般我們在A進程和B進程的時候,call或者jmp的地址都是一樣的,所以一般我們如果調用的是系統函數,一般我們不需要擔心,但是,昨天我想到了一個問題,比如我們進程A要命令進程B調用CreateToolhelp32Snapshot這個系統API,現在我們假設CreateToolhelp32Snapshot這個API在單獨的TLHELP32.DLL裡面(實際上這個在KERNEL32.DLL裡面,所有進程都會加載這個DLL,所以不需要擔心下面的問題,這個只是舉例),操作系統在加載DLL的時候,會統一把這個API的地址映射到虛擬內存的0XFF40100的地址,按照我們原來的想法進程B會自己跑去call 0XFF40100這個地址。但問題在於,如果我們的進程根本就沒有加載TLHELP32.DLL這個DLL,那麼進程call 0XFF40100會怎麼樣??這個就要看你這個地方是什麼代碼了,有人說操作系統會幫你加載這個DLL,但我覺得是錯的,因為操作系統要幫你加載的DLL都在PE頭裡面的導入表裡面,要嘛就是我們要顯示地去加載,否則操作系統不會知道我們的API在哪個DLL裡面

4.注入代碼多次調用我們自己編寫的函數

比如我們有IntejectionCode,裡面調用了IntejectionCode1,這個時候我們需要把IntejectionCode1也寫入對方進程裡面,不能只寫入IntejectionCode,並且,我們需要更改IntejectionCode裡面call IntejectionCode1跳轉指令,讓其跳轉到正確的位置。總之,別人的地盤別人做主,對方進程想把代碼放哪裡就放哪裡,我們無法管理(實際上virtualAllocEx是可以指定位置的,但是一般我們都盡量讓操作系統去指定),我們只能入鄉隨俗,人家讓我們去哪裡調用我們就要去哪裡調用,不然很容易導致進程崩潰

5.關於代碼的基地址

在本例中PrintMsg的基地址是固定的,是我們人為去固定基地址的,我們在開發的時候很少人會去把基地址固定掉,所以在進程運行的時候,PrintMsg這個函數的地址是會改變的,當然我們也可以算出來這段代碼在運行的時候會放在哪裡,因為PrintMsg這段代碼以二進制放在EXE文件的時候,也有一個文件偏移量,當操作系統把EXE文件加載進內存後,會根據基地址和文件偏移量,來算出PrintMsg在虛擬內存中的位置,所以我們只要能拿到進程運行時候的基地址,並且把EXE反匯編查看這段代碼的文件偏移量,也能算出每次運行的時候PrintMsg的地址,雖然很麻煩,特別是反匯編找代碼的那部分,但也沒辦法,這個在後面我會講

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved