コード例 #1
0
ファイル: RemoteExec.cpp プロジェクト: topblast/Blackbone
/// <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;
}
コード例 #2
0
ファイル: RemoteExec.cpp プロジェクト: topblast/Blackbone
/// <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;
}
コード例 #3
0
ファイル: RemoteExec.cpp プロジェクト: hezzrrah/Blackbone
/// <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 ))
    {
        AsmJit::Assembler a;
        AsmJitHelper ah( a );

#ifdef _M_AMD64
        const int count = 15;
        AsmJit::GPReg regs[] = { AsmJit::rax, AsmJit::rbx, AsmJit::rcx, AsmJit::rdx, AsmJit::rsi,
                                 AsmJit::rdi, AsmJit::r8,  AsmJit::r9,  AsmJit::r10, AsmJit::r11,
                                 AsmJit::r12, AsmJit::r13, AsmJit::r14, AsmJit::r15, AsmJit::rbp
                               };
        //
        // Preserve thread context
        // I don't care about FPU, XMM and anything else
        //
        a.sub(AsmJit::rsp, count * WordSize);  // Stack must be aligned on 16 bytes
        a.pushfq();                            //

        // Save registers
        for (int i = 0; i < count; i++)
            a.mov( AsmJit::Mem( AsmJit::rsp, i * WordSize ), regs[i] );

        ah.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } );
        AddReturnWithEvent( ah, rt_int32, INTRET_OFFSET );

        // Restore registers
        for (int i = 0; i < count; i++)
            a.mov( regs[i], AsmJit::Mem( AsmJit::rsp, i * WordSize ) );

        a.popfq();
        a.add( AsmJit::rsp, count * WordSize );

        a.jmp( ctx.Rip );
#else
        a.pushad();
        a.pushfd();

        ah.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } );
        AddReturnWithEvent( ah, rt_int32, INTRET_OFFSET );

        a.popfd();
        a.popad();

        a.push( 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;
}