在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: %dn", (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: %dn", 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
原文始发于微信公众号(天幕安全团队):进程创建
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论