|
|
@@ -0,0 +1,465 @@ |
|
|
/*! |
|
|
* |
|
|
* BOOTINFO |
|
|
* |
|
|
* GuidePoint Security LLC |
|
|
* |
|
|
* Threat and Attack Simulation Team |
|
|
* |
|
|
!*/ |
|
|
|
|
|
#include "Common.h" |
|
|
|
|
|
typedef struct |
|
|
{ |
|
|
D_API( NtWaitForSingleObject ); |
|
|
D_API( NtCreateNamedPipeFile ); |
|
|
D_API( RtlInitUnicodeString ); |
|
|
D_API( NtFlushBuffersFile ); |
|
|
D_API( NtFsControlFile ); |
|
|
D_API( NtCreateEvent ); |
|
|
D_API( NtWriteFile ); |
|
|
D_API( NtReadFile ); |
|
|
D_API( _vsnprintf ); |
|
|
D_API( NtClose ); |
|
|
} API ; |
|
|
|
|
|
/* API Hashes */ |
|
|
#define H_API_NTWAITFORSINGLEOBJECT 0xe8ac0c3c /* NtWaitForSingleObject */ |
|
|
#define H_API_NTCREATENAMEDPIPEFILE 0x1da0062e /* NtCreateNamedPipeFile */ |
|
|
#define H_API_RTLINITUNICODESTRING 0xef52b589 /* RtlInitUnicodeString */ |
|
|
#define H_API_NTFLUSHBUFFERSFILE 0xc7654d16 /* NtFlushBuffersFile */ |
|
|
#define H_API_NTFSCONTROLFILE 0xecdfd601 /* NtFsControlFile */ |
|
|
#define H_API_NTCREATEEVENT 0x28d3233d /* NtCreateEvent */ |
|
|
#define H_API_NTWRITEFILE 0xe0d61db2 /* NtWriteFile */ |
|
|
#define H_API_NTREADFILE 0xb2d93203 /* NtReadFile */ |
|
|
#define H_API__VSNPRINTF 0xa59022ce /* _vsnprintf */ |
|
|
#define H_API_NTCLOSE 0x40d6e69d /* NtClose */ |
|
|
|
|
|
/* LIB Hashes */ |
|
|
#define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */ |
|
|
|
|
|
/* IOCTL */ |
|
|
#define FSCTL_PIPE_DISCONNECT CTL_CODE( FILE_DEVICE_NAMED_PIPE, 1, METHOD_BUFFERED, FILE_ANY_ACCESS ) |
|
|
#define FSCTL_PIPE_LISTEN CTL_CODE( FILE_DEVICE_NAMED_PIPE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS ) |
|
|
|
|
|
/*! |
|
|
* |
|
|
* Purpose: |
|
|
* |
|
|
* Creates a pipe and waits on a connection. IF no |
|
|
* connection is recieved within the timeout period, |
|
|
* it will fail and shutdown prematurely. |
|
|
* |
|
|
!*/ |
|
|
D_SEC( B ) NTSTATUS PipeInit( _In_ LPWSTR NamedPipe, _In_ UINT32 PipeTimeout, _In_ UINT32 ConnectTimeout, _Out_ PHANDLE PipeHandle ) |
|
|
{ |
|
|
API Api; |
|
|
LARGE_INTEGER Tim; |
|
|
UNICODE_STRING Uni; |
|
|
IO_STATUS_BLOCK Isb; |
|
|
OBJECT_ATTRIBUTES Att; |
|
|
|
|
|
NTSTATUS Nst = STATUS_UNSUCCESSFUL; |
|
|
|
|
|
HANDLE Pip = NULL; |
|
|
HANDLE Evt = NULL; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Uni, sizeof( Uni ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
RtlZeroMemory( &Att, sizeof( Att ) ); |
|
|
|
|
|
Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTWAITFORSINGLEOBJECT ) ); |
|
|
Api.NtCreateNamedPipeFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCREATENAMEDPIPEFILE ) ); |
|
|
Api.RtlInitUnicodeString = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_RTLINITUNICODESTRING ) ); |
|
|
Api.NtFsControlFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTFSCONTROLFILE ) ); |
|
|
Api.NtCreateEvent = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCREATEEVENT ) ); |
|
|
Api.NtClose = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCLOSE ) ); |
|
|
|
|
|
/* Initialize attributes & string */ |
|
|
Api.RtlInitUnicodeString( &Uni, NamedPipe ); |
|
|
InitializeObjectAttributes( &Att, &Uni, OBJ_CASE_INSENSITIVE, NULL, NULL ); |
|
|
|
|
|
/* Set the pipe operation time out */ |
|
|
Tim.QuadPart = -10000LL * PipeTimeout; |
|
|
|
|
|
/* Create the named pipe */ |
|
|
Nst = Api.NtCreateNamedPipeFile( &Pip, |
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, |
|
|
&Att, |
|
|
&Isb, |
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE, |
|
|
FILE_OPEN_IF, |
|
|
0, /* FILE_SYCNHRONOUS_IO_NONALERT */ |
|
|
0, |
|
|
0, |
|
|
0, |
|
|
1, |
|
|
1024 * 1024, |
|
|
1024 * 1024, |
|
|
&Tim ); |
|
|
|
|
|
/* Success! Try and block on it */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
|
|
|
/* Create the blocking event */ |
|
|
Nst = Api.NtCreateEvent( &Evt, |
|
|
EVENT_ALL_ACCESS, |
|
|
NULL, |
|
|
NotificationEvent, |
|
|
FALSE ); |
|
|
|
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Request we start the bloc operation */ |
|
|
Nst = Api.NtFsControlFile( Pip, |
|
|
Evt, |
|
|
NULL, |
|
|
NULL, |
|
|
&Isb, |
|
|
FSCTL_PIPE_LISTEN, |
|
|
NULL, |
|
|
0, |
|
|
NULL, |
|
|
0 ); |
|
|
|
|
|
/* PEnding? */ |
|
|
if ( Nst == STATUS_PENDING ) { |
|
|
/* Blcok until it connects */ |
|
|
Tim.QuadPart = -10000LL * ConnectTimeout; |
|
|
|
|
|
/* Blocks until a timeout is reached, is signaled OR waits indefintely if timeout == 0 */ |
|
|
Nst = Api.NtWaitForSingleObject( Evt, FALSE, Tim.QuadPart != 0 ? &Tim : NULL ); |
|
|
|
|
|
/* No errors?! */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* SEt the status */ |
|
|
Nst = Isb.Status; |
|
|
} |
|
|
} |
|
|
|
|
|
/* Close the pipe */ |
|
|
Api.NtClose( Evt ); |
|
|
} |
|
|
} |
|
|
|
|
|
/* Did we get STATUS_PIPE_CONNECTED? Not really an error */ |
|
|
if ( Nst == STATUS_PIPE_CONNECTED ) { |
|
|
/* Readjust to a connected status */ |
|
|
Nst = STATUS_SUCCESS; |
|
|
} |
|
|
|
|
|
/* We got errors?! */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the output handle */ |
|
|
*PipeHandle = C_PTR( Pip ); |
|
|
} else { |
|
|
/* Failed. Close the pipe */ |
|
|
if ( Pip != NULL ) { |
|
|
/* Closed the pipe */ |
|
|
Api.NtClose( Pip ); |
|
|
} |
|
|
} |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Uni, sizeof( Uni ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
RtlZeroMemory( &Att, sizeof( Att ) ); |
|
|
|
|
|
/* Return the status */ |
|
|
return Nst; |
|
|
} |
|
|
|
|
|
/*! |
|
|
* |
|
|
* Purpose: |
|
|
* |
|
|
* Closes the named pipe and flushes the output buffer |
|
|
* if requested. |
|
|
* |
|
|
!*/ |
|
|
D_SEC( B ) NTSTATUS PipeFree( _In_ HANDLE PipeHandle, _In_ BOOLEAN FlushBuffer ) |
|
|
{ |
|
|
API Api; |
|
|
IO_STATUS_BLOCK Isb; |
|
|
|
|
|
NTSTATUS Nst = STATUS_UNSUCCESSFUL; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTWAITFORSINGLEOBJECT ) ); |
|
|
Api.NtFlushBuffersFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTFLUSHBUFFERSFILE ) ); |
|
|
Api.NtFsControlFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTFSCONTROLFILE ) ); |
|
|
Api.NtClose = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCLOSE ) ); |
|
|
|
|
|
if ( FlushBuffer ) { |
|
|
/* Flush the file buffers. Who care about the result */ |
|
|
Api.NtFlushBuffersFile( PipeHandle, &Isb ); |
|
|
} |
|
|
|
|
|
/* Force a disconnect */ |
|
|
Nst = Api.NtFsControlFile( PipeHandle, |
|
|
NULL, |
|
|
NULL, |
|
|
NULL, |
|
|
&Isb, |
|
|
FSCTL_PIPE_DISCONNECT, |
|
|
NULL, |
|
|
0, |
|
|
NULL, |
|
|
0 ); |
|
|
|
|
|
/* Is this operation pending? */ |
|
|
if ( Nst == STATUS_PENDING ) { |
|
|
/* Wait until the pending operation completes */ |
|
|
Nst = Api.NtWaitForSingleObject( PipeHandle, FALSE, NULL ); |
|
|
|
|
|
/* Did we succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the status */ |
|
|
Nst = Isb.Status; |
|
|
} |
|
|
} |
|
|
/* Did we succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Close the pipe */ |
|
|
Nst = Api.NtClose( PipeHandle ); |
|
|
}; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
/* Return the status */ |
|
|
return Nst; |
|
|
} |
|
|
|
|
|
/*! |
|
|
* |
|
|
* Purpose: |
|
|
* |
|
|
* Reads data from the named pipe. If ReadTimeout is |
|
|
* set to 0, it is presumed that the function will |
|
|
* read until an error occurs. If the function has |
|
|
* succeeded, the LengthRead will be set to the |
|
|
* output. |
|
|
* |
|
|
!*/ |
|
|
D_SEC( B ) NTSTATUS PipeRd( _In_ HANDLE PipeHandle, _In_ PVOID Buffer, _In_ UINT32 Length, _In_ UINT32 ReadTimeout, _Out_ PUINT32 LengthRead ) |
|
|
{ |
|
|
API Api; |
|
|
LARGE_INTEGER Tim; |
|
|
IO_STATUS_BLOCK Isb; |
|
|
|
|
|
NTSTATUS Nst = STATUS_UNSUCCESSFUL; |
|
|
|
|
|
HANDLE Evt = NULL; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTWAITFORSINGLEOBJECT ) ); |
|
|
Api.NtCreateEvent = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCREATEEVENT ) ); |
|
|
Api.NtReadFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTREADFILE ) ); |
|
|
Api.NtClose = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCLOSE ) ); |
|
|
|
|
|
Nst = Api.NtCreateEvent( &Evt, |
|
|
EVENT_ALL_ACCESS, |
|
|
NULL, |
|
|
NotificationEvent, |
|
|
FALSE ); |
|
|
|
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
|
|
|
/* Start the read length */ |
|
|
Nst = Api.NtReadFile( PipeHandle, |
|
|
Evt, |
|
|
NULL, |
|
|
NULL, |
|
|
&Isb, |
|
|
Buffer, |
|
|
Length, |
|
|
NULL, |
|
|
NULL ); |
|
|
|
|
|
/* Not complete? */ |
|
|
if ( Nst == STATUS_PENDING ) { |
|
|
/* Wait until timeout or infinite */ |
|
|
Tim.QuadPart = -10000LL * ReadTimeout; |
|
|
Nst = Api.NtWaitForSingleObject( Evt, FALSE, Tim.QuadPart != 0 ? &Tim : NULL ); |
|
|
|
|
|
/* Did we succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the status */ |
|
|
Nst = Isb.Status; |
|
|
} |
|
|
} |
|
|
/* Reached the end of the file */ |
|
|
if ( Nst == STATUS_END_OF_FILE ) { |
|
|
/* No buffer read */ |
|
|
*LengthRead = 0; |
|
|
|
|
|
/* Return the length */ |
|
|
return STATUS_SUCCESS; |
|
|
} |
|
|
/* Did it succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the length read */ |
|
|
*LengthRead = Isb.Information; |
|
|
}; |
|
|
/* Close the reference */ |
|
|
Api.NtClose( Evt ); |
|
|
}; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
/* Return the status */ |
|
|
return Nst; |
|
|
} |
|
|
|
|
|
/*! |
|
|
* |
|
|
* Purpose: |
|
|
* |
|
|
* Writes to a named pipe. If a timeout is set to 0, |
|
|
* the function will block indefinetly. |
|
|
* |
|
|
!*/ |
|
|
D_SEC( B ) NTSTATUS PipeWr( _In_ HANDLE PipeHandle, _In_ PVOID Buffer, _In_ UINT32 Length, _In_ UINT32 WriteTimeout, _Out_ PUINT32 LengthWritten ) |
|
|
{ |
|
|
API Api; |
|
|
LARGE_INTEGER Tim; |
|
|
IO_STATUS_BLOCK Isb; |
|
|
|
|
|
NTSTATUS Nst = STATUS_UNSUCCESSFUL; |
|
|
|
|
|
HANDLE Evt = NULL; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
Api.NtWaitForSingleObject = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTWAITFORSINGLEOBJECT ) ); |
|
|
Api.NtCreateEvent = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCREATEEVENT ) ); |
|
|
Api.NtWriteFile = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTWRITEFILE ) ); |
|
|
Api.NtClose = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCLOSE ) ); |
|
|
|
|
|
/* Create the event for waiting on */ |
|
|
Nst = Api.NtCreateEvent( &Evt, |
|
|
EVENT_ALL_ACCESS, |
|
|
NULL, |
|
|
NotificationEvent, |
|
|
FALSE ); |
|
|
|
|
|
/* Did it succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
|
|
|
/* Write to the file */ |
|
|
Nst = Api.NtWriteFile( PipeHandle, |
|
|
Evt, |
|
|
NULL, |
|
|
NULL, |
|
|
&Isb, |
|
|
Buffer, |
|
|
Length, |
|
|
NULL, |
|
|
NULL ); |
|
|
|
|
|
/* Is the oepration pending */ |
|
|
if ( Nst == STATUS_PENDING ) { |
|
|
/* Set the timeout */ |
|
|
Tim.QuadPart = -10000LL * WriteTimeout; |
|
|
|
|
|
/* Block unti lits ready */ |
|
|
Nst = Api.NtWaitForSingleObject( Evt, FALSE, Tim.QuadPart != 0 ? &Tim : NULL ); |
|
|
|
|
|
/* Did we succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the success status */ |
|
|
Nst = Isb.Status; |
|
|
} |
|
|
}; |
|
|
/* Did we succeed? */ |
|
|
if ( NT_SUCCESS( Nst ) ) { |
|
|
/* Set the last read */ |
|
|
*LengthWritten = Isb.Information; |
|
|
} |
|
|
/* Close the reference */ |
|
|
Api.NtClose( Evt ); |
|
|
}; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Tim, sizeof( Tim ) ); |
|
|
RtlZeroMemory( &Isb, sizeof( Isb ) ); |
|
|
|
|
|
/* Return status */ |
|
|
return Nst; |
|
|
} |
|
|
|
|
|
/*! |
|
|
* |
|
|
* Purpose: |
|
|
* |
|
|
* Writes a formatted string onto the named pipe. |
|
|
* |
|
|
!*/ |
|
|
D_SEC( B ) NTSTATUS PipePrintf( _In_ HANDLE PipeHandle, _In_ UINT32 WriteTimeout, _In_ PCHAR Format, ... ) |
|
|
{ |
|
|
API Api; |
|
|
va_list Lst; |
|
|
|
|
|
UINT32 Len = 0; |
|
|
UINT32 Wrt = 0; |
|
|
NTSTATUS Nst = STATUS_UNSUCCESSFUL; |
|
|
|
|
|
PUINT8 Buf = NULL; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Lst, sizeof( Lst ) ); |
|
|
|
|
|
Api._vsnprintf = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API__VSNPRINTF ) ); |
|
|
|
|
|
/* Get the length of the buffer */ |
|
|
va_start( Lst, Format ); |
|
|
Len = Api._vsnprintf( NULL, 0, Format, Lst ); |
|
|
va_end( Lst ); |
|
|
|
|
|
/* Allocate an output buffer */ |
|
|
if ( ( Buf = MemoryAlloc( Len + 1 ) ) ) { |
|
|
|
|
|
/* Format the output buffer */ |
|
|
va_start( Lst, Format ); |
|
|
Len = Api._vsnprintf( Buf, Len, Format, Lst ); |
|
|
va_end( Lst ); |
|
|
|
|
|
/* End the line */ |
|
|
Buf[ Len ] = '\n'; |
|
|
|
|
|
/* Write to the buffer */ |
|
|
Nst = PipeWr( PipeHandle, Buf, Len + 1, WriteTimeout, &Wrt ); |
|
|
|
|
|
/* Free the buffer */ |
|
|
MemoryFree( Buf ); |
|
|
}; |
|
|
|
|
|
/* Zero out stack structures */ |
|
|
RtlZeroMemory( &Api, sizeof( Api ) ); |
|
|
RtlZeroMemory( &Lst, sizeof( Lst ) ); |
|
|
|
|
|
/* Return the status */ |
|
|
return Nst; |
|
|
} |