首页
社区
课程
招聘
[原创]查找系统动态链接库(Dll)基地址和指定函数地址的一种方法
发表于: 2012-6-4 22:25 21653

[原创]查找系统动态链接库(Dll)基地址和指定函数地址的一种方法

2012-6-4 22:25
21653

在我的上一篇帖子查找进程API内存地址的小程序中写了一个小工具,枚举进程的输入表函数地址,有朋友要我公布源代码,很惭愧,那个程序代码有待优化,就不公布了,这个帖子公布源代码,那个工具中用到的代码和这篇类似,可以作为相互参考。

看到老罗写的一篇“暴力搜索内存获取API地址”的帖子,很受启发,现在有些程序有保护,用我那个查找进程API内存地址的小程序可能读不了其进程,从而也就无法获取他们的API地址了。老罗的方法可以直接获取用户系统中的API地址,因为它不需要读取其他程序内存地址。按老罗的方法,查找API地址必须首先找到系统Dll的基址,老罗用的方法就是现在网上流行的3种之一,这里我用一种和网上流行的不一样的方法获取系统Dll基址,并将老罗未完成的搜索内存获取API地址未写的代码写出来。

思路:
1、学习过PE文件格式的童鞋应该知道,PE的头文件中就包含了PE文件的基址,那么我们直接读取Dll的PE中的基址不就可以轻松的得到Dll的基址了么,OK,go on
2、要得到Dll文件,首先要知道其地址,一般都放在C:\WINDOWS\system32文件夹中,有的童鞋马上会扔鞋子过来,我丫系统没装C盘呢,我丫系统不是XP呢
3、威武的Windos API来了,GetWindowsDirectory就可以得到系统目录,再在系统目录后加个\system32\xxx.dll就完美解决了
4、OK,找到系统Dll了,载入,读取其基址,读取其输出表RVA
5、然后根据输出表RVA和基址取输出表的FAT,FNT
6、再然后就是暴力男人狂搜FNT说指向的API名称,并和我们想要的API名称进行对比,找到后返回FAT找其地址

是不是很简单呢,同时聪明的童鞋们还可以发现,我们载入了系统Dll,那么直接在Dll中就可以找到我们想要的API地址,具体方法和内存中暴搜一样的,只是把基址换成我们读取的Dll文件在内存中的地址就行了

说了这么多废话,我们以查找开始“OpenFileMapping”这个函数地址为例,上代码:

invoke	FAA_FindKernel32Path, addr szKernel32Path       ;获取Kernel32.dll绝对路径
invoke	FAA_FindExportRVA, addr szKernel32Path          ;载入Kernel32.dll文件,查其输出表RVA和基址

invoke	FAA_FindExportAPIAddr, Kernel32BaseAddr, Kernel32ExportRVA, addr szOpenFileMapping              ;搜索内存查找OpenFileMapping函数的地址
.if		eax == 0
    
    invoke	FAA_MsgBox , addr szFindAPIFail
.else
    
    invoke	wsprintf, addr EditBuffer, addr szFormat, eax
    invoke	SetDlgItemText, hDlgmain, IDC_EDT_OutPut, addr EditBuffer
.endif	

ret
FAA_FindKernel32Path proc uses esi pPathBuffer:DWORD

invoke	GetWindowsDirectory, pPathBuffer, 256
invoke	wsprintf, pPathBuffer, addr szPathFormat, pPathBuffer	;合并系统目录,获取Kernel32.dll完整路径

ret
FAA_FindKernel32Path endp

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (14)
雪    币: 659
活跃值: (499)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
2
写完帖子后发现一个问题:


打开程序,点“查找”即可在编辑中显示OpenFileMapping在内存中的地址,那个“调用地址”按钮本来是想写段代码演示下用找到的地址调用OpenFileMapping的,但我用"查找进程API内存地址的小程序"查了下,验证是一致的,就懒得写了,大家将就着用下,或者在源文件中去掉,界面很丑,已经被朋友批评过了,没办法,汇编写界面是软肋

还有各位童鞋要注意的是OpenFileMapping在Kernel32.dll中的名字是“OpenFileMappingA”,不要弄错了,这个程序是区分大小写的,不然比较会出错

