启动技术-创建进程API

本文最后更新于:2021-08-30 下午

创建进程API

在一个进程中创建并启动一个新的进程,对于病毒木马程序和普通的程序来说,都是常见的技术。在用户层上微软提供WinExec,ShellExecute和CreateProcess等函数来实现进程创建。

具体实现及函数介绍

WinExec

运行指定的应用程序

1
2
3
4
UINT WinExec(
LPCSTR lpCmdLine,
UINT uCmdShow
);

lpCmdLine:要执行的应用程序的命令行。如果参数中的可执行文件名称不包含文件路径,则系统按以下顺序搜索可执行文件:

  1. 应用程序加载的目录
  2. 当前目录
  3. Windows系统目录。GetSystemDirectory函数检索此目录的路径。
  4. Windows目录。GetWindowsDirectory函数检索此目录的路径。
  5. PATH环节变量中列出的目录

uCmdShow:显示选项,具体内容如下表:

含义
SW_HIDE
0
隐藏窗口并激活另一个窗口
SW_SHOWNORMAL
SW_NORMAL
1

激活并显示一个窗口
SW_SHOWMINIMIZED
2
激活窗口并将其显示为最小化的窗口
SW_SHOWMAXIMIZED
SW_MAXIMIZE
3
激活窗口并将其显示为最大化窗口
SW_SHOWNOACTIVATE
4
以最近的大小和位置显示窗口
SW_SHOW
5
激活窗口并以其当前大小和位置显示它
SW_MINIMIZE
6
最小化指定的窗口并激活Z顺序中的下一个顶级窗口
SW_SHOWMINNOACTIVE
7
将窗口显示为最小化窗口
SW_SHOWNA
8
以当前大小和位置显示窗口
SW_RESTORE
9
激活并显示窗口
SW_SHOWDEFAULT
10
根据启动应用程序的程序传递给CreateProcess函数的STARTUPINFO结构中指定的SW_值设置显示状态。
SW_FORCEMINIMIZE
11
最小化一个窗口,即使拥有该窗口的线程没有响应。仅在最小化来自不同线程的窗口时才应使用此标志。

返回值:如果函数成功,则返回值大于31;如果函数失败,则返回值是以下错误值之一。

含义
0 系统内存或资源不足
ERROR_BAD_FORMAT exe文件无效
ERROR_FILE_NOT_FOUND 找不到指定文件
ERROR_PATH_NOT_FOUND 找不到指定的路径

具体代码如下:

1
2
3
4
5
6
7
8
9
10
BOOL Open(char* szPath, UINT uiCmdshow)
{
UINT uiRet = 0;
uiRet = WinExec(szPath, uiCmdshow);
if (uiRet > 31)
{
return TRUE;
}
return FALSE;
}

创建的进程为之前编写过得MFC程序,运行此程序即可提示创建成功,同时TestAPC也被成功创建。

ShellExecute函数

对指定文件执行操作

1
2
3
4
5
6
7
8
HINSTANCE ShellExecuteA(
HWND hwnd,
LPCSTR lpOperation,
LPCSTR lpFile,
LPCSTR lpParameters,
LPCSTR lpDirectory,
INT nShowCmd
);

hwnd:用于显示UI或者错误信息的父窗口的句柄。如果操作与窗口无关,则此值可以为NULL。

lpOperation:指向以空字符结尾的字符串的指针,它在本例中成为动词,用于指定要执行的操作。常使用的动词有:

  • edit:启动编辑器并打开文档进行编辑。如果lpFile不是文档文件,则该函数将失败。
  • explore:探索由lpFile指定的文件夹。
  • find:在由lpDirectory指定的目录中启动搜索。
  • open:打开由lpFile指定的项目。该项目可以是文件也可以是文件夹。
  • print:打印由lpFile指定的文件。如果lpFile不是文档文件,则该函数失败。
  • NULL:如果可用,则使用默认动词。如果不可用,则使用“打开”动词。如果两个动词都不可用,则系统使用注册表中列出的第一个动词。

lpFile:指向以空字符结尾的字符串的指针,该字符串要在其上指向指定谓词的文件或对象。如果lpDirectory参数使用相对路径,则lpFile不要使用相对路径。

lpParameters:如果lpFile指定一个可执行文件,则此参数是一个指向空字符结尾的字符串的指针,该字符串指定要传递给应用程序的参数。如果lpFile指定一个文档文件,则lpParameters应该为NULL。

lpDirectory:指向以空终止的字符串的指针,该字符串指定操作的默认目录。如果此值为NULL,则使用当前的工作目录。如果在lpFile提供了相对路径,请不要对lpDirectory使用相对路径。

nShowCmd:指定应用程序在打开时如何显示标志,具体值在上文。

返回值:如果函数成功,则返回大于32的值。如果函数失败,则它返回一个错误值,指示失败的原因。

具体代码如下:

1
2
3
4
5
6
HINSTANCE hInstance = ShellExecute(NULL, NULL, "自己的文件路径", NULL, NULL, SW_NORMAL);
if ((int)hInstance <= 32) {
printf("ShellExecute创建失败\n");
}
else
printf("ShellExecute创建成功\n");

运行程序提示创建成功,同时TestAPC被成功创建。

CreateProcess

创建一个新进程及主线程。新进程在调用进程的安全的上下文中运行。

1
2
3
4
5
6
7
8
9
10
11
12
BOOL CreateProcess(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);

lpApplicationName:要执行的模块的名称。可以设置为NULL。要运行批处理文件,必须启动命令解释程序,并将其设置为cmd.exe。

lpCommandLine:要执行的命令行。

lpProcessAttributes:指向SECURITY_ATTRIBUTES结构的指针,该 结构确定返回的新进程对象的句柄是否可以被子进程继承。如果lpProcessAttributes为NULL,则不能继承句柄。

lpThreadAttributes:指向SECURITY_ATTRIBUTES结构的指针,该 结构确定返回的新线程对象句柄是否可由子进程继承。如果lpThreadAttributes为 NULL,则不能继承句柄。

bInheritHandles:如果此参数为 TRUE,则调用进程中的每个可继承句柄都由新进程继承。如果参数为 FALSE,则不继承句柄。

dwCreationFlags:控制优先级类和进程创建的标志。

lpEnvironment:指向新进程的环境块的指针。如果此参数为NULL,则新进程使用调用进程的环境。

lpCurrentDirectory:进程当前目录的完整路径。该字符串还可以指定 UNC 路径。如果此参数为NULL,则新进程将与调用进程具有相同的当前驱动器和目录。

lpStartupInfo:指向STARTUPINFO或STARTUPINFOEX结构的指针 。STARTUPINFO或STARTUPINFOEX中的句柄在不需要时必须由CloseHandle关闭。

lpProcessInformation:指向PROCESS_INFORMATION结构的指针,该结构接收有关新进程的标识信息。PROCESS_INFORMATION中的句柄必须在不需要时由CloseHandle关闭。

返回值:如果函数成功,则返回值非0;若失败,则返回值为0。

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_NORMAL;
BOOL flag = CreateProcess(NULL, "自己的文件路径", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (flag) {
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
printf("CreateProcess创建成功\n");
}
else
printf("CreateProcess创建失败\n");

运行之后,即可成功创建TestAPC进程。

参考

参考《Windows黑客编程技术详解》一书