使用汇编代码获取GetProcAddress函数地址的大致步骤(面试题系列)

1、首先通过FS寄存器获取到TEB的地址

2、在TEB偏移为0x30处的成员是PEB

3、PEB偏移为0xC处的成员是PEB_LDR_DATA结构体指针

4、PEB_LDR_DATA结构体偏移为0x1C处成员为InInitializationOrderModuleList,初始化模块链表,这个成员保存的是模块链表的头部地址。

5、通过InInitializationOrderModuleList模块链表可以获得按照顺序加载到进程内存空间的模块,其中第一个始终是ntdll.dll,根据系统的不同,可能第二个加载的模块是kernel32.dll或者kernelbase.dll。

6、无论加载的是kernel32.dll还是kernelbase.dll,其导出表中都有GetProcAddress函数的地址。

汇编代码对应如下:

mov esi,dword ptr fs:[0x30]	   //esi = PEB的地址
mov esi,[esi+0xC]			//esi = 指向PEB_LDR_DATA的结构体指针
mov esi,[esi+0x1C]			//esi = 模块链表指针InInitializationOrderModuleList
mov esi,[esi]				//esi = 访问链表中的第二个模块
mov ebx,[esi+0x08]			//获取Kernel32.dll基址(访问DllBase成员)
7、从kernel32.dll模块中获取DOS头,NT头等信息

8、获取NT中扩展头最后一个字段数据目录表,然后得到导出表项

9、获取导出表的详细信息

10、循环获取ENT(Export Name Table)中的函数名,暂不考虑以序号导出的情况,先以函数名为基准,传入GetProcAddress与ENT中的函数名比较,匹配成功以后,获取相应的序号值,并以此为索引在EAT(Export Address Table)中获取相应的函数地址。

附上部分关键代码:

DWORD dwFunAddr;
for (DWORD = 0;i < pExport->NumberofNames;i++)
{
	PCHAR lpFunName = (PCHAR)(pAddofNames[i] + dwAddrBase);
	if(!strcmp(lpFunName,"GetProcAddress"))
	{
	 dwFunAddr = pAddrOfFun[pAddrOfOrdinals[i]] + dwAddrBase;
	 break;
	}
	if(i == pExport->NumberOfNames - 1)
	return 0;
}
return dwFunAddr;




猜你喜欢

转载自blog.csdn.net/userpass_word/article/details/79138377