手動獲取函數地址

編寫病毒程序時,由於各種原因不能直接調用函數,所以需要手動獲取到函數然後調用它。最常見手動獲取函數地址的方法是通過獲取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;
}

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