/// <summary> /// Generate assembly code for remote call. /// </summary> /// <param name="a">Underlying assembler object</param> /// <param name="pfn">Remote function pointer</param> /// <param name="args">Function arguments</param> /// <param name="cc">Calling convention</param> /// <param name="retType">Return type</param> /// <returns>true on success</returns> bool RemoteExec::PrepareCallAssembly( AsmHelperBase& a, const void* pfn, std::vector<AsmVariant>& args, eCalligConvention cc, eReturnType retType ) { size_t data_offset = ARGS_OFFSET; // Invalid calling convention if (cc < cc_cdecl || cc > cc_fastcall) { LastNtStatus( STATUS_INVALID_PARAMETER_3 ); return false; } // Copy structures and strings for (auto& arg : args) { if (arg.type == AsmVariant::dataStruct || arg.type == AsmVariant::dataPtr) { _userData.Write( data_offset, arg.size, reinterpret_cast<const void*>(arg.imm_val) ); arg.new_imm_val = _userData.ptr<size_t>() + data_offset; // Add some padding after data data_offset += arg.size + 0x10; } } // Insert hidden variable if return type is struct. // This variable contains address of buffer in which return value is copied if (retType == rt_struct) { args.emplace( args.begin(), AsmVariant( _userData.ptr<size_t>() + ARGS_OFFSET ) ); args.front().new_imm_val = args.front().imm_val; args.front().type = AsmVariant::structRet; } a.GenPrologue(); a.GenCall( pfn, args, cc ); // Retrieve result from XMM0 or ST0 if (retType == rt_float || retType == rt_double) { a->mov( asmjit::host::zax, _userData.ptr<size_t>() + RET_OFFSET ); #ifdef USE64 if (retType == rt_double) a->movsd( asmjit::host::Mem( asmjit::host::zax, 0 ), asmjit::host::xmm0 ); else a->movss( asmjit::host::Mem( asmjit::host::zax, 0 ), asmjit::host::xmm0 ); #else a->fstp( asmjit::host::Mem( asmjit::host::zax, 0, retType * sizeof(float) ) ); #endif } AddReturnWithEvent( a, mt_default, retType ); a.GenEpilogue(); return true; }
/// <summary> /// Generate return from function with event synchronization /// </summary> /// <param name="a">Target assembly helper</param> /// <param name="mt">32/64bit loader</param> /// <param name="retType">Function return type</param> /// <param name="retOffset">Return value offset</param> void RemoteExec::AddReturnWithEvent( AsmHelperBase& a, eModType mt /*= mt_default*/, eReturnType retType /*= rt_int32 */, uint32_t retOffset /*= RET_OFFSET*/ ) { size_t ptr = _userData.ptr<size_t>(); auto pSetEvent = _proc.modules().GetExport( _proc.modules().GetModule( L"ntdll.dll", LdrList, mt ), "NtSetEvent" ); a.SaveRetValAndSignalEvent( (size_t)pSetEvent.procAddress, ptr + retOffset, ptr + EVENT_OFFSET, ptr + ERR_OFFSET, retType ); }
/// <summary> /// Generate return from function with event synchronization /// </summary> /// <param name="a">Target assembly helper</param> /// <param name="mt">32/64bit loader</param> /// <param name="retType">Function return type</param> /// <param name="retOffset">Return value offset</param> void RemoteExec::AddReturnWithEvent( AsmHelperBase& a, eModType mt /*= mt_default*/, eReturnType retType /*= rt_int32 */, uint32_t retOffset /*= RET_OFFSET*/ ) { // Allocate block if missing if (!_userData.valid()) _userData = _memory.Allocate( 0x4000, PAGE_READWRITE ); size_t ptr = _userData.ptr<size_t>(); auto pSetEvent = _proc.modules().GetExport( _proc.modules().GetModule( L"ntdll.dll", LdrList, mt ), "NtSetEvent" ); a.SaveRetValAndSignalEvent( (size_t)pSetEvent.procAddress, ptr + retOffset, ptr + EVENT_OFFSET, ptr + ERR_OFFSET, retType ); }