首页
社区
课程
招聘
[原创]搜索输出表取得GetProcAddress地址C++版
发表于: 2010-3-20 12:50 9797

[原创]搜索输出表取得GetProcAddress地址C++版

2010-3-20 12:50
9797
看到某些病毒用到的技术从Kernel32.dll中取GetProcAddress地址,想半天没想明白,为什么要里面有一个*4呢?原来是DWORD长度的指针偏移,我晕!
自己用C++实现一下,加深一下理解,同时方便那些还有些不明白的同学,嘿嘿

这里直接用GetModuleHandle获取,方便的话也能直接从PEB中取得,但这里主要是了解病毒中取GetProcAddress地址的原理,所以直接偷懒了(下面是原码及运行结果):

#include "stdafx.h"
#include <windows.h>

void main(){
        PIMAGE_DOS_HEADER pDosHeader;
        PIMAGE_NT_HEADERS pNtHeader;
        PIMAGE_EXPORT_DIRECTORY pExportDirectory;

        HMODULE hMod = GetModuleHandle("kernel32.dll");
        pDosHeader = (PIMAGE_DOS_HEADER)hMod;
        pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)hMod + pDosHeader->e_lfanew);
        pExportDirectory = PIMAGE_EXPORT_DIRECTORY(pNtHeader->OptionalHeader.DataDirectory[0].VirtualAddress + (PBYTE)hMod);

        PDWORD pAddressName = PDWORD((PBYTE)hMod+pExportDirectory->AddressOfNames); //函数名称表指针
        PWORD pAddressOfNameOrdinals = (PWORD)((PBYTE)hMod+pExportDirectory->AddressOfNameOrdinals); //函数名称序号表指针
        PDWORD pAddresOfFunction = (PDWORD)((PBYTE)hMod+pExportDirectory->AddressOfFunctions);  //函数地址表指针
       
        for (DWORD i = 0; i < pExportDirectory->NumberOfNames; i ++){
                PCHAR pFunc = (PCHAR)((PBYTE)hMod + *pAddressName++);
                printf("%s\r\n", pFunc);
                if (0 == strcmp(pFunc, "GetProcAddress"))
                        break;
                pAddressOfNameOrdinals++;  //ENT和函数名序号数组两个并行数组同时滑动指针(序号数组中的序号就对应函数名对应的函数地址的数组索引)
        }
        printf("function ordinal is: %02x and address is %08x ! \r\n",
                pExportDirectory->Base + *pAddressOfNameOrdinals,   //函数的序号=函数名序号数组中的值+Base
                (PBYTE)hMod + pAddresOfFunction[*pAddressOfNameOrdinals]); //函数地址=EAT[序号表中的值]
        DWORD x = (DWORD)GetProcAddress;  //直接获取的地址
        printf("directly aquire address is %08x\r\n", x);
}


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
  • a.jpg (71.72kb,309次下载)
收藏
免费 7
支持
分享
最新回复 (15)
雪    币: 13
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
正在学习中啊
2010-3-20 13:07
0
雪    币: 13
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
3
希望有一天能看懂 嘿嘿
2010-3-20 13:07
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
4
其实不难,因为好多说明都是汇编版的,比较晦涩。所以自己用C++实现一下加深下理解,同时为那些苦寻C++版的人提供一份参考,呵呵!
2010-3-20 13:19
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
5
效率太低~~二分吧
2010-3-20 13:55
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
6
恳请楼上的拿出一个高效的……-
2010-3-20 14:01
0
雪    币: 7992
活跃值: (2566)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
上网老用手机上.贴一个这代码估计他这月该欠费了

替他贴一个(还是他写的)

DWORD myGetProcAddress(DWORD hModule,char *FuncName)
{
        DWORD retAddr=0;
        DWORD *namerav,*funrav;
        DWORD cnt=0;
        DWORD maxIndex,minIndex,temp,lasttemp;
        WORD *nameOrdinal;
        WORD nIndex=0;
        int cmpresult=0;
        char *ModuleBase=(char*)hModule;
        PIMAGE_DOS_HEADER pDosHeader;
        PIMAGE_FILE_HEADER pFileHeader;
        PIMAGE_OPTIONAL_HEADER pOptHeader;
        PIMAGE_EXPORT_DIRECTORY pExportDir;
        if (hModule==0)
        {
                return 0;
        }
        pDosHeader=(PIMAGE_DOS_HEADER)ModuleBase;
        pFileHeader=(PIMAGE_FILE_HEADER)(ModuleBase+pDosHeader->e_lfanew+4);
        pOptHeader=(PIMAGE_OPTIONAL_HEADER)((char*)pFileHeader+sizeof(IMAGE_FILE_HEADER));
        pExportDir=(PIMAGE_EXPORT_DIRECTORY)(ModuleBase+pOptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
        namerav=(DWORD*)(ModuleBase+pExportDir->AddressOfNames);
        funrav=(DWORD*)(ModuleBase+pExportDir->AddressOfFunctions);
        nameOrdinal=(WORD*)(ModuleBase+pExportDir->AddressOfNameOrdinals);
        if ((DWORD)FuncName<0x0000FFFF)
        {
                retAddr=(DWORD)(ModuleBase+funrav[(WORD)FuncName]);
        }
        else
        {
               
                maxIndex=pExportDir->NumberOfFunctions;
                minIndex=0;
                lasttemp=0;
                while (1)
                {
                        temp=(maxIndex+minIndex)/2;
                        if (temp==lasttemp)
                        {
                                //Not Found!
                                retAddr=0;
                                break;
                        }
                        cmpresult=strcmp(FuncName,ModuleBase+namerav[temp]);
                        if (cmpresult<0)
                        {
                                maxIndex=lasttemp=temp;
                        }
                        else if (cmpresult>0)
                        {
                                minIndex=lasttemp=temp;
                        }
                        else
                        {
                                nIndex=nameOrdinal[temp];
                                retAddr=(DWORD)(ModuleBase+funrav[nIndex]);
                                break;
                        }
                       
                }
        }
        return retAddr;
}
2010-3-20 14:11
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
8
原来所谓的二分就是“二分查找”法啊嗯,不错……这效率比较好。每次发布点东西都会感觉有点进步,这种感觉是非常好的
2010-3-20 14:24
0
雪    币: 7651
活跃值: (523)
能力值: ( LV9,RANK:610 )
在线值:
发帖
回帖
粉丝
9
原来写的这个函数有点小BUG,下面这句要改一下:
maxIndex=pExportDir->NumberOfFunctions;
改成
maxIndex=pExportDir->NumberOfNames;
否则如果有按序数导出的函数,就会出现崩溃。。。
2010-3-20 18:40
0
雪    币: 393
活跃值: (100)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
10
要改的可不止这一处
2010-3-20 20:34
0
雪    币: 393
活跃值: (100)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
11
还得判断指针在不在输出表范围 如果不在 就递归
2010-3-20 20:37
0
雪    币: 393
活跃值: (100)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
12
试试获取getlasterr
2010-3-20 20:39
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
13
晕,不能一句话说完啊……,那还可以试试SEH,ExitThread等呢,呵呵
2010-3-20 22:24
0
雪    币: 393
活跃值: (100)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
14
你试一下能不能正确获取getlasterr的地址 就知道我说的有错没错了。
2010-3-20 22:32
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
15


我还真试了一下,不仅能获取,而且很正确……输出表操作方式。

==========================================================

直接通过函数名取的地址 == 用GetProcAddress(GetModuleHandle("Kernel32.dll"), "GetLastError")取得的地址,这个地址与上面的操作输出表得到的地址不一样,反而有误!嗯。为什么呢?

上传的附件:
  • a.jpg (63.93kb,235次下载)
  • b.JPG (50.54kb,233次下载)
2010-3-21 00:16
0
雪    币: 1074
活跃值: (160)
能力值: ( LV13,RANK:760 )
在线值:
发帖
回帖
粉丝
16
自己动手解决了,通过编程用地址反推函数名,原来GetLastError指向的地址是位于ntdll中:
名为 RtlGetNativeSystemInformation ……

原来Kernel32.dll中的GetLastError是调用RtlGetNativeSystemInformation ,这才是其真身



结论:
事实证明,直接用函数指针的话实际指向的是RtlGetNativeSystemInformation 这个函数地址,而用输出表的话得到的是Kernel32.dll中GetLastError的真实地址。
上传的附件:
  • C.JPG (21.57kb,88次下载)
2010-3-21 01:15
0
游客
登录 | 注册 方可回帖
返回
//