欢迎高手指点
上传的附件:
2012-6-4 22:50
0
雪    币: 3213
活跃值: (5439)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
大哥,这个东西早就有了,叫做“API地址专家”,多看看那些你不屑的小工具,有时候会有大发现,谢谢,想把那个软件什么样,传上来,可是不会弄图片呀!你百度去吧!
2012-6-4 23:34
0
雪    币: 659
活跃值: (499)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
4
呵呵,我写这个不是为了写工具,只是发源代码,分析方法和思路,程序只是把自己的想法表达出来的东西而已,例外提高下自己的PE分析水平
2012-6-5 00:17
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
5
主要就获取映像基址,
映像基址计算式子:*(ULONG*)(base+*(ULONG*)(base+0x3c)+0x34);

输出表地址计算式子: *(ULONG*)(base+*(ULONG*)(base+0x3c)+0x78);

还有
遍历输出表

这不能说是新方法,说白了就是最常规的方法了,首选的方法。

另外,我觉得Kernel32.dll是在系统目录下,CreateFile第一个参数应该可以直接写Kernel32.dll 吧?
2012-6-5 02:40
0
雪    币: 316
活跃值: (128)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
6
遍历PE输入表函数名称,GetProcAddress + wsprintf。
2012-6-5 02:46
0
雪    币: 659
活跃值: (499)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
7
对于系统文件的确可以直接读取文件,忘了,多谢指导
2012-6-5 17:26
0
雪    币: 615
活跃值: (172)
能力值: ( LV9,RANK:140 )
在线值:
发帖
回帖
粉丝
8
不客气,还得向你学习。。
2012-6-7 18:39
0
雪    币: 209
活跃值: (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
弱弱的问个问题,ImageBase说的是优先被加载的内存基址,对于dll来说这个地址很少会被加载到这个地址的。用这种方法获取加载的dll基址是不是有问题啊?我不太懂的,只是有点疑惑,如果我错了,就当笑话了。
2012-6-10 12:24
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
10
微软在发布系綂的时候,针对每个系统dll都进行过处理,使得ImageBase不重叠,这样使得系统dll可以优先加载到自己的首选基址上。详细情况参考《windows核心编程》

还有对于ASLR技术的应用可能导致系统dll的加载地址在首选加载基址附近浮动,不过一旦系统启动以后,不同进程中的加载基址是相同的。
2012-6-10 13:22
0
雪    币: 71
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
学习一下·1

谢谢分享

有码
2012-6-10 21:51
0
雪    币: 73
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
不会呀。已经预定好了。就在优先加载基址上加载。
2012-6-12 18:51
0
雪    币: 78
活跃值: (85)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
大哥,你这个程序有个巨大的BUG哦~~

    jnz    FAA_FindExportAPIAddr_NoFind                    ;如果ecx=0,说明函数字符全部相同
    mov    eax, [ebx].AddressOfFunctions                  ;取FAT表RVA
    add    eax, _BaseAddr                          ;取FAT表RVA内存地址
    add    eax, edx                            ;取查找函数FAT表项的地址
    mov    eax, [eax]                            ;取查找函数的RVA
    add    eax, _BaseAddr                          ;取查找函数的内存地址
    .break                                  ;找到则退出循环

代码简单看了下,居然没有用AddressOfNameOrdinals这个字段对AddressOfNames和AddressOfFunctions的对应关系进行转换呢?函数名RVA数组和函数地址RVA数组可不是顺序对应的哦,不过恰好kernel32.dll里的函数名RVA数组和函数地址RVA数组一一对应,你随便换个dll估计就计算错误了,比如lpk.dll

另外,不管怎么说你的asm写的让人看得太纠结了呢
mov    al, 0
sub    edx, edx
sub    eax, eax
随便看了一下,这些指令优化一下总好看些吧
2012-6-14 16:41
0
雪    币: 6525
活跃值: (3423)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
14
Win7下按 查找 会崩溃
2012-6-19 21:48
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hjm
15
可以多加深理解!谢谢分享
2012-6-19 21:52
0
游客
登录 | 注册 方可回帖
返回
//