Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

DLL injection

From Wikipedia, the free encyclopedia
Computer programming technique

Incomputer programming,DLL injection is a technique used for runningcode within theaddress space of anotherprocess by forcing it to load adynamic-link library.[1]DLL injection is often used by external programs to influence the behavior of another program in a way itsauthors did not anticipate or intend.[1][2][3] For example, the injected code couldhook system function calls,[4][5] or read the contents ofpassword textboxes, which cannot be done the usual way.[6] A program used to inject arbitrary code into arbitrary processes is called aDLL injector.

Approaches on Microsoft Windows

[edit]

There are multiple ways onMicrosoft Windows to force a process to load and execute code in a DLL that the authors did not intend:

  • DLLs listed in theregistry entryHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs are loaded into every process that loadsUser32.dll during the initial call of that DLL.[7][8][9] Beginning withWindows Vista, AppInit_DLLs are disabled by default.[10] Beginning with Windows 7, the AppInit_DLL infrastructure supportscode signing. Starting withWindows 8, the entire AppInit_DLL functionality is disabled whenSecure Boot is enabled, regardless of code signing or registry settings.[11]
  • DLLs listed under the registry keyHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\AppCertDLLs are loaded into every process that calls theWin32 API functionsCreateProcess,CreateProcessAsUser,CreateProcessWithLogonW,CreateProcessWithTokenW andWinExec. That is the right way to use legal DLL injection on current version of Windows - Windows 10. DLL must besigned by a valid certificate.
  • Process manipulation functions such asCreateRemoteThread orcode injection techniques such as AtomBombing,[12] can be used to inject a DLL into a program after it has started.[5][6][13][14][15][16]
    1. Open ahandle to the target process. This can be done by spawning the process[17][18] or by keying off something created by that process that is known to exist – for instance, awindow with a predictable title,[19] or by obtaining a list of running processes[20] and scanning for the targetexecutable's filename.[21]
    2. Allocate some memory in the target process,[22] and the name of the DLL to be injected is written to it.[13][23]
      This step can be skipped if a suitable DLL name is already available in the target process. For example, if a process links toUser32.dll,GDI32.dll,Kernel32.dll or any other library whose name ends in32.dll, it would be possible to load a library named32.dll[citation needed]. This technique has in the past been demonstrated to be effective against a method of guarding processes against DLL injection.[24]
    3. Create a newthread in the target process[25] with the thread's start address set to be the address ofLoadLibrary and the argument set to the address of the string just uploaded into the target.[13][26]
      Instead of writing the name of a DLL-to-load to the target and starting the new thread atLoadLibrary, one can write the code-to-be-executed to the target and start the thread at that code.[6]
    4. Theoperating system then calls the initialization routine of the injected DLL.[13][27]
    Note that without precautions, this approach can be detected by the target process due to theDLL_THREAD_ATTACH notifications sent to every loaded module as a thread starts.[27]
  • Windows hooking calls such asSetWindowsHookEx.[2][5][6][28][29][30]
  • Use theSuspendThread orNtSuspendThread function to suspend all threads, and then useSetThreadContext orNtSetContextThread function to modify an existing thread's context in the application to execute injected code, that in turn could load a DLL.[4][31][32]
  • Exploit design limitations in Windows and applications that call theLoadLibrary orLoadLibraryEx function without specifying a full-qualified path to the DLL being loaded.[33][34][35]
  • Operating system-levelshims.
  • Substituting an application-specific DLL with a rogue replacement that implements the same function exports as the original.[36]

Approaches on Unix-like systems

[edit]

OnUnix-like operating systems with the dynamic linker based on ld.so (onBSD) and ld-linux.so (onLinux), arbitrary libraries can be linked to a new process by giving the library's pathname in theLD_PRELOAD environment variable, that can be set globally or individually for a single process.[37]

For example, on a Linux system, this command launches the command "prog" with the shared library from file "test.so" linked into it at the launchtime:

LD_PRELOAD="./test.so"prog

