mirror of
https://github.com/vtil-project/VTIL-Core
synced 2026-08-17 08:23:03 -04:00
merged & added tests for bblock_thunk_removal_pass
This commit is contained in:
commit
32ee99ee8d
15 changed files with 219 additions and 32 deletions
|
|
@ -4,10 +4,16 @@ cmake_minimum_required(VERSION 3.14.5)
|
|||
# Define the VTIL project
|
||||
project(VTIL-Core)
|
||||
|
||||
option(VTIL_BUILD_TESTS "Build tests" OFF)
|
||||
# Detect if VTIL-Core is compiled as the root project
|
||||
set(VTIL_ROOT_PROJECT OFF)
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(VTIL_ROOT_PROJECT ON)
|
||||
|
||||
# Enable solution folder support
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
# Enable solution folder support
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
|
||||
option(VTIL_BUILD_TESTS "Build tests" ${VTIL_ROOT_PROJECT})
|
||||
|
||||
# Load the dependencies
|
||||
set(CMAKE_FOLDER "VTIL-Core/Dependencies")
|
||||
|
|
|
|||
15
README.md
15
README.md
|
|
@ -40,3 +40,18 @@ This repository contains the core components of the VTIL Project used across the
|
|||
It is currently incomplete as the initial release is not done yet, and documentation and FAQ will be within this repository and the organization website once they're done.
|
||||
|
||||
Until the initial release, you can keep up to date with the VTIL project by checking my [personal twitter account](https://twitter.com/_can1357) or the VTIL website [vtil.org](https://vtil.org/).
|
||||
|
||||
## Building (Windows)
|
||||
|
||||
```
|
||||
cmake -B build
|
||||
```
|
||||
|
||||
Then open `build\VTIL-Core.sln`. You can also open this folder in a CMake-compatible IDE (Visual Studio, CLion, Qt Creator, VS Code).
|
||||
|
||||
## Building (Linux/Mac)
|
||||
|
||||
```
|
||||
cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL-Architecture)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.cpp *.hpp)
|
||||
file(GLOB_RECURSE INCLUDES CONFIGURE_DEPENDS includes/*)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ namespace vtil
|
|||
{
|
||||
intptr_t ival;
|
||||
uintptr_t uval;
|
||||
#if _M_X64 || __x86_64__
|
||||
int64_t i64;
|
||||
uint64_t u64;
|
||||
#endif
|
||||
};
|
||||
|
||||
// Number of bits it is expressed in.
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ namespace vtil
|
|||
{ register_physical, X86_REG_EBP, 32 },
|
||||
|
||||
/*.shadow_space =*/
|
||||
0x20,
|
||||
0x0,
|
||||
|
||||
/*.purge_stack =*/
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -380,27 +380,24 @@ namespace vtil::symbolic
|
|||
|
||||
// If vmexit, declared trashed if below or at the shadow space:
|
||||
//
|
||||
if ( cwrite )
|
||||
if ( cwrite && cc.purge_stack)
|
||||
{
|
||||
if ( it->base == &ins::vexit ? it.block->owner->routine_convention.purge_stack : cc.purge_stack )
|
||||
{
|
||||
// Determine the limit of the stack memory owned by this routine.
|
||||
//
|
||||
expression limit =
|
||||
tracer->trace( { it, REG_SP } ) +
|
||||
it.block->sp_offset +
|
||||
cc.shadow_space;
|
||||
// Determine the limit of the stack memory owned by this routine.
|
||||
//
|
||||
expression limit =
|
||||
tracer->trace( { it, REG_SP } ) +
|
||||
it.block->sp_offset +
|
||||
( it->base == &ins::vexit ? 0 : cc.shadow_space );
|
||||
|
||||
// Calculate the displacement, if constant below 0, declare trashed.
|
||||
//
|
||||
access_details details;
|
||||
fill_displacement( &details, mem.base, pointer{ std::move( limit ) }, tracer, xblock );
|
||||
if ( !details.is_unknown() && ( details.bit_offset + var.bit_count() ) <= 0 )
|
||||
{
|
||||
result += { .bit_offset = 0, .bit_count = var.bit_count(), .read = false, .write = true };
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Calculate the displacement, if constant below 0, declare trashed.
|
||||
//
|
||||
access_details details;
|
||||
fill_displacement( &details, mem.base, pointer{ std::move( limit ) }, tracer, xblock );
|
||||
if ( !details.is_unknown() && ( details.bit_offset + var.bit_count() ) <= 0 )
|
||||
{
|
||||
result += { .bit_offset = 0, .bit_count = var.bit_count(), .read = false, .write = true };
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Report unknown access: (TODO: Proper parsing!)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL-Common)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.cpp *.hpp)
|
||||
file(GLOB_RECURSE INCLUDES CONFIGURE_DEPENDS includes/*)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL-Compiler)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.cpp *.hpp)
|
||||
file(GLOB_RECURSE INCLUDES CONFIGURE_DEPENDS includes/*)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL-SymEx)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.cpp *.hpp)
|
||||
file(GLOB_RECURSE INCLUDES CONFIGURE_DEPENDS includes/*)
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace vtil::symbolic
|
|||
// Log the translation.
|
||||
//
|
||||
log<CON_BLU>( "Translating [%s] => [%s]:\n", *from, *to );
|
||||
from->enum_variables( [ & ] ( const instance& ins )
|
||||
from->enum_variables( [ & ] ( const directive::instance& ins )
|
||||
{
|
||||
log<CON_BLU>( " %s: %s\n", ins.id, *match.translate( ins ) );
|
||||
} );
|
||||
|
|
|
|||
|
|
@ -546,6 +546,19 @@ namespace vtil::symbolic
|
|||
rhs.resize( value.size(), false );
|
||||
break;
|
||||
}
|
||||
case math::operator_id::shift_left:
|
||||
case math::operator_id::shift_right:
|
||||
{
|
||||
rhs.resize( sizeof(uintptr_t), false );
|
||||
break;
|
||||
}
|
||||
|
||||
case math::operator_id::rotate_left:
|
||||
case math::operator_id::rotate_right:
|
||||
{
|
||||
rhs.resize( sizeof(uintptr_t), false );
|
||||
break;
|
||||
}
|
||||
case math::operator_id::multiply_high:
|
||||
case math::operator_id::multiply:
|
||||
case math::operator_id::divide:
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ namespace vtil::symbolic
|
|||
// Log the input.
|
||||
//
|
||||
scope_padding _p( 1 );
|
||||
if ( !state::get()->padding ) log( "\n" );
|
||||
log( "\n" );
|
||||
log( "[Input] = %s ", *exp );
|
||||
log( "(Hash: %s)\n", exp->hash() );
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL-Tests)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS *.cpp *.hpp *.h)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,69 @@ DOCTEST_TEST_CASE("dummy")
|
|||
CHECK(1 == 1);
|
||||
}
|
||||
|
||||
DOCTEST_TEST_CASE("Expression hash")
|
||||
{
|
||||
vtil::logger::log("\n\n>> %s \n", __FUNCTION__);
|
||||
auto const_a = vtil::symbolic::expression{ 123 };
|
||||
auto const_b = (vtil::symbolic::expression{ 123 } + 1 - 1).simplify( true );
|
||||
CHECK( const_a.hash() == const_b.hash() );
|
||||
|
||||
auto block = vtil::basic_block::begin( 0x1234 );
|
||||
block->push( 0 );
|
||||
auto variable_a = vtil::symbolic::variable{ block->begin(), vtil::REG_FLAGS };
|
||||
auto variable_b = vtil::symbolic::variable{ block->begin(), vtil::REG_FLAGS };
|
||||
// vtil::logger::log( "variable_a: %s \n", variable_a.to_string().c_str() );
|
||||
CHECK( variable_a.hash() == variable_b.hash() );
|
||||
|
||||
|
||||
// simple shift_right
|
||||
{
|
||||
auto exp_a = vtil::symbolic::expression{ (uint32_t)123 } >> (uint8_t)6;
|
||||
auto exp_b = vtil::symbolic::expression{ (uint32_t)123 } >> (uint32_t)6;
|
||||
|
||||
exp_a = exp_a.simplify( true );
|
||||
exp_b = exp_b.simplify( true );
|
||||
|
||||
vtil::logger::log("exp_a: %s \n", exp_a.to_string().c_str());
|
||||
vtil::logger::log("exp_b: %s \n", exp_b.to_string().c_str());
|
||||
CHECK(exp_a.hash() == exp_b.hash());
|
||||
}
|
||||
|
||||
// Simple const shift_right
|
||||
{
|
||||
auto exp_a = variable_a.to_expression() >> (uint8_t)6;
|
||||
auto exp_b = variable_a.to_expression() >> (uint32_t)6;
|
||||
|
||||
exp_a = exp_a.simplify(true);
|
||||
exp_b = exp_b.simplify(true);
|
||||
|
||||
vtil::logger::log("exp_a: %s \n", exp_a.to_string().c_str());
|
||||
vtil::logger::log("exp_b: %s \n", exp_b.to_string().c_str());
|
||||
CHECK(exp_a.hash() == exp_b.hash());
|
||||
}
|
||||
|
||||
// advanced shift_right
|
||||
{
|
||||
// eax@6:1
|
||||
vtil::register_desc temp_6(vtil::register_local, 1, 1, 6);
|
||||
auto exp_a = vtil::symbolic::variable{ block->begin(), temp_6 }.to_expression();
|
||||
exp_a.resize( vtil::arch::bit_count );
|
||||
exp_a = exp_a.simplify( true );
|
||||
vtil::logger::log( "exp_a.size: %d \n", exp_a.value.size() );
|
||||
vtil::logger::log( "exp_a: %s \n", exp_a.to_string().c_str() );
|
||||
|
||||
// eax >> 6 & 1
|
||||
vtil::register_desc temp(vtil::register_local, 1, vtil::arch::bit_count, 0);
|
||||
auto exp_b = vtil::symbolic::variable{ block->begin(), temp }.to_expression();
|
||||
exp_b >>= (uint8_t)6;
|
||||
exp_b &= (uint8_t)1;
|
||||
exp_b = exp_b.simplify( true );
|
||||
vtil::logger::log( "exp_b.size: %d \n", exp_b.value.size() );
|
||||
vtil::logger::log( "exp_b: %s \n", exp_b.to_string().c_str() );
|
||||
CHECK(exp_a.hash() == exp_b.hash());
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_TEST_CASE("Optimization vtil file")
|
||||
{
|
||||
vtil::logger::log("\n\n>> %s \n", __FUNCTION__);
|
||||
|
|
@ -384,7 +447,7 @@ DOCTEST_TEST_CASE("Optimization dead_code_elimination_pass")
|
|||
|
||||
auto block3 = block1->fork( 0x3000 );
|
||||
{
|
||||
// mov ecx, [esp - 8]
|
||||
// mov eax, [esp - 8]
|
||||
block3->ldd( reg_eax, vtil::REG_SP, -8 );
|
||||
// sp -= 0x10
|
||||
block3->shift_sp( 0x10 );
|
||||
|
|
@ -490,3 +553,80 @@ DOCTEST_TEST_CASE("Simplification")
|
|||
|
||||
}
|
||||
|
||||
DOCTEST_TEST_CASE("Optimization bblock_thunk_removal_pass")
|
||||
{
|
||||
vtil::logger::log("\n\n>> %s \n", __FUNCTION__);
|
||||
|
||||
auto block1 = vtil::basic_block::begin((uintptr_t)0x1000);
|
||||
auto rtn = block1->owner;
|
||||
{
|
||||
// 0x1000: js eflags@11:1 0x2000, 0x3000
|
||||
block1->js(vtil::REG_FLAGS.select(1, 11), (uintptr_t)0x2000, (uintptr_t)0x3000);
|
||||
}
|
||||
auto block2 = block1->fork((uintptr_t)0x2000);
|
||||
{
|
||||
// 0x2000: jmp 0x4000
|
||||
block2->jmp((uintptr_t)0x4000);
|
||||
block2->fork((uintptr_t)0x4000);
|
||||
}
|
||||
auto block3 = block1->fork((uintptr_t)0x3000);
|
||||
{
|
||||
// 0x3000: jmp 0x4000
|
||||
block3->jmp((uintptr_t)0x4000);
|
||||
block3->fork((uintptr_t)0x4000);
|
||||
}
|
||||
auto block4 = rtn->get_block((uintptr_t)0x4000);
|
||||
{
|
||||
// 0x4000: jmp 0x5000
|
||||
block4->jmp((uintptr_t)0x5000);
|
||||
block4->fork((uintptr_t)0x5000);
|
||||
}
|
||||
auto block5 = rtn->get_block((uintptr_t)0x5000);
|
||||
{
|
||||
// 0x5000: vexit 0
|
||||
block5->vexit((uintptr_t)0);
|
||||
}
|
||||
vtil::logger::log("Before:\n");
|
||||
vtil::debug::dump(rtn);
|
||||
|
||||
vtil::optimizer::bblock_thunk_removal_pass{}(rtn);
|
||||
vtil::logger::log("After:\n");
|
||||
vtil::debug::dump(rtn);
|
||||
|
||||
//block1 now points to block4
|
||||
auto ins = (*block1)[0];
|
||||
CHECK(ins.base == &vtil::ins::jmp);
|
||||
CHECK(ins.operands.size() == 1);
|
||||
CHECK(ins.operands[0].is_immediate());
|
||||
CHECK(ins.operands[0].imm().ival == block4->entry_vip);
|
||||
|
||||
//block4 still points to block5
|
||||
ins = (*block4)[0];
|
||||
CHECK(ins.base == &vtil::ins::jmp);
|
||||
CHECK(ins.operands.size() == 1);
|
||||
CHECK(ins.operands[0].is_immediate());
|
||||
CHECK(ins.operands[0].imm().ival == block5->entry_vip);
|
||||
|
||||
//block5 is still vexit
|
||||
ins = (*block5)[0];
|
||||
CHECK(ins.base == &vtil::ins::vexit);
|
||||
CHECK(block5->size() == 1);
|
||||
|
||||
// Simulate another pass
|
||||
//
|
||||
vtil::optimizer::bblock_thunk_removal_pass{}(rtn);
|
||||
vtil::logger::log("After secondary:\n");
|
||||
vtil::debug::dump(rtn);
|
||||
|
||||
//block1 now points to block5
|
||||
ins = (*block1)[0];
|
||||
CHECK(ins.base == &vtil::ins::jmp);
|
||||
CHECK(ins.operands.size() == 1);
|
||||
CHECK(ins.operands[0].is_immediate());
|
||||
CHECK(ins.operands[0].imm().ival == block5->entry_vip);
|
||||
|
||||
//block5 is still vexit
|
||||
ins = (*block5)[0];
|
||||
CHECK(ins.base == &vtil::ins::vexit);
|
||||
CHECK(block5->size() == 1);
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
project(VTIL)
|
||||
# Extract project name from folder
|
||||
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
|
||||
string(REPLACE " " "_" PROJECT_NAME "${PROJECT_NAME}")
|
||||
|
||||
# This builds no sources -- it simply aliases a collection of all other targets created by VTIL
|
||||
#
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue