编写病毒程序时,由于各种原因不能直接调用函数,所以需要手动获取到函数然后调用它。最常见手动获取函数地址的方法是通过获取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;
}