进程重影!!!

正常的删除文件操作,在删除已经被映射到内存的文件时,windows会报错阻止删除。
也就是是我们要先删除文件再映射到内存,但是文件都已经被删除了怎么映射呢?首先了解进程创建过程

调用CreateProcessW
   调用CreateProcessInternalW
      参数检查
      获取进程文件路径
      调用 BasepMapFile映射文件(内部调用NtCreateSection)
      判断是否是一个DLL文件
      判断子系统类型(只能是GUI和CUI中的一种)
      是GUI时,则去掉CREATE_NEW_CONSOLE标志,增加DETACHED_PROCESS
      如果dwCreationFlags参数中包含DEBUG_PROCESS|DEBUG_ONLY_THIS_PROCESS,则调用DbgUiConnectToDbg创建调试对象(debugPort)
      调用NtCreateProcess开始创建进程
         调用NtCreateProcessEx
             调用PspCreateProcess
                关联相关句柄的内核对象(SectionHandle,DebugPort,ExceptionPort)
                创建进程空间( MmCreateProcessAddressSpace)
                初始化进程内核对象(KeInitializeProcess)
                复制父进程的Token(PspInitializeProcessSecurity)
                初始化进程句柄表(ObInitProcess)
                把进程模块映射进内存(MmInitializeProcessAddressSpace-->MmMapViewOfSection)
                映射系统模块(PspMapSystemDll-->MmMapViewOfSection)
                把该内核对象加入到进程线程对象表(PspCidTable)中,并得到进程ID
                创建PEB(MmCreatePeb)
                获取进程句柄(ObInsertObject)
                权限检查(SeAccessCheck)
                执行(监控进程创建)回调函数(PspRunCreateProcessNotifyRoutines)
      设置进程优先级
      设置进程参数(BasePushProcessParameters)
      关闭由BasepMapFile函数创建的section句柄
      复制标准输入、输出、错误设备句柄
      调用BasepNotifyCsrOfCreation
      创建第一个线程BasepCreateFirstThread
      创建线程栈(BaseCreateStack)
      初始化线程环境块(BaseInitializeContext)
         设置寄存器
         eax = 入口点
         ebx = 参数
         esp = 栈底指针
         eip = BaseProcessStartThunk
      创建线程内核对象(NtCreateThread)
         调用PspCreateThread
            创建线程对象(ObCreateObject)
            得到线程ID(ExCreateHandle)
            初始化相关链表
            创建TEB(MmCreateTeb)
            设置线程的起始地址
            初始化线程对象(KeInitThread)
                第三个参数传入的是:PspUserThreadStartup
                调用KiInitializeContextThread
                    CtxSwitchFrame->RetAddr = KiThreadStartup;
      启动第一个线程NtResumeThread

PsSetCreateProcessNotifyRoutineEx回调函数在进程创建和退出时调用
但是,PsSetCreateProcessNotifyRoutineEx并不是在创建进程的瞬间就完成的。
在执行这一段代码时不会被调用

ntAux = pfNtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, nullptr, GetCurrentProcess(), TRUE, hSectionHandle, NULL, NULL);

而是执行了下面代码才会调用

ntAux = pfNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)ullProcEntry, NULL, FALSE, 0, 0, 0, NULL);

这里就出现了时间差,可以在PsSetCreateProcessNotifyRoutineEx之前对文件进行修改,删除,伪装成普通文件。然后来解决开头的问题
文件都已经被删除了怎么映射呢?
解决方法是
先创建文件,然后通过pfNtSetInformationFile把它挂到删除队列上

ntAux = pfNtSetInformationFile(hTargetFile, &stIOStatus, &stFileInfo, sizeof(stFileInfo), FILE_INFORMATION_CLASS::FileDispositionInformation);

当hTargetFile句柄被关闭的时候文件就会被删除。
进程重影的代码实现

// 创建一个要挂上删除队列的临时文件
HANDLE hTargetFile = CreateFile(lpszTargetFile, GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// 把文件挂上删除队列
ntAux = pfNtSetInformationFile(hTargetFile, &stIOStatus, &stFileInfo, sizeof(stFileInfo), FILE_INFORMATION_CLASS::FileDispositionInformation);
 
// 搜索文件自身名字叫做shell的资源,读出来解密
HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_SHELL2), "shell");
DWORD dwSize = SizeofResource(NULL, hRsrc);
HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
LPVOID pBuffer = LockResource(hGlobal);
memcpy(lpSource, pBuffer, dwFileSize);
memcpy(&dwOriginalSize, (void *)((unsigned long long int)pBuffer + dwFileSize), 4);
GlobalUnlock(hGlobal);
 
// 将文件映射入内存
ntAux = pfNtCreateSection(&hSectionHandle, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTargetFile);
 
// 获取解密程序的入口点
GetImageEntryPointRVA(hTargetFile, imageEntryPointRva, dwOriginalSize)
 
// 创建进程
ntAux = pfNtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, nullptr, GetCurrentProcess(), TRUE, hSectionHandle, NULL, NULL);
// 获取刚创建进程的PBI
ntAux = pfNtQueryInformationProcess(hProcess, ProcessBasicInformation, &stPBI, sizeof(stPBI), nullptr);
// 传入环境参数
ntAux = pfRtlCreateProcessParameters(&lpstProcessParams, (PUNICODE_STRING)&uTargetPath, (PUNICODE_STRING)&uDllDir, (PUNICODE_STRING)&uCurrentDir, (PUNICODE_STRING)&uTargetPath, lpEnv, (PUNICODE_STRING)&uWindowName, nullptr, nullptr, nullptr);
LPVOID lpParams = WriteParamsToProcess(hProcess, lpstProcessParams);
ReadPEB(hProcess, stPI, stPEBCopy)
WriteParamsToPEB(lpParams, hProcess, stPI)
ReadPEB(hProcess, stPI, stPEBCopy)
 
// 启动创建的进程里的主线程
ntAux = pfNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)ullProcEntry, NULL, FALSE, 0, 0, 0, NULL);
// 程序开始运行

理论出来了,要付诸于实践,来看一下实际操作
题目来源BUUCTF VNCTF2023
先给出主代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后一一对应

1.

首先创建一个文件
首先创建一个文件

2.

在这里插入图片描述
这里调用NtSetInformationFile函数,同时把文件挂到删除队列
对应C++

HANDLE hTargetFile = CreateFile(lpszTargetFile, GENERIC_READ | GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
// 把文件挂上删除队列
ntAux = pfNtSetInformationFile(hTargetFile, &stIOStatus, &stFileInfo, sizeof(stFileInfo), FILE_INFORMATION_CLASS::FileDispositionInformation);

3.

在这里插入图片描述
搜索文件资源并解密,然后锁定

// 搜索文件自身名字叫做shell的资源,读出来解密
HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_SHELL2), "shell");
DWORD dwSize = SizeofResource(NULL, hRsrc);
HGLOBAL hGlobal = LoadResource(NULL, hRsrc);
LPVOID pBuffer = LockResource(hGlobal);
memcpy(lpSource, pBuffer, dwFileSize);
memcpy(&dwOriginalSize, (void *)((unsigned long long int)pBuffer + dwFileSize), 4);
GlobalUnlock(hGlobal);

4.

在这里插入图片描述
将文件映射入内存

// 将文件映射入内存
ntAux = pfNtCreateSection(&hSectionHandle, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTargetFile);

5.

在这里插入图片描述
在这里插入图片描述
获取解密程序的入口点

// 获取解密程序的入口点
GetImageEntryPointRVA(hTargetFile, imageEntryPointRva, dwOriginalSize)

6.

在这里插入图片描述

创建进程

// 创建进程
ntAux = pfNtCreateProcess(&hProcess, PROCESS_ALL_ACCESS, nullptr, GetCurrentProcess(), TRUE, hSectionHandle, NULL, NULL);

7.

在这里插入图片描述
获取刚创建进程的PBI

// 获取刚创建进程的PBI
ntAux = pfNtQueryInformationProcess(hProcess, ProcessBasicInformation, &stPBI, sizeof(stPBI), nullptr);

8.

在这里插入图片描述
环境参数处理

// 传入环境参数
ntAux = pfRtlCreateProcessParameters(&lpstProcessParams, (PUNICODE_STRING)&uTargetPath, (PUNICODE_STRING)&uDllDir, (PUNICODE_STRING)&uCurrentDir, (PUNICODE_STRING)&uTargetPath, lpEnv, (PUNICODE_STRING)&uWindowName, nullptr, nullptr, nullptr);
LPVOID lpParams = WriteParamsToProcess(hProcess, lpstProcessParams);
ReadPEB(hProcess, stPI, stPEBCopy)
WriteParamsToPEB(lpParams, hProcess, stPI)
ReadPEB(hProcess, stPI, stPEBCopy)

9.

在这里插入图片描述
启动创建的进程里的主线程

// 启动创建的进程里的主线程
ntAux = pfNtCreateThreadEx(&hThread, THREAD_ALL_ACCESS, NULL, hProcess, (LPTHREAD_START_ROUTINE)ullProcEntry, NULL, FALSE, 0, 0, 0, NULL);
// 程序开始运行
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值