• 进程相关的API函数


    0x01. ID与句柄

    如果我们成功创建一个进程之后,CreateProcess会返回四个数据,id和句柄
    句柄的话就是 当前进程私有的句柄表索引(这是当前进程,给别进程也没用)

    每个进程都有一张自己的句柄表,这是私有的句柄表;
    而操作系统也有一张,叫全局句柄表,里面包含了所有的正在运行的进程和线程

    两种私有和全局的结构都是一样的

    看下代码,这个就是进程句柄,当进程创建成功后,这就是当前进程的句柄(私有)
    进程ID就是全局句柄表中的编号,也就是索引 (全局)

    这个进程ID是全局的,唯一的,但是它不会永远不变的,当进程死了之后,再开启,ID就会变
    这边就使用代码来验证一下

    #include <stdio.h>
    #include <windows.h>
    
    BOOL CreateChildProcess(PTCHAR szChildProcessName, PTCHAR szCommandLine)
    {
    	STARTUPINFO si;
    	PROCESS_INFORMATION pi;
    
    	ZeroMemory(&pi, sizeof(pi));
    	ZeroMemory(&si, sizeof(si));
    	si.cb = sizeof(si);
    
    	//创建子进程 返回成功与失败
    	if (!CreateProcess(
    		szChildProcessName,  //对象名称(完整的路径+exe)
    		szCommandLine,		 //命令行
    		NULL,				 //不继承进程句柄
    		NULL,				 //不继承线程句柄
    		FALSE,				 //不继承句柄
    		0,				     //没有创建标志
    		NULL,                //使用父进程环境变量
    		NULL,				 //使用父进程目录作为当前目录,可以自己设置目录
    		&si,				 //STARTUPINFOW结构体详细信息
    		&pi)				 //PROCESS_INFOMATION结构体进程信息
    		)
    	{
    		printf("CreateChildProces Error: %d
    ", GetLastError());
    		return FALSE;
    	}
    	//打印进程
    	printf("PID:%d   ", pi.dwProcessId);
    	printf("进程句柄:%#x
    ", pi.hProcess);
    
    
    	//printf("线程ID:%d   ", pi.dwThreadId);
    	//printf("线程句柄:%#x
    ", pi.hThread);
    
    	//获取进程信息
    	/*SuspendThread(pi.hThread);
    	ResumeThread(pi.hThread);*/
    
    	//释放句柄
    	CloseHandle(pi.hProcess);
    	CloseHandle(pi.hThread);
    	return TRUE;
    }
    
    
    int main(int argc, char* argv[])
    {
    	//TCHAR szApplicationName[] = TEXT("D:/Program Files/Tencent/QQ/Bin/QQScLauncher.exe");
    	TCHAR szApplicationName[] = TEXT("C:/Users/86183/Desktop/shellcode.exe");
    	//TCHAR szCmdline[] = TEXT("ipconfig");
    	CreateChildProcess(szApplicationName, NULL);
    
    	getchar();
    	return 0;
    }
    

    我们先把main函数的代码注释掉,然后再修改一下

    我们通过程序知道了句柄是 0xf8

    int main(int argc, char* argv[])
    {
    	HANDLE hProcess;
    	hProcess - (HANDLE)0xf8;
    	//hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 0x);
    	if (!TerminateProcess(hProcess, 1))
    	{
    		printf("终止进程失败: %d 
    ", GetLastError());
    	}
    
    	/*
    	//TCHAR szApplicationName[] = TEXT("D:/Program Files/Tencent/QQ/Bin/QQScLauncher.exe");
    	TCHAR szApplicationName[] = TEXT("C:/Users/86183/Desktop/shellcode.exe");
    	//TCHAR szCmdline[] = TEXT("ipconfig");
    	CreateChildProcess(szApplicationName, NULL);
    	*/
    
    	getchar();
    	return 0;
    }
    

    改好后如上
    我们把A进程的句柄赋值给B进程,然后我们直接运行看看

    看到了这边得到了报错码 6,我们直接去查看下这是什么错误

    这就验证我们的念想了,每个进程中的句柄都是私有的,把A进程的句柄给 B进程是没有用的,会显示句柄无效

    我们知道PID是公有的,那我们就可以用PID试试,换种玩法,涉及到了新函数,OpenProcess

    f1 查看下是什么,OpenProcess打开已经存在的一个进程,有三个参数
    直接查看最后一个,获取PID进行识别,因为PID是全局的,所以可以识别
    第二个参数,判断打开的进程允不允许子进程是否继承它(父进程就是我写的这个程序)
    第一个参数,你要打开的进程希望拥有什么权利,是拥有创建进程的权利,还是创建进程的,还是所有的

    当我们启动这个进程的时候就会杀掉下面那个程序,最后发现成功关闭了

    0x02. 以挂起的形式创建进程

    CreateProcessW(
        LPCWSTR lpApplicationName,
        LPWSTR lpCommandLine,
        LPSECURITY_ATTRIBUTES lpProcessAttributes,
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        BOOL bInheritHandles,
        DWORD dwCreationFlags,     /
        LPVOID lpEnvironment,
        LPCWSTR lpCurrentDirectory,
        LPSTARTUPINFOW lpStartupInfo,
        LPPROCESS_INFORMATION lpProcessInformation
        );
    

    我们F1看下第 6 个参数 dwCreationFlags 是什么

    其实我们之前创建的代码都是公用一个窗口


    这是CreateProcessCreationFlags 可以选择新创建一个控制台,具体可以自己试试

    然后这边以挂起的方式创建,流程就会变

          1、映射EXE文件
          2、创建内核对象`EPROCESS`
          3、映射系统DLL(ntdll.dll)
          4、创建线程内核对象`ETHREAD`
          5、如果是挂起的方式创建的:
                然后就能在这边做其他的...
                ....
          6、恢复以后再执行
                映射DLL(ntdll.LdrlnitializeThunk)
                线程开始执行
    

    当走到这的时候进程已经创建好了,还有映射和线程还没做,所以我们可以在下面做些小动作

    具体还可以换成恶意程序,这边使用for循环来演示,如果这个循环没有执行完,这个进程就不会启动
    执行完了也不能继续跑,因为我们要放开它,让它继续跑,要使用 ResumeThread() 这个函数

    实验代码就在如下:

    #include <stdio.h>
    #include <windows.h>
    
    BOOL CreateChildProcess(PTCHAR szChildProcessName, PTCHAR szCommandLine)
    {
    	STARTUPINFO si;
    	PROCESS_INFORMATION pi;
    
    	ZeroMemory(&pi, sizeof(pi));
    	ZeroMemory(&si, sizeof(si));
    	si.cb = sizeof(si);
    
    	//创建子进程 返回成功与失败
    	if (!CreateProcess(
    		szChildProcessName,  //对象名称(完整的路径+exe)
    		szCommandLine,		 //命令行
    		NULL,				 //不继承进程句柄
    		NULL,				 //不继承线程句柄
    		FALSE,				 //不继承句柄
    		CREATE_SUSPENDED,				     //没有创建标志
    		NULL,                //使用父进程环境变量
    		NULL,				 //使用父进程目录作为当前目录,可以自己设置目录
    		&si,				 //STARTUPINFOW结构体详细信息
    		&pi)				 //PROCESS_INFOMATION结构体进程信息
    		)
    	{
    		printf("CreateChildProces Error: %d
    ", GetLastError());
    		return FALSE;
    	}
    	//打印进程
    	printf("PID:%d   ", pi.dwProcessId);
    	printf("进程句柄:%#x
    ", pi.hProcess);
    
    	for (int i = 0; i < 5; i++)
    	{
    		Sleep(1000);
    		printf("---------------------------
    ");
    	}
    
    	ResumeThread(pi.hThread);
    	//printf("线程ID:%d   ", pi.dwThreadId);
    	//printf("线程句柄:%#x
    ", pi.hThread);
    
    	//获取进程信息
    	/*SuspendThread(pi.hThread);
    	ResumeThread(pi.hThread);*/
    
    	//释放句柄
    	CloseHandle(pi.hProcess);
    	CloseHandle(pi.hThread);
    	return TRUE;
    }
    
    
    int main(int argc, char* argv[])
    {
    	//HANDLE hProcess;
    	////hProcess = (HANDLE)0xf8;
    	//hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6124);
    	//if (!TerminateProcess(hProcess, 1))
    	//{
    	//	printf("终止进程失败: %d 
    ", GetLastError());
    	//}
    
    	
    	//TCHAR szApplicationName[] = TEXT("D:/Program Files/Tencent/QQ/Bin/QQScLauncher.exe");
    	TCHAR szApplicationName[] = TEXT("C:/Users/86183/Desktop/shellcode.exe");
    	//TCHAR szCmdline[] = TEXT("ipconfig");
    	CreateChildProcess(szApplicationName, NULL);
    	
    
    	getchar();
    	return 0;
    }
    

    然后CreateProcess还有四个参数没讲

    CreateProcessW(
        LPCWSTR lpApplicationName,
        LPWSTR lpCommandLine,
        LPSECURITY_ATTRIBUTES lpProcessAttributes,
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        BOOL bInheritHandles,
        DWORD dwCreationFlags,     
        LPVOID lpEnvironment,                  //使用父进程环境变量,没啥的,NULL就可以了
        LPCWSTR lpCurrentDirectory,            //使用父进程目录作为当前目录,可以自己设置目录
        LPSTARTUPINFOW lpStartupInfo            //STARTUPINFOW结构体详细信息
        LPPROCESS_INFORMATION lpProcessInformation      //PROCESS_INFOMATION结构体进程信息
        );
    
    int main(int argc, char* argv[])
    {
    	//HANDLE hProcess;
    	////hProcess = (HANDLE)0xf8;
    	//hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 6124);
    	//if (!TerminateProcess(hProcess, 1))
    	//{
    	//	printf("终止进程失败: %d 
    ", GetLastError());
    	//}
    
    	
    	//TCHAR szApplicationName[] = TEXT("D:/Program Files/Tencent/QQ/Bin/QQScLauncher.exe");
    	//TCHAR szApplicationName[] = TEXT("C:/Users/86183/Desktop/shellcode.exe");
    	//TCHAR szCmdline[] = TEXT("ipconfig");
    	//CreateChildProcess(szApplicationName, NULL);
    	
    
    	wchar_t strModule[256];
    	GetModuleFileName(NULL, strModule, 256); //获取当前exe所在的路径(得到当前模块路径)
    
    	wchar_t strWork[1000];
    	int i = 1000;
    	GetCurrentDirectory(1000, strWork);  //得到当前工作路径
    
    	printf("模块路径: %s 
    工作路径:%s 
    ", strModule, strWork);
    
    	getchar();
    	return 0;
    }
    

    exe在哪里,模块路径就在哪里
    工作路径就是创建进程的地方

    lpCurrentDirectory可以设置成null,那这个有什么意义吗?
    比如我们之前读取文件函数
    FILE* fp = fopen("A.exe","r")
    这个时候就会在当前目录找,

    0x03. 其他进程相关的API:

    获取进程PID
    GetCurrentProcessid
    获取进程句柄
    GetCurrentProcess

    获取命令行
    GetCommandLine
    获取启动信息
    GetStartupInfo

    遍历进程ID
    EnumProcesses

    快照
    CreateToolhelp32Snapshot

  • 相关阅读:
    C++_标准模板库STL概念介绍2-泛型编程
    C++_标准模板库STL概念介绍1-建立感性认知
    C++_新特性1-类型转换运算符
    C++_新特性2-RTTI运行阶段类型识别
    C++_异常9-异常的注意事项
    C++_异常8-异常、类和基础
    C++_异常7-exception类
    C++_异常6-其他异常特性
    redis数据类型之—List
    redis数据类型之—Hash
  • 原文地址:https://www.cnblogs.com/0x7e/p/13826125.html
Copyright © 2020-2023  润新知