Such a library can be created in the same way as othershared objects. WithGCC, this involves compiling the source file containing the new globals to be linked, with the-fpic or-fPIC option,[38] and linking with the-shared option.[39] The library has access to external symbols declared in the program like any other library.

OnmacOS, the following command launches the command "prog" with the shared library from file "test.dylib" linked into it at the launchtime:[40]

DYLD_INSERT_LIBRARIES="./test.dylib"DYLD_FORCE_FLAT_NAMESPACE=1prog

It is also possible to use debugger-based techniques on Unix-like systems.[41]

Sample code

[edit]

Copying a LoadLibrary-loaded DLL to a remote process

[edit]

As there is noLoadLibrary() call to load a DLL into a foreign process you have to copy a locally loaded DLL into remotely allocated memory.The following commented code shows how to do that.

#include<Windows.h>#include<TlHelp32.h>#include<iostream>#include<memory>#include<system_error>#include<charconv>#include<vector>#include<cassert>#if defined(_MSC_VER)#pragma warning(disable: 6387)#endifusingnamespacestd;usingXHANDLE=unique_ptr<void,decltype([](void*h){h&&h!=INVALID_HANDLE_VALUE&&CloseHandle((HANDLE)h);})>;usingXHMODULE=unique_ptr<remove_reference_t<decltype(*HMODULE())>,decltype([](HMODULEhm){hm&&FreeLibrary(hm);})>;MODULEENTRY32WgetModuleDescription(HMODULEhmModule);size_tmaxReadableRange(void*pRegion);stringgetAbsolutePathA(charconst*fileName,charconst*err);DWORDdumbParseDWORD(wchar_tconst*str);wstringgetAbsolutePath(wchar_tconst*makeAbsolute,charconst*errStr);[[noreturn]]voidthrowSysErr(charconst*str);constexprwchar_tconst*LOADER_DLL_NAME=L"loaderDll.dll";constexprcharconst*LOADER_THREAD_PROC="loadLibraryThread";intwmain(intargc,wchar_t**argv){try{if(argc<3)returnEXIT_FAILURE;wchar_tconst*processId=argv[1],*remoteLoadedDll=argv[2],*initData=argc>=4?argv[3]:L"";DWORDdwProcessId=dumbParseDWORD(processId);XHANDLExhProcess(OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessId));if(!xhProcess.get())throwSysErr("can't open remote process with unlimited access");XHMODULExhmLocalLoader;MODULEENTRY32WmeLocalLoader;for(;;){xhmLocalLoader.reset(LoadLibraryW(LOADER_DLL_NAME));if(!xhmLocalLoader.get())throwSysErr("can't locally load loader DLL");// get module starting address and sizemeLocalLoader=getModuleDescription((HMODULE)xhmLocalLoader.get());// try to allocate memory range in the foreign process with the same size the DLL in our process occupiesif(VirtualAllocEx(xhProcess.get(),meLocalLoader.modBaseAddr,meLocalLoader.modBaseSize,MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE))break;// allocation failed, free libraryxhmLocalLoader.reset(nullptr);// try to reserve address range which the library occupied before to prevent// recycling of that address range with the next LoadLibrary() call.if(!VirtualAlloc(meLocalLoader.modBaseAddr,meLocalLoader.modBaseSize,MEM_RESERVE,PAGE_NOACCESS))throwSysErr("can't reserve address range of previously mapped DLL");}LPTHREAD_START_ROUTINEloaderThreadProc=(LPTHREAD_START_ROUTINE)GetProcAddress((HMODULE)xhmLocalLoader.get(),::LOADER_THREAD_PROC);if(!loaderThreadProc)throwSysErr("can't get procedure entry point");// coppy all readable DLL-contents to the destination processif(SIZE_Tcopied;!WriteProcessMemory(xhProcess.get(),meLocalLoader.modBaseAddr,meLocalLoader.modBaseAddr,meLocalLoader.modBaseSize,&copied)&&GetLastError()!=ERROR_PARTIAL_COPY)throwSysErr("can't copy loader DLL to remote process");// create two concatenated C strings that contain the DLL to load as well as the parameter// given to the remotely loaded DLLwstringdata(getAbsolutePath(remoteLoadedDll,"can't get absolute path to DLL to be remotely loaded"));data+=L'\0';data+=initData;data+=L'\0';size_tdataSize=data.size()*sizeof(wchar_t);autoinitStrErr=[](){throwSysErr("failed to copy initialization data to loader DLL");};void*remoteData;// remotely allocate memory large enough to hold at least our both stringsif(!(remoteData=VirtualAllocEx(xhProcess.get(),nullptr,dataSize,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE)))initStrErr();// write our both strings to remote memoryif(SIZE_Tcopied;!WriteProcessMemory(xhProcess.get(),remoteData,data.data(),dataSize,&copied)||copied!=dataSize)initStrErr();// create a remote DLL loader thread; the given entry point has the same address in our process as well as the remote address// give this thread the address of our both remotely copied stringsXHANDLExhRemoteInitThread(CreateRemoteThread(xhProcess.get(),nullptr,0,loaderThreadProc,remoteData,0,nullptr));if(!xhRemoteInitThread.get())throwSysErr("failed to create remote initializaton thread");// wait on our remote loader thread to finish// it should that very soon as its only task is to copy the strings for the remotely loaded DLL and load this DLL itselfif(WaitForSingleObject(xhRemoteInitThread.get(),INFINITE)==WAIT_FAILED)throwSysErr("can't wait for remote initialization thread");DWORDdwInitThreadExitCode;if(!GetExitCodeThread(xhRemoteInitThread.get(),&dwInitThreadExitCode))throwSysErr("can't get initialization thread's success code");// check for remote loader's exit-code, it should be NO_ERROR (0)if(dwInitThreadExitCode!=NO_ERROR)throwsystem_error((int)dwInitThreadExitCode,system_category(),"LoadLibrary() error in remote loader dll");}catch(exceptionconst&se){cout<<se.what()<<endl;}}MODULEENTRY32WgetModuleDescription(HMODULEhmModule){// returns the absolute path to for a given module handleautogetModulePath=[](HMODULEhm,charconst*err)->wstring{wchar_tmodulePath[MAX_PATH];if(DWORDdwRet=GetModuleFileNameW(hm,modulePath,MAX_PATH);!dwRet||dwRet>=MAX_PATH)throwSysErr(err);returnmodulePath;};// local DLL's module pathwstringmoduleAbsolute(getModulePath(hmModule,"can't get absolute path for local loader DLL"));XHANDLExhToolHelp(CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,GetCurrentProcessId()));autotoolHelpErr=[](){throwSysErr("can't list modules in injecting process");};if(xhToolHelp.get()==INVALID_HANDLE_VALUE)toolHelpErr();MODULEENTRY32Wme;me.dwSize=sizeofme;if(!Module32FirstW(xhToolHelp.get(),&me))toolHelpErr();for(;;){// has the current image in the snapshot the same path like the DLL which is given by the module handle// no need to compare case insensitive because we got both paths from the kernel so that they should exactly matchif(getModulePath(me.hModule,"can't get absolute path for toolhelp-enumerated DLL name")==moduleAbsolute)returnme;me.dwSize=sizeofme;if(!Module32NextW(xhToolHelp.get(),&me))toolHelpErr();}}[[noreturn]]voidthrowSysErr(charconst*str){throwsystem_error((int)GetLastError(),system_category(),str);}DWORDdumbParseDWORD(wchar_tconst*str){// idiot's from_chars because there's no from_chars for unicode charactersDWORDdwRet=0;while(*str)dwRet=dwRet*10+(unsignedchar)(*str++-L'0');returndwRet;}wstringgetAbsolutePath(wchar_tconst*makeAbsolute,charconst*errStr){// get absolute path of a given relative pathwstringpath(MAX_PATH,L'\0');DWORDdwLength;if(!(dwLength=GetFullPathNameW(makeAbsolute,MAX_PATH,path.data(),nullptr)))throwSysErr(errStr);// if deRet == MAX_PATH we might miss a zero-termination character, treat this as an errorelseif(dwLength>=MAX_PATH)throwinvalid_argument(errStr);path.resize(dwLength);returnpath;}

