最近在研究IAT加密壳,需要获取API的地址来保证shellcode的通用性。
1)利用PEB结构来查找
原理:FS段寄存器作为选择子指向当前的TEB结构,在TEB偏移0x30处是PEB指针。而在PEB偏移的0x0c处是指向PEB_LDR_DATA结构的指针,位于
PEB_LDR_DATA结构偏移0x1c处,是一个叫InInitialzationOrderModuleList的成员,他是指向LDR_MODULE链表结构中,相应的双向链表头部
的指针(汗死,绕口令),该链表加载的DLL的顺序是ntdll.dll,kernel32.dll
因此该成员所指的链表偏移0x08处为kernel32.dll地址
PEB结构
typedef struct _PEB { // Size: 0x1D8
/*000*/ UCHAR InheritedAddressSpace;
/*001*/ UCHAR ReadImageFileExecOptions;
/*002*/ UCHAR BeingDebugged;
/*003*/ UCHAR SpareBool; // Allocation size
/*004*/ HANDLE Mutant;
/*008*/ HINSTANCE ImageBaseAddress; // Instance
/*00C*/ VOID *DllList;
/*010*/ PPROCESS_PARAMETERS *ProcessParameters;
/*014*/ ULONG SubSystemData;
/*018*/ HANDLE DefaultHeap;
/*01C*/ KSPIN_LOCK FastPebLock;
/*020*/ ULONG FastPebLockRoutine;
/*024*/ ULONG FastPebUnlockRoutine;
/*028*/ ULONG EnvironmentUpdateCount;
/*02C*/ ULONG KernelCallbackTable;
/*030*/ LARGE_INTEGER SystemReserved;
/*038*/ ULONG FreeList;
/*03C*/ ULONG TlsExpansionCounter;
/*040*/ ULONG TlsBitmap;
/*044*/ LARGE_INTEGER TlsBitmapBits;
/*04C*/ ULONG ReadOnlySharedMemoryBase;
/*050*/ ULONG ReadOnlySharedMemoryHeap;
/*054*/ ULONG ReadOnlyStaticServerData;
/*058*/ ULONG AnsiCodePageData;
/*05C*/ ULONG OemCodePageData;
/*060*/ ULONG UnicodeCaseTableData;
/*064*/ ULONG NumberOfProcessors;
/*068*/ LARGE_INTEGER NtGlobalFlag; // Address of a local copy
/*070*/ LARGE_INTEGER CriticalSectionTimeout;
/*078*/ ULONG HeapSegmentReserve;
/*07C*/ ULONG HeapSegmentCommit;
/*080*/ ULONG HeapDeCommitTotalFreeThreshold;
/*084*/ ULONG HeapDeCommitFreeBlockThreshold;
/*088*/ ULONG NumberOfHeaps;
/*08C*/ ULONG MaximumNumberOfHeaps;
/*090*/ ULONG ProcessHeaps;
/*094*/ ULONG GdiSharedHandleTable;
/*098*/ ULONG ProcessStarterHelper;
/*09C*/ ULONG GdiDCAttributeList;
/*0A0*/ KSPIN_LOCK LoaderLock;
/*0A4*/ ULONG OSMajorVersion;
/*0A8*/ ULONG OSMinorVersion;
/*0AC*/ USHORT OSBuildNumber;
/*0AE*/ USHORT OSCSDVersion;
/*0B0*/ ULONG OSPlatformId;
/*0B4*/ ULONG ImageSubsystem;
/*0B8*/ ULONG ImageSubsystemMajorVersion;
/*0BC*/ ULONG ImageSubsystemMinorVersion;
/*0C0*/ ULONG ImageProcessAffinityMask;
/*0C4*/ ULONG GdiHandleBuffer[0x22];
/*14C*/ ULONG PostProcessInitRoutine;
/*150*/ ULONG TlsExpansionBitmap;
/*154*/ UCHAR TlsExpansionBitmapBits[0x80];
/*1D4*/ ULONG SessionId;
} PEB, *PPEB;
typedef struct _PEB_LDR_DATA
{
ULONG Length; // +0x00
BOOLEAN Initialized; // +0x04
PVOID SsHandle; // +0x08
LIST_ENTRY InLoadOrderModuleList; // +0x0c
LIST_ENTRY InMemoryOrderModuleList; // +0x14
LIST_ENTRY InInitializationOrderModuleList;// +0x1c
} PEB_LDR_DATA,*PPEB_LDR_DATA; // +0x24
实例代码:
mov eax,fs:[0x30]
mov eax,[eax+0x0c]
mov esi ,[eax+0x1c]
lodsd
mov eax,[eax+0x08]
ret
2)利用堆栈暴力搜索
原理: 在程序开始时,栈顶所指向的值是kernel32.dll所在页的某个高地址,我们采用向下搜索的方法,来查找。同时,在PE中的
image_optional_header中在偏移0x34处有kernel32.dll的地址。以下是image_optional_header的结构
IMAGE_OPTIONAL_HEADER STRUC ; Optional Header
OH_Magic DW ? ; Magic word
OH_MajorLinkerVersion DB ? ; Major Linker version
OH_MinorLinkerVersion DB ? ; Minor Linker version
OH_SizeOfCode DD ? ; Size of code section
OH_SizeOfInitializedData DD ? ; Initialized Data
OH_SizeOfUninitializedData DD ? ; Uninitialized Data
OH_AddressOfEntryPoint DD BYTE PTR ? ; Initial EIP
OH_BaseOfCode DD BYTE PTR ? ; Code Virtual Address
OH_BaseOfData DD BYTE PTR ? ; Data Virtual Address
OH_ImageBase DD BYTE PTR ? ; Base of image-----------------------------------kernel32.dll地址
OH_SectionAlignment DD ? ; Section Alignment
OH_FileAlignment DD ? ; File Alignment
OH_MajorOperatingSystemVersion DW ? ; Major OS
OH_MinorOperatingSystemVersion DW ? ; Minor OS
OH_MajorImageVersion DW ? ; Major Image version
OH_MinorImageVersion DW ? ; Minor Image version
OH_MajorSubsystemVersion DW ? ; Major Subsys version
OH_MinorSubsystemVersion DW ? ; Minor Subsys version
OH_Win32VersionValue DD ? ; win32 version
OH_SizeOfImage DD ? ; Size of image
OH_SizeOfHeaders DD ? ; Size of Header
OH_CheckSum DD ? ; unused
OH_Subsystem DW ? ; Subsystem
OH_DllCharacteristics DW ? ; DLL characteristic
OH_SizeOfStackReserve DD ? ; Stack reserve
OH_SizeOfStackCommit DD ? ; Stack commit
OH_SizeOfHeapReserve DD ? ; Heap reserve
OH_SizeOfHeapCommit DD ? ; Heap commit
OH_LoaderFlags DD ? ; Loader flags
OH_NumberOfRvaAndSizes DD ? ; Number of directories
UNION ; directory entries
OH_DataDirectory IMAGE_DATA_DIRECTORY/
IMAGE_NUMBEROF_DIRECTORY_ENTRIES DUP (?)
OH_DirectoryEntries IMAGE_DIRECTORY_ENTRIES ?
ENDS ;
ENDS ;
实例代码:
start: mov edx,[esp]
dec edx
mov ebx,[edx+0x3c]
mov ebx,[ebx+edx+0x34]
cmp edx,ebx
jnz start
ret ;此时在edx中的值为kernel32.dll地址
3)使用SEH的链表来查找
原理:在SEH中默认的unhandled exception hander 是利用kernel32.DLL中的一个函数设置的。因此可以历遍所有的exception hander, 找到最后一个成员,该成员的前4个字节是0ffffffffh,后4个字节是kernel32.dll中的函数(看了很多paper,都没有说明为什么通过该函数可以得到kernel32.dll的地址,偶个人认为,通过这个函数定位到了输出表,然后向低地址搜索,就能找到ZM头,也就是kernel32的地址,如果有错误,请告诉偶,谢谢)
实例代码:
mov esi,fs[0]
@@1: lodsd
cmp [eax],0xffffffff
jne @@1
mov eax,[eax+0x04]
@@2: dec eax
xor ax,ax
cmp eax word ptr[eax] 'MZ'
jne @@2
ret
此时eax为kernel32.dll地址
参考:
《恶意代码的亲密接触》
《gloomy对内核的分析》
《通过TEB/PEB枚举当前进程空间中用户模块列表》