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