The main issue solved here is that a locally loaded DLL copied to a remote process must occupy the same addresses as in the injecting process. The above code does this byallocating memory for the same address range as occupied before in the injecting process. If this fails the DLL is locally freed, the former address range is marked as reserved, and theLoadLibrary() call is tried again. By reserving the former address range the code prevents that the nextLoadLibrary() attempt will assign the same address range as used before.

The main drawback with that approach is that the DLL copied into the foreign process is that there aren't any other DLL library dependencies of that DLL loaded into the foreign address space or pointers, f.e. function calls, to DLLs loaded by the foreign process are adjusted according to the dependencies of the copied DLL. Luckily DLLs usually have preferred loading addresses which are honored by thekernel's loader. Some DLLs likekernel32.dll are reliably loaded in the early beginning when the process address space is occupied by the executable image and its depending DLLs. These normally have reliable and non-conflicting addresses. So the copied DLL can use anykernel32.dll calls, f.e. to load another DLL with full advantages of a locally loaded DLL, i.e. having all relative library-dependencies. The path to that DLL is copied to the foreign address space and given as a void-parameter to the thread-function. The above implementation also allows to have additional parameters, which are passed to the remotely copied DLL after the string with the DLL to remotely loaded to passed to that DLL.

The following code is the source of the remotely copied loader DLL which only doeskernel32.dll calls:

