首页
社区
课程
招聘
[分享]搜索内存API函数
发表于: 2009-6-21 15:51 10955

[分享]搜索内存API函数

2009-6-21 15:51
10955

搜索内存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期)

上传的附件:
收藏
免费 7
支持
分享
最新回复 (6)
雪    币: 243
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
scm
2
请问,能在Windows7之类的系统运行。在搜索内存API函数的好处是不是可以有效防止Ring3的APIHOOK?
2009-6-21 16:08
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
3
楼主不厚道. 引用别人的东西不加说明,而且还进行删减
http://hi.baidu.com/sudami/blog/item/ac76e84befff84f383025c41.html

当然,谢谢分享~~
2009-6-21 22:50
0
雪    币: 212
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
谁能翻译成DELPHI的呀
2009-6-30 21:03
0
雪    币: 231
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
沙发,先坐,不错
学习了,谢谢楼主
2009-7-1 01:06
0
雪    币: 206
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
anti virus专题里面也有提到过啊!
2009-7-1 13:46
0
雪    币: 185
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
不错呢!!!!!!!
2009-10-10 12:43
0
游客
登录 | 注册 方可回帖
返回
//