无导入表编译原理

前置知识

pe文件结构
windows api
API字符串隐藏原理

思路

- 获取kernel32.dll 基地址;
- 定位 GetProcAddress函数的地址;
- 使用GetProcAddress确定 LoadLibrary函数的地址;
- 然后使用 LoadLibrary加载DLL文件(例如user32.dll);
- 使用 GetProcAddress查找某个函数的地址(例如MessageBox);
- 指定函数参数;
- 调用函数。

通过PEB获取kernel32.dll 基地址

在windows操作系统中每一个进程系统都维护着一个描述该进程的结构体,我们称之为peb(进程环境块),如可执行文件加载到内存的位置,模块列表(DLL),指示进程是否被调试的标志,不同发行版的windows系统该结构体可能存在着差异,在这个结构体里就维护者一个描述所有载入模块的链表(InMemoryOrderModuleList),无论我们是否使用,系统都会载入kernel32.dll到进程的虚拟地址空间。

C++代码

// ConsoleApplication6.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
 
#include "pch.h"
#include <stdio.h>
#include "windows.h"
 
#define NT_SUCCESS(x) ((x) >= 0)
#define ProcessBasicInformation 0
 
typedef NTSTATUS(NTAPI *pfnNtWow64QueryInformationProcess64)(
    IN HANDLE ProcessHandle,
    IN ULONG ProcessInformationClass,
    OUT PVOID ProcessInformation,
    IN ULONG ProcessInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    );
 
 
typedef NTSTATUS(NTAPI *pfnNtWow64ReadVirtualMemory64)(
    IN HANDLE ProcessHandle,
    IN PVOID64 BaseAddress,
    OUT PVOID Buffer,
    IN ULONG64 Size,
    OUT PULONG64 NumberOfBytesRead
    );
 
typedef
NTSTATUS(WINAPI *pfnNtQueryInformationProcess)
(HANDLE ProcessHandle, ULONG ProcessInformationClass,
    PVOID ProcessInformation, UINT32 ProcessInformationLength,
    UINT32* ReturnLength);
 