#include<Windows.h>#include<atomic>usingnamespacestd;BOOLAPIENTRYDllMain(HMODULEhModule,DWORDul_reason_for_call,LPVOIDlpReserved){returnTRUE;}DWORDWINAPIloadLibraryThread(LPVOIDlpvThreadParam);// MSVC / clang-cl mangling#if defined(_M_IX86)#pragma comment(linker, "/export:loadLibraryThread=?loadLibraryThread@@YGKPAX@Z")#elif defined(_M_X64)#pragma comment(linker, "/export:loadLibraryThread=?loadLibraryThread@@YAKPEAX@Z")#else#error unsupported platform#endifDWORDWINAPIloadLibraryThread(LPVOIDlpvThreadParam){// use atomics to prevent the "optimizer" from replacing my code with// wsclen or memcpy library calls to external addresses actually not valid// with this copied DLL// ignore any atomic load barriers since this hasn't to be fastatomic_wchar_tconst// path to the library to load from inside*libPath=(atomic_wchar_t*)lpvThreadParam,// pointer to the parameters given to this library*data=libPath;// advance data to the actual parameterswhile(*data++);HANDLEhOutboundEvent;// create named event to notify the remote DLL that data has already copied// necessary because the remote DLL execution begins directly after LoadLibrary()Sif(!(hOutboundEvent=CreateEventA(nullptr,FALSE,FALSE,"nasty hackers")))returnGetLastError();// size of the paramers given to the DLLsize_tdataSize=0;while(data[dataSize++]);if(dataSize>=MAX_PATH)returnERROR_INVALID_PARAMETER;// clean LoadLibrary() with all DLL-dependenciesHMODULEhm=LoadLibraryW((wchar_t*)libPath);if(!hm)returnGetLastError();// get address of parameters export from the loaded DLLwchar_tvolatile(&initData)[MAX_PATH]=*(wchar_t(*)[MAX_PATH])GetProcAddress(hm,"initData");// the loaded DLL doesn't provide such an export, i.e. its not relying on parameters ?if(!initData)returnNO_ERROR;// copy parameters to the DLLfor(size_ti=0;i!=dataSize;initData[i]=data[i],++i);// notify that parameters availableif(!SetEvent(hOutboundEvent))returnGetLastError();returnNO_ERROR;}

The last code shows an example of a DLL loaded by the loader DLL which prints the parameters to a file.

#include<Windows.h>#include<fstream>#include<atomic>usingnamespacestd;#if defined(_MSC_VER)#pragma warning(disable: 6387)// returned handle could be null#endif#if defined(_M_IX86)#pragma comment(linker, "/export:DllMain=_DllMain@12")#elif defined(_M_X64)#pragma comment(linker, "/export:DllMain=_DllMain@12")#else#error unsupported platform#endifusingnamespacestd;DWORDWINAPImyThread(LPVOIDlpvThreadParam);BOOLAPIENTRYDllMain(HMODULEhModule,DWORDdwReason,LPVOIDlpReserved){switch(dwReason){caseDLL_PROCESS_ATTACH:// create thread since there is no export called from the loader DLLCreateThread(nullptr,0,myThread,nullptr,0,nullptr);default:break;}returnTRUE;}extern"C"__declspec(dllexport)wchar_tinitData[MAX_PATH]={0};DWORDWINAPImyThread(LPVOIDlpvThreadParam){// wait for initData to be filled by loader DLL// skip that if you don't rely on any initData// as the named event "nasty hackers" has been created by our own DLL's// LoadLibrary() we're just connecting to a named event, but not creating oneif(WaitForSingleObject(CreateEventA(nullptr,FALSE,FALSE,"nasty hackers"),INFINITE)!=WAIT_OBJECT_0)return0;// write parameters in a file to test function// the following code doesn't work when the DLL is non-statically linked for unknown reasonswofstreamwofs;wofs.open("c:\\Users\\xxx\\test.txt",ofstream::out|ofstream::trunc);wofs<<initData<<endl;return0;}

One important fact is that there are no exports called from the loader DLL, but instead all initialization is done fromDllMain. The only export is that ofinitData, which receives the parameters given by the injecting process through the loader DLL. And one must be aware that the thread created from a DllMain-function isn't scheduled until after itsDLL_THREAD_ATTACH-function has succeeded. So there may not be any synchronization from insideDllMain with the created thread.

References

