CreateProcess
BOOL CreateProcessA(
LPCSTR lpApplicationName, //指向一个NULL结尾的、用来指定可执行模块的字符串。
LPSTR lpCommandLine, //指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。
LPSECURITY_ATTRIBUTES lpProcessAttributes, //指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。
LPSECURITY_ATTRIBUTES lpThreadAttributes, //同lpProcessAttribute,不过这个参数决定的是线程是否被继承,通常置为NULL。
BOOL bInheritHandles, //指示新进程是否从调用进程处继承了句柄。
DWORD dwCreationFlags, //指定附加的、用来控制优先类和进程的创建的标志。还用来控制新进程的优先类,优先类用来决定此进程的线程调度的优先级。
LPVOID lpEnvironment, //指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。
LPCSTR lpCurrentDirectory, //指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。
LPSTARTUPINFOA lpStartupInfo, //指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体。
LPPROCESS_INFORMATION lpProcessInformation //指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。
);
结构体
STARTUPINFO
进程启动时的相关信息,由父进程填充并传递进来。
typedef struct _STARTUPINFOA {
DWORD cb; //指定该结构大小
LPSTR lpReserved; //保留, 置为NULL
LPSTR lpDesktop; //指定一个字符串, 包括该进程的桌面名或窗口位置名
LPSTR lpTitle; //指定控制台进程创建的新控制台窗口标题
DWORD dwX; //指定新窗口左上角的X、Y偏移量(像素点)
DWORD dwY;
DWORD dwXSize; //指定新窗口的宽度和高度
DWORD dwYSize;
DWORD dwXCountChars; //指定新窗口的屏幕缓冲区的宽度和高度
DWORD dwYCountChars;
DWORD dwFillAttribute; //指定新窗口的初始文字和背景颜色
DWORD dwFlags; //创建窗口标志
WORD wShowWindow; //新窗口的显示状态
WORD cbReserved2; //保留, 置为0
LPBYTE lpReserved2; //保留, 必须置为NULL
HANDLE hStdInput; //指定一个句柄, 该句柄用作进程的标准输入句柄
HANDLE hStdOutput; //指定一个句柄, 该句柄用作进程的标准输出句柄
HANDLE hStdError; //指定一个句柄, 该句柄用作进程的标准错误句柄
} STARTUPINFOA, *LPSTARTUPINFOA;
PROCESS_INFORMATION
在创建进程时相关的数据结构之一,该结构返回有关新进程及其主线程的信息。
为什么会有线程句柄和线程ID?
进程的创建过程中一定会创建一个线程,所以该结构体中含有线程信息就能理解。
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess; //进程句柄
HANDLE hThread; //线程句柄
DWORD dwProcessId; //进程ID
DWORD dwThreadId; //线程ID
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
创建进程例子
创建一个IE浏览器进程,并打开网址。
#include <iostream>
#include <Windows.h>
//创建子进程
BOOL CreateChildProcess(PTCHAR szChildProcessName, PTCHAR szCommandLine)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
//ZeroMemory:用0来填充一块内存区域
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
//设置当前结构体大小
si.cb = sizeof(si);
//创建子进程
if (!CreateProcess(
szChildProcessName, //对象名称
szCommandLine, //命令行
NULL, //不继承进程句柄
NULL, //不继承线程句柄
FALSE, //不继承句柄
0, //没有创建标志
NULL, //使用父进程环境变量
NULL, //使用父进程目录作为当前目录
//in参数,需要传递进去给函数使用的。
&si, //STARTUPINFO 结构体详细信息
//out参数,当执行完后通过该指针写结果,相当于返回值。
&pi //PROCESS_INFORMATION 结构体进程信息
))
{
//如果创建子进程失败, 使用 GetLastError 查看错误信息。
printf("CreateChildProcess Error:%d\n", GetLastError());
return FALSE;
}
//释放句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return TRUE;
}
int main(int argc, char* argv[])
{
TCHAR szApplicationName[] = TEXT("C:\\Program Files\\Internet Explorer\\iexplore.exe");
TCHAR szCmdline[] = TEXT(" https://blog.csdn.net/qq_18120361");
CreateChildProcess(szApplicationName, szCmdline);
return 0;
}
简单反调试例子
- 由于 STARTUPINFO 结构体是由被创建的进程的父进程填充并传递过来的。
- 所以不同的父进程传递进来的结构体也可能不同。
- 可以对该结构体中的内容比较,来判断是否被调试。
#include <iostream>
#include <Windows.h>
void AntiDebug()
{
//当前进程初始化信息
//由该进程的父进程传递进来, 不同的父进程传递的结构体内容可能不同
//可以用于反调试
STARTUPINFO tmp;
//获取进程在启动时的 STARTUPINFO 结构体
GetStartupInfo(&tmp);
//没有打印结构体中的所有内容
printf("%x %x %x %x %x %x %x %x\n", tmp.dwX, tmp.dwY, tmp.dwXCountChars, tmp.dwYCountChars, tmp.dwFillAttribute, tmp.dwXSize, tmp.dwYSize, tmp.dwFlags);
return;
}