日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【ReflectDllInjection】 反射型DLL注入

發布時間:2023/12/31 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【ReflectDllInjection】 反射型DLL注入 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

常規dll注入

這里引用一張圖來表示:

反射型DLL注入思路:

  • 讀入原始DLL文件至內存緩沖區
  • 解析DLL標頭并獲取SizeOfImage
  • 將DLL標頭和PE節復制到步驟3中分配的內存空間
  • 執行重定位
  • 加載DLL導入的庫
  • 解析導入地址表(IAT)
  • 調用DLL的DLL_PROCESS_ATTACH
  • 反射型dll注入與其他dll注入不同的是,其不需要使用LoadLibrary這一函數,而是自己來實現整個裝載過程。我們可以為待注入的DLL添加一個導出函數,ReflectiveLoader,這個函數的功能就是裝載它自身。
    由于是自己實現,因此不會利用系統自身Loadlibrary,不會“注冊”到系統,不會被系統記錄。也不會被ProcessExplorerer發現。

    要實現反射型DLL注入需要兩個部分,注射器和被注入的DLL。

    注射器的執行流程:

  • 將待注入DLL讀入自身內存(避免落地)
  • 利用VirtualAlloc和WriteProcessMemory在目標進程中寫入待注入的DLL文件
  • 利用CreateRemoteThread等函數啟動位于目標進程中的ReflectLoader
  • 而ReflectiveLoader的實現:
    就是對自身的裝載。

    反射型dll注入與常規注入有何不同:

  • 直接在內存中展開,無需.dll 文件存在。
  • 沒有通過Load Library等API加載,ProcessExplorer、procexp64 等工具無法檢測到這個dll
  • 更容易免殺。
  • 反射dll注入思路:

    1.根據需要注入的進程,向服務器申請dll下發;
    2.將下發的數據解密后,直接寫入申請的堆中;
    3.打開進程(OpenProcess)、分配內存(VirtualAllocEx)、將堆中的數據寫入內存4.(WriteProcessMemory);
    4.獲取 RtlCreateUserThread 函數指針
    .RtlCreateUserThread = (PRTL_CREATE_USER_THREAD)(GetProcAddress(GetModuleHandle(TEXT(“ntdll”)), “RtlCreateUserThread”));
    5.通過 RtlCreateUserThread 創建線程,調用 目標進程 內存中的 ReflectiveLoader;
    ReflectiveLoader 將dll在內存中展開,修復重定位、導入表(類似ShellCode);
    6.ReflectiveLoader 調用dll入口點

    核心思路

    在CS的dll中所有的dll都有自加載能力,所有beacon的擴展功能幾乎都是這樣實現的。CS將其稱為“可修補的dll”,它的原理是不改變MZ的情況下把整個dll文件修補成可被當作shellcode加載的格式,具體的操作是將dll內導出自加載函數,然后將MZ頭起始字節修改為可執行ReflectiveLoader函數的硬編碼。

    dll自加載原理

    因為PE文件包含了很多區段,為了節省空間,這些區段在磁盤上存儲時候比較緊湊,如果把它們原樣放入內存中運行是一定是會出問題的。所以RelectieDllLoader的一個任務就是按照規則將這些區段按照規則映射到對應的虛擬地址中去。
    另外我們的dll也會用到其他的dll,這時需要把我們的dll所依賴的dll也裝入內存。并修復導入表。

    • 首先使用_ReturnAddress()函數獲取當前函數的返回地址,因為調用這個函數是在Reflectiveloader的內部,因此從這個地址向上便利,找到0x4d, 0x5a就可以定位到PE文件頭所在的婿你地址
    • 通過FS:[0x30]獲取到PEB,用PEB遍歷出進程所需要的所有模塊dll的基地址(LDR),之后通過解析 dll PE文件的導出表獲取導出函數偏移地址,如: LoadLibrary GetProcAddress VirtualAlloc 等函數的虛擬地址。
    • 在調用ReflectiveLoader前,注入器程序會在目標進程申請一塊內存空間,但是那是存放的是dll的在磁盤上的結構,要將dll映射到內存中并重新進行內存分配。在 IMAGE_OPTIONAL_HEADER -> SizeOfImage記錄這個dll裝入內存時候的占用的大小,用這個值作為VirtualAlloc的參數。
    • 將dll的PE文件頭和各個節復制到對應的位置上。
    • 被注入的DLL可能還依賴于其他DLL,因此我們還需要使用LoadLibrary加載這些dll(LoadLibrary地址在上面已拿到)
    • 被注入的DLL只有Reflectiveloader中的代碼是被寫成地址無關的,不需要重定位,其他部分的代碼則需要重定位才能正確運行。對于重定位問題,PE的可選頭中DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]指向重定位表:關于重定位在PE文件結構中有介紹。
    • 然后就是DLL重定位。

    總結:

  • 獲得被注入進程未解析的dll的基地址
  • 獲取必要的dll句柄和函數為修復導入表做準備。
  • 分配一塊新內存解析dll,并將pe頭伏知道新內存匯總和將各節復制到新內存。
  • 修復導入表和重定向表。
  • 執行dllmain函數
  • CS 反射dll原理

    現今仍在使用的DOS結構只有PE文件的MZ標志和PE頭的e_lfanew,其他隨意修改不會影響這個PE文件的正常運行。
    引用一張圖如下:

    msf的migrate 原理:

    migrate 和 ReflectiveDllInjection項目大致相同。原理如下:

    • 讀取metsrv.dll(metpreter payload模板dll)文件到內存中。
    • 生成最終的payload。
      a) msf生成一小段匯編migrate stub主要用于建立socket連接。
      b) 將metsrv.dll的dos頭修改為一小段匯編meterpreter_loader主要用于調用reflective loader函數和dllmain函數。在metsrv.dll的config block區填充meterpreter建立session時的配置信息。
      c) 最后將migrate stub和修改后的metsrv.dll拼接在一起生成最終的payload。
    • 向msf server發送migrate請求和payload。
    • msf向遷移目標進程分配一塊內存并寫入payload。
    • msf首先會創建的遠程線程執行migrate stub,如果失敗了,就會嘗試用apc注入的方式執行migrate stub。migrate stub會調用meterpreter loader,meterpreter loader才會調用reflective loader。
    • reflective loader進行反射式dll注入。
    • 最后msf client和msf server建立一個新的session。

    原理

    ReflectiveLoader()首先會調用caller()函數。

    uiLibraryAddress = caller();

    caller()函數實質上是_ReturnAddress()函數封裝。calller()函數的作用是獲取ReflectiveLoader()函數中調用caller()函數的下一條指令地址。

    #ifdef __MINGW32__ #define WIN_GET_CALLER() __builtin_extract_return_addr(__builtin_return_address(0)) #else #pragma intrinsic(_ReturnAddress) #define WIN_GET_CALLER() _ReturnAddress() #endif __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)WIN_GET_CALLER(); }

    然后向低地址(向上,回退搜索)逐字節比較石頭為dos頭的標志ME字串。如果當前地址的內容為MZ字符串,則把當前地址認為是dos頭結構體的開頭,并校驗dos頭e_leanew結構是否指向pe頭的標識“PE”字符串。若校驗通過,則認為當前地址是正確的DOS頭結構體的開頭。

    while( TRUE ) {//將當前地址當成dos頭結構,此結構的e_magic成員變量是否指向MZ子串if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) {uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ){uiHeaderValue += uiLibraryAddress;//判斷e_lfanew結構成員是否指向PE子串,是則跳出循環,取得未解析dll的基地址if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE )break;}}uiLibraryAddress--; }

    獲取必要的dll句柄和函數地址:

    獲取必要的dll句柄是通過遍歷peb結構體中的ldr成員中的InMemoryOrderList鏈表獲取dll名稱,之后算出dll名稱hash,最后進行hash對比得到最后dll名。

    uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; while( uiValueA ) {uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer;usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length;uiValueC = 0;ULONG_PTR tmpValC = uiValueC;//計算tmpValC所指向子串的hash值,并存儲在uiValueC中....if( (DWORD)uiValueC == KERNEL32DLL_HASH )

    必要的函數是遍歷函數所在dll導出表獲得函數名稱,然后進行hash對比得到的:

    uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); usCounter = 3; while( usCounter > 0 ){dwHashValue = _hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) );if( dwHashValue == LOADLIBRARYA_HASH//等于其他函數hash的情況|| ...){uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );if( dwHashValue == LOADLIBRARYA_HASH )pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) );//等于其他函數hash的情況...usCounter--;}uiNameArray += sizeof(DWORD);uiNameOrdinals += sizeof(WORD);} }

    將dll映射到新內存:

    Nt optional header結構體中的SizeOfImage 變量存儲著PE文件在內存中解析后所占內存的大小。所以ReflectiveLoader獲取到SizeOfImage的大小,分配一塊新內存,然后按照section header結構中的文件相對偏移和相對虛擬地址,將PE節一一映射到新內存中。

    //分配SizeOfImage的新內存 uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); ... uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; uiValueB = uiLibraryAddress; uiValueC = uiBaseAddress; //將所有頭和節表逐字節復制到新內存 while( uiValueA-- )*(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; //解析每一個節表項 uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; while( uiValueE-- ) {uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress );uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData );uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData;//將每一節的內容復制到新內存對應的位置while( uiValueD-- )*(BYTE *)uiValueB++ = *(BYTE *)uiValueC++;uiValueA += sizeof( IMAGE_SECTION_HEADER ); } #### 修復導入表和重定位表: 首先根據導入表結構,找到導入函數所在的dll名稱,然后使用loadlibrary()函數載入dll,根據函數序號或函數名稱,在載入的dll的導出表中,通過hash對比,把找出的函數地址寫入到新內存的ITA表中。 uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); //當沒有到達導入表末尾時 while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Characteristics ) {//使用LoadLibraryA()函數加載對應的dlluiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) );...uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk );//IAT表uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk );while( DEREF(uiValueA) ){//如果導入函數是通過函數編號導入if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ){ //通過函數編號索引導入函數所在dll的導出函數 uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew;uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress );uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions );uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) );//將對應的導入函數地址寫入IAT表DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) );}else{//導入函數通過名稱導入的uiValueB = ( uiBaseAddress + DEREF(uiValueA) );DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name );}uiValueA += sizeof( ULONG_PTR );if( uiValueD )uiValueD += sizeof( ULONG_PTR );}uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); }

    然后是進行重定位:

    uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; //如果重定向表的值不為0,則修正重定向節 if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) {uiValueE = ((PIMAGE_BASE_RELOCATION)uiValueB)->SizeOfBlock;uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress );while( uiValueE && ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ){uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress );uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC );uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION);//根據不同的標識,修正每一項對應地址的值while( uiValueB-- ){if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 )*(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress;else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW )*(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress;else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH )*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress);else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW )*(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress);uiValueD += sizeof( IMAGE_RELOC );}uiValueE -= ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock;} }

    總結:

    反射型dll注入的 Reflectiveloader 可以理解為實質上是自己實現了一遍windows dll loader。

    歡迎各位大佬一起來免費知識星球學習: 一起探究安全原理,探索更多攻擊方法。
    https://t.zsxq.com/2rjA6yn

    總結

    以上是生活随笔為你收集整理的【ReflectDllInjection】 反射型DLL注入的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。