进程创建
在C++中,有多种进程创建的方法 :WinExec、ShellExecute、CreateProcess、system、popen等,下面一一介绍并给出案例
1. WinExec
WinExec是一个过时的函数,用于在 Windows 操作系统中执行外部程序。它存在于早期版本的 Windows API 中,但自 Windows 2000 以后,Microsoft 已不再推荐使用它,Winexec通过返回值是否大于31来判断进程是否成功启动。 函数原型:
UINT WinExec(
LPCSTR lpCmdLine, //要执行的命令行或可执行文件的路径,可以直接传递参数
UINT uCmdShow //表示应用程序窗口的显示方式,如SW_NORMAL、SW_HIDE、SW_MAXIMIZE等
);
void WinExecFunc(){
int result = WinExec("notepad.exe WinExec", SW_NORMAL);
if (result > 31) {
// WinExec 返回大于 31 表示成功启动
printf("Notepad started successfully.\n");
} else {
printf("Failed to start Notepad.\n");
}
}
2. ShellExecute
ShellExecute用于在 Windows 操作系统中执行外部程序、打开文档、浏览网页等任务的 Windows API 函数,根据文件关联来确定如何处理指定的文件,返回大于32的值代表成功,否则失败。函数原型:
HINSTANCE ShellExecute(
HWND hwnd, //窗口句柄,可选一般是父窗口的,不关联可以用null
LPCTSTR lpOperation, //要执行的动作,例如edit、explore、find、open、print、NULL等
LPCTSTR lpFile, //要执行的文件、文档、程序或URL的路径
LPCTSTR lpParameters, //要传进去的参数
LPCTSTR lpDirectory, //执行程序的默认目录
INT nShowCmd //窗口显示方式,如SW_NORMAL、SW_HIDE、SW_MAXIMIZE等
);
void ShellExecFunc(){
HINSTANCE hInst = ShellExecute(NULL, "open", "notepad.exe", "ShellExecute", NULL, SW_SHOWNORMAL);
if ((int)(intptr_t)hInst > 32) {
printf("Notepad started successfully.\n");
} else {
printf("Failed to start Notepad. Error code: %d\n", (int)(intptr_t)hInst);
}
}
3. CreateProcess
CreateProcess是Windows API 中用于创建新进程的函数,通常用于执行外部可执行文件,非0值表示成功,否则失败。函数原型:
BOOL CreateProcess(
LPCSTR lpApplicationName, //要执行的程序的名称
LPSTR lpCommandLine, //要执行的命令,可执行文件的路径和参数。
LPSECURITY_ATTRIBUTES lpProcessAttributes, //是否可以由子进程继承返回的新进程对象的句柄
LPSECURITY_ATTRIBUTES lpThreadAttributes, //是否可以由子进程继承返回的新进程对象的句柄
BOOL bInheritHandles, //如果参数为true,则调用进程中每个可继承句柄都由新进程来继承
DWORD dwCreationFlags, //指定创建进程的方式和优先级,CREATE_NEW_CONSOLE是创建一个新控制台、CREATE_SUSPENDED表示新进程的主线程会以暂停的状态来创建,直到使用ResumeThread函数时才运行、DETACHED_PROCESS对于控制台进程,新进程没有访问父进程控制台的权限.新进程可以通过allocconsole函数自己创建一个新的控制台
LPVOID lpEnvironment, //指向新进程的环境块
LPCSTR lpCurrentDirectory, //指向进程当前目录的路径,如果为null,则新进程使用与调用进程相同的驱动器和目录
LPSTARTUPINFO lpStartupInfo, //指向一个用于决定新进程的主窗体如何显示的startupinfo结构体
LPPROCESS_INFORMATION lpProcessInformation //指向一个用来接收新进程的识别信息的process_information结构体
);
void CreateProcessFunc(){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
// 启动记事本
if (CreateProcess(
NULL, // 应用程序名称,可以设为 NULL "notepad.exe CreateProcess", // 命令行,表示要启动记事本
NULL, // 进程安全属性,可以设为 NULL NULL, // 线程安全属性,可以设为 NULL FALSE, // 不继承句柄
0, // 标志,通常为 0 NULL, // 环境变量,可以设为 NULL NULL, // 当前工作目录,可以设为 NULL &si, // STARTUPINFO 结构
&pi // PROCESS_INFORMATION 结构
)) {
printf("Notepad started successfully.\n");
CloseHandle(pi.hProcess); // 关闭进程句柄
CloseHandle(pi.hThread); // 关闭线程句柄
} else {
printf("Failed to start Notepad. Error code: %d\n", GetLastError());
}
}
4. system
system是标准C/C++库中的函数,用于执行操作系统命令,返回非0值代表执行失败,函数原型:
案例:void systemFunc(){
int result = system("notepad system");
if (result == 0) {
printf("Command executed successfully.\n");
} else {
printf("Command failed to execute.\n");
}
}
5. popen
popen是标准C库中的函数,用于创建一个管道并启动子进程执行外部程序,这个在上一篇文章《远程线程注入》中的tasklist我就用的这个,函数原型:
案例代码:void popenFunc(){
FILE *fp;
char buffer[128];
// 打开管道并执行命令
fp = popen("notepad popen", "r");
if (fp == NULL) {
printf("Failed to execute command.\n");
exit(0);
}
// 读取子进程的输出
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("Output: %s", buffer);
}
// 关闭管道
pclose(fp);
}
另,补充一下
远程线程注入dll的时候无法多次注入,刚刚找到了一个方法卸载掉dll(参数与注入的一致):
BOOL UnInjectDll(DWORD dwProcessId, char *ptszDllFile)
{
// 参数无效
if (NULL == ptszDllFile || 0 == ::_tcslen(ptszDllFile))
{
return false;
}
HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
// 获取模块快照
hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId);
if (INVALID_HANDLE_VALUE == hModuleSnap)
{
return false;
}
MODULEENTRY32 me32;
memset(&me32, 0, sizeof(MODULEENTRY32));
me32.dwSize = sizeof(MODULEENTRY32);
// 开始遍历
if (FALSE == ::Module32First(hModuleSnap, &me32))
{
::CloseHandle(hModuleSnap);
return false;
}
// 遍历查找指定模块
bool isFound = false;
do
{
isFound = (0 == ::_tcsicmp(me32.szModule, ptszDllFile) || 0 == ::_tcsicmp(me32.szExePath, ptszDllFile));
if (isFound) // 找到指定模块
{
break;
}
} while (TRUE == ::Module32Next(hModuleSnap, &me32));
::CloseHandle(hModuleSnap);
if (false == isFound)
{
return false;
}
// 获取目标进程句柄
hProcess = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (NULL == hProcess)
{
return false;
}
// 从 Kernel32.dll 中获取 FreeLibrary 函数地址
LPTHREAD_START_ROUTINE lpThreadFun = (PTHREAD_START_ROUTINE)::GetProcAddress(::GetModuleHandle(_T("Kernel32")), "FreeLibrary");
if (NULL == lpThreadFun)
{
::CloseHandle(hProcess);
return false;
}
// 创建远程线程调用 FreeLibrary hThread = ::CreateRemoteThread(hProcess, NULL, 0, lpThreadFun, me32.modBaseAddr /* 模块地址 */, 0, NULL);
if (NULL == hThread)
{
::CloseHandle(hProcess);
return false;
}
// 等待远程线程结束
::WaitForSingleObject(hThread, INFINITE);
// 清理
::CloseHandle(hThread);
::CloseHandle(hProcess);
return true;
}