typedef struct _PROCESS_BASIC_INFORMATION32 {
    NTSTATUS ExitStatus;
    UINT32 PebBaseAddress;
    UINT32 AffinityMask;
    UINT32 BasePriority;
    UINT32 UniqueProcessId;
    UINT32 InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION32;
 
typedef struct _UNICODE_STRING32
{
    USHORT Length;
    USHORT MaximumLength;
    PWSTR Buffer;
} UNICODE_STRING32, *PUNICODE_STRING32;
 
typedef struct _PEB32
{
    UCHAR InheritedAddressSpace;
    UCHAR ReadImageFileExecOptions;
    UCHAR BeingDebugged;
    UCHAR BitField;
    ULONG Mutant;
    ULONG ImageBaseAddress;
    ULONG Ldr;
    ULONG ProcessParameters;
    ULONG SubSystemData;
    ULONG ProcessHeap;
    ULONG FastPebLock;
    ULONG AtlThunkSListPtr;
    ULONG IFEOKey;
    ULONG CrossProcessFlags;
    ULONG UserSharedInfoPtr;
    ULONG SystemReserved;
    ULONG AtlThunkSListPtr32;
    ULONG ApiSetMap;
} PEB32, *PPEB32;
 
typedef struct _PEB_LDR_DATA32
{
    ULONG Length;
    BOOLEAN Initialized;
    ULONG SsHandle;
    LIST_ENTRY32 InLoadOrderModuleList;
    LIST_ENTRY32 InMemoryOrderModuleList;
    LIST_ENTRY32 InInitializationOrderModuleList;
    ULONG EntryInProgress;
} PEB_LDR_DATA32, *PPEB_LDR_DATA32;
 
typedef struct _LDR_DATA_TABLE_ENTRY32
{
    LIST_ENTRY32 InLoadOrderLinks;
    LIST_ENTRY32 InMemoryOrderModuleList;
    LIST_ENTRY32 InInitializationOrderModuleList;
    ULONG DllBase;
    ULONG EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING32 FullDllName;
    UNICODE_STRING32 BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    union
    {
        LIST_ENTRY32 HashLinks;
        ULONG SectionPointer;
    };
    ULONG CheckSum;
    union
    {
        ULONG TimeDateStamp;
        ULONG LoadedImports;
    };
    ULONG EntryPointActivationContext;
    ULONG PatchInformation;
} LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
 
typedef struct _PROCESS_BASIC_INFORMATION64 {
    NTSTATUS ExitStatus;
    UINT32 Reserved0;
    UINT64 PebBaseAddress;
    UINT64 AffinityMask;
    UINT32 BasePriority;
    UINT32 Reserved1;
    UINT64 UniqueProcessId;
    UINT64 InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION64;
typedef struct _PEB64
{
    UCHAR InheritedAddressSpace;
    UCHAR ReadImageFileExecOptions;
    UCHAR BeingDebugged;
    UCHAR BitField;
    ULONG64 Mutant;
    ULONG64 ImageBaseAddress;
    ULONG64 Ldr;
    ULONG64 ProcessParameters;
    ULONG64 SubSystemData;
    ULONG64 ProcessHeap;
    ULONG64 FastPebLock;
    ULONG64 AtlThunkSListPtr;
    ULONG64 IFEOKey;
    ULONG64 CrossProcessFlags;
    ULONG64 UserSharedInfoPtr;
    ULONG SystemReserved;
    ULONG AtlThunkSListPtr32;
    ULONG64 ApiSetMap;
} PEB64, *PPEB64;
 
typedef struct _PEB_LDR_DATA64
{
    ULONG Length;
    BOOLEAN Initialized;
    ULONG64 SsHandle;
    LIST_ENTRY64 InLoadOrderModuleList;
    LIST_ENTRY64 InMemoryOrderModuleList;
    LIST_ENTRY64 InInitializationOrderModuleList;
    ULONG64 EntryInProgress;
} PEB_LDR_DATA64, *PPEB_LDR_DATA64;
 
typedef struct _UNICODE_STRING64
{
    USHORT Length;
    USHORT MaximumLength;
    ULONG64 Buffer;
} UNICODE_STRING64, *PUNICODE_STRING64;
 
typedef struct _LDR_DATA_TABLE_ENTRY64
{
    LIST_ENTRY64 InLoadOrderLinks;
    LIST_ENTRY64 InMemoryOrderModuleList;
    LIST_ENTRY64 InInitializationOrderModuleList;
    ULONG64 DllBase;
    ULONG64 EntryPoint;
    ULONG SizeOfImage;
    UNICODE_STRING64 FullDllName;
    UNICODE_STRING64 BaseDllName;
    ULONG Flags;
    USHORT LoadCount;
    USHORT TlsIndex;
    union
    {
        LIST_ENTRY64 HashLinks;
        ULONG64 SectionPointer;
    };
    ULONG CheckSum;
    union
    {
        ULONG TimeDateStamp;
        ULONG64 LoadedImports;
    };
    ULONG64 EntryPointActivationContext;
    ULONG64 PatchInformation;
} LDR_DATA_TABLE_ENTRY64, *PLDR_DATA_TABLE_ENTRY64;
 
int main()
{
    DWORD dwPid = 4480;
    HANDLE m_ProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
    BOOL bTarget = FALSE;
    BOOL bSource = FALSE;
 
    IsWow64Process(GetCurrentProcess(), &bSource);
    IsWow64Process(m_ProcessHandle, &bTarget);
 
    SYSTEM_INFO si;
    GetSystemInfo(&si);
 
    if (bTarget == FALSE && bSource == TRUE)
    {
        HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll");
        pfnNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfnNtWow64QueryInformationProcess64)GetProcAddress(NtdllModule, "NtWow64QueryInformationProcess64");
        pfnNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfnNtWow64ReadVirtualMemory64)GetProcAddress(NtdllModule, "NtWow64ReadVirtualMemory64");
        PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
        if (NT_SUCCESS(NtWow64QueryInformationProcess64(m_ProcessHandle, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL)))
        {
            DWORD64 Ldr64 = 0;
            LIST_ENTRY64 ListEntry64 = { 0 };
            LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
            wchar_t ProPath64[256];
            if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL)))
            {
                if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL)))
                {
                    if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL)))
                    {
                        while (1)
                        {
                            if (LDTE64.InLoadOrderLinks.Flink == ListEntry64.Flink) break;
                            if (NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.FullDllName.Buffer, ProPath64, sizeof(ProPath64), NULL)))
                            {
                                printf("模块基址:0x%llX\n模块大小:0x%X\n模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
                            }
                            if (!NT_SUCCESS(NtWow64ReadVirtualMemory64(m_ProcessHandle, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(_LDR_DATA_TABLE_ENTRY64), NULL))) break;
                        }
                    }
                }
            }
        }
 
    }
    else if (bTarget == TRUE && bSource == TRUE || si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_AMD64 ||
        si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_IA64)
    {
        HMODULE NtdllModule = GetModuleHandle(L"ntdll.dll");
        pfnNtQueryInformationProcess NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(NtdllModule, "NtQueryInformationProcess");
        PROCESS_BASIC_INFORMATION32 pbi32 = { 0 };
        if (NT_SUCCESS(NtQueryInformationProcess(m_ProcessHandle, ProcessBasicInformation, &pbi32, sizeof(pbi32), NULL)))
        {
            DWORD Ldr32 = 0;
            LIST_ENTRY32 ListEntry32 = { 0 };
            LDR_DATA_TABLE_ENTRY32 LDTE32 = { 0 };
            wchar_t ProPath32[256];
            if (ReadProcessMemory(m_ProcessHandle, (PVOID)(pbi32.PebBaseAddress + offsetof(PEB32, Ldr)), &Ldr32, sizeof(Ldr32), NULL))
            {
                if (ReadProcessMemory(m_ProcessHandle, (PVOID)(Ldr32 + offsetof(PEB_LDR_DATA32, InLoadOrderModuleList)), &ListEntry32, sizeof(LIST_ENTRY32), NULL))
                {
                    if (ReadProcessMemory(m_ProcessHandle, (PVOID)(ListEntry32.Flink), &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL))
                    {
                        while (1)
                        {
                            if (LDTE32.InLoadOrderLinks.Flink == ListEntry32.Flink) break;
                            if (ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.FullDllName.Buffer, ProPath32, sizeof(ProPath32), NULL))
                            {
                                printf("模块基址:0x%X\n模块大小:0x%X\n模块路径:%ls\n",LDTE32.DllBase,LDTE32.SizeOfImage,ProPath32);
                            }
                            if (!ReadProcessMemory(m_ProcessHandle, (PVOID)LDTE32.InLoadOrderLinks.Flink, &LDTE32, sizeof(_LDR_DATA_TABLE_ENTRY32), NULL)) break;
                        }
                    }
                }
            }
        }
    }
    CloseHandle(m_ProcessHandle);
    getchar();
}
 
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
 