[edit]
  1. ^abJames Shewmaker (2006)."Analyzing DLL Injection"(PDF).GSM Presentation. Bluenotch. Archived fromthe original(PDF) on December 3, 2008. RetrievedAugust 31, 2008.
  2. ^abIczelion (August 2002)."Tutorial 24: Windows Hooks".Iczelion's Win32 Assembly Homepage. Archived fromthe original on August 1, 2008. RetrievedAugust 31, 2008.
  3. ^Rocky Pulley (May 19, 2005)."Extending Task Manager with DLL Injection".CodeProject. Archived fromthe original on February 6, 2009. RetrievedSeptember 1, 2008.
  4. ^abNasser R. Rowhani (October 23, 2003)."DLL Injection and function interception tutorial".CodeProject. Archived fromthe original on April 15, 2018. RetrievedAugust 31, 2008.
  5. ^abcIvo Ivanov (December 2, 2002)."API hooking revealed".CodeProject. RetrievedAugust 31, 2008.
  6. ^abcdRobert Kuster (August 20, 2003)."Three Ways to Inject Your Code into Another Process".CodeProject. RetrievedAugust 31, 2008.
  7. ^"Working with the AppInit_DLLs registry value".Microsoft Help and Support. Microsoft. November 21, 2006. RetrievedAugust 31, 2008.
  8. ^Raymond Chen (December 13, 2007)."AppInit_DLLs should be renamed Deadlock_Or_Crash_Randomly_DLLs".The Old New Thing. Microsoft. RetrievedAugust 31, 2008.
  9. ^"dllmain.c".ReactOS. ReactOS Foundation. July 8, 2008. RetrievedAugust 31, 2008.[permanent dead link]
  10. ^AppInit_DLLs in Windows 7 and Windows Server 2008 R2
  11. ^"AppInit DLLs and Secure Boot". MSDN. RetrievedMarch 29, 2016.
  12. ^"'AtomBombing' Microsoft Windows Via Code Injection".Dark Reading. RetrievedApril 20, 2017.
  13. ^abcdTrent Waddington."InjectDLL". Archived fromthe original on December 30, 2019. RetrievedAugust 31, 2008.
  14. ^"Dll Injection".DreamInCode.net. MediaGroup1. May 4, 2006. Archived from the original on September 2, 2008. RetrievedAugust 31, 2008.
  15. ^Greg Jenkins (November 2007)."DLL Injection Framework".Ring3 Circus. WordPress. Archived fromthe original on June 28, 2020. RetrievedAugust 31, 2008.
  16. ^Drew Benton (August 17, 2007)."A More Complete DLL Injection Solution Using CreateRemoteThread".CodeProject. RetrievedSeptember 1, 2008.
  17. ^"CreateProcess".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  18. ^"PROCESS_INFORMATION".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  19. ^"GetWindowThreadProcessId Function".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  20. ^"EnumProcesses".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  21. ^"GetModuleBaseName".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  22. ^"VirtualAllocEx".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  23. ^"WriteProcessMemory".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  24. ^"Outpost Bypassing Self-Protection via Advanced DLL injection with handle stealing Vulnerability".Matousec. December 1, 2006. Archived fromthe original on February 6, 2009. RetrievedAugust 31, 2008.
  25. ^"CreateRemoteThread".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  26. ^"LoadLibrary".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  27. ^ab"DllMain".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  28. ^"SetWindowsHookEx Function".Platform SDK for Windows XP SP2. Microsoft. RetrievedAugust 31, 2008.
  29. ^"AppInit_DLLs Registry Value and Windows 95".Microsoft Help and Support. Microsoft. March 1, 2005. RetrievedAugust 31, 2008.
  30. ^"Dll Injection using SetWindowsHookEx() Method".Game Reversal. April 3, 2008. RetrievedSeptember 1, 2008.
  31. ^"SetThreadContext DLL Injection". January 16, 2007. Archived fromthe original on August 23, 2011. RetrievedSeptember 1, 2008.
  32. ^Ben Botto (September 6, 2008)."DLL Injector". Archived fromthe original on February 7, 2009. RetrievedSeptember 1, 2008.
  33. ^"Insecure Library Loading Could Allow Remote Code Execution".Microsoft. June 10, 2011. RetrievedApril 20, 2016.
  34. ^"Secure loading of libraries to prevent DLL preloading attacks".Microsoft. June 10, 2011. RetrievedAugust 8, 2012.
  35. ^"Microsoft Security Advisory: Insecure library loading could allow remote code execution".Microsoft. June 10, 2011. RetrievedApril 20, 2016.
  36. ^Nicolas Falliere (September 26, 2010)."Stuxnet Infection of Step 7 Projects". Symantec.
  37. ^Linus Torvalds; David Engel; Eric Youngdale; Peter MacDonald; Hongjiu Lu; Lars Wirzenius; Mitch D'Souza (March 14, 1998)."ld.so/ld-linux.so – dynamic linker/loader".UNIX man pages. Archived fromthe original on February 6, 2009. RetrievedAugust 31, 2008.
  38. ^"Code Gen Options".Using the GNU Compiler Collection (GCC). Free Software Foundation. RetrievedAugust 31, 2008.-fpic Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target machine.sqq.
  39. ^"Link Options".Using the GNU Compiler Collection (GCC). Free Software Foundation. RetrievedAugust 31, 2008.-shared Produce a shared object which can then be linked with other objects to form an executable.sqq.
  40. ^"The LD_PRELOAD trick". Peter Goldsborough. RetrievedMay 17, 2017.
  41. ^Gregory Shpitalnik (February 12, 2009)."Code Injection into Running Linux Application".Code Project. RetrievedNovember 18, 2010.
Retrieved from "https://en.wikipedia.org/w/index.php?title=DLL_injection&oldid=1247060557"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp