1.什么是线程?
答:一个线程就是操作系统的一个内核对象,在Windows操作系统内核中没有进程的概念,只有线程的概念,进程只不过是在逻辑上对一组线程及相关的资源进行的一种封装。
2.什么是进程?
答:进程是一个正在运行的程序,有一个虚拟的地址空间(4gb),地址空间有加载的exe,同时也有程序运行时所必须的dll,进程内核对象,至少一个运行的线程。
3.什么是模块,模块句柄的本质是什么?
答:模块是在内核控件运行的程序,实际上是一种目标对象文件,没有链接,不能独立运行,但是其代码可以在运行是链接到系统中作为内核的一部分运行或从内核中取下,可以动态扩展内核的功能,模块句柄的本质是模块加载进内存空间的基址。
对于内核对象句柄来说,进程中有一个句柄,不同进程中的句柄表存储的相同的句柄值代表的不是一个内核对象,句柄内核对象在进程句柄表中的索引,不同进程的相同句柄指向的不一定是同一个对象。
在不同进程中访问同一个内核对象:
1.由父进程继承给子进程。注意:即便继承了句柄,子进程却不知道自己继承了谁,句柄是什么,这只能由父进程通过进程间的通讯的方式告诉它。
2.在进程A中创建内核对象的时候,给内核对象命名,在进程B中,通过名字打开内核对象,假如此内核对象不能命名或者没有一个标识,那么就无法使用这种方式
3.使用DUplicateHandle()函数,将一个句柄从一个进程传递给另一个进程。
创建进程:
#include <windows.h>
int main()
{
STARTUPINFO st = {};
PROCESS_INFORMATION pi = {};
CreateProcess(
L"D:\\Program Files\\Tencent\\QQ\\Bin\\QQScLauncher.exe",//路径
NULL, //命令
NULL, //进程的安全属性
NULL, //线程的安全属性
FALSE, //句柄是否继承
NULL, //子进程创建方式
NULL, //环境
NULL, //程序的运行目录
&st, //启动信息
&pi //进程信息
);
return 0;
}
结束进程
void KillProcess()
{
//1 打开进程
HANDLE hProcess = OpenProcess(
PROCESS_ALL_ACCESS, //要申请的一个权限
FALSE, //句柄是否可继承
6636 //进程ID
);
//2 结束进程
TerminateProcess(hProcess, 0);
}
遍历进程
1 循环遍历(XXXFirst XXXNext) 文件遍历 (不能确定要遍历的东西的个数)
2 API两次调用(通常用于获取一个XXX的信息。第一次用于获得缓冲区大小,便于你申请,第二次用于获取信息)
void FindAllProcess()
{
//
PROCESSENTRY32 pe = {sizeof(PROCESSENTRY32)};
//1 创建一个快照
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
//2 找到第一个进程的信息
if (Process32First(hSnap, &pe) == TRUE)
{
//3 循环遍历其他进程的信息
do
{
printf("ID: %-8d", pe.th32ProcessID);
wprintf(L"%s",pe.szExeFile);
printf("\n");
} while (Process32Next(hSnap, &pe));
}
}
int main()
{
FindAllProcess();
return 0;
}
遍历模块
bool GetModuleList(DWORD dwPId) {
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
MODULEENTRY32 me32 = { sizeof(MODULEENTRY32) };
// 1. 创建一个模块相关的快照句柄
hModuleSnap = CreateToolhelp32Snapshot(
TH32CS_SNAPMODULE, // 指定快照的类型
dwPId); // 指定进程
if (hModuleSnap == INVALID_HANDLE_VALUE)
return false;
// 2. 通过模块快照句柄获取第一个模块信息
if (!Module32First(hModuleSnap, &me32)) {
CloseHandle(hModuleSnap);
return false;
}
// 3. 循环获取模块信息
do {
//printf("%d",me32.th32ProcessID);
wprintf(L"%s\n", me32.szExePath);
//...
} while (Module32Next(hModuleSnap, &me32));
// 4. 关闭句柄并退出函数
CloseHandle(hModuleSnap);
return true;
}
int main()
{
GetModuleList(5232);
return 0;
}
线程与线程调度:
创建线程
线程没有从属关系,没有主次之分,大家都是一样的,共同去抢占CPU的资源。
#include <Windows.h>
DWORD WINAPI ThreadProc(
LPVOID lpThreadParameter
)
{
int n = 0;
//1 随便循环输出一下
while (true)
{
printf("我是子线程 %d\n", n);
n++;
Sleep(100);
}
}
int main()
{
//1 创建线程
CreateThread(
NULL,
NULL,
ThreadProc,
(LPVOID)2,
NULL,
NULL
);
//2 随便循环输出一下
while (true)
{
printf("我是主线程\n");
Sleep(100);
}
return 0;
}
关于线程的等待
DWORD WINAPI ThreardPro(LPVOID pParam)
{
int i = 0;
while (i!=0x10000) //循环0x10000次
printf("%d\n", i++);
return 0;
}
int _tmain(int argc, _TCHAR* argv[]){
DWORD dwThreadId = 0;
HANDLE hThread = CreateThread(
NULL, 0,ThreardPro, NULL, 0, &dwThreadId);
// 等待线程结束,否则主线程退出,程序结束
WaitForSingleObject(hThread, -1);//-1就是等到线程结束 我们可以设置一个值,约定最多等多少毫秒
return 0;
}
枚举线程
VOID ListProcessThreads(DWORD dwPID){
HANDLE hThread = INVALID_HANDLE_VALUE;
THREADENTRY32 te32;
// 创建快照 ,创建的是当前操作系统中所有线程的快照
hThreadSnap =
CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
// 设置输入参数,结构的大小
te32.dwSize = sizeof(THREADENTRY32);
// 开始获取信息
Thread32First(hThread, &te32);
do {
if (te32.th32OwnerProcessID == dwPID)//判断一下你要获取的进程中的线程ID是不是相等。
// 显示相关信息 te32结构体的信息
} while (Thread32Next(hThread, &te32));
CloseHandle(hThread);
}
//调用时候需要输入进程ID(dwPID)
关于伪句柄与真句柄
真句柄就是存在于句柄表中的句柄。
伪句柄是一个固定值
GetCurrentProcess()能够获得当前进程的句柄,但是获得的是伪句柄,永远都是-1
GetCurrentThread()能够获得当前线程的句柄,但是获得的是伪句柄,永远都是-2。
DWORD WINAPI ChildThread(PVOID pParam) {
HANDLE hThreadParent = (HANDLE)pParam;
FILETIME stcCreationTime, stcExitTime;
FILETIME stcKernelTime, stcUserTime;
GetThreadTimes(hThreadParent, &stcCreationTime,
&stcExitTime, &stcKernelTime, &stcUserTime);
FILETIME stcLocalTime;
SYSTEMTIME stTime;
FileTimeToLocalFileTime(&stcCreationTime, &stcLocalTime);
FileTimeToSystemTime(&stcLocalTime, &stTime);
return 0;
}
int main()
{
//1 获取当前线程运行了多少时间
FILETIME stcCreationTime, stcExitTime;
FILETIME stcKernelTime, stcUserTime;
HANDLE hThread = GetCurrentThread();//当前线程句柄,实际上得到的永远都是-2.
GetThreadTimes(hThread, &stcCreationTime,
&stcExitTime, &stcKernelTime, &stcUserTime);
FILETIME stcLocalTime;
SYSTEMTIME stTime;
FileTimeToLocalFileTime(&stcCreationTime, &stcLocalTime);
FileTimeToSystemTime(&stcLocalTime, &stTime);
HANDLE hThreadParent = GetCurrentThread();
//这个函数可以将一个进程中的句柄拷贝到另外一个进程中
//我们在这里的用法,就是将本进程中的句柄往本进程中拷贝。
//拷贝成功的时候,得到的是真句柄
DuplicateHandle(
GetCurrentProcess(), // 拥有源句柄的进程句柄
GetCurrentThread(), // 指定对象的现有句柄(伪句柄)
GetCurrentProcess(), // 拥有新对象句柄的进程句柄
&hThreadParent, // 用于保存新句柄
0, // 安全访问级别
false, // 是否可以被子进程继承
DUPLICATE_SAME_ACCESS); // 转换选项
//2 创建了一个线程
HANDLE hTh = CreateThread(NULL, 0, ChildThread,
(PVOID)hThreadParent, 0, NULL);
WaitForSingleObject(hTh, -1);
return 0;
}