// 入门提示: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

汇编代码

HMODULE GetKernel32() {
    HMODULE hModule;
    _asm {
       mov eax, fs: [0x30]//fs:[00]位置存放着当前线程的线程环境块(teb),teb的0x30偏移处存放着当前线程所属进程的peb。
       mov eax, [eax + 0xc]//EAX = PEB->Ldr
       mov esi, [eax + 0x14]//ESI = PEB->Ldr.InMemOrder
       lodsd          //EAX = Second module
       xchg eax, esi     //EAX = ESI, ESI = EAX
       lodsd          //Next module
       mov ebx, [eax + 0x10]//EBX = Base address
       mov hModule,ebx
    }
    return hModule;
}

无导入表运行shellcode

int main() {
    //UCHAR shellcode[] =  {'\xbd','\xb0','\x63','\xa7','\x89','\xda','..........【shellcode】..........'};


    typedef LPVOID(WINAPI *pVirtualAlloc)(LPVOID, DWORD, DWORD, DWORD);
    typedef BOOL(WINAPI *pVirtualProtect)(LPVOID,DWORD,DWORD,PDWORD);
    typedef BOOL(WINAPI* pWriteProcessMemory)(HANDLE, LPVOID, LPVOID, DWORD, LPDWORD);

    DWORD oldProtect=0;
    HMODULE hKernal32 = GetKernal32();
    pVirtualAlloc VirtualAlloc=(pVirtualAlloc)GetProcAddress(hKernal32, "VirtualAlloc");
    pVirtualProtect VirtualProtect = (pVirtualProtect)GetProcAddress(hKernal32, "VirtualProtect");
    pWriteProcessMemory WriteProcessMemory = (pWriteProcessMemory)GetProcAddress(hKernal32, "WriteProcessMemory");

    //PVOID Address = VirtualAlloc(NULL, sizeof(shellcode) + 1, MEM_COMMIT, PAGE_READWRITE);

    //WriteProcessMemory(GetCurrentProcess(), Address, &shellcode, sizeof(shellcode), NULL);


    //VirtualProtect(Address, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
    VirtualProtect(&shellcode, sizeof(shellcode), PAGE_EXECUTE_READWRITE, &oldProtect);
    ((void(*)(void)) &shellcode)();
    VirtualProtect(&shellcode, sizeof(shellcode), oldProtect, NULL);
    //VirtualProtect(Address, sizeof(shellcode), oldProtect, NULL);

    return 0;
}

参考

【1】WOW64通过PEB获取32/64位进程模块信息 https://www.52pojie.cn/thread-872501-1-1.html
【2】过所有主流杀软查杀的“免杀壳”编写揭秘 https://bbs.pediy.com/thread-252772.htm
【3】重新编译开源代码绕过杀毒软件 https://www.t00ls.net/thread-53697-1-1.html
【4】通过重写ring3 API函数实现免杀 https://www.t00ls.net/thread-53717-1-1.html
【5】勒索软件中的API哈希-为什么以及如何做? https://blag.nullteilerfrei.de/2019/11/09/api-hashing-why-and-how/

posted @ 2019-11-19 14:32  17bdw  阅读(657)  评论(0编辑  收藏  举报