Skip to content

进程创建

在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值代表执行失败,函数原型:

int system(
   const char *command  //command你要执行的命令,可以带参数
);
案例:
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我就用的这个,函数原型:

FILE *popen(
   const char *command,   //要执行的命令
   const char *mode       //文件访问模式,r、w
);
案例代码:
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;  
}
dll卸载代码引用:https://www.cnblogs.com/szyicol/p/13023428.html

Comments