NTSTATUS MExcept::CreateVEH(size_t pTargetBase, size_t imageSize, eModType mt, bool partial) { AsmJitHelper a; uint64_t result = 0; auto& mods = _proc.Modules(); #ifdef USE64 // Add module to module table if(!_pModTable.Valid()) { _pModTable = _proc.Memory().Allocate(0x1000); _pModTable.Release(); if(!_pModTable.Valid()) return LastNtStatus(); } ModuleTable table; _pModTable.Read(0, table); // Add new entry to the table table.entry[table.count].base = pTargetBase; table.entry[table.count].size = imageSize; table.count++; _pModTable.Write(0, table); // No handler required if(partial) return STATUS_SUCCESS; // VEH codecave _pVEHCode = _proc.Memory().Allocate(0x2000); _pVEHCode.Release(); if(!_pVEHCode.Valid()) return LastNtStatus(); BLACBONE_TRACE("ManualMap: Vectored hander: 0x%p\n", _pVEHCode.Ptr()); asmjit::Label lExit = a->newLabel(); asmjit::Label lLoop1 = a->newLabel(); asmjit::Label skip1 = a->newLabel(); asmjit::Label found1 = a->newLabel(); // // Assembly code for VectoredHandler64 // 0x10 - EXCEPTION_RECORD.ExceptionAddress // 0x20 - EXCEPTION_RECORD.ExceptionInformation[0] // 0x30 - EXCEPTION_RECORD.ExceptionInformation[2] // 0x38 - EXCEPTION_RECORD.ExceptionInformation[3] // a->mov(asmjit::host::rax, asmjit::host::qword_ptr(asmjit::host::rcx)); a->cmp(asmjit::host::dword_ptr(asmjit::host::rax), EH_EXCEPTION_NUMBER); // Exception code a->jne(lExit); a->cmp(asmjit::host::qword_ptr(asmjit::host::rax, 0x20), EH_PURE_MAGIC_NUMBER1); // Sub code a->jne(lExit); a->cmp(asmjit::host::qword_ptr(asmjit::host::rax, 0x38), 0); // Image base a->jne(lExit); a->mov(asmjit::host::r9, _pModTable.Ptr()); a->mov(asmjit::host::rdx, asmjit::host::qword_ptr(asmjit::host::r9)); // Record count a->add(asmjit::host::r9, sizeof(table.count)); a->xor_(asmjit::host::r10, asmjit::host::r10); a->bind(lLoop1); a->mov(asmjit::host::r8, asmjit::host::qword_ptr(asmjit::host::rax, 0x30)); a->mov(asmjit::host::r11, asmjit::host::qword_ptr(asmjit::host::r9)); a->cmp(asmjit::host::r8, asmjit::host::r11); a->jl(skip1); a->add(asmjit::host::r11, asmjit::host::qword_ptr(asmjit::host::r9, sizeof(table.entry[0].base))); // Size a->cmp(asmjit::host::r8, asmjit::host::r11); a->jg(skip1); a->jmp(found1); a->bind(skip1); a->add(asmjit::host::r9, sizeof(ExceptionModule)); a->add(asmjit::host::r10, 1); a->cmp(asmjit::host::r10, asmjit::host::rdx); a->jne(lLoop1); a->jmp(lExit); a->bind(found1); a->mov(asmjit::host::qword_ptr(asmjit::host::rax, 0x20), EH_MAGIC_NUMBER1); a->mov(asmjit::host::rcx, asmjit::host::qword_ptr(asmjit::host::rcx)); a->mov(asmjit::host::rdx, asmjit::host::qword_ptr(asmjit::host::r9)); a->mov(asmjit::host::qword_ptr(asmjit::host::rax, 0x38), asmjit::host::rdx); a->bind(lExit); a->xor_(asmjit::host::rax, asmjit::host::rax); a->ret(); a->db(0xCC); a->db(0xCC); a->db(0xCC); if(_pVEHCode.Write(0, a->getCodeSize(), a->make()) != STATUS_SUCCESS) { _pVEHCode.Free(); return LastNtStatus(); } #else UNREFERENCED_PARAMETER(pTargetBase); UNREFERENCED_PARAMETER(imageSize); // No handler required if(partial) return STATUS_SUCCESS; // VEH codecave _pVEHCode = _proc.Memory().Allocate(0x2000); _pVEHCode.Release(); if(!_pVEHCode.Valid()) return LastNtStatus(); // Resolve compiler incremental table address, if any void *pFunc = ResolveJmp(&VectoredHandler); size_t fnSize = static_cast<size_t>(SizeOfProc(pFunc)); size_t dataOfs = 0, code_ofs = 0, code_ofs2 = 0;; // Find and replace magic values for(uint8_t *pData = reinterpret_cast<uint8_t*>(pFunc); pData < reinterpret_cast<uint8_t*>(pFunc) + fnSize - 4; pData++) { // LdrpInvertedFunctionTable if(*(size_t*)pData == 0xDEADDA7A) { dataOfs = pData - reinterpret_cast<uint8_t*>(pFunc); continue; } // DecodeSystemPointer address if(*(size_t*)pData == 0xDEADC0DE) { code_ofs = pData - reinterpret_cast<uint8_t*>(pFunc); break; } // LdrProtectMrdata address if(*(size_t*)pData == 0xDEADC0D2) { code_ofs2 = pData - reinterpret_cast<uint8_t*>(pFunc); continue; } } auto pDecode = mods.GetExport(mods.GetModule(L"ntdll.dll", Sections, mt), "RtlDecodeSystemPointer").procAddress; // Write handler data into target process if(!NT_SUCCESS(_pVEHCode.Write(0, fnSize, pFunc)) || !NT_SUCCESS(_pVEHCode.Write(dataOfs, _proc.NativeLdr().LdrpInvertedFunctionTable())) || !NT_SUCCESS(_pVEHCode.Write(code_ofs, static_cast<size_t>(pDecode))) || !NT_SUCCESS(_pVEHCode.Write(code_ofs2, _proc.NativeLdr().LdrProtectMrdata()))) { _pVEHCode.Free(); return LastNtStatus(); } #endif // AddVectoredExceptionHandler(0, pHandler); auto pAddHandler = mods.GetExport(mods.GetModule(L"ntdll.dll", Sections, mt), "RtlAddVectoredExceptionHandler").procAddress; if(pAddHandler == 0) return STATUS_NOT_FOUND; a->reset(); a.GenPrologue(); a.GenCall(static_cast<size_t>(pAddHandler), {0, _pVEHCode.Ptr<size_t>()}); _proc.Remote().AddReturnWithEvent(a, mt); a.GenEpilogue(); _proc.Remote().ExecInWorkerThread(a->make(), a->getCodeSize(), result); _hVEH = static_cast<size_t>(result); return (_hVEH == 0 ? STATUS_NOT_FOUND : STATUS_SUCCESS); }
/// <summary> /// Create worker RPC thread /// </summary> /// <returns>Thread ID</returns> DWORD RemoteExec::CreateWorkerThread() { AsmJitHelper a; asmjit::Label l_loop = a->newLabel(); // // Create execution thread // if(!_hWorkThd.valid()) { eModType mt = mt_default; if (_memory.core().native()->GetWow64Barrier().type == wow_64_32) { mt = mt_mod64; a.SwitchTo64(); // Align stack on 16 byte boundary a->and_( asmjit::host::zsp, -16 ); // Allocate new x64 activation stack auto createActStack = _mods.GetExport( _mods.GetModule( L"ntdll.dll", LdrList, mt ), "RtlAllocateActivationContextStack" ).procAddress; if(createActStack) { a.GenCall( static_cast<size_t>(createActStack), { _userData.ptr<size_t>() + 0x3000 } ); a->mov( asmjit::host::zax, _userData.ptr<size_t>() + 0x3000 ); a->mov( asmjit::host::zax, asmjit::host::intptr_ptr( asmjit::host::zax ) ); a.SetTebPtr(); a->mov( asmjit::host::intptr_ptr( asmjit::host::zdx, 0x2c8 ), asmjit::host::zax ); } } auto ntdll = _mods.GetModule( L"ntdll.dll", Sections, mt ); auto proc = _mods.GetExport( ntdll, "NtDelayExecution" ).procAddress; auto pExitThread = _mods.GetExport( ntdll, "NtTerminateThread" ).procAddress; if (proc == 0 || pExitThread == 0) return 0; /* for(;;) SleepEx(5, TRUE); ExitThread(SetEvent(m_hWaitEvent)); */ a->bind( l_loop ); a.GenCall( static_cast<size_t>(proc), { TRUE, _workerCode.ptr<size_t>() } ); a->jmp( l_loop ); a.ExitThreadWithStatus( (size_t)pExitThread, _userData.ptr<size_t>() ); // Write code into process LARGE_INTEGER liDelay = { 0 }; liDelay.QuadPart = -10 * 1000 * 5; _workerCode.Write( 0, liDelay ); _workerCode.Write( sizeof(LARGE_INTEGER), a->getCodeSize(), a->make() ); _hWorkThd = _threads.CreateNew( _workerCode.ptr<size_t>() + sizeof(LARGE_INTEGER), _userData.ptr<size_t>() ); } return _hWorkThd.id(); }
/// <summary> /// Inject VEH wrapper into process /// Used to enable execution of SEH handlers out of image /// </summary> /// <param name="pTargetBase">Target image base address</param> /// <param name="imageSize">Size of the image</param> /// <returns>Error code</returns> NTSTATUS MExcept::CreateVEH( size_t pTargetBase, size_t imageSize ) { AsmJitHelper ea; uint64_t result = 0; // VEH codecave _pVEHCode = _proc.memory().Allocate( 0x2000 ); _pVEHCode.Release(); if (!_pVEHCode.valid()) return LastNtStatus(); #ifdef USE64 asmjit::Label lExit = ea->newLabel(); // // Assembly code for VectoredHandler64 // 0x10 - EXCEPTION_RECORD.ExceptionAddress // 0x20 - EXCEPTION_RECORD.ExceptionInformation[0] // 0x30 - EXCEPTION_RECORD.ExceptionInformation[2] // 0x38 - EXCEPTION_RECORD.ExceptionInformation[3] // ea->mov( asmjit::host::rax, qword_ptr( asmjit::host::rcx ) ); ea->cmp( asmjit::host::dword_ptr( asmjit::host::rax ), EH_EXCEPTION_NUMBER ); ea->jne( lExit ); ea->mov( asmjit::host::rdx, pTargetBase ); ea->mov( asmjit::host::r8, asmjit::host::qword_ptr( asmjit::host::rax, 0x30 ) ); ea->cmp( asmjit::host::r8, asmjit::host::rdx );; ea->jl( lExit ); ea->add( asmjit::host::rdx, imageSize ); ea->cmp( asmjit::host::r8, asmjit::host::rdx );; ea->jg( lExit ); ea->cmp( asmjit::host::qword_ptr( asmjit::host::rax, 0x20 ), EH_PURE_MAGIC_NUMBER1 );; ea->jne( lExit ); ea->cmp( asmjit::host::qword_ptr( asmjit::host::rax, 0x38 ), 0 ); ea->jne( lExit ); ea->mov( asmjit::host::qword_ptr( asmjit::host::rax, 0x20 ), EH_MAGIC_NUMBER1 ); ea->mov( asmjit::host::rcx, qword_ptr( asmjit::host::rcx ) ); ea->mov( asmjit::host::rdx, pTargetBase ); ea->mov( asmjit::host::qword_ptr( asmjit::host::rax, 0x38 ), asmjit::host::rdx ); ea->bind( lExit ); ea->xor_( asmjit::host::rax, asmjit::host::rax ); ea->ret(); ea->emit( 0xCC ); ea->emit( 0xCC ); ea->emit( 0xCC ); if (_pVEHCode.Write( 0, ea->getCodeSize(), ea->make() ) != STATUS_SUCCESS) { _pVEHCode.Free(); return LastNtStatus(); } #else UNREFERENCED_PARAMETER( pTargetBase ); UNREFERENCED_PARAMETER( imageSize ); // Resolve compiler incremental table address if any void *pFunc = ResolveJmp( &VectoredHandler ); size_t fnSize = static_cast<size_t>(SizeOfProc( pFunc )); size_t dataOfs = 0, code_ofs = 0; // Find and replace magic values for (uint8_t *pData = reinterpret_cast<uint8_t*>(pFunc); pData < reinterpret_cast<uint8_t*>(pFunc) + fnSize - 4; pData++) { // LdrpInvertedFunctionTable if(*(size_t*)pData == 0xDEADDA7A) { dataOfs = pData - reinterpret_cast<uint8_t*>(pFunc); continue; } // DecodeSystemPointer address if(*(size_t*)pData == 0xDEADC0DE) { code_ofs = pData - reinterpret_cast<uint8_t*>(pFunc); break; } } // Write handler data into target process if (_pVEHCode.Write( 0, fnSize, pFunc ) != STATUS_SUCCESS || _pVEHCode.Write( dataOfs, _proc.nativeLdr().LdrpInvertedFunctionTable() ) != STATUS_SUCCESS || _pVEHCode.Write( code_ofs, &DecodeSystemPointer ) != STATUS_SUCCESS) { _pVEHCode.Free(); return LastNtStatus(); } #endif ea.GenPrologue(); // AddVectoredExceptionHandler(0, pHandler); ea.GenCall( reinterpret_cast<void*>(&AddVectoredExceptionHandler), { 0, _pVEHCode.ptr<size_t>() } ); _proc.remote().AddReturnWithEvent( ea ); ea.GenEpilogue(); _proc.remote().ExecInWorkerThread( ea->make(), ea->getCodeSize(), result ); _hVEH = static_cast<size_t>(result); return (result == 0 ? STATUS_NOT_FOUND : STATUS_SUCCESS); }