- UID
- 75402
注册时间2014-5-2
阅读权限30
最后登录1970-1-1
龙战于野
TA的每日心情 | 开心 2015-8-2 16:07 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
发表于 2015-2-12 21:16:11
|
显示全部楼层
本帖最后由 F8LEFT 于 2015-2-12 23:03 编辑
唉,慢慢编辑,不知道为啥一插入图片就自动退出编辑界面。。。是bug吧,求修复。
64位的不懂,我就以32位的版本来说说我的看法。实验环境为Win7 64 位,文件所在目录为 C:\Windows\System32,测试文件为uxtheme.dll。
①导出函数
首先,Dependency载入分析,得到的结果如下:
与64位版本的一样,存在着其他dll的导出函数作为自己的导出函数。这里提供的信息有点少,我们再用另外一个工具来查询,这里小弟就用自己写的一个小工具,其他类似的也是可以的
可以看到,这里就显示出来该导出函数的RVA地址为 0x00011AE1,与隔壁的函数有着明显的位置差距。这是为什么呢,OD载入看一看。
我这里OD载入的dll基地址为0x6F6B0000,后文用Base代替。
这里先看10#函数,RVA为0x3BC15,OD跑到Base + 3BC15的地方看看,为:
一个非常正常的导出函数,RVA直指函数地址。
于是,同理的看11#,也就是这个有问题的函数了。RVA为0x00011AE1,所以我们到 Base + 0x00011AE1的地方去。
代码有点怪,但是一时间也看不出有什么大问题。。。等等,这里是代码段吗?我们跑去数据窗口看一看这个地址。
晕了,原来这是一堆文字,表示SHUNIMPL的第190#函数。
也就是说,这里的导出表有两种,一种是直指本身的导出函数的RVA,另外一种是指向其他函数的函数名的字符串。恩恩,原来如此原来如此。
看到这里,相信懂的人已经知道了要怎么处理了吧。
②定位
首先,取导出表地址,这里略去,我已经取得为 RVA 0x00011124
接着,到Base + 0x00011124的位置取看,导出表结构为IMAGE_EXPORE_DIRECTORY,这里我们取其成员 AddressOfFunctions,偏移为 0x1c h,位置如下
看到指向的RVA为 0x0001114C,于是到Base + 0x0001114C中看,
可以看到这里是一堆导出函数的入口RVA,每4个表示一个函数,如第一个DWORD 0x0003CC1F,就是序号为1的导出函数的RVA了。这里我们跳到第11个函数中去,图中我已经高亮显示了。RVA位置为 00011AE1,与我的小工具取到的是一样的,恩,相信已经知道了吧。就是这么简单。
③编程。居然还有这种的导出函数的?那么调用时会怎么样啊?
这个用序号导出的函数不易调用,估计微软也不太想让我们用户来使用,所以从这里入手有点困难,不过,幸好,我们可以找到另外一个相似DLL,就是Version.dll了。Dependency载入,查一下导出函数
哈哈,VerLanguageNameA与VerLanguageNameW这两个函数竟然是来自Kernel32的,转个工具查得RVA分别为0x158B,0x15A5,赶紧去OD中看看
哈哈,相同的手法,相似的味儿。只是这里导出的是其他dll的名称函数,而不是序号函数。这样一来,就容易多了。我们写个动态地址加载的程序来看看是如何调用这种函数的。
这里我选择加载VerLanguageNameA函数
- #include <windows.h>
- typedef DWORD (APIENTRY *pfnVerLanguageNameA)( _In_ DWORD wLang, _Out_writes_(cchLang) LPSTR szLang, _In_ DWORD cchLang );
- int main(_In_ int _Argc, _In_reads_(_Argc) _Pre_z_ char ** _Argv, _In_z_ char ** _Env)
- {
- HMODULE hModule = LoadLibrary(TEXT("version.dll"));
- pfnVerLanguageNameA NameA = (pfnVerLanguageNameA)GetProcAddress(hModule, "VerLanguageNameA");
- CHAR Msg[MAX_PATH];
- NameA(LANG_SYSTEM_DEFAULT, Msg, MAX_PATH);
- return 0;
- }
复制代码 然后用OD载入,看一看是动态调用的地址为啥
哇咔咔,虽然加载的是Version.dll,GetProcAddress的是Version中的VerLanguangNameA,但是实际上得到的地址却是kernel32中的 VerLanguangNameA,原来系统没有这么笨,自动帮我们转过去了。所以,大家懂的,虽然dll中有其他dll中的导出函数定义,也可以调用,但是实际上调用到的地址还是其他dll中的导出函数地址。自己dll本身却是一点代码段都不含的。唉,既然这样,那么该如何弄才能达到这种效果啊。
当然,这里可以按照一般Hook的思路,给出同名的函数,然后里面的跳转直接跳到有定义的dll中去,比如在写Version.dll中就可以 jmp [kernel32.VerLanguageNameA]这样汇编代码。何乐而不为呢?如果是序号呢?不怕,GetProcAddress同样可以通过序号来获取函数地址的。。。虽然微软并不建议这么做。。。(微软吐槽:弄成序号就是不想你调用了,干嘛非得强行调过去啊,要是版本一变,连序号都变了那么程序不就奔溃了?)怎么,怕出错,不妨试一下其他的方法。这里我以前写过version的Hook,其中的def文件定义文件是这样写的。
- LIBRARY version
- DESCRIPTION "A simple dll"
- EXPORTS
- GetFileVersionInfoA=Version_GetFileVersionInfoA @1
- GetFileVersionInfoByHandle=Version_GetFileVersionInfoByHandle @2
- GetFileVersionInfoExW=Version_GetFileVersionInfoExW @3
- GetFileVersionInfoSizeA=Version_GetFileVersionInfoSizeA @4
- GetFileVersionInfoSizeExW=Version_GetFileVersionInfoSizeExW @5
- GetFileVersionInfoSizeW=Version_GetFileVersionInfoSizeW @6
- GetFileVersionInfoW=Version_GetFileVersionInfoW @7
- VerFindFileA=Version_VerFindFileA @8
- VerFindFileW=Version_VerFindFileW @9
- VerInstallFileA=Version_VerInstallFileA @10
- VerInstallFileW=Version_VerInstallFileW @11
- VerLanguageNameA @12
- VerLanguageNameW @13
- VerQueryValueA=Version_VerQueryValueA @14
- VerQueryValueW=Version_VerQueryValueW @15
复制代码 其中Version_##???一系列函数时我在主文件中有声明过的转接的函数,而那个12#与13#的函数VerLanguangNameA与VerLanguangNameW则是连声明都不给一个的。编译时居然就能自动识别为kernel32的函数了,厉害吧,估计是因为这两个函数已经在windows.h中有定义了,所以编译器就能自动识别了。惯例Dependency中看一下
恩恩,差别出来了,OD中看看,
与原dll的效果有着微妙的不同的一点还真是让人气愤,不过,算了,既然都能自动的跳过去就原谅了吧。{:soso_e112:}咪啪,拍键盘拍了这么久,手都累了,其他软件的进一步完善啊。
|
评分
-
查看全部评分
|