/// <summary> /// Execute code in context of any existing thread /// </summary> /// <param name="pCode">Cde to execute</param> /// <param name="size">Code size.</param> /// <param name="callResult">Execution result</param> /// <param name="thd">Target thread</param> /// <returns>Status</returns> NTSTATUS RemoteExec::ExecInAnyThread( PVOID pCode, size_t size, uint64_t& callResult, Thread& thd ) { NTSTATUS dwResult = STATUS_SUCCESS; CONTEXT_T ctx; // Prepare for remote exec CreateRPCEnvironment( true ); // Write code dwResult = CopyCode( pCode, size ); if (dwResult != STATUS_SUCCESS) return dwResult; if (_hWaitEvent) ResetEvent( _hWaitEvent ); if (!thd.Suspend()) return LastNtStatus(); if (thd.GetContext( ctx, CONTEXT_ALL, true )) { AsmJitHelper a; #ifdef USE64 const int count = 15; asmjit::host::GpReg regs[] = { asmjit::host::rax, asmjit::host::rbx, asmjit::host::rcx, asmjit::host::rdx, asmjit::host::rsi, asmjit::host::rdi, asmjit::host::r8, asmjit::host::r9, asmjit::host::r10, asmjit::host::r11, asmjit::host::r12, asmjit::host::r13, asmjit::host::r14, asmjit::host::r15, asmjit::host::rbp }; // // Preserve thread context // I don't care about FPU, XMM and anything else // a->sub( asmjit::host::rsp, count * WordSize ); // Stack must be aligned on 16 bytes a->pushf(); // // Save registers for (int i = 0; i < count; i++) a->mov( asmjit::host::Mem( asmjit::host::rsp, i * WordSize ), regs[i] ); a.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( a, mt_default, rt_int32, INTRET_OFFSET ); // Restore registers for (int i = 0; i < count; i++) a->mov( regs[i], asmjit::host::Mem( asmjit::host::rsp, i * WordSize ) ); a->popf(); a->add( asmjit::host::rsp, count * WordSize ); a->jmp( asmjit::Imm( ctx.Rip ) ); #else a->pusha(); a->pushf(); a.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( a, mt_default, rt_int32, INTRET_OFFSET ); a->popf(); a->popa(); a->push( (size_t)ctx.NIP ); a->ret(); #endif if (_userCode.Write( size, a->getCodeSize(), a->make() ) == STATUS_SUCCESS) { ctx.NIP = _userCode.ptr<size_t>() + size; if (!thd.SetContext( ctx, true )) dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); thd.Resume(); if (dwResult == STATUS_SUCCESS) { WaitForSingleObject( _hWaitEvent, INFINITE ); callResult = _userData.Read<size_t>( INTRET_OFFSET, 0 ); } return dwResult; }
bool MMap::CreateActx(const std::wstring& path, int id /*= 2 */, bool asImage /*= true*/) { AsmJitHelper a; uint64_t result = 0; ACTCTXW act = {0}; _pAContext = _process.Memory().Allocate(512, PAGE_READWRITE); act.cbSize = sizeof(act); act.lpSource = reinterpret_cast<LPCWSTR>(_pAContext.Ptr<size_t>() + sizeof(HANDLE) + sizeof(act)); // Ignore some fields for pure manifest file if(asImage) { act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; act.lpResourceName = MAKEINTRESOURCEW(id); } bool switchMode = (_process.Core().GetNative()->GetWow64Barrier().type == wow_64_32); auto pCreateActx = _process.Modules().GetExport(_process.Modules().GetModule(L"kernel32.dll"), "CreateActCtxW"); if(pCreateActx.procAddress == 0) { BLACBONE_TRACE(L"ManualMap: Failed to create activation context for image '%ls'. 'CreateActCtxW' is absent", path.c_str()); return false; } // CreateActCtx(&act) // Emulate Wow64 if(switchMode) { _ACTCTXW_T<DWORD> act32 = {0}; act32.cbSize = sizeof(act32); act32.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; act32.lpSource = _pAContext.Ptr<uint32_t>() + sizeof(HANDLE) + sizeof(act32); act32.lpResourceName = id; a->push(_pAContext.Ptr<uint32_t>() + static_cast<uint32_t>(sizeof(HANDLE))); a->mov(asmjit::host::eax, static_cast<uint32_t>(pCreateActx.procAddress)); a->call(a->zax); a->mov(asmjit::host::edx, _pAContext.Ptr<uint32_t>()); //a->mov( asmjit::host::dword_ptr( asmjit::host::edx ), asmjit::host::eax ); a->dw('\x01\x02'); auto pTermThd = _process.Modules().GetExport(_process.Modules().GetModule(L"ntdll.dll"), "NtTerminateThread"); a->push(a->zax); a->push(uint32_t(0)); a->mov(asmjit::host::eax, static_cast<uint32_t>(pTermThd.procAddress)); a->call(a->zax); a->ret(4); // Write path to file _pAContext.Write(sizeof(HANDLE), act32); _pAContext.Write(sizeof(HANDLE) + sizeof(act32), (path.length() + 1) * sizeof(wchar_t), path.c_str()); auto pCode = _process.Memory().Allocate(0x1000); pCode.Write(0, a->getCodeSize(), a->make()); result = _process.Remote().ExecDirect(pCode.Ptr<ptr_t>(), _pAContext.Ptr<size_t>() + sizeof(HANDLE)); } // Native way else { a.GenPrologue(); a.GenCall(static_cast<size_t>(pCreateActx.procAddress), {_pAContext.Ptr<size_t>() + sizeof(HANDLE)}); a->mov(a->zdx, _pAContext.Ptr<size_t>()); a->mov(a->intptr_ptr(a->zdx), a->zax); _process.Remote().AddReturnWithEvent(a); a.GenEpilogue(); // Write path to file _pAContext.Write(sizeof(HANDLE), act); _pAContext.Write(sizeof(HANDLE) + sizeof(act), (path.length() + 1) * sizeof(wchar_t), path.c_str()); _process.Remote().ExecInWorkerThread(a->make(), a->getCodeSize(), result); } if(reinterpret_cast<HANDLE>(result) == INVALID_HANDLE_VALUE) { _pAContext.Free(); // SetLastError( err::mapping::CantCreateActx ); BLACBONE_TRACE(L"ManualMap: Failed to create activation context for image '%ls'. Status: 0x%x", path.c_str(), _process.Remote().GetLastStatus()); return false; } return true; }