IMAGE_FIRST_SECTION

本文介绍了如何通过IMAGE_NT_HEADERS找到区段表(Section Table)的地址,讲解了IMAGE_FIRST_SECTION宏的实现原理,并提及了IMAGE_OPTIONAL_HEADER32在不同情况下的大小变化。同时,文中还分享了OptionalHeader大小的指定方式以及FIELD_OFFSET宏在计算结构体成员偏移中的应用。

定位区块表(Section Table)
首先我们要知道,区段表是紧接在IMAGE_NT_HEADERS的后面的,如果我们找到了IMAGE_NT_HEADERS的地址,然后再加上IMAGE_NT_HEADERS的大小,是不是就找到了Section Table的地址了呢。知道了这个好开心

微软在WinNT.h中提供了一个宏定义——IMAGE_FIRST_SECTION,用来定位区块表的

它的具体实现如下

// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is the same either way.

#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER)        \
    ((ULONG_PTR)(ntheader) +                                            \
     FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) +                 \
     ((ntheader))->FileHeader.SizeOfOptionalHeader   \
    ))

由这个宏的定义我们可以看出来,其实区段表是3部分的和。
1、IMAGE_NT_HEADERS的起始地址
2、IMAGE_OPTIONAL_HEADER32 (PE扩展头)在IMAGE_NT_HEADERS中的偏移
3、IMAGE_OPTIONAL_HEADER32

#pragma once #include <ntifs.h> #include <ntddk.h> #include <ntimage.h> #define RELOC_FLAG64(ReInfo) ((ReInfo>>0x0C)==IMAGE_REL_BASED_DIR64) #define RELOC_FLAG RELOC_FLAG64 UINT64 g_fnLoadLibrary = 0; UINT64 g_fnGetProcAddress = 0; UINT64 g_fnRtlAddFuntion = 0; void Log(const char* sz_info, bool is_error, ULONG err_code); EXTERN_C NTSTATUS MmCopyVirtualMemory( IN PEPROCESS FromProcess, IN CONST VOID* FromAddress, IN PEPROCESS ToProcess, OUT PVOID ToAddress, IN SIZE_T BufferSize, IN KPROCESSOR_MODE PreviousMode, OUT PSIZE_T NumberOfBytesCopied ); EXTERN_C NTSTATUS NTAPI ZwSetInformationProcess( __in HANDLE ProcessHandle, __in PROCESSINFOCLASS ProcessInformationClass, __in_bcount (ProcessInformationLength) PVOID ProcessInformation, __in ULONG ProcessInformationLength ); typedef PVOID HINSTANCE, HMODULE; using f_LoadLibraryA = HMODULE(_stdcall*)(const char* lpLibFileName); using f_GetProcAddress = PVOID(_stdcall*)(HMODULE hModule, LPCSTR lpProcName); using f_DLL_ENTRY_POINT = BOOLEAN(_stdcall*)(PVOID DllHandle, ULONG Reason, PVOID Reserved); using f_RtlAddFunctionTable = BOOLEAN(_stdcall*)(_IMAGE_RUNTIME_FUNCTION_ENTRY* FunctionTable, DWORD32 EntryCount, DWORD64 BaseAddress); struct Manual_Mapping_data { //用于重定位iat f_LoadLibraryA pLoadLibraryA; f_GetProcAddress pGetProcAddress; //x64专有 f_RtlAddFunctionTable pRtlAddFunctionTable; char* pBase; DWORD32 dwReadson; //设置为0线程开始时执行dll PVOID reserveParam; BOOLEAN bFirst;//只允许第一次系统调用进入 BOOLEAN bStart;//开始执行shellcode了 可以同步关闭instCallBack BOOLEAN bContinue;//用于继续执行 去掉pe头后执行dllmain size_t DllSize; }; void __stdcall InstruShellCode(Manual_Mapping_data* pData); #pragma pack(push) #pragma pack(1) struct shellcode_t { private: char padding[43]; public: uintptr_t manual_data; private: char pdding[47]; public: uintptr_t rip; uintptr_t shellcode; }; char g_instcall_shel1code[] = { 0x50, 0x51, 0x52, 0x53, 0x55, 0x56, 0x57, 0x41, 0x50, 0x41, 0x51, 0x41, 0x52, 0x41, 0x53, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48,0x89 ,0x25,0x4C,0x00,0x00,0x00, 0x48, 0x83, 0xEC, 0x38, 0x48,0x81,0xE4,0xF0,0xFF,0xFF,0xFF, 0x48,0xB9,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11, 0xFF,0x15,0x29,0x00,0x00,0x00,0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90,//call 0x48, 0x8B, 0x25, 0x22,0x00,0x00,0x00, 0x41, 0x5F, 0x41, 0x5E, 0x41, 0x5D, 0x41, 0x5C, 0x41, 0x5B, 0x41, 0x5A, 0x41, 0x59, 0x41, 0x58, 0x5F, 0x5E, 0x5D, 0x5B, 0x5A, 0x59, 0x58, 0x41, 0xFF, 0xE2, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 }; #pragma pack(pop) NTSTATUS inst_callback_set_callback(PVOID inst_callback) { NTSTATUS status = STATUS_SUCCESS; PVOID InstCallBack = inst_callback; PACCESS_TOKEN Token{ 0 }; PULONG TokenMask{ 0 }; Token = PsReferencePrimaryToken(IoGetCurrentProcess()); TokenMask = (PULONG)((ULONG_PTR)Token + 0x40);//取_TOKEN结构下Privileges TokenMask[0] |= 0x100000; TokenMask[1] |= 0x100000; TokenMask[2] |= 0x100000; status = ZwSetInformationProcess(NtCurrentProcess(), ProcessInstrumentationCallback, &InstCallBack, sizeof(PVOID)); if (!NT_SUCCESS(status)) { Log("failed to set instrcallback !", true, status); } else { Log("failed to set instrcallback SUCCESS!", false, 0); } return status; } void Log(const char* sz_info, bool is_error, ULONG err_code) { if (is_error) { DbgPrintEx(77, 0, "[instCallBack Error] : %s err_code:%x\n", sz_info, err_code); } else { DbgPrintEx(77, 0, "[instCallBack] : %s \n", sz_info); } } PUCHAR inst_callback_get_dll_memory(UNICODE_STRING* us_dll_path) { NTSTATUS status = STATUS_SUCCESS; HANDLE hFile = 0; OBJECT_ATTRIBUTES objattr = { 0 }; IO_STATUS_BLOCK IoStatusBlock = { 0 }; LARGE_INTEGER lainter = { 0 }; LARGE_INTEGER byteOffset = { 0 }; FILE_STANDARD_INFORMATION fileinfo = { 0 }; ULONG64 fileSize = 0; PUCHAR pDllMemory = 0; InitializeObjectAttributes(&objattr, us_dll_path, OBJ_CASE_INSENSITIVE, 0, 0); status = ZwCreateFile(&hFile, GENERIC_READ, &objattr, &IoStatusBlock, &lainter, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, FILE_OPEN, 0, 0, 0); if (!NT_SUCCESS(status)) { Log("failed to Create File!", true, status); return 0; } status = ZwQueryInformationFile(hFile, &IoStatusBlock, &fileinfo, sizeof(fileinfo), FileStandardInformation); fileSize = (ULONG)fileinfo.AllocationSize.QuadPart; if (!NT_SUCCESS(status)) { Log("failed to get File size!", true, status); return 0; } fileSize += 0x1000; fileSize = (ULONG64)PAGE_ALIGN(fileSize); //ExAllocatePoolWithTag pDllMemory = (PUCHAR)ExAllocatePoolWithTag(PagedPool, fileSize, 'Dllp'); //pDllmem = (PUCHAR)ExAllocatePool3(NonPagedPool, fileSize, 'Dllp', NULL, NULL);//NonPagedPool PagedPool RtlSecureZeroMemory(pDllMemory, fileSize); status = ZwReadFile(hFile, 0, 0, 0, &IoStatusBlock, pDllMemory, fileSize, &byteOffset, 0); ZwFlushBuffersFile(hFile, &IoStatusBlock); if (!NT_SUCCESS(status)) { ExFreePool(pDllMemory); ZwClose(hFile); Log("failed to read File context!", true, status); return 0; } ZwClose(hFile); return pDllMemory; } NTSTATUS inst_callback_alloc_memory(PUCHAR p_dll_memory, _Out_ PVOID* inst_callbak_addr, PVOID* p_manual_data) { PEPROCESS Process{ 0 }; IMAGE_NT_HEADERS* pNtHeader = nullptr; IMAGE_FILE_HEADER* pFileHeader = nullptr; IMAGE_OPTIONAL_HEADER* pOptheader = nullptr; NTSTATUS status = STATUS_SUCCESS; PVOID pManualMapData = 0,pShellCode = 0; char* pStartMapAdd = 0; size_t AllocSize = 0, RETSize; Manual_Mapping_data ManualMapData{ 0 }; if (reinterpret_cast<IMAGE_DOS_HEADER*>(p_dll_memory)->e_magic != 0x5A4D) { status = STATUS_INVALID_PARAMETER; Log("the dll is not valid pe structure\n", true, status); return status; } pNtHeader = (IMAGE_NT_HEADERS*)((ULONG_PTR)p_dll_memory + reinterpret_cast<IMAGE_DOS_HEADER*>(p_dll_memory)->e_lfanew); pFileHeader = &pNtHeader->FileHeader; pOptheader = &pNtHeader->OptionalHeader; if (pFileHeader->Machine != IMAGE_FILE_MACHINE_AMD64) { status = STATUS_INVALID_PARAMETER; Log("the dll is is x86 structure ,not support!\n", true, status); return status; } AllocSize = pOptheader->SizeOfImage; status = ZwAllocateVirtualMemory(NtCurrentProcess(), (PVOID*)&pStartMapAdd, 0, &AllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(status)) { Log("failed to alloc Memory!", true, status); return status; } RtlSecureZeroMemory(pStartMapAdd, AllocSize); ManualMapData.dwReadson = 0; ManualMapData.pGetProcAddress = (f_GetProcAddress)g_fnGetProcAddress; ManualMapData.pLoadLibraryA = (f_LoadLibraryA)g_fnLoadLibrary; ManualMapData.pRtlAddFunctionTable = (f_RtlAddFunctionTable)g_fnRtlAddFuntion; ManualMapData.pBase = pStartMapAdd; ManualMapData.bContinue = false;//判断是否抹除了pe标识 ManualMapData.bFirst = true; ManualMapData.bStart = false; ManualMapData.DllSize = AllocSize; Process = IoGetCurrentProcess(); status = MmCopyVirtualMemory(Process, p_dll_memory, Process, pStartMapAdd, PAGE_SIZE, KernelMode, &RETSize); if (!NT_SUCCESS(status)) { Log("failed to load pe header!", true, status); return status; } IMAGE_SECTION_HEADER* pSectionHeadr = IMAGE_FIRST_SECTION(pNtHeader); for (size_t i = 0; i < pFileHeader->NumberOfSections; i++, pSectionHeadr++) { if (pSectionHeadr->SizeOfRawData) { status = MmCopyVirtualMemory(Process, p_dll_memory + pSectionHeadr->PointerToRawData, Process, pStartMapAdd + pSectionHeadr->VirtualAddress, pSectionHeadr->SizeOfRawData, KernelMode, &RETSize); if (!NT_SUCCESS(status)) { Log("failed to load pe header!", true, status); return status; } } } AllocSize = PAGE_SIZE; status = ZwAllocateVirtualMemory(NtCurrentProcess(), &pManualMapData, 0, &AllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(status)) { Log("failed to alloc Memory for maunalmapdata!", true, status); return status; } RtlSecureZeroMemory(pManualMapData, AllocSize); status = MmCopyVirtualMemory(Process, &ManualMapData, Process, pManualMapData, sizeof(ManualMapData), KernelMode, &RETSize); if (!NT_SUCCESS(status)) { Log("failed to write Memory for maunalmapdata!", true, status); return status; } //重定位ShellCode status = ZwAllocateVirtualMemory(NtCurrentProcess(), &pShellCode, 0, &AllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(status)) { Log("failed to alloc Memory for shellcode!", true, status); return status; } RtlSecureZeroMemory(pShellCode, AllocSize); status = MmCopyVirtualMemory(Process, InstruShellCode, Process, pShellCode, AllocSize, KernelMode, &RETSize); if (!NT_SUCCESS(status)) { Log("failed to write Memory for shellcode!", true, status); return status; } //ShellCode shellcode_t shell_code; memset(&shell_code, 0, sizeof shell_code); memcpy(&shell_code, &g_instcall_shel1code, sizeof shellcode_t); shell_code.manual_data = (UINT64)pManualMapData; shell_code.rip = (UINT64)pShellCode; status = ZwAllocateVirtualMemory(NtCurrentProcess(), inst_callbak_addr, 0, &AllocSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (!NT_SUCCESS(status)) { Log("failed to alloc Memory for instrcall shellcode!", true, status); return status; } RtlSecureZeroMemory(*inst_callbak_addr, AllocSize); status = MmCopyVirtualMemory(Process, &shell_code, Process, *inst_callbak_addr, sizeof shell_code, KernelMode, &RETSize); if (!NT_SUCCESS(status)) { Log("failed to write Memory for instrcall shellcode!", true, status); return status; } *p_manual_data = pManualMapData; return status; } NTSTATUS inst_callback_inject(HANDLE process_id, UNICODE_STRING* us_dll_path) { NTSTATUS status = STATUS_SUCCESS; PEPROCESS pEhtreadyx = NULL; KAPC_STATE apc_state; PUCHAR pDllMem = 0; PVOID InstCallBack = 0, pManualMapData = 0; status = PsLookupProcessByProcessId(process_id, &pEhtreadyx); if (!NT_SUCCESS(status)) { Log("failed to get process!", true, status); status = STATUS_UNSUCCESSFUL; return status; } KeStackAttachProcess(pEhtreadyx, &apc_state); while (true) { pDllMem = inst_callback_get_dll_memory(us_dll_path); if (!pDllMem) { status = STATUS_UNSUCCESSFUL; break; } status = inst_callback_alloc_memory(pDllMem, &InstCallBack, &pManualMapData); if (!NT_SUCCESS(status))break; //设置instrecallback status = inst_callback_set_callback(InstCallBack); break; } if (pManualMapData && MmIsAddressValid(pManualMapData)) { __try { while (1) { if (((Manual_Mapping_data*)pManualMapData)->bStart)break; } } __except (1) { Log("process exit! 1", true, 0); ObDereferenceObject(pEhtreadyx); KeUnstackDetachProcess(&apc_state); return status; } } inst_callback_set_callback(0); if (pManualMapData && MmIsAddressValid(pManualMapData) && PsLookupProcessByProcessId(process_id, &pEhtreadyx) != STATUS_PENDING) { __try { *(PUCHAR)((((Manual_Mapping_data*)pManualMapData))->pBase) = 0; ((Manual_Mapping_data*)pManualMapData)->bContinue = true; } __except (1) { Log("process exit!", true, 0); } } ObDereferenceObject(pEhtreadyx); KeUnstackDetachProcess(&apc_state); if (pDllMem && MmIsAddressValid(pDllMem))ExFreePool(pDllMem); return status; } void __stdcall InstruShellCode(Manual_Mapping_data* pData) { if (!pData->bFirst)return; pData->bFirst = false; pData->bStart = true; char* pBase = pData->pBase; auto* pOptionHeader = &reinterpret_cast<IMAGE_NT_HEADERS*>(pBase + reinterpret_cast<IMAGE_DOS_HEADER*> ((uintptr_t)pBase)->e_lfanew)->OptionalHeader; char* LocationDelta = pBase - pOptionHeader->ImageBase;//差值 if (LocationDelta) { if (pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size) { auto* pRelocData = reinterpret_cast<IMAGE_BASE_RELOCATION*> (pBase + pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); auto* pRelocEnd = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<uintptr_t>(pRelocData) + pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size); while (pRelocData< pRelocEnd && pRelocData->SizeOfBlock) { UINT64 AmountOfEntries = (pRelocData->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(short); unsigned short* pRelativeInfo = reinterpret_cast<unsigned short*>(pRelocData + 1); for (UINT64 i = 0; i != AmountOfEntries; ++i, ++pRelativeInfo) { if (RELOC_FLAG(*pRelativeInfo)) { //计算出需要重定位的地址 auto* pPatch = reinterpret_cast<UINT_PTR*>(pBase + pRelocData->VirtualAddress + ((*pRelativeInfo) & 0xFFF)); //手动重定位 *pPatch += reinterpret_cast<UINT_PTR>(LocationDelta); } } pRelocData = reinterpret_cast<IMAGE_BASE_RELOCATION*>(reinterpret_cast<char*>(pRelocData) + pRelocData->SizeOfBlock); } } } if (pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size) { IMAGE_IMPORT_DESCRIPTOR* pImportDescr = reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR*> (pBase+pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); while (pImportDescr->Name) { HMODULE hDll = pData->pLoadLibraryA(pBase + pImportDescr->Name); //INT IAT //int ULONG_PTR* pInt = (ULONG_PTR*)(pBase + pImportDescr->OriginalFirstThunk); ULONG_PTR* pIat = (ULONG_PTR*)(pBase + pImportDescr->FirstThunk); //IAT if (!pInt)pInt = pIat; for (; *pIat; ++pIat, ++pInt) { if (IMAGE_SNAP_BY_ORDINAL(*pInt)) { *pIat = (ULONG_PTR)pData->pGetProcAddress(hDll, (char*)(*pInt & 0xffff)); } else { IMAGE_IMPORT_BY_NAME* pImport = (IMAGE_IMPORT_BY_NAME*)(pBase + *pInt); *pIat = (ULONG_PTR)pData->pGetProcAddress(hDll, pImport->Name); } } pImportDescr++; } } #define DLL_PROCESS_ATTACH 1 if (pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].Size) { auto* pTLS = reinterpret_cast<IMAGE_TLS_DIRECTORY*> (pBase + pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); auto* pCallBack = reinterpret_cast<PIMAGE_TLS_CALLBACK*>(pTLS->AddressOfCallBacks); for (;pCallBack && *pCallBack; ++pCallBack) { (*pCallBack)(pBase, DLL_PROCESS_ATTACH, nullptr); } } auto excep = pOptionHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION]; if (excep.Size) { pData->pRtlAddFunctionTable((_IMAGE_RUNTIME_FUNCTION_ENTRY*) (pBase + excep.VirtualAddress), excep.Size / sizeof(_IMAGE_RUNTIME_FUNCTION_ENTRY),(DWORD64)pBase); } while (!pData->bContinue); //手动调用dllmain ((f_DLL_ENTRY_POINT)(pBase+pOptionHeader->AddressOfEntryPoint))(pBase, DLL_PROCESS_ATTACH, 0); } 用这些代码注入dll 导致c00005异常
最新发布
08-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值