CreateThread和CreateRemoteThread
文章目錄
- CreateThread
- 函數功能
- 函數原型
- 第一個參數:
- 第二個參數:
- 第三個參數:
- 第四個參數:
- 第五個參數:
- 第六個參數:
- 返回值:
- 補充:
- 代碼實現
- 注意:
- CreateRemoteThread
- 函數功能
- 函數原型:
- 第一個參數
- 第二個參數
- 第三個參數
- 第四個參數
- 第五個參數
- 第六個參數
- 第七個參數
- 返回值
- 備注:
- 代碼實現
- GAMEOVER
- 未開啟遠程線程時,
CreateThread
函數功能
創建一個線程以在調用進程的虛擬地址空間內執行。
函數原型
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,__drv_aliasesMem LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId );第一個參數:
指向SECURITY_ATTRIBUTES 結構的指針,該結構確定子進程是否可以繼承返回的句柄。如果 lpThreadAttributes為NULL,則不能繼承該句柄。
結構的lpSecurityDescriptor成員為新線程指定一個安全描述符。如果lpThreadAttributes為NULL,則線程獲取默認的安全描述符。線程的默認安全描述符中的ACL來自創建者的主要令牌。
第二個參數:
堆棧的初始大小,以字節為單位。系統將此值舍入到最接近的頁面。如果此參數為零,則新線程將使用可執行文件的默認大小。
第三個參數:
指向要由線程執行的應用程序定義的函數的指針。該指針表示線程的起始地址。
第四個參數:
指向要傳遞給線程的變量的指針。
第五個參數:
控制線程創建的標志。
| 0 | 線程在創建后立即運行。 |
| CREATE_SUSPENDED 0x00000004 | 該線程以掛起狀態創建,并且直到調用ResumeThread函數后才運行 |
| STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 | 所述dwStackSize參數指定堆棧的初始保留大小。如果未指定此標志,則dwStackSize指定提交大小。 |
第六個參數:
指向接收線程標識符的變量的指針。如果此參數為 NULL,則不返回線程標識符。
返回值:
如果函數成功,則返回值是新線程的句柄。
如果函數失敗,則返回值為NULL。要獲取擴展的錯誤信息,請調用 GetLastError。
請注意,即使lpStartAddress指向數據,代碼或不可訪問,CreateThread也可能成功 。如果線程運行時起始地址無效,則會發生異常,并終止線程。由于無效的起始地址而導致的線程終止將被視為線程進程的錯誤退出。此行為類似于CreateProcess的異步性質,在該過程中,即使進程引用無效或丟失的動態鏈接庫(DLL),也會創建該進程。
補充:
進程可以創建的線程數受可用虛擬內存的限制。默認情況下,每個線程都有一兆的堆棧空間。因此,您最多可以創建2,048個線程。如果減小默認堆棧大小,則可以創建更多線程。但是,如果您為每個處理器創建一個線程并構建應用程序為其維護上下文信息的請求隊列,則您的應用程序將具有更好的性能。在處理下一個隊列中的請求之前,線程將處理隊列中的所有請求。
使用THREAD_ALL_ACCESS訪問權限創建新的線程句柄。如果在創建線程時未提供安全描述符,則使用創建線程的進程的主要令牌為新線程構造默認的安全描述符。當調用者嘗試使用OpenThread函數訪問線程時,將根據此安全描述符評估調用者的有效令牌,以授予或拒絕訪問。
調用GetCurrentThread 函數時,新創建的線程對其具有完全訪問權限。
Windows Server 2003: 通過針對線程構造的默認安全描述符評估線程創建過程的主令牌,從而計算出線程對其自身的訪問權限。如果線程是在遠程進程中創建的,則使用遠程進程的主令牌。結果,新創建的線程在調用GetCurrentThread時可能會減少對其自身的訪問權限。某些訪問權限(包括THREAD_SET_THREAD_TOKEN和THREAD_GET_CONTEXT)可能不存在,從而導致意外故障。因此,不建議在模擬其他用戶的同時創建線程。
如果線程是在可運行狀態下創建的(即,如果未使用CREATE_SUSPENDED標志),則該線程可以在CreateThread返回之前(尤其是在調用者接收到所創建線程的句柄和標識符之前)開始運行。
線程執行從lpStartAddress參數指定的函數開始。如果此函數返回,則DWORD返回值用于在對ExitThread函數的隱式調用中終止線程 。使用 GetExitCodeThread函數獲取線程的返回值。
創建線程的線程優先級為THREAD_PRIORITY_NORMAL。使用 GetThreadPriority和 SetThreadPriority函數來獲取和設置線程的優先級值。
當線程終止時,線程對象將達到信號狀態,從而滿足在該對象上等待的所有線程。
線程對象將保留在系統中,直到線程終止并通過調用CloseHandle關閉了它的所有 句柄。
的 ExitProcess的, 了ExitThread, CreateThread的, CreateRemoteThread的功能,以及正在啟動的處理(如通過一個調用的結果 的CreateProcess)的一個進程中彼此之間串行化。這些事件一次只能在一個地址空間中發生。這意味著以下限制成立:
- 在進程啟動和DLL初始化例程期間,可以創建新線程,但是直到對該進程完成DLL初始化之后,它們才開始執行。
- 一個進程中只有一個線程可以同時處于DLL初始化或分離例程中。
- 直到DLL初始化或分離例程中沒有線程時,ExitProcess才會完成。
可執行文件中的調用C運行時庫(CRT)的線程應將_beginthreadex和_endthreadex函數用于線程管理,而不是 CreateThread和 ExitThread;這需要使用CRT的多線程版本。如果使用CreateThread創建的線程調用CRT,則CRT可能會在內存不足的情況下終止進程。
Windows Phone 8.1: Windows Phone 8.1及更高版本上的Windows Phone Store應用程序支持此功能。
Windows 8.1和Windows Server 2012 R2:Windows 8.1,Windows Server 2012 R2和更高版本上的Windows Store應用程序支持此功能。
代碼實現
#include <iostream> #include<Windows.h>void fun() {for (int i = 0; i < 15;i++) {printf("fun%d\n", i);} } DWORD WINAPI ThreadProc(LPVOID lpParameter) {fun();return 0; }int main() {HANDLE handle = CreateThread(NULL, 0, ThreadProc,NULL,0,NULL);CloseHandle(handle);system(" pause");}注意:
千萬不要忘了 system(" pause");,否則主線程return結束了 進程就結束了,進程結束,所有線程都沒了,輸出也就沒了,如下圖
CreateRemoteThread
函數功能
創建一個在另一個進程的虛擬地址空間中運行的線程。
使用CreateRemoteThreadEx函數可創建在另一個進程的虛擬地址空間中運行的線程,并可以選擇指定擴展屬性
函數原型:
HANDLE CreateRemoteThread(HANDLE hProcess,LPSECURITY_ATTRIBUTES lpThreadAttributes,SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId );第一個參數
要在其中創建線程的進程的句柄。該句柄必須具有PROCESS_CREATE_THREAD,PROCESS_QUERY_INFORMATION,PROCESS_VM_OPERATION,PROCESS_VM_WRITE和PROCESS_VM_READ訪問權限,并且在某些平臺上沒有這些權限可能會失敗
第二個參數
指向SECURITY_ATTRIBUTES結構的指針,該 結構為新線程指定安全描述符,并確定子進程是否可以繼承返回的句柄。如果lpThreadAttributes為NULL,則線程獲取默認的安全描述符,并且該句柄無法繼承。線程的默認安全描述符中的訪問控制列表(ACL)來自創建者的主要令牌。
Windows XP: 線程的默認安全描述符中的ACL來自創建者的主令牌或模擬令牌。對于帶有SP2的Windows XP和Windows Server 2003,此行為已更改
第三個參數
堆棧的初始大小,以字節為單位。系統將此值舍入到最接近的頁面。如果此參數為0(零),則新線程將使用可執行文件的默認大小
第四個參數
指向由線程執行的,類型為LPTHREAD_START_ROUTINE的應用程序定義的函數的指針,該指針表示遠程進程中線程的起始地址。該功能必須存在于遠程進程中
第五個參數
指向要傳遞給線程函數的變量的指針
第六個參數
控制線程創建的標志。
| 0 | 線程在創建后立即運行。 |
| CREATE_SUSPENDED 0x00000004 | 該線程以掛起狀態創建,并且直到調用ResumeThread函數后才運行 |
| STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 | 所述dwStackSize參數指定堆棧的初始保留大小。如果未指定此標志,則dwStackSize指定提交大小。 |
第七個參數
指向接收線程標識符的變量的指針。
如果此參數為NULL,則不返回線程標識符
返回值
如果函數成功,則返回值是新線程的句柄。
如果函數失敗,則返回值為NULL。要獲取擴展的錯誤信息,請調用 GetLastError。
請注意,即使lpStartAddress指向數據,代碼或不可訪問, CreateRemoteThread也可能成功。如果線程運行時起始地址無效,則會發生異常,并終止線程。由于無效的起始地址而導致的線程終止將被視為線程進程的錯誤退出。此行為類似于CreateProcess的異步性質 ,在該過程中,即使進程引用了無效或丟失的動態鏈接庫(DLL),也會創建該進程
備注:
該 遠程線程函數會導致一個新的執行線程指定進程的地址空間開始。線程有權訪問該進程打開的所有對象。
終端服務通過設計隔離每個終端會話。因此,如果目標進程與調用進程不在同一個會話中,則 CreateRemoteThread將失敗。
創建具有新線程完全訪問權限的新線程句柄。如果未提供安全描述符,則該句柄可以在需要線程對象句柄的任何函數中使用。提供安全描述符后,將在授予訪問權限之前對句柄的所有后續使用執行訪問檢查。如果訪問檢查拒絕訪問,則請求進程無法使用該句柄獲取對該線程的訪問。
如果線程是在可運行狀態下創建的(即,如果未使用CREATE_SUSPENDED標志),則該線程可以在CreateThread返回之前(尤其是在調用者接收到所創建線程的句柄和標識符之前)開始運行。
創建線程的線程優先級為THREAD_PRIORITY_NORMAL。使用 GetThreadPriority和 SetThreadPriority函數來獲取和設置線程的優先級值。
當線程終止時,線程對象將達到信號狀態,該狀態滿足正在等待該對象的線程。
線程對象將保留在系統中,直到線程終止并通過調用CloseHandle關閉了所有 句柄。
的 ExitProcess的, 了ExitThread, CreateThread的, CreateRemoteThread的功能,以及正在啟動一個過程(作為結果 的CreateProcess呼叫)的過程中彼此之間串行化。這些事件一次僅在地址空間中發生一次。這意味著以下限制成立:
- 在進程啟動和DLL初始化例程期間,可以創建新線程,但是直到對該進程完成DLL初始化之后,它們才開始執行。
- 一個進程中只有一個線程可以同時處于DLL初始化或分離例程中。
- 所有線程完成其DLL初始化或分離例程后,ExitProcess返回。
此功能的常見用法是將線程注入正在調試的進程中以發出中斷。但是,不建議使用此方法,因為多余的線程會使調試應用程序的人感到困惑,并且使用此技術有一些副作用:
- 它將單線程應用程序轉換為多線程應用程序。
- 它更改了進程的時間和內存布局。
- 它導致對進程中每個DLL的入口點的調用。
此功能的另一個常見用法是將線程注入到進程中以查詢堆或其他進程信息。這可能會導致前段所述的副作用。同樣,如果線程嘗試獲取另一個線程正在使用的鎖的所有權,則應用程序可能會死鎖。
代碼實現
test.cpp代碼:
#include <iostream>void add() {for (int i = 0; i < 15; i++){printf("add%d\n", i);} }int main() {getchar(); }CreatRemote.cpp
#include <iostream> #include<Windows.h>void fun() {for (int i = 0; i < 15;i++) {printf("fun%d\n", i);} } DWORD WINAPI ThreadProc(LPVOID lpParameter) {fun();return 0; }int main() {HANDLE handle1=OpenProcess(PROCESS_ALL_ACCESS, FALSE, 7348);HANDLE handle = CreateRemoteThread(handle1,NULL, 0, (LPTHREAD_START_ROUTINE)0x00EC1EE0,NULL,0,NULL);CloseHandle(handle); CloseHandle(handle1);system(" pause");}需要獲取兩個值,一個是PID值,一個是test中線程函數地址值
PID值7348
線程函數地址值0x00EC1EE0
運行CPP后,顯示啟動成功
然后按下test.cpp繼續運行
GAMEOVER
調用成功,GAMEOVER
未開啟遠程線程時,
運行結果:
總結
以上是生活随笔為你收集整理的CreateThread和CreateRemoteThread的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BabyXor flower逆向寒假生涯
- 下一篇: 两个小程序利用注入如何进行简单交互