diff --git a/VTIL-Compiler/common/auxiliaries.cpp b/VTIL-Compiler/common/auxiliaries.cpp index 7e62e45..f8d51f8 100644 --- a/VTIL-Compiler/common/auxiliaries.cpp +++ b/VTIL-Compiler/common/auxiliaries.cpp @@ -137,7 +137,7 @@ namespace vtil::optimizer::aux symbolic::expression exp = local_var.mem().decay() - local_var.at.block->sp_offset - + symbolic::variable{ it.block->begin(), REG_SP }.to_expression() + + rel_ptr( symbolic::variable{ it.block->begin(), REG_SP } ) - symbolic::variable{ local_var.at.block->begin(), REG_SP }.to_expression(); local_var = symbolic::variable{ it.block->begin(), { symbolic::pointer{ exp }, local_var.mem().bit_count } }; } diff --git a/VTIL-Tests/dummy.cpp b/VTIL-Tests/dummy.cpp index 31e903d..d45ede5 100644 --- a/VTIL-Tests/dummy.cpp +++ b/VTIL-Tests/dummy.cpp @@ -8,9 +8,13 @@ namespace registers #if _M_X64 || __x86_64__ constexpr auto ax = X86_REG_RAX; constexpr auto bx = X86_REG_RBX; + constexpr auto cx = X86_REG_RCX; + constexpr auto dx = X86_REG_RDX; #elif _M_IX86 || __i386__ constexpr auto ax = X86_REG_EAX; constexpr auto bx = X86_REG_EBX; + constexpr auto cx = X86_REG_ECX; + constexpr auto dx = X86_REG_EDX; #endif } @@ -40,8 +44,9 @@ DOCTEST_TEST_CASE("Optimization stack_pinning_pass") vtil::register_desc reg_ax(vtil::register_physical, registers::ax, vtil::arch::bit_count, 0); - block->mov(reg_ax, (uintptr_t) 0); + block->mov(reg_ax, (uintptr_t)0); block->sub(vtil::REG_SP, vtil::arch::size); + block->mov(reg_ax, (uintptr_t)0); block->push(reg_ax); block->pop(reg_ax); block->mov(reg_ax, vtil::arch::size); @@ -57,7 +62,7 @@ DOCTEST_TEST_CASE("Optimization stack_pinning_pass") vtil::logger::log(":: After:\n"); vtil::debug::dump(block->owner); - CHECK(block->size() == 5); + CHECK(block->size() == 6); CHECK(block->sp_offset == 0); } @@ -275,6 +280,136 @@ DOCTEST_TEST_CASE("Optimization symbolic_rewrite_pass") } +DOCTEST_TEST_CASE("Optimization dead_code_elimination_pass") +{ + vtil::logger::log("\n\n>> %s \n", __FUNCTION__); + + // simple single block + { + auto block = vtil::basic_block::begin( 0x1337 ); + vtil::register_desc reg_eax( vtil::register_physical, registers::ax, vtil::arch::bit_count, 0 ); + vtil::register_desc reg_ebx( vtil::register_physical, registers::bx, vtil::arch::bit_count, 0 ); + + // push eax + block->push( reg_eax ); + // push ebx + block->push( reg_ebx ); + + // sp -= 0x10 + block->shift_sp( 0x10 ); + // mov eax, 0 + block->mov( reg_eax, (uintptr_t)0 ); + // vexit 0 + block->vexit( 0ull ); // marks the end of a basic_block + + vtil::logger::log( ":: Before:\n" ); + vtil::debug::dump( block->owner ); + + vtil::optimizer::dead_code_elimination_pass{}( block->owner ); + + vtil::logger::log( ":: After:\n" ); + vtil::debug::dump( block->owner ); + + // mov eax, 0 + // vexit 0 + CHECK( block->size() == 2 ); + } + + // with jmp + { + auto block1 = vtil::basic_block::begin( 0x1337 ); + + vtil::register_desc reg_eax( vtil::register_physical, registers::ax, vtil::arch::bit_count, 0 ); + vtil::register_desc reg_ebx( vtil::register_physical, registers::bx, vtil::arch::bit_count, 0 ); + + { + // push eax + block1->push( reg_eax ); + // push ebx + block1->push( reg_ebx ); + // jmp 0x2000 + block1->jmp( (uintptr_t) 0x2000 ); + } + + auto block2 = block1->fork( 0x2000 ); + { + // sp -= 0x10 + block2->shift_sp( 0x10 ); + // mov eax, 0 + block2->mov( reg_eax, (uintptr_t)0 ); + // vexit 0 + block2->vexit( 0ull ); // marks the end + } + + vtil::logger::log( ":: Before:\n" ); + vtil::debug::dump( block1->owner ); + + vtil::optimizer::dead_code_elimination_pass{}( block1->owner ); + + vtil::logger::log( ":: After:\n" ); + vtil::debug::dump( block1->owner ); + + // jmp 0x2000 + CHECK( block1->size() == 1 ); + } + + // with te jmp + { + auto block1 = vtil::basic_block::begin( 0x1337 ); + + vtil::register_desc reg_eax( vtil::register_physical, registers::ax, vtil::arch::bit_count, 0 ); + vtil::register_desc reg_ebx( vtil::register_physical, registers::bx, vtil::arch::bit_count, 0 ); + vtil::register_desc reg_ecx( vtil::register_physical, registers::cx, vtil::arch::bit_count, 0 ); + + { + // push eax + block1->push( reg_eax ); + // push ebx + block1->push( reg_ebx ); + // ecx = ecx == 0xAABB + block1->te( reg_ecx, reg_ecx, (uintptr_t)0xAABB ); + // js ecx ? 0x2000, 0x3000 + block1->js( reg_ecx, (uintptr_t)0x2000, (uintptr_t)0x3000 ); + } + + auto block2 = block1->fork( 0x2000 ); + { + // sp -= 0x10 + block2->shift_sp( 0x10 ); + // mov eax, 0 + block2->add( reg_eax, (uintptr_t)1 ); // need this to contains [shift_sp] + // vexit 0 + block2->vexit( 0ull ); // marks the end + } + + auto block3 = block1->fork( 0x3000 ); + { + // mov ecx, [esp - 8] + block3->ldd( reg_eax, vtil::REG_SP, -8 ); + // sp -= 0x10 + block3->shift_sp( 0x10 ); + // add eax, 1 + block3->add( reg_eax, (uintptr_t)1 ); // need this to contains [shift_sp] + // vexit 0 + block3->vexit( 0ull ); // marks the end + } + + + vtil::logger::log( ":: Before:\n" ); + vtil::debug::dump( block1->owner ); + + vtil::optimizer::dead_code_elimination_pass{}( block1->owner ); + + vtil::logger::log( ":: After:\n" ); + vtil::debug::dump( block1->owner ); + + // Cant optimize the block1 (strq) because we use it in block3 + CHECK( block1->size() == 4 ); + } + + +} + DOCTEST_TEST_CASE("Simplification") { vtil::logger::log("\n\n>> %s \n", __FUNCTION__);