手动获取函数地址

编写病毒程序时,由于各种原因不能直接调用函数,所以需要手动获取到函数然后调用它。最常见手动获取函数地址的方法是通过获取kernel32.dll句柄,然后遍历kernel32.dll的导出表找到它的GetProcAddress()函数,再通过向这个函数传递函数名就可以获取函数的地址了,最后通过一个函数指针就可以调用获取的函数。

主要步骤

1.通过fs寄存器获取到TEB的地址
2.通过teb+0x30获取到PEB
3.通过peb+0x0c获取到PEB_LDR_DATA结构体指针
4.PEB_LDR_DATA结构体偏移0x1c处为成员InInitializationOrderModuleList,即初始化模块链表,通过这个链表可以找到按顺序加载到进程中的模块,第一个加载的通常是ntdll.dll,第二个是kernel32.dll或者是kernelbase.dll。无论是kernel32.dll还是kernelbase.dll,它们的导出表中都有GetProcAddress函数的地址。
5.经过上面的步骤可以找到kernel32.dll,对应代码如下:

__asm
	{
		push eax
		mov eax, fs:[0x30]
		mov eax, [eax + 0xc]
		mov eax, [eax + 0x1c]
		mov eax, [eax]
		mov eax, [eax + 8]
		mov hModule,eax
		pop eax
	}

6.找到kernel32.dll的导出表,遍历导出表找到LoadLibrary和GetProcAddress,需要LoadLibrary的原因是有些程序默认没有加载user32.dll(或其他dll),而想要手动调用的函数大多数都在这些dll当中,比如说MessageBox就属于user32.dll,所以需要调用LoadLibrary将user32.dll加载到进程空间中,否则调用MessageBox会失败。对应代码如下:

for (int i = 0; i < pIED->NumberOfNames;i++)
	{
		if (!isfound && strcmp((char *)(*(DWORD *)name + hModule),"LoadLibraryW") == 0)
		{
			ll = (MyLoadLibrary)(hModule + arrayAddress[ordinals[i]]);
			lib = ll(_T("user32.dll"));
			break;
			isfound = true;
		}
		if (strcmp((char *)(*(DWORD *)name + hModule),"GetProcAddress") == 0)
		{
			gpa = (MyGetProcAddress)(arrayAddress[ordinals[i]] + hModule);
		}
		name += 4;
	}

7.找到LoadLibrary和GetProcAddress以后就可以调用需要的函数了。

代码实现

代码实现了手动查找MessageBox的函数地址并调用它,完整代码如下:

#include "stdafx.h"
#include <windows.h>

typedef HMODULE(WINAPI *MyLoadLibrary)(_In_ LPCTSTR lpFileName);
typedef FARPROC(WINAPI *MyGetProcAddress)(_In_ HMODULE hModule, LPCSTR lpProcName);
typedef int (WINAPI *MyMessageBox)(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

int _tmain(int argc, _TCHAR* argv[])
{

	MyLoadLibrary ll;
	MyGetProcAddress gpa;
	MyMessageBox mb;

	DWORD hModule = 0;
	HMODULE lib = NULL;

	__asm
	{
		push eax
		mov eax, fs:[0x30]
		mov eax, [eax + 0xc]
		mov eax, [eax + 0x1c]
		mov eax, [eax]
		mov eax, [eax + 8]
		mov hModule,eax
		pop eax
	}

	IMAGE_DOS_HEADER *pDos = (IMAGE_DOS_HEADER *)hModule;
	IMAGE_NT_HEADERS *pNt = (IMAGE_NT_HEADERS *)(hModule + pDos->e_lfanew);
	IMAGE_DATA_DIRECTORY *pIDD = (IMAGE_DATA_DIRECTORY *)((DWORD)pNt + 0x78);//+0x78指向数据目录表中的导出表
	IMAGE_EXPORT_DIRECTORY *pIED = (IMAGE_EXPORT_DIRECTORY *)(hModule + pIDD->VirtualAddress);
	DWORD *arrayAddress = (DWORD *)(hModule + pIED->AddressOfFunctions);//函数地址表
	DWORD name = hModule + pIED->AddressOfNames;//函数名称表
	SHORT *ordinals = (SHORT *)(pIED->AddressOfNameOrdinals + hModule);
	bool isfound = false;
	

	for (int i = 0; i < pIED->NumberOfNames;i++)
	{
		if (!isfound && strcmp((char *)(*(DWORD *)name + hModule),"LoadLibraryW") == 0)
		{
			ll = (MyLoadLibrary)(hModule + arrayAddress[ordinals[i]]);
			lib = ll(_T("user32.dll"));
			break;
			isfound = true;
		}
		if (strcmp((char *)(*(DWORD *)name + hModule),"GetProcAddress") == 0)
		{
			gpa = (MyGetProcAddress)(arrayAddress[ordinals[i]] + hModule);
		}
		name += 4;
	}

	if (lib != INVALID_HANDLE_VALUE && lib != NULL)
	{
		mb = (MyMessageBox)gpa(lib, "MessageBoxW");
		mb(NULL, _T("test"), _T("test"), 0);

	}
	else
	{
		printf("Load error");
	}

	system("pause");
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章