搜索内存API函数在网上大部分都是汇编的例子,通过参考网上例子,使用C++实现了一下怎么样搜索内存API函数,权当练手。高手飘过。主要是获取Kernel32.dll的基址,GetProcAddress、LoadLibraryA函数的地址。
先通过以下二种方法动态获取Kernel32.dll的基地址
1. 遍历seh异常链,然后获得EXCEPTION_REGISTRATION结构prev为-1的异常处理过程地址,这个异常处理过程地址是位于kernel32.dll,通过它搜索得到kernel32.dll的基地址。
2. 通过TEB获得PEB结构地址,然后再获得PEB_LDR_DATA结构地址,然后遍历模块列表,查找kernel32.dll模块的基地址。
以下的函数
__inline __declspec(naked) unsigned int GetKernel32()与
__inline __declspec(naked) unsigned int GetKernel32Base()分别实现的上面的方法1与2
详细的理论与方法可以参考:http://bbs.pediy.com/showthread.php?t=85910
/*
原型:unsigned int GetKernel32(void);
参数:无
返回值:
函数总是能返回Kernel32.dll的基地址
说明:根据PE可执行文件特征从UnhandledExceptionFilter函数地址向上线性查找,使用__inline是为了与
最终的ShellCode融为一体,使用__declspec(naked)是为了不让编译器自作聪明生成一些"废话",让它
完全按照我们自己的Asm语句来描述函数.
*/
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include <stdio.h>
#pragma warning(disable:4311)
#pragma warning(disable:4312)
__inline __declspec(naked) unsigned int GetKernel32()
{
__asm
{
push esi
push ecx
mov esi,fs:0
//lodsd
mov eax,esi
GetExeceptionFilter:
cmp [eax],0xffffffff
je GetedExeceptionFilter//如果到达最后一个节点(它的pfnHandler指向UnhandledExceptionFilter)
mov eax,[eax]//否则往后遍历,一直到最后一个节点
jmp GetExeceptionFilter
GetedExeceptionFilter:
mov eax, [eax+4]
FindMZ:
and eax,0xffff0000//根据PE执行文件以64k对界的特征加快查找速度
cmp word ptr [eax],'ZM'//根据PE可执行文件特征查找KERNEL32.DLL的基址
jne MoveUp//如果当前地址不符全MZ头部特征,则向上查找
mov ecx,[eax+0x3c]
add ecx,eax
cmp word ptr [ecx],'EP'//根据PE可执行文件特征查找KERNEL32.DLL的基址
je Found//如果符合MZ及PE头部特征,则认为已经找到,并通过Eax返回给调用者
MoveUp:
dec eax//准备指向下一个界起始地址
jmp FindMZ
Found:
pop ecx
pop esi
ret
}
}
__inline __declspec(naked) unsigned int GetKernel32Base()
{
__asm
{
push esi
push ecx
mov eax, fs:30h //Get Peb
mov eax, [eax+0ch] //Get _PEB_LDR_DATA
//此时eax指向的是ntdll模块的InInitializationOrderModuleList线性地址。所以我们获得它的下一个则是kernel32.dll
mov eax, [eax+1ch] //Get InInitializationOrderModuleList.Flink,
mov eax, [eax]
mov eax, [eax+8] //8 = sizeof.LIST_ENTRY
pop ecx
pop esi
ret
}
}
DWORD GetExportTable(ULONG pBase, const char* SearchFun)
{
DWORD dwLoadLibrary = 0;
PIMAGE_DOS_HEADER pImageDosHeader = (PIMAGE_DOS_HEADER)pBase;
if ( pImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
{
printf("This is not PE file!");
return 0;
}
PIMAGE_NT_HEADERS pImageNtHeaders = (PIMAGE_NT_HEADERS)((ULONG)pBase + pImageDosHeader->e_lfanew);
PIMAGE_EXPORT_DIRECTORY pExDir = (PIMAGE_EXPORT_DIRECTORY)((DWORD)pBase+
pImageNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
char* pModeName = (char*)((DWORD)pBase+pExDir->Name);
printf("Module Name:%s\n", pModeName);
DWORD* pNameArray = (DWORD*) ((DWORD)pBase+pExDir->AddressOfNames);
WORD* pOrdinal = (WORD*) ((DWORD)pBase+pExDir->AddressOfNameOrdinals);
DWORD* pFunction = (DWORD*) ((DWORD)pBase+pExDir->AddressOfFunctions);
for (unsigned int i=0; i<pExDir->NumberOfFunctions; i++)
{
char* FuncName = (char*)( (DWORD)pBase + pNameArray[i] );
DWORD FuncAddress = (DWORD)pBase + pFunction[pOrdinal[i]];
if ( strcmp(FuncName, SearchFun) == 0 )
{
printf("0x%03x\t%s\t0x%x\n", i, FuncName, FuncAddress);
return FuncAddress;
}
}
return 0;
}
typedef FARPROC (WINAPI *GETPROCADDRESS)(
HMODULE hModule,
LPCSTR lpProcName
);
typedef HMODULE (WINAPI *LOADLIBRARYA)(
LPCTSTR lpFileName
);
typedef int (WINAPI *MESSAGEBOXA)(HWND hWnd,
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
GETPROCADDRESS MyGetProcAddress;
LOADLIBRARYA MyLoadLibrary;
MESSAGEBOXA MyMessageBoxA;
int main(int argc, char* argv[])
{
ULONG hKernelBase = GetKernel32();
printf("%0.8X\n",GetKernel32Base());
printf("%0.8X\n", hKernelBase);
MyGetProcAddress = (GETPROCADDRESS)GetExportTable(hKernelBase, "GetProcAddress");
MyLoadLibrary = (LOADLIBRARYA) GetExportTable(hKernelBase, "LoadLibraryA");
HMODULE hMode = MyLoadLibrary("user32.dll");
MyMessageBoxA = (MESSAGEBOXA)MyGetProcAddress(hMode, "MessageBoxA");
MyMessageBoxA(NULL, "搜索内存API函数!", "测试", 0);
return 0;
}
参考文章:http://hi.baidu.com/sudami/blog/item...383025c41.html
测试结果:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
上传的附件: