VTIL-Core/VTIL-Architecture/symex/pointer.cpp

155 lines
5.1 KiB
C++
Raw Permalink Normal View History

2020-05-25 07:40:23 +02:00
// Copyright (c) 2020 Can Boluk and contributors of the VTIL Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
2020-07-09 02:43:51 +02:00
// 3. Neither the name of VTIL Project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
2020-05-25 07:40:23 +02:00
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "pointer.hpp"
#include <numeric>
#include <vtil/math>
#include "../arch/register_desc.hpp"
#include "variable.hpp"
namespace vtil::symbolic
{
// Given a variable or an expression, checks if it is basing from a
// known restricted pointer, if so returns the register it's based off of.
//
static std::optional<register_desc> get_restricted_base( const variable& var )
{
// If variable is not a register, return null.
//
if ( !var.is_register() )
return std::nullopt;
// Search for it in the restricted base list, if found return.
//
const register_desc& reg = var.reg();
return pointer::restricted_bases.contains( reg ) ? std::optional{ reg } : std::nullopt;
}
static std::optional<register_desc> get_restricted_base( const expression& e )
{
// If expression is a variable, check as is:
//
if ( e.is_variable() )
return get_restricted_base( e.uid.get<variable>() );
// Else apply a custom logic per operation:
//
switch ( e.op )
{
case math::operator_id::add:
{
auto lhs = get_restricted_base( *e.lhs );
auto rhs = get_restricted_base( *e.rhs );
if ( !rhs ) return lhs;
if ( !lhs ) return rhs;
return lhs == rhs ? rhs : std::nullopt;
}
case math::operator_id::bitwise_or:
case math::operator_id::bitwise_and:
if ( auto lhs = get_restricted_base( *e.lhs ) )
return lhs;
else
return get_restricted_base( *e.rhs );
case math::operator_id::subtract:
return get_restricted_base( *e.lhs );
case math::operator_id::value_if:
return get_restricted_base( *e.rhs );
default:
return {};
}
}
2020-05-25 07:40:23 +02:00
// Construct from symbolic expression.
//
2020-07-13 00:27:05 +02:00
pointer::pointer( const expression::reference& _base ) : base( _base.simplify() )
2020-05-25 07:40:23 +02:00
{
2020-07-23 04:46:54 +02:00
// Determine pointer flags.
2020-05-25 07:40:23 +02:00
//
base->evaluate( [ & ] ( const unique_identifier& uid )
2020-05-25 07:40:23 +02:00
{
// If variable is a register that is a restricted base pointer:
2020-05-25 07:40:23 +02:00
//
if ( auto base = get_restricted_base( uid.get<variable>() ) )
{
// Set flags.
//
flags |= base->flags;
}
2020-05-25 07:40:23 +02:00
// Return dummy result.
2020-05-25 07:40:23 +02:00
//
return 0ull;
} );
// Initialize x values.
//
xvalues = base->xvalues();
2020-05-25 07:40:23 +02:00
}
// Simple pointer offseting.
//
2021-08-30 23:35:55 +08:00
pointer pointer::operator+( intptr_t dst ) const
2020-05-25 07:40:23 +02:00
{
pointer copy = *this;
copy.base = std::move( copy.base ) + dst;
std::transform(
std::begin( xvalues ), std::end( xvalues ),
std::begin( copy.xvalues ),
[ = ] ( auto v ) { return v + dst; }
);
2020-05-25 07:40:23 +02:00
return copy;
}
// Calculates the distance between two pointers as an optional constant.
//
2021-08-30 23:35:55 +08:00
std::optional<intptr_t> pointer::operator-( const pointer& o ) const
2020-05-25 07:40:23 +02:00
{
int64_t delta = xvalues[ 0 ] - o.xvalues[ 0 ];
for ( size_t n = 1; n < xvalues.size(); n++ )
if ( ( xvalues[ n ] - o.xvalues[ n ] ) != delta )
2020-05-25 07:40:23 +02:00
return std::nullopt;
return ( base - o.base ).get<true>();
2020-05-25 07:40:23 +02:00
}
// Checks whether the two pointers can overlap in terms of real destination,
// note that it will consider [rsp+C1] and [rsp+C2] "overlapping" so you will
// need to check the displacement with the variable sizes considered if you
// are checking "is overlapping" instead.
//
bool pointer::can_overlap( const pointer& o ) const
{
2020-07-24 05:49:29 +02:00
return ( ( flags & o.flags ) == flags ) ||
2020-06-21 00:04:33 +02:00
( ( flags & o.flags ) == o.flags );
}
// Same as can_overlap but will return false if flags do not overlap.
//
bool pointer::can_overlap_s( const pointer& o ) const
{
2020-07-24 05:49:29 +02:00
return ( ( flags & o.flags ) == flags ) &&
( ( flags & o.flags ) == o.flags );
}
2020-05-25 07:40:23 +02:00
};