本人学习《Windows黑客编程技术详解》所做的学习笔记
- 简介:在一个进程中创建一个新的进程,是一个十分简单的技术,我们可以利用WIN32 API WinExec,ShellExecute,CreateProcess三个函数来创建进程。
1,何为进程?
① 程序,进程,线程分别是什么?
- 程序:程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念。
- 进程:进程是动态的,进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动,是系统进行资源分配和调度运行的基本单位。
- 线程:一个进程包括很多线程,是操作系统能够进行运算调度的最小单位,线程是一个进程中代码的不同执行路线。
② 进程控制块(PCB) 。
进程控制块:系统通过进程控制块来描述一个进程。进程控制块包含了进程的状态信息、控制信息以及资源信息等。
我们可以把进程想象成一个人,去了解进程控制块。
- 标识号(身份证号码):每一个进程拥有一个唯一的PID和父进程PPID,同时还拥有UID(用户标识码)和GID(组标识码),通过该两个标识符来让系统确定进程访问文件和设备的权限。
- 状态信息(年龄):进程,线程都和人一样都有着出生到死亡的几个阶段。进程的状态分别是 运行、等待、停止和僵死
- 调度信息(社会地位):系统根据你的调度信息判断先运行哪个进程
- 有关进程间通讯的信息(社交):系统利用这一信息实现进程间的通讯。
- 进程与其他进程之间的关系信息(家族族谱):除根进程以外,一个进程有指向父进程的指针,兄弟进程的指针以及子进程的指针。
- 时间和定时器信息(出生日期以及生存时间):系统保存进程的创建时间,以及在其生命周期中所花费的CPU时间。
- 文件系统信息(住宅地址):这类字段记录进程所打开的文件描述符信息。另外,还包含指向虚拟文件系统(Virtual File Systems,VFS)两个索引节点的指针,这两个索引节点分别是进程的主目录以及进程的当前目录。索引节点中有一个引用计数器,当有新的进程指向某个索引节点时,该索引节点的引用计数器会增加。未被引用的索引节点的引用计数为 0,因此,当包含在某个目录中的文件正在运行时,就无法删除这一目录,因为这一目录的引用计数大于0(与jvm可达性分析算法类似)。
- 虚拟内存与物理内存相关信息(住宅大小):每个人的房子都有大小,进程也均有自己的内存空间,为了让系统随时了解和控制进程的内存空间,PCB中必须保存进程内存空间的相关信息。
- 进程相关的上下文信息(当前的生活状态):进程上下文是用来保存进程相关的系统状态的字段。当调度程序将某个进程从运行状态切换到暂停状态时,会在上下文中保存当前的进程运行环境,包括 CPU 所有寄存器的值、进程的状态以及堆栈信息;当调度程序再次选择该进程运行时,则会从进程上下文信息中恢复进程的运行环境。
③ 进程分类
- 交互式进程:可在前后台运行,终端接受用户输入
- 批处理进程:与终端无关,以进程列的方式,无需人工干预的条件下自动完成一系列任务
- 守护进程:系统后台进程,WIN10安全中心等,系统引导时创建,系统关闭时死亡。
2,创建进程API
WinExec
函数介绍:运行一个指定的程序。
UNIT WINAPI WinExec(
_In_ LPCTSTR lpCmdLine; //要执行应用程序的命令行,如果不包含目录路径,则按应用程序目录,当前目录,Windows系统目录,Windows目录以及Path环境目录来搜索
_In_ UNIT uCmdShow //显示选项,SW_HIDE表示隐藏窗口并激活其他窗口。
)
函数成功:return Value>31
函数失败:返回以下值
- 0:系统内存资源不足
- ERROR_BAD_FORMAT:exe文件无效
- ERROR_FILE_NOT_FOUND:找不到文件
- ERROR_PATH_NOT_FOUND:找不到路径
ShellExecute
函数介绍:运行一个外部程序,并进行一定程度的控制
HINSTANCE ShellExecute(
HWND hwnd, //显示UI或错误消息的窗口句柄,可以为NULL
LPCTSTR lpOperation, //要执行的操作
LPCTSTR lpFile, //要选择的文件,如果Directory是相对路径则该字符串不能是相对路径
LPCTSTR lpParameters, //执行文件所需参数,可以为NULL
LPCTSTR lpDirectory, //文件目录,如果为当前工作目录则为NULL
INT nShowCmd //窗口显示标志
);
函数成功:return Value>32
函数失败:返回一个错误值
CreateProcess
函数介绍:创建一个新线程及主线程
BOOL CreateProcess
(
LPCTSTR lpApplicationName, //要执行的模块名称,99%的情况都为NULL
LPTSTR lpCommandLine, //要执行的命令行,不指明文件类型的话,即为.exe
LPSECURITY_ATTRIBUTES lpProcessAttributes。 //用于确定是否可以由子进程继承返回的新进程对象的句柄,NULL则不继承
LPSECURITY_ATTRIBUTES lpThreadAttributes, //用于确定是否可以由子进程继承返回的新线程对象的句柄,NULL则不继承
BOOL bInheritHandles, //若为true 则进程中的每个可继承句柄都由新进程来继承,若为false即不继承
DWORD dwCreationFlags, //控制优先级和创建进程标志
LPVOID lpEnvironment, //指向新进程环境块指针,若为NULL,则使用调用进程的环境
LPCTSTR lpCurrentDirectory, //指向文件完整目录,若为NULL,则使用调用进程目录
LPSTARTUPINFO lpStartupInfo, //新进程窗口如何显示的STARTUPINFO的结构体
LPPROCESS_INFORMATION lpProcessInformation //指向PROCESS_INFORMATION结构的指针,接受有关新进程的标识符信息
);
STARTUPINFO 结构体
typedef struct _STARTUPINFO
{
DWORD cb;
LPTSTR lpReserved;
LPTSTR lpDesktop;
LPTSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
DWORD dwYSize;
DWORD dwXCountChars;
DWORD dwYCountChars;
DWORD dwFillAttribute;
DWORD dwFlags;
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
HANDLE hStdOutput;
HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;
PROCESS_INFORMATION 结构体
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION;
注:lpProcessInformation中的PROCESS_INFORMATION不需要时应该使用CloseHandle关闭,防止发生资源泄露
函数成功:return Value != 0;
函数失败:return Value = 0;
完成代码
WinExec
BOOL WinExec_Test(char *pszExePath, UINT uiCmdShow)
{
UINT uiRet = 0;
uiRet = ::WinExec(pszExePath, uiCmdShow);
if (31 < uiRet)
{
return TRUE;
}
return FALSE;
}
//调用 bRet = WinExec_Test("E:\\Genius\Genius.exe", SW_SHOWNORMAL);
ShellExecute
BOOL ShellExecute_Test(char *pszExePath, UINT uiCmdShow)
{
HINSTANCE hInstance = 0;
hInstance = ::ShellExecute(NULL, NULL, pszExePath, NULL, NULL, uiCmdShow);
if (32 < (DWORD)hInstance)
{
return TRUE;
}
return FALSE;
}
//调用 bRet = ShellExecute_Test("E:\\Genius\\Genius.exe", SW_SHOWNORMAL);
CreateProcess
BOOL CreateProcess_Test(char *pszExePath, UINT uiCmdShow)
{
STARTUPINFO si = { 0 }; //初始化为0,必须要写
PROCESS_INFORMATION pi;
BOOL bRet = FALSE;
si.cb = sizeof(si); //cb大小设置为结构体大小
si.dwFlags = STARTF_USESHOWWINDOW; //指定wShowWindow成员有效
si.wShowWindow = uiCmdShow;
bRet = ::CreateProcess(NULL, pszExePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (bRet)
{
//不使用的句柄最好关掉,防止资源泄露
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
return TRUE;
}
return FALSE;
}
//调用 bRet = CreateProcess_Test("C:\\Genius\\Genius.exe", SW_SHOWNORMAL);