目录
0x00 进程:
什么叫进程?所谓进程,就是一个运行中的程序。
进程的相关信息:
1.如何去了解进程?
- 任务管理器
- 命令:tasklist
- 命令:wmic 然后输入process
2.进程的组成:
- 每个进程都有它的可执行文件(代码,每个进程都会有一个主函数)
- 每个进程都有其所控制的内存段(这个内存可以只由这个进程使用,即绑定了所有权;也可以共享使用,即共享内存)
- 每个进程都有属于自己的时钟
- CPU的时间片
- 进程所占据的其他资源(图片资源呀,堆内存呀)
3.两种简单的CPU调度算法
1.绝对公平机制
CPU公平的分配给每个进程,这些进程存放在一个队列中。例如:CPU先分配给进程1处理5ms,然后分配给进程2处理5ms,然后分配给进程3处理5ms
2.优先机制
例如操作系统的启动进程boot,优先占据CPU,只有当这个进程用完CPU之后,其他进程才能使用CPU
4.进程的优先级:
5.进程的状态:
- 运行时
- 等待
- 挂起状态
- 睡眠状态
- 死亡状态:进程结束了,但是它占据的资源还没有被释放,这个时间非常短,但是存在。死亡状态占据的资源最终是可以被回收的。
- 僵尸状态:进程结束了,但是它占据的资源还没有被释放,并且我们没有办法释放这些资源。解决方法:重启操作系统。
培训机构有时真是误人子弟呀,学了操作系统回头来看自己的笔记,真是谬误颇多。进程的状态应该如下分类:
1.就绪态:被分配了内存等资源,但是还有被分配CPU
2.运行态:被分配了资源,并且被分配了CPU
3.等待态(阻塞态,挂起态):进程被剥夺CPU和资源,进入外存的阻塞队列。
4.僵尸态:子进程结束后,父进程收尸前的这一段时间子进程的状态称为僵尸态。
6.僵尸进程出现的原因:
进程结束的方式:
1.进程自己结束自己,操作系统os控制这个进程的进程会回收这个进程的资源。
2.进程被别的进程干掉:如果该进程有父进程,那么父进程负责进程资源的回收。如果没有父进程,操作系统的init进程(它是操作系统的第一个进程)会收养这个进程,负责进程资源的回收。
如果一个进程有父进程,但是父进程先于子进程结束,在init进程收养子进程之前,子进程被别的进程干掉了。那么子进程就会变成僵尸进程。
所以,保证父进程晚于子进程结束,就能避免僵尸进程的产生。
7.创建进程的方式
- 运行可执行程序
- 命令行运行。
- 在程序中执行命令行命令:system("c://xxxx//Desktop//xxx.exe")
- 在程序中调用windowsAPI 创建进程
- CreateProcess创建一个进程
CreateProcessW( LPCWSTR lpApplicationName, //应用程序名 LPWSTR lpCommandLine, //命令行参数 LPSECURITY_ATTRIBUTES lpProcessAttributes, //进程属性 LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程属性,因为一个进程可以有多个线程 BOOL bInheritHandles,//是否继承 DWORD dwCreationFlags,//创建方式 LPVOID lpEnvironment,//环境变量 LPCWSTR lpCurrentDirectory,//当前目录 LPSTARTUPINFOW lpStartupInfo,//启动信息 LPPROCESS_INFORMATION lpProcessInformation//返回进程信息 );
实例:用一个程序打开12-三级缓存.exe并输出该进程的相关信息
#include <iostream> #include <Windows.h> #include <cstring> using namespace std; int main() { STARTUPINFO startInfo = { 0 }; startInfo.lpTitle = new char[256]; strcpy(startInfo.lpTitle, TEXT("程序中打开GDI程序")); PROCESS_INFORMATION processInfo; bool is = CreateProcess(TEXT("C:\\Users\\Administrator\\Desktop\\我的代码\\2019-11\\13-三级缓存防闪烁\\12-三级缓存防闪烁\\Debug\\12-三级缓存防闪烁.exe"),NULL,NULL,NULL,false,NULL,NULL,NULL,&startInfo,&processInfo); if (is) { cout << TEXT("创建进程成功!") << endl; cout << "进程id:" << processInfo.dwProcessId << endl; cout << "线程id:" << processInfo.dwThreadId << endl; cout << "进程句柄:" << processInfo.hProcess << endl; cout << "线程句柄:" << processInfo.hThread << endl; } else { cout << TEXT("创建进程失败!") << endl; } return 0; }
-
当一个应用程序需要对系统资源进行管理时,这个应用程序的图标上就会有一个盾牌,CreateProcess函数无法直接启动一个有盾牌的应用程序,因为CreateProcess会默认以标准用户的身份去启动这个程序。但是启动“盾牌”程序需要管理员身份。这时就需要我们在代码中手动提权,以管理员身份启动程序(对应函数ShellExecuteEx)。代码如下:
-
首先,我封装了一个专门用来提权启动的函数CreateProcessAsAdmin(PTCHAR fileName):
HANDLE CreateProcessAsAdmin(PTCHAR fileName) { SHELLEXECUTEINFO sei = {0}; sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.lpVerb = TEXT("runas"); sei.lpFile = fileName; sei.nShow = SW_SHOWNORMAL; sei.fMask = SEE_MASK_NOCLOSEPROCESS; if (!ShellExecuteEx(&sei)) { DWORD dwError = GetLastError(); if (dwError == ERROR_CANCELLED) { cout << "提权失败!" << endl; } else if (dwError == ERROR_FILE_NOT_FOUND) { cout << "未找到文件" << endl; } //return NULL;//可有可无 } return sei.hProcess; }
注意:fMask必须设置为SEE_MASK_NOCLOSEPROCESS,否则sei.hProcess的值为空。return NULL可有可无,因为如果进程打开失败,sei.hProcess的值本来就是NULL(第一步时我们将整个结构体置零了哦)。
-
主函数逻辑:创建进程,如果进程创建失败
int main(){ TCHAR buff[1024] = TEXT("C:\\Users\\Rui\\Desktop\\MapKeyboard.exe"); STARTUPINFO startUpInfo = { sizeof(startUpInfo) }; PROCESS_INFORMATION processInformation; BOOL isCreate = CreateProcess(NULL, buff, NULL, NULL, false, NULL, NULL, NULL, &startUpInfo, &processInformation); if (!isCreate) { cout << "创建子进程失败!" << endl; DWORD error = GetLastError(); if (error == ERROR_FILE_NOT_FOUND) { cout << "未找到文件" << endl; } else if (error = ERROR_CANCELLED) { cout << "权限不足" << endl; HANDLE hProcess = CreateProcessAsAdmin(buff); } } return 0; }
- CreateProcess创建一个进程
8.进程的其他函数:
1.FindWindow()
HWND FindWindowA(
LPCSTR lpClassName,//窗口类的类名
LPCSTR lpWindowName);//窗口的名字
这个函数只要给它窗口类的类名和窗口的名字,它就能返回窗口的句柄。如何知道窗口类的类名,通过工具>>spy++,只要获得窗口的句柄,那么就可以通过SendMessage来控制窗口。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <cstring>
using namespace std;
int main()
{
HWND hwnd = FindWindow("DuiHostWnd", "欢迎使用百度网盘");
if (INVALID_HANDLE_VALUE == hwnd) {
cout << "获取窗口句柄失败!" << endl;
}
else {
cout << "获取窗口句柄成功!" << endl;
}
SendMessage(hwnd, WM_DESTROY, NULL, NULL);
return 0;
}
2.OpenProccess:
用来打开一个进程,指获得这个进程的控制权限。前提是知道这个进程的id
3.TerminateProcess(进程句柄,错误码):
通过句柄来关闭一个进程
4.DWORD GetProcessId(句柄) :
通过句柄来返回一个进程的id
for instance:思路是创建一个进程,然后通过句柄关闭它,然后在通过OpenProcess打开它。通过命令行查看前后两次打开id和句柄的变化。
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include <cstring>
using namespace std;
int main()
{
STARTUPINFO startInfo = { 0 };
startInfo.lpTitle = new char[256];
strcpy(startInfo.lpTitle, TEXT("程序中打开GDI程序"));
PROCESS_INFORMATION processInfo;
bool is = CreateProcess(TEXT("C:\\Users\\Administrator\\Desktop\\我的代码\\2019-11\\13-三级缓存防闪烁\\12-三级缓存防闪烁\\Debug\\12-三级缓存防闪烁.exe"), NULL, NULL, NULL, false, NULL, NULL, NULL, &startInfo, &processInfo);
#if 1
if (is) {
cout << TEXT("创建进程成功!") << endl;
cout << "进程id:" << processInfo.dwProcessId << endl;
cout << "线程id:" << processInfo.dwThreadId << endl;
cout << "进程句柄:" << processInfo.hProcess << endl;
cout << "线程句柄:" << processInfo.hThread << endl;
TerminateProcess(processInfo.hProcess, -2);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processInfo.dwProcessId);
if (INVALID_HANDLE_VALUE == hProcess) {
printf("failure!");
}
else {
printf("open successfully\n");
cout << "process handle :" << hProcess << endl;
cout << "process id:" << GetProcessId(hProcess) << endl;
}
}
else {
cout << TEXT("创建进程失败!") << endl;
}
#endif
return 0;
}
执行结果:进程被正确的打开,正确的关闭,然后又诡异的打开,所谓诡异的打开,就是说,命令行窗口显示进程打开成功了,并且id号相同,句柄不同(正常,因为id是不变的,句柄是实施动态变化的)。但是你看不到进程被打开了。
5.EnumProcess:
枚举系统中所有进程的id,并存入到一个数组中
BOOL EnumProcesses(
DWORD *lpidProcess,
DWORD cb,
LPDWORD lpcbNeeded
);
例如:
#include <psapi.h>
#pragma comment(lib,"Psapi.lib")
DWORD processArray[1024] = { 0 };
EnumProcesses(processArray, 1024, NULL);
0x01 线程:
1.进程和线程区别:
进程是操作系统分配资源的基本单位。
线程是操作系统调度的基本单位。
一个进程至少拥有一个线程(main函数是进程的主线程),可以拥有多个线程(同一个进程的所有线程共用进程的资源,包括文件、内存)。
线程被创建后,自动开始运行,结束后不需要释放进程资源,只需释放线程本身资源
2.线程使用
2.1线程的创建
HANDLE CreateThread(//返回线程的句柄
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,//线程的属性,NULL表示默认属性
_In_ SIZE_T dwStackSize,//线程栈的大小
_In_ LPTHREAD_START_ROUTINE lpStartAddress,//线程代码的起始地址,即函数名
_In_opt_ __drv_aliasesMem LPVOID lpParameter,//线程的参数
_In_ DWORD dwCreationFlags,//创建方式
_Out_opt_ LPDWORD lpThreadId//线程的id
);
创建三个线程,分别打印不同的值
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
void f1() {
int n = 0;
while (1) {
cout << "我是主线程:"<<n++ << endl;
Sleep(1000);
}
}
void f2() {
int n = 0;
while (1) {
cout << "我是线程f2:" << n++ << endl;
Sleep(1000);
}
}
void f3() {
int n = 0;
while (1) {
cout << "我是线程f3:" << n++ << endl;
Sleep(1000);
}
}
int main()
{
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f2, NULL, NULL, NULL);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f3, NULL, NULL, NULL);
f1();
return 0;
}
注意:当f1执行结束后,就会执行return 0,进程结束,即便是f2,f3还没有返回(执行结束),也会被强制结束。
解决方法:
int main()
{
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f2, NULL, NULL, NULL);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)f3, NULL, NULL, NULL);
f1();
WaitForSingleObject(h1,INFINITE);//该函数一定要等到h1结束才会返回(阻塞函数)
return 0;
}
2.2线程参数:
注意类型转化
#include "pch.h"
#include <Windows.h>
#include <cstdio>
#include <iostream>
using namespace std;
DWORD WINAPI func(LPVOID lpThreadParameter) {
int n = *((int*)lpThreadParameter);
//int n = (int)lpThreadParameter;
cout << n << endl;
return 0;
}
int main()
{
int m = 1024;
CreateThread(NULL, NULL, func, &m, NULL, NULL);
// CreateThread(NULL,NULL,func,(LPVOID)m,NULL,NULL);
while (1);
return 0;
}
传递字符串参数举例:
#include "pch.h"
#include <Windows.h>
#include <cstdio>
#include <iostream>
using namespace std;
DWORD WINAPI func(LPVOID lpThreadParameter) {
cout <<(char*)lpThreadParameter<< endl;
return 0;
}
int main()
{
char m[1024] = "xidian university";
CreateThread(NULL, NULL, func,(LPVOID)m, NULL, NULL);
while (1);
return 0;
}
2.3线程的控制:
线程内:ExitThread 退出当前线程
线程外:TerminateThread 结束某个线程
作业:
写一个程序去关闭QQ,别人只要运行这个程序就关闭QQ
写一个程序去循环打开记事本,别人只要运行这个程序,就循环打开十几个记事本。