Windows父进程创建子进程 自我创建——我还年轻 我还年轻

在Windows操作系统环境下,通过父进程创建一个子进程来执行不同的功能,在病毒分析的过程中是一种比较常见的手段。这次的实验过程是通过伏见城来创建一个同名的子进程,也就是进程的自创建,当然也可以推广到在其他进程空间创建子线程,这就涉及到注入了,下次再聊。直接上代码:

#include<Windows.h>
#include <iostream>
void ChildProcess()
{
	MessageBoxA(NULL,"子进程","成功",MB_OK);
	Sleep(3000);
	printf("This is son process");
	ExitProcess(0);
}
int main()
{
	TCHAR szPath[MAX_PATH] = {0};
	STARTUPINFO si = { sizeof(STARTUPINFO), };//STARTUPINFO的第一个元素必须初始化为该结构体的大小
	PROCESS_INFORMATION pi = {0,};
	CONTEXT ctx = {0,};
	

	printf("This is Father Process");

	GetModuleFileName(NULL, szPath, (sizeof(TCHAR)*MAX_PATH));//当第一个参数为NULL的时候,会返回当前进程的文件路径,第二个参数指向缓冲区,第三个参数指明缓冲区的大小
	LPCSTR Path =(LPCSTR) (szPath);
	CreateProcessA(Path,NULL,NULL,NULL,FALSE, CREATE_SUSPENDED,NULL,NULL,(LPSTARTUPINFOA)&si,&pi);//以挂起的方式创建新进程

	//接下来设置线程上下文
	ctx.ContextFlags = CONTEXT_FULL;
	GetThreadContext(pi.hThread,&ctx);//获取子进程的线程上下文

	ctx.Eip = (DWORD)ChildProcess;
	//设置子进程的上下文,将ctx结构体里边的eip选项指向定义的函数(也就是将当前的eip指向子进程,直接执行子进程的函数)
	SetThreadContext(pi.hThread,&ctx);

	//之后将线程恢复
	ResumeThread(pi.hThread);

	WaitForSingleObject(pi.hProcess,INFINITE);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
}

实现的过程中一下几个结构体比较重要:

STARTUPINFO 
PROCESS_INFORMATION 
CONTEXT 

简要介绍:
STARTUPINFO

typedef struct _STARTUPINFO
{
    DWORD cb;            //包含STARTUPINFO结构中的字节数.如果Microsoft将来扩展该结构,它可用作版本控制手段.应用程序必须将cb初始化为sizeof ( STARTUPINFO )
    PSTR lpReserved;      //保留。必须初始化为N U L L
    PSTR lpDesktop;    //用于标识启动应用程序所在的桌面的名字。如果该桌面存在,新进程便与指定的桌面相关联。如果桌面不存在,便创建一个带有默认属性的桌面,并使用为新进程指定的名字。    如果lpDesktop是NULL(这是最常见的情况 ),那么该进程将与当前桌面相关联
    PSTR lpTitle;    //用于设定控制台窗口的名称。如果l p Ti t l e 是N U L L ,则可执行文件的名字将用作窗口名
    DWORD dwX;       //用于设定应用程序窗口在屏幕上应该放置的位置的x 和y 坐标(以像素为单位)。
    DWORD dwY;       //只有当子进程用CW_USEDEFAULT作为CreateWindow的x参数来创建它的第一个重叠窗口时,    才使用这两个坐标。若是创建控制台窗口的应用程序,这些成员用于指明控制台窗口的左上角

    DWORD dwXSize;  //用于设定应用程序窗口的宽度和长度(以像素为单位)只有dwYsize
    DWORD dwYSize;  // 当子进程将CW_USEDEFAULT 用作CreateWindow 的nWidth参数来创建它的第一个重叠窗口时,才使用这些值。若是创建控制台窗口的应用程序,这些成员将用于指明控制台窗口的宽度
    DWORD dwXCountChars;  //用于设定子应用程序的控制台窗口的宽度和高度(以字符为单位)
    DWORD dwYCountChars;
    DWORD dwFillAttribute;   //用于设定子应用程序的控制台窗口使用的文本和背景颜色
    DWORD dwFlags;           //请参见下一段和表4 - 7 的说明
    WORD wShowWindow;        //用于设定如果子应用程序初次调用的ShowWindow 将SW_SHOWDEFAULT 作为    nCmdShow 参数传递时,该应用程序的第一个重叠窗口应该如何出现。本成员可以是通常用于ShowWindow 函数的任何一个SW_*标识符
    WORD cbReserved2;        //保留。必须被初始化为0
    PBYTE lpReserved2;       //保留。必须被初始化为N U L L
    HANDLE hStdInput;        //用于设定供控制台输入和输出用的缓存的句柄。按照默认设置,hStdInput 用于标识键盘缓存,hStdOutput 和hStdError用于标识控制台窗口的缓存
    HANDLE hStdOutput;
    HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

这个结构体在初始化的时候需要注意,其它的字段都可以不填,但是第一个字段cb必须初始化为该结构体的大小。
PROCESS_INFORMATION

typedef struct _PROCESS_INFORMATION { 
    HANDLE hProcess; //存放每个对象的与进程相关的句柄 
    HANDLE hThread;        //返回的线程句柄。 
    DWORD dwProcessId;    //用来存放进程ID号 
    DWORD dwThreadId;      //用来存放线程ID号 
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;

在调用API函数CreateProcess之后,系统会自动的填充这个结构体
CONTEXT

typedef struct _CONTEXT
{
    DWORD           ContextFlags    // -|               +00h
    DWORD           Dr0             //  |               +04h
    DWORD           Dr1             //  |               +08h
    DWORD           Dr2             //  >调试寄存器     +0Ch
    DWORD           Dr3             //  |               +10h
    DWORD           Dr6             //  |               +14h
    DWORD           Dr7             // -|               +18h

    FLOATING_SAVE_AREA FloatSave;   //浮点寄存器区      +1Ch~~~88h

    DWORD           SegGs           //-|                +8Ch
    DWORD           SegFs           // |\段寄存器       +90h
    DWORD           SegEs           // |/               +94h
    DWORD           SegDs           //-|                +98h

    DWORD           Edi             //________          +9Ch
    DWORD           Esi             // |  通用          +A0h
    DWORD           Ebx             // |   寄           +A4h
    DWORD           Edx             // |   存           +A8h
    DWORD           Ecx             // |   器           +ACh
    DWORD           Eax             //_|___组_          +B0h

    DWORD           Ebp             //++++++            +B4h
    DWORD           Eip             // |控制            +B8h
    DWORD           SegCs           // |寄存            +BCh
    DWORD           EFlag           // |器组            +C0h
    DWORD           Esp             // |                +C4h
    DWORD           SegSs           //++++++            +C8h

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;
    typedef     CONTEXT     *PCONTEXT;
    #define     MAXIMUM_SUPPORTED_EXTENSION     512

CONTEXT_CONTROL:包含CPU的控制寄存器,比如指今指针,堆栈指针,标志和函数返回地址…AX, BX, CX, DX, SI, D
CONTEXT_INTEGER:用于标识CPU的整数寄存器.DS, ES, FS, GS
CONTEXT_FLOATING_POINT:用于标识CPU的浮点寄存器.
CONTEXT_SEGMENTS:用于标识CPU的段寄存器.SS:SP, CS:IP, FLAGS, BP
CONTEXT_DEBUG_REGISTER:用于标识CPU的调试寄存器. CONTEXT_EXTENDED_REGISTERS:用于标识CPU的扩展寄存器I
CONTEXT_FULL:相当于CONTEXT_CONTROL or CONTEXT_INTEGER or CONTEXT_SEGMENTS,即这三个标志的组合
参考链接:https://blog.csdn.net/annhf/article/details/1272601

以上代码段的实现的主要功能是,父进程创建子进程,子进程实现弹窗功.具体的实现原理是:
1、获取父进程的模块路径
2、父进程以挂起状态创建子进程(需要注意,因为是父进程实现自我创建,也就是说父进程创建的进程也是他自己,所以当父进程以挂起状态创建子进程的时候,父进程此时本身也是处于挂起状态的)
3、获取此时父进程的进程上下文来当作子进程的上下文
4、设置子进程上下文的Eip
5、重启线程
6、关闭句柄
综上,最重要的一点就是子进程的Eip的替换,直接将Eip指向子进程的函数入口处,执行子进程的功能。
最后,需要注意一点,在实际的实验过程中,注意字节的转换(也就是字符集的使用),我的实验环境是多字节字符集

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值