├── .gitattributes ├── .gitignore ├── BDASM.sln ├── BDASM ├── BDASM.vcxproj ├── BDASM.vcxproj.filters ├── BDASM.vcxproj.user ├── addr_width.h ├── align.h ├── backtrace.h ├── common_code.h ├── condition_code.h ├── constant_encryption.h ├── dasm.h ├── dasm2.h ├── dpattern.h ├── emu.h ├── encoder.h ├── encrypted_blocks.h ├── encrypted_routines.h ├── flags.h ├── flat_control.h ├── inst.h ├── ir.h ├── linker.h ├── main.cpp ├── mba.h ├── obf.h ├── opaques.h ├── original.h ├── other_vm.h ├── pex.h ├── pi_blocks.h ├── rvas.txt ├── sff.h ├── size_casting.h ├── stack_allocation.h ├── substitution.h ├── symbol.h ├── traits.h ├── virtual_operands.h └── x64 │ ├── Debug │ ├── BDASM.ilk │ └── vc143.idb │ └── Release │ └── BDASM.vcxproj.FileListAbsolute.txt ├── README.md ├── TestExe ├── TestExe.vcxproj ├── TestExe.vcxproj.filters ├── TestExe.vcxproj.user ├── main.cpp └── x64 │ └── Release │ └── TestExe.vcxproj.FileListAbsolute.txt └── sdk.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipch 33 | *.tlog 34 | *.ipdb 35 | *.db 36 | *.db-shm 37 | *.db-wal 38 | *.opendb 39 | *.log 40 | *.recipe 41 | *.iobj 42 | *.pdb 43 | *.vsidx 44 | *.id0 45 | *.id1 46 | *.id2 47 | x64/Release/TestExe.exe.nam 48 | x64/Release/TestExe.exe.til 49 | *.idb 50 | *.ilk 51 | *.nam 52 | 53 | .vs/ 54 | x64/ 55 | build/ 56 | -------------------------------------------------------------------------------- /BDASM.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32210.238 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BDASM", "BDASM\BDASM.vcxproj", "{69339CAA-45EE-4CA5-A688-B37653825BE8}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {4006C556-E4CF-4562-8D04-1F3ABB594571} = {4006C556-E4CF-4562-8D04-1F3ABB594571} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestExe", "TestExe\TestExe.vcxproj", "{4006C556-E4CF-4562-8D04-1F3ABB594571}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|x64 = Release|x64 18 | Release|x86 = Release|x86 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Debug|x64.ActiveCfg = Debug|x64 22 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Debug|x64.Build.0 = Debug|x64 23 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Debug|x86.ActiveCfg = Debug|Win32 24 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Debug|x86.Build.0 = Debug|Win32 25 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Release|x64.ActiveCfg = Release|x64 26 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Release|x64.Build.0 = Release|x64 27 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Release|x86.ActiveCfg = Release|Win32 28 | {69339CAA-45EE-4CA5-A688-B37653825BE8}.Release|x86.Build.0 = Release|Win32 29 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Debug|x64.ActiveCfg = Debug|x64 30 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Debug|x64.Build.0 = Debug|x64 31 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Debug|x86.ActiveCfg = Debug|Win32 32 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Debug|x86.Build.0 = Debug|Win32 33 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Release|x64.ActiveCfg = Release|x64 34 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Release|x64.Build.0 = Release|x64 35 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Release|x86.ActiveCfg = Release|Win32 36 | {4006C556-E4CF-4562-8D04-1F3ABB594571}.Release|x86.Build.0 = Release|Win32 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {9BE56D46-FA20-4666-A005-A27213D17D26} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /BDASM/BDASM.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {69339caa-45ee-4ca5-a688-b37653825be8} 25 | BDASM 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | true 81 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)build\obj\wkit\include 82 | 83 | 84 | false 85 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(SolutionDir)build\obj\wkit\include 86 | 87 | 88 | 89 | Level3 90 | true 91 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | 98 | 99 | 100 | 101 | Level3 102 | true 103 | true 104 | true 105 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | 108 | 109 | Console 110 | true 111 | true 112 | true 113 | 114 | 115 | 116 | 117 | Level3 118 | true 119 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 120 | true 121 | $(SolutionDir);%(AdditionalIncludeDirectories) 122 | stdcpp20 123 | 124 | 125 | Console 126 | true 127 | xed.lib;%(AdditionalDependencies) 128 | $(SolutionDir)build\obj\wkit\lib 129 | 130 | 131 | 132 | 133 | Level3 134 | true 135 | true 136 | true 137 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 138 | true 139 | $(SolutionDir);%(AdditionalIncludeDirectories) 140 | stdcpp20 141 | 142 | 143 | Console 144 | true 145 | true 146 | true 147 | xed.lib;%(AdditionalDependencies) 148 | $(SolutionDir)build\obj\wkit\lib 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 195 | 196 | 197 | -------------------------------------------------------------------------------- /BDASM/BDASM.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Testing 6 | 7 | 8 | headers\dasm 9 | 10 | 11 | headers\dasm 12 | 13 | 14 | headers\dasm 15 | 16 | 17 | headers\xed 18 | 19 | 20 | headers 21 | 22 | 23 | headers\utils 24 | 25 | 26 | headers 27 | 28 | 29 | headers\dasm 30 | 31 | 32 | headers\dasm 33 | 34 | 35 | headers\utils 36 | 37 | 38 | headers\utils 39 | 40 | 41 | headers\utils 42 | 43 | 44 | headers\dasm 45 | 46 | 47 | headers\obfuscator 48 | 49 | 50 | headers\obfuscator 51 | 52 | 53 | headers\obfuscator\passes\mutation 54 | 55 | 56 | headers\obfuscator\passes\mutation 57 | 58 | 59 | headers\obfuscator\passes\mutation 60 | 61 | 62 | headers\obfuscator\passes\mutation 63 | 64 | 65 | headers\obfuscator\passes\mutation 66 | 67 | 68 | headers\obfuscator\passes\mutation 69 | 70 | 71 | headers\obfuscator\passes\mutation 72 | 73 | 74 | headers\dasm 75 | 76 | 77 | headers\obfuscator\virtualizer\ir 78 | 79 | 80 | headers\obfuscator\passes\mutation 81 | 82 | 83 | headers\xed 84 | 85 | 86 | headers\obfuscator\passes\utility 87 | 88 | 89 | headers\utils 90 | 91 | 92 | headers\obfuscator\passes\mutation 93 | 94 | 95 | headers\obfuscator\passes\mutation 96 | 97 | 98 | headers\obfuscator\passes\mutation 99 | 100 | 101 | 102 | 103 | {210126f2-8894-4b8d-b89c-13ad10de0906} 104 | 105 | 106 | {2022b579-6edd-4d14-817d-d13fda4315b0} 107 | 108 | 109 | {e838d32b-d295-409f-ada1-ff952beed48a} 110 | 111 | 112 | {f08220bb-65a3-4763-82ea-b6ab6662ed8f} 113 | 114 | 115 | {0136dbc2-1a9e-4fed-b3eb-8333ba453967} 116 | 117 | 118 | {7bff6ba0-bb46-4961-81b0-3fc14ffc27cf} 119 | 120 | 121 | {16f57466-8880-4c24-918d-0ea63aa306b9} 122 | 123 | 124 | {98d91127-8483-46b5-beca-2eb974560df8} 125 | 126 | 127 | {8b341389-a348-4f53-a425-4812e390a8b8} 128 | 129 | 130 | {c1e8db83-bfed-4591-8c7e-cba64dbe7148} 131 | 132 | 133 | {9e4fd3df-da25-41a0-81cd-560754733ebf} 134 | 135 | 136 | {e616c714-937e-4ff4-8164-b1cb15628f08} 137 | 138 | 139 | 140 | 141 | Testing 142 | 143 | 144 | 145 | 146 | headers\obfuscator\passes\utility 147 | 148 | 149 | -------------------------------------------------------------------------------- /BDASM/BDASM.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WindowsLocalDebugger 5 | 6 | -------------------------------------------------------------------------------- /BDASM/addr_width.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern "C" 6 | { 7 | #include 8 | } 9 | 10 | namespace addr_width 11 | { 12 | enum class type : uint32_t 13 | { 14 | __x86 = 0, 15 | __x64 = 1, 16 | __invalid, 17 | }; 18 | 19 | constexpr type x86 = type::__x86; 20 | constexpr type x64 = type::__x64; 21 | constexpr type invalid = type::__invalid; 22 | 23 | template struct bits; 24 | template<> struct bits { constexpr static uint32_t value = 32; }; 25 | template<> struct bits { constexpr static uint32_t value = 64; }; 26 | 27 | template struct bytes; 28 | template<> struct bytes { constexpr static uint32_t value = 4; }; 29 | template<> struct bytes { constexpr static uint32_t value = 8; }; 30 | 31 | template struct storage; 32 | template<> struct storage { using type = uint32_t; }; 33 | template<> struct storage { using type = uint64_t; }; 34 | 35 | template struct register_count; 36 | template<> struct register_count { constexpr static uint32_t value = 8; }; 37 | template<> struct register_count { constexpr static uint32_t value = 16; }; 38 | 39 | template struct machine_state; 40 | template<> struct machine_state 41 | { 42 | constexpr static xed_state_t value = { XED_MACHINE_MODE_LONG_COMPAT_32, XED_ADDRESS_WIDTH_32b }; 43 | }; 44 | template<> struct machine_state 45 | { 46 | constexpr static xed_state_t value = { XED_MACHINE_MODE_LONG_64, XED_ADDRESS_WIDTH_64b }; 47 | }; 48 | 49 | template struct fastcall_regs; 50 | template<> struct fastcall_regs 51 | { 52 | constexpr static xed_reg_enum_t regs[] = { XED_REG_EDX, XED_REG_ECX }; 53 | }; 54 | template<> struct fastcall_regs 55 | { 56 | constexpr static xed_reg_enum_t regs[] = { XED_REG_R9, XED_REG_R8, XED_REG_RDX, XED_REG_RCX }; 57 | }; 58 | 59 | //template struct gprs; 60 | //template<> struct gprs 61 | //{ 62 | // constexpr static xed_reg_enum_t regs[] = { XED_REG_EAX, XED_REG_RBX }; 63 | //}; 64 | //template<> struct gprs 65 | //{ 66 | // constexpr static xed_reg_enum_t regs[] = { XED_REG_RAX, XED_REG_RBX }; 67 | //}; 68 | 69 | } 70 | -------------------------------------------------------------------------------- /BDASM/align.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | 7 | 8 | template 9 | inline Align_type align_up(Align_type val, uint32_t alignment) 10 | { 11 | static_assert(std::is_integral::value, "Invalid parameter passed to align_up."); 12 | const Align_type ralign = alignment - 1; 13 | return static_cast((val + ralign) & (~ralign)); 14 | } 15 | 16 | template 17 | inline Align_type align_up_ptr(Align_type val, uint32_t alignment) 18 | { 19 | static_assert(std::is_pointer::value, "Invalid parameter passed to align_up_ptr."); 20 | const uint64_t ralign = alignment - 1; 21 | return reinterpret_cast((reinterpret_cast(val) + ralign) & (~ralign)); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /BDASM/backtrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "dasm.h" 4 | 5 | 6 | 7 | // Trace backwards in the current block to see if a register equals another 8 | // This is useful when the compiler decodes to randomly do something like: 9 | // 10 | // mov rax,rsp 11 | // mov [rax+offset],val 12 | // 13 | // Or some other annoyingly weird thing. this can follow something like this: 14 | // mov rcx,rsp 15 | // mov rax,rcx 16 | // mov [rax+10h],rbx 17 | // 18 | template 19 | bool trace_for_reg_alias(dasm::block_t& block, dasm::inst_it_t start, xed_reg_enum_t reg1, xed_reg_enum_t reg2) 20 | { 21 | for (auto rev = std::make_reverse_iterator(start); rev != block.instructions.rend(); ++rev) 22 | { 23 | if (auto iform = rev->iform(); 24 | (iform == XED_IFORM_MOV_GPRv_GPRv_89 || iform == XED_IFORM_MOV_GPRv_GPRv_8B) && 25 | reg1 == xed_decoded_inst_get_reg(&rev->decoded_inst, XED_OPERAND_REG0)) 26 | { 27 | auto right_reg = xed_decoded_inst_get_reg(&rev->decoded_inst, XED_OPERAND_REG0); 28 | if (reg2 == right_reg) 29 | return true; 30 | else 31 | reg1 = right_reg; 32 | } 33 | else 34 | { 35 | auto inst = rev->inst(); 36 | auto num_operands = rev->noperands(); 37 | 38 | for (uint32_t i = 0; i < num_operands; ++i) 39 | { 40 | auto operand = xed_inst_operand(inst, i); 41 | if (xed_operand_written(operand)) 42 | { 43 | auto operand_name = xed_operand_name(operand); 44 | if (xed_operand_is_register(operand_name)) 45 | { 46 | if (reg1 == xed_decoded_inst_get_reg(&rev->decoded_inst, operand_name)) 47 | return false; 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | system("pause"); 55 | return false; 56 | } 57 | -------------------------------------------------------------------------------- /BDASM/common_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | 5 | #include "dpattern.h" 6 | // So, a lot of code is repeated in binaries. So the idea is ill put these common blocks of code that 7 | // all routines can jump to. Like vm handlers :) 8 | // 9 | // [IMPORTANT] You access these blocks by transfering control flow with a call, then its returned to you 10 | // with a ret. this however moves the stack by 8(or 4) bytes so this must be accounted for. All [rsp] 11 | // displacements must be adjusted, [rbp] does not need this however. 12 | // 13 | // The most obvious example of this can be applied in function prologues. Specifically around stack 14 | // allocations and home space storage. 15 | // 16 | 17 | struct common_stack_manip_t 18 | { 19 | // Inserts a function that does this 20 | // Assumes rax is caller saved 21 | // Ex: 22 | // push stack_adjustment ; +8 23 | // call stack_manipulator ; +8-8 24 | // 25 | // 26 | // stack_manipulator proc 27 | // xchg rax,[rsp+8h] ; swap rax and stack adjustment 28 | // xchg rbx,[rsp] 29 | // sub rsp,rax ; +stack_adjustment 30 | // mov [rsp+8h],rbx ; [rsp+8] is return address 31 | // mov rbx,[rsp+rax] ; restore the original rbx value 32 | // mov rax,[rsp+rax+8h] 33 | // add rsp,8h ; take care of the 8 bytes from pushed stack_adjustment value 34 | // ret ; pops [rsp] 35 | // stack_manipulator endp 36 | // 37 | // //xchg rbx,[rsp+rax+8] 38 | // add rsp,8h 39 | // mov [rsp],rax 40 | // 41 | template 42 | static uint32_t insert_stack_manipulator(obf::obf_t& ctx) 43 | { 44 | auto link = ctx.linker->allocate_link(); 45 | 46 | dasm::routine_t& routine = ctx.additional_routines.emplace_back(); 47 | routine.entry_link = link; 48 | 49 | auto& block = routine.blocks.emplace_back(routine.blocks.end()); 50 | block.termination_type = dasm::termination_type_t::returns; 51 | block.link = link; 52 | 53 | routine.entry_block = routine.blocks.begin(); 54 | 55 | auto& insts = block.instructions; 56 | 57 | 58 | 59 | } 60 | 61 | template 62 | static obf::pass_status_t pass(obf::obf_t& ctx) 63 | { 64 | 65 | } 66 | }; 67 | 68 | struct common_prologue_t 69 | { 70 | 71 | template 72 | static obf::pass_status_t pass(obf::obf_t& ctx) 73 | { 74 | 75 | } 76 | }; 77 | 78 | struct common_epilogue_t 79 | { 80 | template 81 | static obf::pass_status_t pass(obf::obf_t& ctx) 82 | { 83 | 84 | } 85 | }; 86 | 87 | struct common_code_t 88 | { 89 | template 90 | static obf::pass_status_t pass(obf::obf_t& ctx) 91 | { 92 | 93 | } 94 | }; 95 | 96 | -------------------------------------------------------------------------------- /BDASM/condition_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | extern "C" 5 | { 6 | #include 7 | } 8 | 9 | #include 10 | 11 | enum xed_condition_code_t : uint8_t 12 | { 13 | XED_CC_B, 14 | XED_CC_BE, 15 | XED_CC_L, 16 | XED_CC_LE, 17 | XED_CC_NB, 18 | XED_CC_NBE, 19 | XED_CC_NL, 20 | XED_CC_NLE, 21 | XED_CC_NO, 22 | XED_CC_NP, 23 | XED_CC_NS, 24 | XED_CC_NZ, 25 | XED_CC_O, 26 | XED_CC_P, 27 | XED_CC_S, 28 | XED_CC_Z, 29 | XED_CC_COMPAT_END, //Everything before this has jcc and cmovcc versions 30 | XED_CC_CXZ, 31 | XED_CC_ECXZ, 32 | XED_CC_RCXZ, 33 | XED_CC_INVALID, 34 | }; 35 | 36 | xed_condition_code_t __cc_inversion_map[] = { 37 | XED_CC_NB, 38 | XED_CC_NBE, 39 | XED_CC_NL, 40 | XED_CC_NLE, 41 | XED_CC_B, 42 | XED_CC_BE, 43 | XED_CC_L, 44 | XED_CC_LE, 45 | XED_CC_O, 46 | XED_CC_P, 47 | XED_CC_S, 48 | XED_CC_Z, 49 | XED_CC_NO, 50 | XED_CC_NP, 51 | XED_CC_NS, 52 | XED_CC_NZ, 53 | XED_CC_INVALID, 54 | XED_CC_INVALID, 55 | XED_CC_INVALID, 56 | XED_CC_INVALID, 57 | XED_CC_INVALID, 58 | }; 59 | 60 | xed_iclass_enum_t __cc_cmovcc_map[] = { 61 | XED_ICLASS_CMOVB, 62 | XED_ICLASS_CMOVBE, 63 | XED_ICLASS_CMOVL, 64 | XED_ICLASS_CMOVLE, 65 | XED_ICLASS_CMOVNB, 66 | XED_ICLASS_CMOVNBE, 67 | XED_ICLASS_CMOVNL, 68 | XED_ICLASS_CMOVNLE, 69 | XED_ICLASS_CMOVNO, 70 | XED_ICLASS_CMOVNP, 71 | XED_ICLASS_CMOVNS, 72 | XED_ICLASS_CMOVNZ, 73 | XED_ICLASS_CMOVO, 74 | XED_ICLASS_CMOVP, 75 | XED_ICLASS_CMOVS, 76 | XED_ICLASS_CMOVZ, 77 | XED_ICLASS_INVALID, 78 | XED_ICLASS_INVALID, 79 | XED_ICLASS_INVALID, 80 | XED_ICLASS_INVALID, 81 | XED_ICLASS_INVALID, 82 | }; 83 | 84 | xed_iclass_enum_t __cc_jcc_map[] = { 85 | XED_ICLASS_JB, 86 | XED_ICLASS_JBE, 87 | XED_ICLASS_JL, 88 | XED_ICLASS_JLE, 89 | XED_ICLASS_JNB, 90 | XED_ICLASS_JNBE, 91 | XED_ICLASS_JNL, 92 | XED_ICLASS_JNLE, 93 | XED_ICLASS_JNO, 94 | XED_ICLASS_JNP, 95 | XED_ICLASS_JNS, 96 | XED_ICLASS_JNZ, 97 | XED_ICLASS_JO, 98 | XED_ICLASS_JP, 99 | XED_ICLASS_JS, 100 | XED_ICLASS_JZ, 101 | XED_ICLASS_INVALID, 102 | XED_ICLASS_JCXZ, 103 | XED_ICLASS_JECXZ, 104 | XED_ICLASS_JRCXZ, 105 | XED_ICLASS_INVALID, 106 | }; 107 | 108 | bool __cc_supports_cmovcc[] = { 109 | true, 110 | true, 111 | true, 112 | true, 113 | true, 114 | true, 115 | true, 116 | true, 117 | true, 118 | true, 119 | true, 120 | true, 121 | true, 122 | true, 123 | true, 124 | true, 125 | false, 126 | false, 127 | false, 128 | false, 129 | false, 130 | }; 131 | 132 | bool __cc_supports_jcc[] = { 133 | true, 134 | true, 135 | true, 136 | true, 137 | true, 138 | true, 139 | true, 140 | true, 141 | true, 142 | true, 143 | true, 144 | true, 145 | true, 146 | true, 147 | true, 148 | true, 149 | false, 150 | true, 151 | true, 152 | true, 153 | false, 154 | }; 155 | 156 | constexpr bool xed_condition_code_supports_cmovcc(xed_condition_code_t cc) 157 | { 158 | return __cc_supports_cmovcc[cc]; 159 | } 160 | 161 | constexpr bool xed_condition_code_supports_jcc(xed_condition_code_t cc) 162 | { 163 | return __cc_supports_jcc[cc]; 164 | } 165 | 166 | constexpr xed_condition_code_t xed_invert_condition_code(xed_condition_code_t cc) 167 | { 168 | return __cc_inversion_map[cc]; 169 | } 170 | 171 | constexpr bool xed_condition_code_is_convertible(xed_condition_code_t cc) 172 | { 173 | return (xed_condition_code_supports_cmovcc(cc) && xed_condition_code_supports_jcc(cc)); 174 | } 175 | 176 | constexpr xed_iclass_enum_t xed_condition_code_to_cmovcc(xed_condition_code_t cc) 177 | { 178 | return __cc_cmovcc_map[cc]; 179 | } 180 | 181 | constexpr xed_iclass_enum_t xed_condition_code_to_jcc(xed_condition_code_t cc) 182 | { 183 | return __cc_jcc_map[cc]; 184 | } 185 | 186 | constexpr xed_condition_code_t xed_iclass_to_condition_code(xed_iclass_enum_t iclass) 187 | { 188 | switch (iclass) 189 | { 190 | case XED_ICLASS_JB: [[fallthrough]]; case XED_ICLASS_CMOVB: return XED_CC_B; 191 | case XED_ICLASS_JBE: [[fallthrough]]; case XED_ICLASS_CMOVBE: return XED_CC_BE; 192 | case XED_ICLASS_JL: [[fallthrough]]; case XED_ICLASS_CMOVL: return XED_CC_L; 193 | case XED_ICLASS_JLE: [[fallthrough]]; case XED_ICLASS_CMOVLE: return XED_CC_LE; 194 | case XED_ICLASS_JNB: [[fallthrough]]; case XED_ICLASS_CMOVNB: return XED_CC_NB; 195 | case XED_ICLASS_JNBE: [[fallthrough]]; case XED_ICLASS_CMOVNBE: return XED_CC_NBE; 196 | case XED_ICLASS_JNL: [[fallthrough]]; case XED_ICLASS_CMOVNL: return XED_CC_NL; 197 | case XED_ICLASS_JNLE: [[fallthrough]]; case XED_ICLASS_CMOVNLE: return XED_CC_NLE; 198 | case XED_ICLASS_JNO: [[fallthrough]]; case XED_ICLASS_CMOVNO: return XED_CC_NO; 199 | case XED_ICLASS_JNP: [[fallthrough]]; case XED_ICLASS_CMOVNP: return XED_CC_NP; 200 | case XED_ICLASS_JNS: [[fallthrough]]; case XED_ICLASS_CMOVNS: return XED_CC_NS; 201 | case XED_ICLASS_JNZ: [[fallthrough]]; case XED_ICLASS_CMOVNZ: return XED_CC_NZ; 202 | case XED_ICLASS_JO: [[fallthrough]]; case XED_ICLASS_CMOVO: return XED_CC_O; 203 | case XED_ICLASS_JP: [[fallthrough]]; case XED_ICLASS_CMOVP: return XED_CC_P; 204 | case XED_ICLASS_JS: [[fallthrough]]; case XED_ICLASS_CMOVS: return XED_CC_S; 205 | case XED_ICLASS_JZ: [[fallthrough]]; case XED_ICLASS_CMOVZ: return XED_CC_Z; 206 | case XED_ICLASS_JCXZ: return XED_CC_CXZ; 207 | case XED_ICLASS_JECXZ: return XED_CC_ECXZ; 208 | case XED_ICLASS_JRCXZ: return XED_CC_RCXZ; 209 | default: return XED_CC_INVALID; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /BDASM/constant_encryption.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | #include "flags.h" 5 | #include "size_casting.h" 6 | 7 | struct constant_encryption_t 8 | { 9 | template 10 | static uint32_t encrypted_const_custom_encoder(dasm::inst_t* inst, pex::binary_t* bin, dasm::linker_t* linker, uint8_t* dest, uint32_t xor_key) 11 | { 12 | uint32_t expected_length = inst->length(); 13 | 14 | inst->resolve_deltas(bin, linker, dest, expected_length); 15 | 16 | auto imm = xed_decoded_inst_get_unsigned_immediate(&inst->decoded_inst); 17 | //printf("Custom encoder called %X %X %X\n", imm, inst->used_link, inst->flags); 18 | imm ^= xor_key; 19 | xed_decoded_inst_set_immediate_unsigned_bits(&inst->decoded_inst, imm, xed_decoded_inst_get_immediate_width_bits(&inst->decoded_inst)); 20 | 21 | uint32_t ilen = 0; 22 | xed_error_enum_t err = xed_encode(&inst->decoded_inst, dest, XED_MAX_INSTRUCTION_BYTES, &ilen); 23 | if (XED_ERROR_NONE != err) 24 | return 0; 25 | 26 | if (ilen != expected_length) 27 | { 28 | printf("Encoded inst length did not match what was expected.\n"); 29 | return 0; 30 | } 31 | 32 | return ilen; 33 | } 34 | 35 | template 36 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 37 | { 38 | for (auto block_it = routine.blocks.begin(); block_it != routine.blocks.end(); ++block_it) 39 | { 40 | for (auto inst_it = block_it->instructions.begin(); inst_it != block_it->instructions.end();) 41 | { 42 | auto next = std::next(inst_it); 43 | 44 | switch (inst_it->iform()) 45 | { 46 | case XED_IFORM_MOV_GPRv_IMMv: 47 | case XED_IFORM_MOV_GPRv_IMMz: 48 | case XED_IFORM_MOV_GPR8_IMMb_B0: 49 | { 50 | auto imm_width = xed_decoded_inst_get_immediate_width_bits(&inst_it->decoded_inst); 51 | if (imm_width > 32 || xed_decoded_inst_get_immediate_is_signed(&inst_it->decoded_inst) || inst_it->custom_encoder) 52 | break; 53 | 54 | xed_flag_set_t ledger; 55 | ledger.s.of = 1; 56 | ledger.s.cf = 1; 57 | ledger.s.sf = 1; 58 | ledger.s.zf = 1; 59 | ledger.s.pf = 1; 60 | ledger.s.af = 1; 61 | bool need_to_save = dasm::flags_clobbered_before_use(routine, block_it, next, ledger); 62 | 63 | 64 | //printf("Found mov gpr,imm to obfuscate.\n"); 65 | auto reg = xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0); 66 | auto max_reg = change_reg_width(reg, addr_width::reg_width::value); 67 | uint64_t imm_value = xed_decoded_inst_get_unsigned_immediate(&inst_it->decoded_inst); 68 | //printf("Imm value %llu %X\n", imm_value, inst_it->original_rva); 69 | uint32_t xor_key = (((static_cast(rand()) << 16) | 70 | (static_cast(rand()) << 0)) & 0xFFFFFFFF); 71 | 72 | switch (imm_width) 73 | { 74 | case 8: xor_key &= 0xFF; break; 75 | case 16: xor_key &= 0xFFFF; break; 76 | } 77 | 78 | dasm::inst_list_t enc; 79 | enc.emplace_back( 80 | XED_ICLASS_PUSH, 81 | addr_width::bits::value, 82 | xed_imm0(imm_value, imm_width) 83 | ).common_edit(ctx.linker->allocate_link(), inst_it->used_link, inst_it->flags); 84 | enc.back().custom_encoder = std::bind(encrypted_const_custom_encoder, 85 | std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, xor_key); 86 | 87 | if (!need_to_save) 88 | enc.emplace_back( 89 | XED_ICLASS_PUSHF, 90 | addr_width::bits::value 91 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 92 | 93 | enc.emplace_back( 94 | XED_ICLASS_MOV, 95 | addr_width::bits::value, 96 | xed_reg(max_reg), 97 | xed_imm0(xor_key, addr_width::bits::value) 98 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 99 | 100 | if (!need_to_save) 101 | { 102 | enc.emplace_back( 103 | XED_ICLASS_XOR, 104 | addr_width::bits::value, 105 | xed_mem_bd( 106 | max_reg_width::value, 107 | xed_disp(8, 8), 108 | addr_width::bits::value 109 | ), 110 | xed_reg(max_reg) 111 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 112 | 113 | enc.emplace_back( 114 | XED_ICLASS_POPF, 115 | addr_width::bits::value 116 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 117 | } 118 | else 119 | { 120 | enc.emplace_back( 121 | XED_ICLASS_XOR, 122 | addr_width::bits::value, 123 | xed_mem_b( 124 | max_reg_width::value, 125 | addr_width::bits::value 126 | ), 127 | xed_reg(max_reg) 128 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 129 | } 130 | 131 | enc.emplace_back( 132 | XED_ICLASS_POP, 133 | addr_width::bits::value, 134 | xed_reg(max_reg) 135 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 136 | 137 | block_it->instructions.splice(inst_it, enc); 138 | block_it->instructions.erase(inst_it); 139 | break; 140 | } 141 | case XED_IFORM_PUSH_IMMb: 142 | case XED_IFORM_PUSH_IMMz: 143 | { 144 | printf("Found a push imm to obfuscate.\n"); 145 | break; 146 | } 147 | 148 | } 149 | 150 | //auto inst = inst_it->inst(); 151 | //auto num_operands = isnt->noperands(); 152 | //for (uint32_t i = 0; i < num_operands; ++i) 153 | //{ 154 | // auto operand_name = xed_operand_name(xed_inst_operand(inst, i)); 155 | // if (operand_name == XED_OPERAND_IMM0/* || operand_name == XED_OPERAND_IMM0SIGNED*/) 156 | // { 157 | // 158 | // } 159 | //} 160 | 161 | inst_it = next; 162 | } 163 | } 164 | return obf::pass_status_t::success; 165 | } 166 | }; -------------------------------------------------------------------------------- /BDASM/dasm2.h: -------------------------------------------------------------------------------- 1 | //#pragma once 2 | // 3 | //#include "addr_width.h" 4 | //#include "inst.h" 5 | //#include "pex.h" 6 | //#include "size_casting.h" 7 | // 8 | //namespace dasm 9 | //{ 10 | // template 11 | // struct rva_descriptor_t 12 | // { 13 | // std::list>::iterator block; 14 | // 15 | // std::atomic_bool decoded; 16 | // }; 17 | // 18 | // template 19 | // struct thread_context_t 20 | // { 21 | // pex::binary_t* bin; 22 | // 23 | // const uint8_t* rva_base; 24 | // const uint64_t rva_max; 25 | // 26 | // rva_descriptor_t* lookup_table; 27 | // 28 | // std::function report_func_rva; 29 | // 30 | // thread_context_t(pex::binary_t* binary) 31 | // : rva_base(binary->mapped_image) 32 | // , rva_max(static_cast(binary->optional_header.get_size_of_image())) 33 | // , bin(binary) 34 | // { } 35 | // 36 | // bool validate_rva(uint64_t rva) 37 | // { 38 | // return rva < rva_max; 39 | // } 40 | // }; 41 | // 42 | // template 43 | // struct block_discovery_thread_t 44 | // { 45 | // thread_context_t* m_context; 46 | // 47 | // std::thread* m_thread; 48 | // 49 | // std::atomic_bool m_signal_start; 50 | // std::atomic_bool m_signal_shutdown; 51 | // 52 | // std::mutex m_queued_routines_lock; 53 | // std::vector m_queued_routines; 54 | // public: 55 | // inline static std::atomic_uint32_t queued_routine_count; 56 | // 57 | // std::vector routine_starts; 58 | // 59 | // std::list> blocks; 60 | // 61 | // explicit block_discovery_thread_t(thread_context_t* context) 62 | // : m_context(context) 63 | // , m_signal_start(false) 64 | // , m_signal_shutdown(false) 65 | // { 66 | // m_thread = new std::thread(&block_discovery_thread_t::run, this); 67 | // } 68 | // explicit block_discovery_thread_t(block_discovery_thread_t const& to_copy) = delete; 69 | // ~block_discovery_thread_t() 70 | // { 71 | // if (m_thread->joinable()) 72 | // m_thread->join(); 73 | // delete m_thread; 74 | // } 75 | // bool pop_queued_routine(uint64_t& routine_rva) 76 | // { 77 | // if (!m_signal_start) 78 | // return false; 79 | // 80 | // std::lock_guard g(m_queued_routines_lock); 81 | // if (m_queued_routines.size()) 82 | // { 83 | // routine_rva = m_queued_routines.back(); 84 | // m_queued_routines.pop_back(); 85 | // return true; 86 | // } 87 | // return false; 88 | // } 89 | // 90 | // void queue_routine(uint64_t routine_rva) 91 | // { 92 | // ++queued_routine_count; 93 | // std::lock_guard g(m_queued_routines_lock); 94 | // m_queued_routines.emplace_back(routine_rva); 95 | // } 96 | // 97 | // void start() 98 | // { 99 | // m_signal_start = true; 100 | // } 101 | // void stop() 102 | // { 103 | // m_signal_shutdown = true; 104 | // } 105 | // 106 | // void run() 107 | // { 108 | // while (!m_signal_shutdown) 109 | // { 110 | // uint64_t routine_rva = 0; 111 | // if (pop_queued_routine(routine_rva)) 112 | // { 113 | // decode(routine_rva); 114 | // --queued_routine_count; 115 | // continue; //Skip the sleep. 116 | // } 117 | // 118 | // std::this_thread::sleep_for(std::chrono::milliseconds(1)); 119 | // } 120 | // } 121 | // 122 | // void decode_block(uint64_t rva) 123 | // { 124 | // uint64_t rva_start = rva; 125 | // blocks.emplace_front(); 126 | // auto cur_block_it = blocks.begin(); 127 | // while (!m_context->lookup_table->decoded.exchange(true)) 128 | // { 129 | // 130 | // auto& inst = cur_block_it->emplace_back(); 131 | // 132 | // int32_t ilen = inst.decode(const_cast(m_context->rva_base + rva), m_context->rva_max - rva); 133 | // if (ilen == 0) 134 | // { 135 | // std::printf("Failed to decode, 0 inst length. RVA: 0x%p\n", rva); 136 | // return; 137 | // } 138 | // 139 | // if (auto iform = xed_decoded_inst_get_iform_enum(&inst.decoded_inst); 140 | // (iform == XED_IFORM_SUB_GPRv_IMMb || 141 | // iform == XED_IFORM_SUB_GPRv_IMMz) && 142 | // xed_decoded_inst_get_reg(&inst.decoded_inst, XED_OPERAND_REG0)) 143 | // m_context->report_func_rva(rva_start); 144 | // 145 | // 146 | // //std::printf("IClass: %s\n", xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(&inst.decoded_inst))); 147 | // 148 | // inst.original_rva = rva; // m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva(rva); 149 | // 150 | // bool has_reloc = m_context->bin->data_table->inst_uses_reloc(rva, ilen, inst.additional_data.reloc.offset_in_inst, inst.additional_data.reloc.type); 151 | // 152 | // // Parse operands for rip relative addressing and relocs 153 | // // 154 | // uint32_t num_operands = xed_decoded_inst_noperands(&inst.decoded_inst); 155 | // auto decoded_inst_inst = xed_decoded_inst_inst(&inst.decoded_inst); 156 | // for (uint32_t i = 0; i < num_operands; ++i) 157 | // { 158 | // auto operand_name = xed_operand_name(xed_inst_operand(decoded_inst_inst, i)); 159 | // if (XED_OPERAND_MEM0 == operand_name || XED_OPERAND_AGEN == operand_name) 160 | // { 161 | // auto base_reg = xed_decoded_inst_get_base_reg(&inst.decoded_inst, 0); 162 | // if (max_reg_width::value == base_reg) 163 | // { 164 | // inst.used_link = rva + ilen + xed_decoded_inst_get_memory_displacement(&inst.decoded_inst, 0);/* m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva( 165 | // rva + ilen + xed_decoded_inst_get_memory_displacement(&inst.decoded_inst, 0) 166 | // );*/ 167 | // inst.flags |= inst_flag::disp; 168 | // } 169 | // else if (XED_REG_INVALID == base_reg && 170 | // xed_decoded_inst_get_memory_displacement_width_bits(&inst.decoded_inst, 0) == addr_width::bits::value) 171 | // { 172 | // if (has_reloc) 173 | // { 174 | // inst.used_link = static_cast(xed_decoded_inst_get_memory_displacement(&inst.decoded_inst, 0)) - 175 | // m_decoder_context->binary_interface->optional_header.get_image_base(); 176 | // /*m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva( 177 | // static_cast(xed_decoded_inst_get_memory_displacement(&inst.decoded_inst, 0)) - 178 | // m_decoder_context->binary_interface->optional_header.get_image_base() 179 | // );*/ 180 | // inst.additional_data.reloc.original_rva = rva + inst.additional_data.reloc.offset_in_inst; 181 | // inst.flags |= inst_flag::reloc_disp; 182 | // } 183 | // } 184 | // } 185 | // else if (has_reloc && XED_OPERAND_IMM0 == operand_name && 186 | // xed_decoded_inst_get_immediate_width_bits(&inst.decoded_inst) == addr_width::bits::value) 187 | // { 188 | // inst.used_link = xed_decoded_inst_get_unsigned_immediate(&inst.decoded_inst) - 189 | // m_decoder_context->binary_interface->optional_header.get_image_base(); 190 | // /*m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva( 191 | // xed_decoded_inst_get_unsigned_immediate(&inst.decoded_inst) - 192 | // m_decoder_context->binary_interface->optional_header.get_image_base() 193 | // );*/ 194 | // inst.additional_data.reloc.original_rva = rva + inst.additional_data.reloc.offset_in_inst; 195 | // inst.flags |= inst_flag::reloc_imm; 196 | // } 197 | // } 198 | // 199 | // rva += ilen; 200 | // 201 | // // Update the end of the current block so its correct if we need to call split_block 202 | // cur_block_it->rva_end = rva; 203 | // 204 | // // Follow control flow 205 | // // 206 | // auto cat = xed_decoded_inst_get_category(&inst.decoded_inst); 207 | // if (cat == XED_CATEGORY_COND_BR) 208 | // { 209 | // int32_t br_disp = xed_decoded_inst_get_branch_displacement(&inst.decoded_inst); 210 | // uint64_t taken_rva = rva + br_disp; 211 | // 212 | // if (!m_decoder_context->validate_rva(taken_rva)) 213 | // { 214 | // std::printf("Conditional branch to invalid rva.\n"); 215 | // return current_routine->blocks.end(); 216 | // } 217 | // 218 | // inst.used_link = taken_rva; // m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva(taken_rva); 219 | // inst.flags |= inst_flag::rel_br; 220 | // 221 | // if (!m_lookup_table.is_inst_start(taken_rva)) 222 | // { 223 | // if (decode_block(taken_rva) == current_routine->blocks.end()) 224 | // return current_routine->blocks.end(); 225 | // 226 | // //if (m_decoder_context->routine_table[taken_rva] == true) 227 | // //{ 228 | // //if (found_prologue) 229 | // m_decoder_context->relbr_table[taken_rva] = true; 230 | // //} 231 | // } 232 | // else 233 | // { 234 | // if (!split_block(taken_rva)) 235 | // return current_routine->blocks.end(); 236 | // } 237 | // 238 | // auto fallthrough = decode_block(rva); 239 | // if (fallthrough == current_routine->blocks.end()) 240 | // return current_routine->blocks.end(); 241 | // 242 | // cur_block_it->fallthrough_block = fallthrough; 243 | // 244 | // goto ExitInstDecodeLoop; 245 | // } 246 | // else if (cat == XED_CATEGORY_UNCOND_BR) 247 | // { 248 | // switch (xed_decoded_inst_get_iform_enum(&inst.decoded_inst)) 249 | // { 250 | // case XED_IFORM_JMP_GPRv: 251 | // // Jump table. 252 | // // 253 | // std::printf("Unhandled inst[%08X]: XED_IFORM_JMP_GPRv.\n", rva - ilen); 254 | // return current_routine->blocks.end(); 255 | // case XED_IFORM_JMP_MEMv: 256 | // if (!inst.used_link) 257 | // { 258 | // std::printf("Unhandled inst[%08X]: XED_IFORM_JMP_MEMv.\n", rva - ilen); 259 | // return current_routine->blocks.end(); 260 | // } 261 | // goto ExitInstDecodeLoop; 262 | // case XED_IFORM_JMP_RELBRb: 263 | // case XED_IFORM_JMP_RELBRd: 264 | // case XED_IFORM_JMP_RELBRz: 265 | // { 266 | // int32_t jmp_disp = xed_decoded_inst_get_branch_displacement(&inst.decoded_inst); 267 | // uint64_t dest_rva = rva + jmp_disp; 268 | // 269 | // if (!m_decoder_context->validate_rva(dest_rva)) 270 | // { 271 | // std::printf("Unconditional branch to invalid rva.\n"); 272 | // goto ExitInstDecodeLoop; 273 | // } 274 | // inst.used_link = dest_rva; // m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva(dest_rva); 275 | // inst.flags |= inst_flag::rel_br; 276 | // 277 | // 278 | // // REWRITE ME 279 | // if (!m_lookup_table.is_inst_start(dest_rva)) 280 | // { 281 | // // Here i will try to detect odd function calls that use a jump instead. 282 | // // 283 | // if constexpr (aw == addr_width::x64) 284 | // { 285 | // if (dest_rva < e_range_start || dest_rva >= e_range_end) 286 | // { 287 | // // No func data, this is a tail call to a leaf. 288 | // // 289 | // if (!m_decoder_context->binary_interface->data_table->has_func_data(dest_rva)) 290 | // { 291 | // m_decoder_context->report_routine_rva(dest_rva); 292 | // goto ExitInstDecodeLoop; 293 | // } 294 | // else 295 | // { 296 | // // Not a leaf? lets see if the unwind info is the same 297 | // // If it is, this is just an oddly formed function 298 | // // 299 | // auto runtime_func = m_decoder_context->binary_interface->get_it( 300 | // m_decoder_context->binary_interface->data_table->get_func_data(rva).runtime_function_rva 301 | // ); 302 | // 303 | // // This relies on the fact that multiple runtime function structures for a single func will 304 | // // use the same unwind info structure, and the rvas will be the same 305 | // // 306 | // if (runtime_func.get_unwindw_info_address() != e_unwind_info) 307 | // { 308 | // m_decoder_context->report_routine_rva(dest_rva); 309 | // goto ExitInstDecodeLoop; 310 | // } 311 | // } 312 | // } 313 | // } 314 | // 315 | // if (decode_block(dest_rva) == current_routine->blocks.end()) 316 | // return current_routine->blocks.end(); 317 | // 318 | // //if (m_decoder_context->routine_table[dest_rva].load() == true) 319 | // //{ 320 | // //if (found_prologue) 321 | // m_decoder_context->relbr_table[dest_rva] = true; 322 | // //} 323 | // } 324 | // else 325 | // { 326 | // if (!split_block(dest_rva)) 327 | // return current_routine->blocks.end(); 328 | // } 329 | // 330 | // goto ExitInstDecodeLoop; 331 | // } 332 | // case XED_IFORM_JMP_FAR_MEMp2: 333 | // case XED_IFORM_JMP_FAR_PTRp_IMMw: 334 | // std::printf("Unhandled inst[%08X]: JMP_FAR_MEM/PTR.\n", rva - ilen); 335 | // return current_routine->blocks.end(); 336 | // } 337 | // } 338 | // else if (cat == XED_CATEGORY_CALL && m_decoder_context->settings.recurse_calls) 339 | // { 340 | // switch (xed_decoded_inst_get_iform_enum(&inst.decoded_inst)) 341 | // { 342 | // case XED_IFORM_CALL_NEAR_GPRv: 343 | // // Call table?! 344 | // // 345 | // std::printf("Unhandled inst[%08X]: XED_IFORM_CALL_NEAR_GPRv.\n", rva - ilen); 346 | // return current_routine->blocks.end(); 347 | // case XED_IFORM_CALL_NEAR_MEMv: 348 | // // Import or call to absolute address... 349 | // // 350 | // if (!inst.used_link) 351 | // { 352 | // std::printf("Unhandled inst[%08X]: XED_IFORM_CALL_NEAR_MEMv.\n", rva - ilen); 353 | // return current_routine->blocks.end(); 354 | // } 355 | // break; 356 | // 357 | // case XED_IFORM_CALL_NEAR_RELBRd: 358 | // case XED_IFORM_CALL_NEAR_RELBRz: 359 | // { 360 | // int32_t call_disp = xed_decoded_inst_get_branch_displacement(&inst.decoded_inst); 361 | // uint64_t dest_rva = rva + call_disp; 362 | // if (!m_decoder_context->validate_rva(dest_rva)) 363 | // { 364 | // std::printf("Call to invalid rva.\n"); 365 | // return current_routine->blocks.end(); 366 | // } 367 | // 368 | // //std::printf("Found call at 0x%X, 0x%X\n", rva - ilen, dest_rva); 369 | // 370 | // inst.used_link = dest_rva; // m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva(dest_rva); 371 | // inst.flags |= inst_flag::rel_br; 372 | // 373 | // if (!m_lookup_table.is_self(dest_rva)) 374 | // { 375 | // m_decoder_context->report_routine_rva(dest_rva); 376 | // } 377 | // break; 378 | // } 379 | // case XED_IFORM_CALL_FAR_MEMp2: 380 | // case XED_IFORM_CALL_FAR_PTRp_IMMw: 381 | // std::printf("Unhandled inst[%08X]: XED_IFORM_CALL_FAR_MEM/PTR.\n", rva - ilen); 382 | // return current_routine->blocks.end(); 383 | // } 384 | // } 385 | // else if (cat == XED_CATEGORY_RET) 386 | // { 387 | // break; 388 | // } 389 | // else if (XED_ICLASS_INT3 == xed_decoded_inst_get_iclass(&inst.decoded_inst)/* && current_block.instructions.size() > 1*/) 390 | // { 391 | // break; 392 | // } 393 | // } 394 | // 395 | // // If we make it here, we found an already decoded instruction and need to set the fallthrough 396 | // // 397 | // for (auto block_it_t = current_routine->blocks.begin(); block_it_t != current_routine->blocks.end(); ++block_it_t) 398 | // { 399 | // if (rva >= block_it_t->rva_start && rva < block_it_t->rva_end) 400 | // { 401 | // for (auto inst_it = block_it_t->instructions.begin(); inst_it != block_it_t->instructions.end(); ++inst_it) 402 | // { 403 | // if (inst_it->original_rva == rva) 404 | // { 405 | // cur_block_it->fallthrough_block = block_it_t; 406 | // } 407 | // } 408 | // } 409 | // } 410 | // 411 | // ExitInstDecodeLoop: 412 | // cur_block_it->rva_end = rva; 413 | // 414 | // return cur_block_it; 415 | // } 416 | // void decode(uint64_t rva) 417 | // { 418 | // if (!m_decoder_context->validate_rva(rva)) 419 | // { 420 | // std::printf("Attempting to decode routine at invalid rva.\n"); 421 | // return; 422 | // } 423 | // /*if (m_decoder_context->relbr_table[rva]) 424 | // { 425 | // std::printf("Skipping decode on a proposed routine start that is actually just a function chunk. %X\n", rva); 426 | // return; 427 | // }*/ 428 | // 429 | // // Since this is only available for x64... 430 | // // 431 | // if constexpr (aw == addr_width::x64) 432 | // { 433 | // if (m_decoder_context->binary_interface->data_table->unsafe_get_symbol_for_rva(rva).has_func_data()) 434 | // { 435 | // e_runtime_func.set(m_decoder_context->binary_interface->mapped_image + 436 | // m_decoder_context->binary_interface->data_table->get_func_data(rva).runtime_function_rva); 437 | // 438 | // e_range_start = e_runtime_func.get_begin_address(); 439 | // e_range_end = e_runtime_func.get_end_address(); 440 | // e_unwind_info = e_runtime_func.get_unwindw_info_address(); 441 | // } 442 | // } 443 | // 444 | // completed_routines.emplace_back(); 445 | // current_routine = &completed_routines.back(); 446 | // 447 | // if (decode_block(rva) == current_routine->blocks.end()) 448 | // { 449 | // ++invalid_routine_count; 450 | // return; 451 | // } 452 | // 453 | // current_routine->original_entry_rva = rva; 454 | // current_routine->entry_link = rva; // m_decoder_context->binary_interface->data_table->unsafe_get_symbol_index_for_rva(rva); 455 | // } 456 | // }; 457 | // 458 | // 459 | // // Step1: FIND all code and put them into dasm_blocks which are just lists of consecutively executed 460 | // // instructions. these are not basic blocks because they only end at ABSOLUTE jumps or ret. 461 | // // 462 | // // Step2: Use a list of determined function entry points to use up blocks and create functions. 463 | // // 464 | // template 465 | // class dasm2_t 466 | // { 467 | // pex::binary_t m_binary; 468 | // }; 469 | // 470 | // 471 | // 472 | //} -------------------------------------------------------------------------------- /BDASM/dpattern.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "inst.h" 7 | #include "traits.h" 8 | 9 | 10 | namespace dasm 11 | { 12 | template... Compare_list> 13 | struct static_pattern_t 14 | { 15 | // Searches a list for a pattern. 16 | // 17 | inline static const bool match(inst_list_t& list, inst_it_t start) 18 | { 19 | return ( 20 | ( 21 | (Compare_list == Accessor(&start->decoded_inst)) && 22 | (++start != list.end()) 23 | ) && 24 | ... 25 | ); 26 | } 27 | 28 | // Does not check to make sure we dont iterate past the end of the list 29 | // 30 | inline static const bool unsafe_match(inst_it_t start) 31 | { 32 | return ((Compare_list == Accessor(&(start++)->decoded_inst)) && ...); 33 | } 34 | }; 35 | 36 | template> 37 | class multi_pattern 38 | { 39 | std::vector> patterns; 40 | std::vector valid_mask; 41 | }; 42 | 43 | //template 44 | //class ipattern_t 45 | //{ 46 | //public: 47 | // std::vector pattern; 48 | // 49 | // constexpr ipattern_t(std::initializer_list pat) 50 | // { 51 | // pattern.insert(pattern.end(), pat.end(), pat.begin()); 52 | // } 53 | // constexpr ipattern_t(ipattern_t const& to_copy) 54 | // { 55 | // pattern.insert(pattern.end(), to_copy.pattern.end(), to_copy.pattern.begin()); 56 | // } 57 | 58 | // void set_to(std::initializer_list pat) 59 | // { 60 | // pattern.clear(); 61 | // pattern.insert(pattern.end(), pat.end(), pat.begin()); 62 | // } 63 | // bool match(inst_list_t& list, inst_it_t start) 64 | // { 65 | // for (uint32_t i = 0; i < pattern.size() && start != list.end(); ++i, ++start) 66 | // { 67 | // if (pattern[i] != xed_decoded_inst_get_iclass(&start->decoded_inst)) 68 | // return false; 69 | // } 70 | // return true; 71 | // } 72 | // const bool unsafe_match(inst_it_t start) 73 | // { 74 | // for (uint32_t i = 0; i < pattern.size(); ++i, ++start) 75 | // { 76 | // if (pattern[i] != xed_decoded_inst_get_iclass(&start->decoded_inst)) 77 | // return false; 78 | // } 79 | // return true; 80 | // } 81 | // bool check(inst_it_t it, uint32_t pat_idx) 82 | // { 83 | // if (pat_idx < pattern.size()) 84 | // return (pattern[pat_idx] == xed_decoded_inst_get_iclass(&it->decoded_inst)); 85 | // return false; 86 | // } 87 | //}; 88 | 89 | 90 | //// The idea will be to use this to detect prologues so I can weed out exports that 91 | //// are data vs exports that are functions 92 | //// 93 | //template 94 | //class pattern_tracker_t 95 | //{ 96 | // std::vector> m_pattern_list; 97 | // uint32_t m_index; 98 | //public: 99 | // std::vector valid_mask; 100 | 101 | // constexpr pattern_tracker_t(std::initializer_list> pattern_list) 102 | // { 103 | // m_pattern_list.insert(m_pattern_list.end(), pattern_list.begin(), pattern_list.end()); 104 | // for (uint32_t i = 0; i < m_pattern_list.size(); ++i) 105 | // valid_mask.push_back(true); 106 | // m_index = 0; 107 | // } 108 | // void reset() 109 | // { 110 | // for (uint32_t i = 0; i < m_pattern_list.size(); ++i) 111 | // valid_mask[i] = true; 112 | // m_index = 0; 113 | // } 114 | // void advance(inst_it_t it) 115 | // { 116 | // for (uint32_t i = 0; i < m_pattern_list.size(); ++i) 117 | // { 118 | // if (!m_pattern_list[i].check(it, m_index)) 119 | // valid_mask[i] = false; 120 | // } 121 | // ++m_index; 122 | // } 123 | //}; 124 | } 125 | 126 | -------------------------------------------------------------------------------- /BDASM/emu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | namespace obf 5 | { 6 | namespace emu 7 | { 8 | 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /BDASM/encoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Damn I do be pretty smart. 4 | // 5 | 6 | extern "C" 7 | { 8 | #include 9 | } 10 | 11 | #include 12 | #include 13 | // 14 | // 15 | //uint8_t* __encode_encoder_inst(xed_encoder_instruction_t* enc_inst, xed_state_t machine_state) 16 | //{ 17 | // xed_encoder_request_t encoder_request; 18 | // xed_encoder_request_zero_set_mode(&encoder_request, &machine_state); 19 | // 20 | // if (!xed_convert_to_encoder_request(&encoder_request, enc_inst)) 21 | // { 22 | // std::printf("Failed to convert encoder inst to encoder request.\n"); 23 | // return nullptr; 24 | // } 25 | // uint8_t* encode_buffer = new uint8_t[XED_MAX_INSTRUCTION_BYTES]; 26 | // uint32_t out_length = 0; 27 | // if (auto err = xed_encode(&encoder_request, encode_buffer, XED_MAX_INSTRUCTION_BYTES, &out_length); XED_ERROR_NONE != err) 28 | // { 29 | // std::printf("Failed to dumb_encode instruction with error: %s\n", xed_error_enum_t2str(err)); 30 | // delete[] encode_buffer; 31 | // return nullptr; 32 | // } 33 | // return encode_buffer; 34 | //} 35 | // 36 | //template 37 | //uint32_t encode_inst(xed_state_t machine_state, xed_iclass_enum_t iclass, xed_uint_t effective_operand_width, Operands... operands) 38 | //{ 39 | // xed_encoder_instruction_t inst; 40 | // 41 | //#define ENCODE_IF(N) \ 42 | // if constexpr (Operand_count == N) \ 43 | // xed_inst##N(&inst, machine_state, iclass, effective_operand_width, operands...) 44 | // 45 | // ENCODE_IF(0); 46 | // ENCODE_IF(1); 47 | // ENCODE_IF(2); 48 | // ENCODE_IF(3); 49 | // ENCODE_IF(4); 50 | // ENCODE_IF(5); 51 | // ENCODE_IF(6); 52 | // ENCODE_IF(7); 53 | // 54 | //#undef ENCODE_IF 55 | // 56 | // static_assert(Operant_count <= 7, "Invalid number of operands passed to encode_instruction_in_place"); 57 | // 58 | // return __encode_encoder_inst(&inst, machine_state); 59 | //} 60 | 61 | 62 | uint32_t __encode_encoder_inst_in_place(uint8_t* place, xed_encoder_instruction_t* enc_inst, xed_state_t machine_state) 63 | { 64 | xed_encoder_request_t encoder_request; 65 | xed_encoder_request_zero_set_mode(&encoder_request, &machine_state); 66 | 67 | if (!xed_convert_to_encoder_request(&encoder_request, enc_inst)) 68 | { 69 | std::printf("Failed to convert encoder inst to encoder request.\n"); 70 | return 0; 71 | } 72 | uint32_t out_length = 0; 73 | if (auto err = xed_encode(&encoder_request, place, XED_MAX_INSTRUCTION_BYTES, &out_length); XED_ERROR_NONE != err) 74 | { 75 | std::printf("Failed to encode instruction with error: %s\n", xed_error_enum_t2str(err)); 76 | return 0; 77 | } 78 | return out_length; 79 | } 80 | 81 | template 82 | uint32_t encode_inst_in_place(uint8_t* place, xed_state_t machine_state, xed_iclass_enum_t iclass, xed_uint_t effective_operand_width, Operands... operands) 83 | { 84 | xed_encoder_instruction_t inst; 85 | 86 | #define ENCODE_IF(N) \ 87 | if constexpr (Operand_count == N) \ 88 | xed_inst##N(&inst, machine_state, iclass, effective_operand_width, operands...) 89 | 90 | ENCODE_IF(0); 91 | ENCODE_IF(1); 92 | ENCODE_IF(2); 93 | ENCODE_IF(3); 94 | ENCODE_IF(4); 95 | ENCODE_IF(5); 96 | ENCODE_IF(6); 97 | ENCODE_IF(7); 98 | 99 | #undef ENCODE_IF 100 | 101 | static_assert(Operand_count <= 7, "Invalid number of operands passed to encode_instruction_in_place"); 102 | 103 | return __encode_encoder_inst_in_place(place, &inst, machine_state); 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /BDASM/encrypted_blocks.h: -------------------------------------------------------------------------------- 1 | //#pragma once 2 | // 3 | //#include 4 | // 5 | //#include "obf.h" 6 | // 7 | //// These are all the passes that play around with the original memory of the function 8 | //// 9 | // 10 | // 11 | // // So this is an interesting one, it should be done LAST if you want all instructions to be encrypted 12 | // // The way it works and maintains its thread saftey is by acquiring a spinlock before entering the function 13 | // // then releasing it on exit. The order is as follows 14 | // // 15 | // // - Wait to acquire spinlock 16 | // // - Decrypt block 17 | // // - Execute block 18 | // // - Encrypt block 19 | // // - Release spinlock 20 | // // 21 | // // 22 | // 23 | //struct encrypted_blocks_t 24 | //{ 25 | // template 26 | // static bool post_encode_xor_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin, Xor_val_type xor_val) 27 | // { 28 | // *reinterpret_cast(target) ^= xor_val; 29 | // return true; 30 | // } 31 | // 32 | // template 33 | // static bool post_encode_xor_loop_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin, uint8_t xor_val) 34 | // { 35 | // auto len = inst->length(); 36 | // for (uint32_t i = 0; i < len; ++i) 37 | // target[i] ^= xor_val; 38 | // return true; 39 | // } 40 | // 41 | // // Takes a link that represents a byte in memory to use as the spinlock 42 | // // 43 | // template 44 | // static dasm::inst_list_t acquire_spinlock(obf::obf_t& ctx, uint32_t spinlock_link) 45 | // { 46 | // // pushfq 47 | // // push rax 48 | // // continue_wait: 49 | // // mov al,0 50 | // // lock xchg [rip+spinlock_offset],al 51 | // // test al,al 52 | // // jz continue_wait 53 | // // 54 | // 55 | // uint32_t continue_wait = ctx.linker->allocate_link(); 56 | // 57 | // dasm::inst_list_t result; 58 | // 59 | // 60 | // result.emplace_back( 61 | // XED_ICLASS_PUSHF, 62 | // addr_width::bits::value 63 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 64 | // 65 | // result.emplace_back( 66 | // XED_ICLASS_PUSH, 67 | // addr_width::bits::value, 68 | // xed_reg(max_reg_width::value) 69 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 70 | // 71 | // result.emplace_back( 72 | // XED_ICLASS_MOV, 73 | // 8, 74 | // xed_reg(XED_REG_AL), 75 | // xed_imm0(0, 8) 76 | // ).common_edit(continue_wait, 0, 0); 77 | // 78 | // result.emplace_back( 79 | // XED_ICLASS_XCHG, 80 | // 8, 81 | // xed_mem_bd( 82 | // max_reg_width::value, 83 | // xed_disp(0, 32), 84 | // 8 85 | // ), 86 | // xed_reg(XED_REG_AL) 87 | // ).common_edit(ctx.linker->allocate_link(), spinlock_link, dasm::inst_flag::disp); 88 | // 89 | // result.emplace_back( 90 | // XED_ICLASS_TEST, 91 | // 8, 92 | // xed_reg(XED_REG_AL), 93 | // xed_reg(XED_REG_AL) 94 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 95 | // 96 | // result.emplace_back( 97 | // XED_ICLASS_JZ, 98 | // 8, 99 | // xed_relbr(0, 32) 100 | // ).common_edit(ctx.linker->allocate_link(), continue_wait, dasm::inst_flag::rel_br); 101 | // 102 | // 103 | // return result; 104 | // } 105 | // 106 | // template 107 | // static dasm::inst_list_t release_spinlock(obf::obf_t& ctx, uint32_t spinlock_link) 108 | // { 109 | // // mov al,0x90 110 | // // lock xchg [rip+spinlock_offset],al 111 | // // pop rax 112 | // // popfq 113 | // // 114 | // 115 | // dasm::inst_list_t result; 116 | // 117 | // result.emplace_back( 118 | // XED_ICLASS_MOV, 119 | // 8, 120 | // xed_reg(XED_REG_AL), 121 | // xed_imm0(0x90, 8) 122 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 123 | // 124 | // result.emplace_back( 125 | // XED_ICLASS_XCHG, 126 | // 8, 127 | // xed_mem_bd( 128 | // max_reg_width::value, 129 | // xed_disp(0, 32), 130 | // 8 131 | // ), 132 | // xed_reg(XED_REG_AL) 133 | // ).common_edit(ctx.linker->allocate_link(), spinlock_link, dasm::inst_flag::disp); 134 | // 135 | // result.emplace_back( 136 | // XED_ICLASS_POP, 137 | // addr_width::bits::value, 138 | // xed_reg(max_reg_width::value) 139 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 140 | // 141 | // result.emplace_back( 142 | // XED_ICLASS_POPF, 143 | // addr_width::bits::value 144 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 145 | // 146 | // return result; 147 | // } 148 | // 149 | // template 150 | // static void shuffle_list(dasm::inst_list_t& list) 151 | // { 152 | // for (uint32_t i = 0; i < 8; ++i) 153 | // { 154 | // for (auto inst_it = list.begin(); inst_it != list.end();) 155 | // { 156 | // auto next = std::next(inst_it); 157 | // if (rand() % 100 < 50) 158 | // list.splice(list.begin(), list, inst_it); 159 | // inst_it = next; 160 | // } 161 | // } 162 | // } 163 | // 164 | // static uint8_t encr_width(uint32_t inst_width) 165 | // { 166 | // constexpr static uint8_t table[3] = { 1,2,4 }; 167 | // 168 | // if (inst_width > 3) 169 | // return table[rand() % 3]; 170 | // else if (inst_width > 1) 171 | // return table[rand() % 2]; 172 | // else 173 | // return 1; 174 | // } 175 | // 176 | // template 177 | // static void gen_encryption_pair(obf::obf_t& ctx, dasm::inst_t& inst, dasm::inst_list_t& prologue, dasm::inst_list_t& epilogue, bool post_encode) 178 | // { 179 | // // For xoring, prologue and epilogue are the same 180 | // // 181 | // 182 | // auto len = inst.length(); 183 | // auto width = encr_width(len); 184 | // auto width_bits = width * 8; 185 | // 186 | // uint32_t val = rand(); 187 | // 188 | // prologue.emplace_back( 189 | // XED_ICLASS_XOR, 190 | // width_bits, 191 | // xed_mem_bd( 192 | // max_reg_width::value, 193 | // xed_disp(0, 32), 194 | // width_bits 195 | // ), 196 | // xed_imm0(val, width_bits) 197 | // ).common_edit(ctx.linker->allocate_link(), inst.my_link, dasm::inst_flag::disp); 198 | // 199 | // epilogue.emplace_back( 200 | // XED_ICLASS_XOR, 201 | // width_bits, 202 | // xed_mem_bd( 203 | // max_reg_width::value, 204 | // xed_disp(0, 32), 205 | // width_bits 206 | // ), 207 | // xed_imm0(val, width_bits) 208 | // ).common_edit(ctx.linker->allocate_link(), inst.my_link, dasm::inst_flag::disp); 209 | // 210 | // if (post_encode) 211 | // { 212 | // switch (width) 213 | // { 214 | // case 1: 215 | // inst.encode_callback = std::bind(post_encode_xor_callback, 216 | // std::placeholders::_1, 217 | // std::placeholders::_2, 218 | // std::placeholders::_3, 219 | // std::placeholders::_4, 220 | // val 221 | // ); 222 | // break; 223 | // case 2: 224 | // inst.encode_callback = std::bind(post_encode_xor_callback, 225 | // std::placeholders::_1, 226 | // std::placeholders::_2, 227 | // std::placeholders::_3, 228 | // std::placeholders::_4, 229 | // val 230 | // ); 231 | // break; 232 | // case 4: 233 | // inst.encode_callback = std::bind(post_encode_xor_callback, 234 | // std::placeholders::_1, 235 | // std::placeholders::_2, 236 | // std::placeholders::_3, 237 | // std::placeholders::_4, 238 | // val 239 | // ); 240 | // break; 241 | // default: 242 | // std::printf("Invalid width for encryption.\n"); 243 | // } 244 | // } 245 | // } 246 | // 247 | // template 248 | // static dasm::inst_list_t gen_encryption_loop(obf::obf_t& ctx, dasm::block_t& block, uint8_t xor_key, bool pre) 249 | // { 250 | // // pushfq 251 | // // push rax 252 | // // push rbx 253 | // // lea rax,[rip+start_link] 254 | // // lea rbx,[rip+end_link] 255 | // // continue_loop: 256 | // // xor byte ptr[rax],xor_key 257 | // // add rax,1 258 | // // cmp rax,rbx 259 | // // jnz continue_loop 260 | // // pop rbx 261 | // // pop rax 262 | // // 263 | // // no popfq because its handled by the spinlock or appended after 264 | // // 265 | // 266 | // dasm::inst_list_t result; 267 | // 268 | // uint32_t start_link = block.instructions.front().my_link; 269 | // uint32_t end_link = start_link; 270 | // 271 | // // This is the additional disp added on to the end 272 | // int32_t end_add = block.instructions.front().length(); 273 | // 274 | // for (auto& inst : block.instructions) 275 | // { 276 | // inst.redecode(); 277 | // 278 | // if (inst.flags & dasm::inst_flag::block_terminator) 279 | // break; 280 | // 281 | // end_link = inst.my_link; 282 | // end_add = inst.length(); 283 | // 284 | // inst.encode_callback = std::bind(post_encode_xor_loop_callback, 285 | // std::placeholders::_1, 286 | // std::placeholders::_2, 287 | // std::placeholders::_3, 288 | // std::placeholders::_4, 289 | // xor_key 290 | // ); 291 | // } 292 | // 293 | // 294 | // auto continue_loop = ctx.linker->allocate_link(); 295 | // 296 | // if (!pre) 297 | // { 298 | // result.emplace_back( 299 | // XED_ICLASS_PUSHF, 300 | // addr_width::bits::value 301 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 302 | // 303 | // result.emplace_back( 304 | // XED_ICLASS_PUSH, 305 | // addr_width::bits::value, 306 | // xed_reg(max_reg_width::value) 307 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 308 | // } 309 | // 310 | // result.emplace_back( 311 | // XED_ICLASS_PUSH, 312 | // addr_width::bits::value, 313 | // xed_reg(max_reg_width::value) 314 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 315 | // 316 | // result.emplace_back( 317 | // XED_ICLASS_LEA, 318 | // addr_width::bits::value, 319 | // xed_reg(max_reg_width::value), 320 | // xed_mem_bd( 321 | // max_reg_width::value, 322 | // xed_disp(0, 32), 323 | // addr_width::bits::value 324 | // ) 325 | // ).common_edit(ctx.linker->allocate_link(), start_link, dasm::inst_flag::disp); 326 | // 327 | // result.emplace_back( 328 | // XED_ICLASS_LEA, 329 | // addr_width::bits::value, 330 | // xed_reg(max_reg_width::value), 331 | // xed_mem_bd( 332 | // max_reg_width::value, 333 | // xed_disp(0, 32), 334 | // addr_width::bits::value 335 | // ) 336 | // ).common_edit(ctx.linker->allocate_link(), end_link, dasm::inst_flag::disp); 337 | // result.back().encode_data.additional_disp = end_add; 338 | // 339 | // result.emplace_back( 340 | // XED_ICLASS_XOR, 341 | // addr_width::bits::value, 342 | // xed_mem_b(max_reg_width::value, 8), 343 | // xed_imm0(xor_key, 8) 344 | // ).common_edit(continue_loop, 0, 0); 345 | // 346 | // result.emplace_back( 347 | // XED_ICLASS_ADD, 348 | // addr_width::bits::value, 349 | // xed_reg(max_reg_width::value), 350 | // xed_imm0(1, 8) 351 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 352 | // 353 | // result.emplace_back( 354 | // XED_ICLASS_CMP, 355 | // addr_width::bits::value, 356 | // xed_reg(max_reg_width::value), 357 | // xed_reg(max_reg_width::value) 358 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 359 | // 360 | // result.emplace_back( 361 | // XED_ICLASS_JNZ, 362 | // addr_width::bits::value, 363 | // xed_relbr(0, 8) 364 | // ).common_edit(ctx.linker->allocate_link(), continue_loop, dasm::inst_flag::rel_br); 365 | // 366 | // result.emplace_back( 367 | // XED_ICLASS_POP, 368 | // addr_width::bits::value, 369 | // xed_reg(max_reg_width::value) 370 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 371 | // 372 | // if (pre) 373 | // { 374 | // result.emplace_back( 375 | // XED_ICLASS_POP, 376 | // addr_width::bits::value, 377 | // xed_reg(max_reg_width::value) 378 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 379 | // } 380 | // 381 | // return result; 382 | // } 383 | // 384 | // template 385 | // static std::pair, dasm::inst_list_t> encryption(obf::obf_t& ctx, dasm::block_t& block) 386 | // { 387 | // dasm::inst_list_t prologue, epilogue; 388 | // 389 | // if (block.instructions.size() < 10) 390 | // { 391 | // for (auto& inst : block.instructions) 392 | // { 393 | // if (!inst.encode_callback) 394 | // { 395 | // inst.redecode(); 396 | // gen_encryption_pair(ctx, inst, prologue, epilogue, !(inst.flags & dasm::inst_flag::block_terminator)); 397 | // } 398 | // } 399 | // 400 | // shuffle_list(prologue); 401 | // shuffle_list(epilogue); 402 | // 403 | // epilogue.emplace_front( 404 | // XED_ICLASS_PUSH, 405 | // addr_width::bits::value, 406 | // xed_reg(max_reg_width::value) 407 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 408 | // 409 | // epilogue.emplace_front( 410 | // XED_ICLASS_PUSHF, 411 | // addr_width::bits::value 412 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 413 | // 414 | // 415 | // prologue.emplace_back( 416 | // XED_ICLASS_POP, 417 | // addr_width::bits::value, 418 | // xed_reg(max_reg_width::value) 419 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 420 | // 421 | // } 422 | // else 423 | // { 424 | // uint8_t xor_key = rand(); 425 | // prologue = gen_encryption_loop(ctx, block, xor_key, true); 426 | // epilogue = gen_encryption_loop(ctx, block, xor_key, false); 427 | // } 428 | // 429 | // prologue.emplace_back( 430 | // XED_ICLASS_POPF, 431 | // addr_width::bits::value 432 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 433 | // 434 | // return { prologue, epilogue }; 435 | // } 436 | // 437 | // // TODO: 438 | // // - Make large blocks over a certain threshold use a loop and simple xor encrypting 439 | // // - Add different types of crypting 440 | // // 441 | // 442 | // template 443 | // static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx, bool spinlock = true) 444 | // { 445 | // /*auto [prologue, epilogue] = encryption();*/ 446 | // 447 | // for (auto& block : routine.blocks) 448 | // { 449 | // // Now we need to find where to insert the epilogue and spinlock release 450 | // // 451 | // auto inst_it = std::prev(block.instructions.end()); 452 | // uint32_t terminator_size = 0; 453 | // 454 | // while (true) 455 | // { 456 | // if (!(inst_it->flags & dasm::inst_flag::block_terminator)) 457 | // { 458 | // ++inst_it; 459 | // break; 460 | // } 461 | // 462 | // ++terminator_size; 463 | // 464 | // if (inst_it == block.instructions.begin()) 465 | // break; 466 | // 467 | // --inst_it; 468 | // } 469 | // 470 | // 471 | // // Make sure there are actually some instructions we can encrypt 472 | // // 473 | // if (block.instructions.size() <= terminator_size) 474 | // continue; 475 | // 476 | // 477 | // uint32_t spinlock_link = ctx.linker->allocate_link(); 478 | // 479 | // // Gen the prologue and epilogues here, prepend and append them 480 | // // 481 | // auto [prologue, epilogue] = encryption(ctx, block); 482 | // 483 | // block.instructions.splice(block.instructions.begin(), prologue); 484 | // block.instructions.splice(inst_it, epilogue); 485 | // 486 | // // Now add the spinlock acquire and release 487 | // // 488 | // auto acquire = acquire_spinlock(ctx, spinlock_link); 489 | // auto release = release_spinlock(ctx, spinlock_link); 490 | // 491 | // block.instructions.splice(block.instructions.begin(), acquire); 492 | // block.instructions.splice(inst_it, release); 493 | // 494 | // block.instructions.emplace_back( 495 | // XED_ICLASS_NOP, 496 | // 32 497 | // ).common_edit(spinlock_link, 0, dasm::inst_flag::block_terminator); 498 | // } 499 | // 500 | // return obf::pass_status_t::success; 501 | // } 502 | //}; 503 | -------------------------------------------------------------------------------- /BDASM/encrypted_routines.h: -------------------------------------------------------------------------------- 1 | //#pragma once 2 | // 3 | //#include 4 | // 5 | //#include "obf.h" 6 | // 7 | //// Very similar to encrypted_blocks_t but this encrypts/decrypts the entire routine at one time 8 | //// This is going to be MUCH(thousands of times) faster for routines that contain loops. 9 | //// 10 | // 11 | //// Basic function entry logic: 12 | //// 13 | //// Save registers and flags 14 | //// Acquire logic spinlock 15 | //// mov rax,[rip+counter_offset] 16 | //// test rax,rax 17 | //// jnz no_decrypt 18 | //// 19 | //// Decrypt function here 20 | //// 21 | //// no_decrypt: 22 | //// add [rip+counter_offset],1 23 | //// Release logic spinlock 24 | //// Restore registers and flags 25 | //// 26 | //// 27 | //// 28 | //// Basic function exit logic: 29 | //// 30 | //// Save registers and flags 31 | //// Acquire logic spinlock 32 | //// sub [rip+counter_offset],1 33 | //// jnz no_encrypt 34 | //// 35 | //// Encrypt the function here 36 | //// 37 | //// no_encrypt: 38 | //// Release logic spinlock 39 | //// Restore registers and flags 40 | //// Function exit terminator(ret or undetermined unconditional jmp) 41 | //// 42 | //// 43 | //// I think i dont actually need to save the flags? Since this only happens on entry and exit 44 | //// to a function. I also dont need to save rax on entry. 45 | //// 46 | // 47 | //struct encrypted_routine_t 48 | //{ 49 | // template 50 | // static bool xor_encode_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin, Xor_val_type xor_val) 51 | // { 52 | // *reinterpret_cast(target) ^= xor_val; 53 | // return true; 54 | // } 55 | // 56 | // template 57 | // static bool xor_loop_encode_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin, uint8_t xor_val) 58 | // { 59 | // auto len = inst->length(); 60 | // for (uint32_t i = 0; i < len; ++i) 61 | // target[i] ^= xor_val; 62 | // return true; 63 | // } 64 | // 65 | // template 66 | // static bool spinlock_encode_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin) 67 | // { 68 | // *target = 0; 69 | // return true; 70 | // } 71 | // 72 | // template 73 | // static bool counter_encode_callback(dasm::inst_t* inst, uint8_t* target, dasm::linker_t* linker, pex::binary_t* bin) 74 | // { 75 | // *reinterpret_cast(target) = 0; 76 | // return true; 77 | // } 78 | // 79 | // template 80 | // static void shuffle_list(dasm::inst_list_t& list) 81 | // { 82 | // for (uint32_t i = 0; i < 8; ++i) 83 | // { 84 | // for (auto inst_it = list.begin(); inst_it != list.end();) 85 | // { 86 | // auto next = std::next(inst_it); 87 | // if (rand() % 100 < 50) 88 | // list.splice(list.begin(), list, inst_it); 89 | // inst_it = next; 90 | // } 91 | // } 92 | // } 93 | // 94 | // template 95 | // static dasm::inst_list_t acquire_spinlock(obf::obf_t& ctx, uint32_t spinlock_link) 96 | // { 97 | // // continue_wait: 98 | // // mov al,0 99 | // // lock xchg [rip+spinlock_offset],al 100 | // // test al,al 101 | // // jz continue_wait 102 | // // 103 | // 104 | // uint32_t continue_wait = ctx.linker->allocate_link(); 105 | // 106 | // dasm::inst_list_t result; 107 | // 108 | // result.emplace_back( 109 | // XED_ICLASS_MOV, 110 | // 8, 111 | // xed_reg(XED_REG_AL), 112 | // xed_imm0(1, 8) 113 | // ).common_edit(continue_wait, 0, 0); 114 | // 115 | // result.emplace_back( 116 | // XED_ICLASS_XCHG, 117 | // 8, 118 | // xed_mem_bd( 119 | // max_reg_width::value, 120 | // xed_disp(0, 32), 121 | // 8 122 | // ), 123 | // xed_reg(XED_REG_AL) 124 | // ).common_edit(ctx.linker->allocate_link(), spinlock_link, dasm::inst_flag::disp); 125 | // 126 | // result.emplace_back( 127 | // XED_ICLASS_TEST, 128 | // 8, 129 | // xed_reg(XED_REG_AL), 130 | // xed_reg(XED_REG_AL) 131 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 132 | // 133 | // result.emplace_back( 134 | // XED_ICLASS_JNZ, 135 | // 8, 136 | // xed_relbr(0, 32) 137 | // ).common_edit(ctx.linker->allocate_link(), continue_wait, dasm::inst_flag::rel_br); 138 | // 139 | // return result; 140 | // } 141 | // 142 | // template 143 | // static dasm::inst_list_t release_spinlock(obf::obf_t& ctx, uint32_t spinlock_link) 144 | // { 145 | // // mov al,0 146 | // // lock xchg [rip+spinlock_offset],al 147 | // // 148 | // 149 | // dasm::inst_list_t result; 150 | // 151 | // result.emplace_back( 152 | // XED_ICLASS_MOV, 153 | // 8, 154 | // xed_reg(XED_REG_AL), 155 | // xed_imm0(0, 8) 156 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 157 | // 158 | // result.emplace_back( 159 | // XED_ICLASS_XCHG, 160 | // 8, 161 | // xed_mem_bd( 162 | // max_reg_width::value, 163 | // xed_disp(0, 32), 164 | // 8 165 | // ), 166 | // xed_reg(XED_REG_AL) 167 | // ).common_edit(ctx.linker->allocate_link(), spinlock_link, dasm::inst_flag::disp); 168 | // 169 | // return result; 170 | // } 171 | // 172 | // template 173 | // static dasm::inst_list_t save_values(obf::obf_t& ctx) 174 | // { 175 | // dasm::inst_list_t result; 176 | // 177 | // result.emplace_front( 178 | // XED_ICLASS_PUSHF, 179 | // addr_width::bits::value 180 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 181 | // 182 | // result.emplace_front( 183 | // XED_ICLASS_PUSH, 184 | // addr_width::bits::value, 185 | // xed_reg(max_reg_width::value) 186 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 187 | // 188 | // result.emplace_front( 189 | // XED_ICLASS_PUSH, 190 | // addr_width::bits::value, 191 | // xed_reg(max_reg_width::value) 192 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 193 | // 194 | // return result; 195 | // } 196 | // 197 | // template 198 | // static dasm::inst_list_t restore_values(obf::obf_t& ctx) 199 | // { 200 | // dasm::inst_list_t result; 201 | // 202 | // result.emplace_front( 203 | // XED_ICLASS_POP, 204 | // addr_width::bits::value, 205 | // xed_reg(max_reg_width::value) 206 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 207 | // 208 | // result.emplace_front( 209 | // XED_ICLASS_POP, 210 | // addr_width::bits::value, 211 | // xed_reg(max_reg_width::value) 212 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 213 | // 214 | // result.emplace_front( 215 | // XED_ICLASS_POPF, 216 | // addr_width::bits::value 217 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 218 | // 219 | // return result; 220 | // } 221 | // 222 | // template 223 | // static void build_prologue_logic(obf::obf_t& ctx, dasm::inst_list_t& prologue, uint32_t spinlock_link, uint32_t counter_link) 224 | // { 225 | // auto no_decrypt = ctx.linker->allocate_link(); 226 | // 227 | // // Setup the beginning 228 | // // 229 | // prologue.emplace_front( 230 | // XED_ICLASS_JNZ, 231 | // 32, 232 | // xed_relbr(0, 32) 233 | // ).common_edit(ctx.linker->allocate_link(), no_decrypt, dasm::inst_flag::rel_br); 234 | // 235 | // prologue.emplace_front( 236 | // XED_ICLASS_TEST, 237 | // 32, 238 | // xed_reg(XED_REG_EAX), 239 | // xed_reg(XED_REG_EAX) 240 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 241 | // 242 | // prologue.emplace_front( 243 | // XED_ICLASS_MOV, 244 | // 32, 245 | // xed_reg(XED_REG_EAX), 246 | // xed_mem_bd( 247 | // max_reg_width::value, 248 | // xed_disp(0, 32), 249 | // 32 250 | // ) 251 | // ).common_edit(ctx.linker->allocate_link(), counter_link, dasm::inst_flag::disp); 252 | // 253 | // prologue.splice(prologue.begin(), acquire_spinlock(ctx, spinlock_link)); 254 | // prologue.splice(prologue.begin(), save_values(ctx)); 255 | // 256 | // // Setup the end. 257 | // // 258 | // prologue.emplace_back( 259 | // XED_ICLASS_ADD, 260 | // 32, 261 | // xed_mem_bd( 262 | // max_reg_width::value, 263 | // xed_disp(0, 32), 264 | // 32 265 | // ), 266 | // xed_imm0(1, 8) 267 | // ).common_edit(no_decrypt, counter_link, dasm::inst_flag::disp); 268 | // 269 | // prologue.splice(prologue.end(), release_spinlock(ctx, spinlock_link)); 270 | // prologue.splice(prologue.end(), restore_values(ctx)); 271 | // } 272 | // 273 | // template 274 | // static void build_epilogue_logic(obf::obf_t& ctx, dasm::inst_list_t& epilogue, uint32_t spinlock_link, uint32_t counter_link) 275 | // { 276 | // 277 | // // Setup the end 278 | // // 279 | // auto spinlock_release = release_spinlock(ctx, spinlock_link); 280 | // auto no_encrypt = spinlock_release.front().my_link; 281 | // epilogue.splice(epilogue.end(), spinlock_release); 282 | // epilogue.splice(epilogue.end(), restore_values(ctx)); 283 | // 284 | // 285 | // // Setup the beginning 286 | // // 287 | // epilogue.emplace_front( 288 | // XED_ICLASS_JNZ, 289 | // 32, 290 | // xed_relbr(0, 32) 291 | // ).common_edit(ctx.linker->allocate_link(), no_encrypt, dasm::inst_flag::rel_br); 292 | // 293 | // epilogue.emplace_front( 294 | // XED_ICLASS_SUB, 295 | // 32, 296 | // xed_mem_bd( 297 | // max_reg_width::value, 298 | // xed_disp(0, 32), 299 | // 32 300 | // ), 301 | // xed_imm0(1, 8) 302 | // ).common_edit(ctx.linker->allocate_link(), counter_link, dasm::inst_flag::disp); 303 | // 304 | // epilogue.splice(epilogue.begin(), acquire_spinlock(ctx, spinlock_link)); 305 | // epilogue.splice(epilogue.begin(), save_values(ctx)); 306 | // 307 | // epilogue.emplace_back( 308 | // XED_ICLASS_RET_NEAR, 309 | // addr_width::bits::value 310 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 311 | // 312 | // } 313 | // 314 | // static uint8_t encr_width(uint32_t inst_width) 315 | // { 316 | // constexpr static uint8_t table[3] = { 1,2,4 }; 317 | // 318 | // if (inst_width > 3) 319 | // return table[rand() % 3]; 320 | // else if (inst_width > 1) 321 | // return table[rand() % 2]; 322 | // else 323 | // return 1; 324 | // } 325 | // 326 | // template 327 | // static void gen_encryption_pair(obf::obf_t& ctx, dasm::inst_t& inst, dasm::inst_list_t& prologue, dasm::inst_list_t& epilogue, bool post_encode) 328 | // { 329 | // // For xoring, prologue and epilogue are the same 330 | // // 331 | // 332 | // auto len = inst.length(); 333 | // auto width = encr_width(len); 334 | // auto width_bits = width * 8; 335 | // 336 | // uint32_t val = rand(); 337 | // 338 | // prologue.emplace_back( 339 | // XED_ICLASS_XOR, 340 | // width_bits, 341 | // xed_mem_bd( 342 | // max_reg_width::value, 343 | // xed_disp(0, 32), 344 | // width_bits 345 | // ), 346 | // xed_imm0(val, width_bits) 347 | // ).common_edit(ctx.linker->allocate_link(), inst.my_link, dasm::inst_flag::disp); 348 | // 349 | // epilogue.emplace_back( 350 | // XED_ICLASS_XOR, 351 | // width_bits, 352 | // xed_mem_bd( 353 | // max_reg_width::value, 354 | // xed_disp(0, 32), 355 | // width_bits 356 | // ), 357 | // xed_imm0(val, width_bits) 358 | // ).common_edit(ctx.linker->allocate_link(), inst.my_link, dasm::inst_flag::disp); 359 | // 360 | // if (post_encode) 361 | // { 362 | // switch (width) 363 | // { 364 | // case 1: 365 | // inst.encode_callback = std::bind(xor_encode_callback, 366 | // std::placeholders::_1, 367 | // std::placeholders::_2, 368 | // std::placeholders::_3, 369 | // std::placeholders::_4, 370 | // val 371 | // ); 372 | // break; 373 | // case 2: 374 | // inst.encode_callback = std::bind(xor_encode_callback, 375 | // std::placeholders::_1, 376 | // std::placeholders::_2, 377 | // std::placeholders::_3, 378 | // std::placeholders::_4, 379 | // val 380 | // ); 381 | // break; 382 | // case 4: 383 | // inst.encode_callback = std::bind(xor_encode_callback, 384 | // std::placeholders::_1, 385 | // std::placeholders::_2, 386 | // std::placeholders::_3, 387 | // std::placeholders::_4, 388 | // val 389 | // ); 390 | // break; 391 | // default: 392 | // std::printf("Invalid width for encryption.\n"); 393 | // } 394 | // } 395 | // } 396 | // 397 | // template 398 | // static dasm::inst_list_t gen_encryption_loop(obf::obf_t& ctx, dasm::block_t& block, uint8_t xor_key) 399 | // { 400 | // // lea rax,[rip+start_link] 401 | // // lea rbx,[rip+end_link] 402 | // // continue_loop: 403 | // // xor byte ptr[rax],xor_key 404 | // // add rax,1 405 | // // cmp rax,rbx 406 | // // jnz continue_loop 407 | // // 408 | // // 409 | // 410 | // dasm::inst_list_t result; 411 | // 412 | // uint32_t start_link = block.instructions.front().my_link; 413 | // uint32_t end_link = start_link; 414 | // 415 | // // This is the additional disp added on to the end 416 | // int32_t end_add = block.instructions.front().length(); 417 | // 418 | // for (auto& inst : block.instructions) 419 | // { 420 | // if (inst.flags & dasm::inst_flag::routine_terminator) 421 | // break; 422 | // 423 | // inst.redecode(); 424 | // 425 | // end_link = inst.my_link; 426 | // end_add = inst.length(); 427 | // 428 | // inst.encode_callback = std::bind(xor_loop_encode_callback, 429 | // std::placeholders::_1, 430 | // std::placeholders::_2, 431 | // std::placeholders::_3, 432 | // std::placeholders::_4, 433 | // xor_key 434 | // ); 435 | // } 436 | // 437 | // 438 | // auto continue_loop = ctx.linker->allocate_link(); 439 | // 440 | // result.emplace_back( 441 | // XED_ICLASS_LEA, 442 | // addr_width::bits::value, 443 | // xed_reg(max_reg_width::value), 444 | // xed_mem_bd( 445 | // max_reg_width::value, 446 | // xed_disp(0, 32), 447 | // addr_width::bits::value 448 | // ) 449 | // ).common_edit(ctx.linker->allocate_link(), start_link, dasm::inst_flag::disp); 450 | // 451 | // result.emplace_back( 452 | // XED_ICLASS_LEA, 453 | // addr_width::bits::value, 454 | // xed_reg(max_reg_width::value), 455 | // xed_mem_bd( 456 | // max_reg_width::value, 457 | // xed_disp(0, 32), 458 | // addr_width::bits::value 459 | // ) 460 | // ).common_edit(ctx.linker->allocate_link(), end_link, dasm::inst_flag::disp); 461 | // result.back().encode_data.additional_disp = end_add; 462 | // 463 | // result.emplace_back( 464 | // XED_ICLASS_XOR, 465 | // addr_width::bits::value, 466 | // xed_mem_b(max_reg_width::value, 8), 467 | // xed_imm0(xor_key, 8) 468 | // ).common_edit(continue_loop, 0, 0); 469 | // 470 | // result.emplace_back( 471 | // XED_ICLASS_ADD, 472 | // addr_width::bits::value, 473 | // xed_reg(max_reg_width::value), 474 | // xed_imm0(1, 8) 475 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 476 | // 477 | // result.emplace_back( 478 | // XED_ICLASS_CMP, 479 | // addr_width::bits::value, 480 | // xed_reg(max_reg_width::value), 481 | // xed_reg(max_reg_width::value) 482 | // ).common_edit(ctx.linker->allocate_link(), 0, 0); 483 | // 484 | // result.emplace_back( 485 | // XED_ICLASS_JNZ, 486 | // addr_width::bits::value, 487 | // xed_relbr(0, 8) 488 | // ).common_edit(ctx.linker->allocate_link(), continue_loop, dasm::inst_flag::rel_br); 489 | // 490 | // return result; 491 | // } 492 | // 493 | // template 494 | // static void append_block_encryption(obf::obf_t& ctx, dasm::block_t& block, dasm::inst_list_t& prologue, dasm::inst_list_t& epilogue) 495 | // { 496 | // if (block.instructions.size() < 10) 497 | // { 498 | // dasm::inst_list_t p, e; 499 | // for (auto& inst : block.instructions) 500 | // { 501 | // inst.redecode(); 502 | // gen_encryption_pair(ctx, inst, p, e, !(inst.flags & dasm::inst_flag::routine_terminator)); 503 | // } 504 | // shuffle_list(p); 505 | // shuffle_list(e); 506 | // 507 | // prologue.splice(prologue.end(), p); 508 | // epilogue.splice(epilogue.end(), e); 509 | // } 510 | // else 511 | // { 512 | // uint8_t xor_key = rand(); 513 | // prologue.splice(prologue.end(), gen_encryption_loop(ctx, block, xor_key)); 514 | // epilogue.splice(epilogue.end(), gen_encryption_loop(ctx, block, xor_key)); 515 | // } 516 | // } 517 | // 518 | // template 519 | // static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 520 | // { 521 | // auto spinlock_link = ctx.linker->allocate_link(); 522 | // auto counter_link = ctx.linker->allocate_link(); 523 | // 524 | // // The prologue and epilogue encryption blocks. These are made up of the two different 525 | // // encryption types: rip relative or loop. 526 | // // 527 | // dasm::inst_list_t prologue; 528 | // auto& epilogue = routine.blocks.emplace_front(routine.blocks.end()); 529 | // epilogue.termination_type = dasm::termination_type_t::unknown_logic; 530 | // epilogue.link = ctx.linker->allocate_link(); 531 | // 532 | // for (auto block_it = std::next(routine.blocks.begin()); block_it != routine.blocks.end(); ++block_it) 533 | // { 534 | // append_block_encryption(ctx, *block_it, prologue, epilogue.instructions); 535 | // } 536 | // 537 | // build_prologue_logic(ctx, prologue, spinlock_link, counter_link); 538 | // build_epilogue_logic(ctx, epilogue.instructions, spinlock_link, counter_link); 539 | // 540 | // for (auto block_it = std::next(routine.blocks.begin()); block_it != routine.blocks.end(); ++block_it) 541 | // { 542 | // if (block_it->termination_type == dasm::termination_type_t::returns || 543 | // block_it->termination_type == dasm::termination_type_t::undetermined_unconditional_br) 544 | // { 545 | // block_it->instructions.emplace(std::prev(block_it->instructions.end()), 546 | // XED_ICLASS_CALL_NEAR, 547 | // 32, 548 | // xed_relbr(0, 32) 549 | // )->common_edit(ctx.linker->allocate_link(), epilogue.link, dasm::inst_flag::rel_br); 550 | // } 551 | // } 552 | // 553 | // routine.entry_block->instructions.splice(routine.entry_block->instructions.begin(), prologue); 554 | // 555 | // auto& data_block = routine.blocks.emplace_front(routine.blocks.end()); 556 | // data_block.link = ctx.linker->allocate_link(); 557 | // data_block.instructions.emplace_back( 558 | // XED_ICLASS_NOP, 559 | // 32 560 | // ).common_edit(spinlock_link, 0, 0); 561 | // data_block.instructions.back().encode_callback = spinlock_encode_callback; 562 | // 563 | // data_block.instructions.emplace_back( 564 | // XED_ICLASS_NOP4, 565 | // 32 566 | // ).common_edit(counter_link, 0, 0); 567 | // data_block.instructions.back().encode_callback = counter_encode_callback; 568 | // 569 | // return obf::pass_status_t::success; 570 | // } 571 | //}; -------------------------------------------------------------------------------- /BDASM/flags.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "dasm.h" 5 | 6 | 7 | 8 | namespace dasm 9 | { 10 | // This routine determines if the flags edited by 'start' in question are actually used by iterating forward until 11 | // they are either accessed, or completely overwritten 12 | // 13 | // This clears 31th bit of visited for all blocks. Make sure you dont use. 14 | // 15 | template 16 | bool flags_clobbered(routine_t& routine, block_it_t block, inst_it_t start) 17 | { 18 | routine.reset_visited_bit(31); 19 | 20 | xed_flag_set_t ledger; 21 | const xed_simple_flag_t* start_flags = xed_decoded_inst_get_rflags_info(&start->DecodedInst); 22 | ledger.flat = (xed_simple_flag_get_written_flag_set(start_flags)->flat | xed_simple_flag_get_undefined_flag_set(start_flags)->flat); 23 | 24 | auto it = std::next(start); 25 | while (it != block->instructions.end()) 26 | { 27 | const xed_simple_flag_t* inst_flag = xed_decoded_inst_get_rflags_info(&it->decoded_inst); 28 | 29 | if (ledger.flat & xed_simple_flag_get_read_flag_set(inst_flag)->flat) 30 | return true; 31 | 32 | ledger.flat &= ~(xed_simple_flag_get_written_flag_set(inst_flag)->flat | xed_simple_flag_get_undefined_flag_set(inst_flag)->flat); 33 | 34 | ++it; 35 | } 36 | return false; 37 | } 38 | 39 | // This does the same as above but with an arbitrary flagset 40 | // 41 | template 42 | bool flags_clobbered(routine_t& routine, block_t& block, inst_it_t start, xed_flag_set_t flagset) 43 | { 44 | 45 | } 46 | 47 | // Trace forward until the flags we are concerned about are completely overwritten. 48 | // 49 | template 50 | std::pair, inst_it_t> trace_to_overwrite() 51 | { 52 | 53 | } 54 | 55 | template 56 | bool flags_clobbered_before_use_recursion(block_it_t block, block_it_t start_block, inst_it_t start_inst, xed_flag_set_t ledger) 57 | { 58 | if (block->visited & (1 << 31)) 59 | return true; 60 | 61 | block->visited |= (1 << 31); 62 | 63 | for (auto inst_it = block->instructions.begin(); inst_it != block->instructions.end(); ++inst_it ) 64 | { 65 | auto cur_inst_flags = xed_decoded_inst_get_rflags_info(&inst_it->decoded_inst); 66 | 67 | if (cur_inst_flags) 68 | { 69 | // Make sure if we are in the starting block, we dont test the instruction that actually set these flags. 70 | // If we found the the inst that did, then we know they aint clobbered. 71 | // 72 | if (block == start_block && inst_it != start_inst) 73 | return true; 74 | 75 | // Check to see if the current inst uses some flags that we changed 76 | // 77 | if (ledger.flat & xed_simple_flag_get_read_flag_set(cur_inst_flags)->flat) 78 | return false; 79 | 80 | // Update the current flags so that they reflect what is clobbered by the current inst 81 | // 82 | ledger.flat &= ~(xed_simple_flag_get_written_flag_set(cur_inst_flags)->flat | xed_simple_flag_get_undefined_flag_set(cur_inst_flags)->flat); 83 | 84 | // Check and return if all flags are clobbered 85 | // 86 | if (ledger.flat == 0) 87 | return true; 88 | } 89 | } 90 | 91 | return block->invoke_for_next_check_bool(flags_clobbered_before_use_recursion, start_block, start_inst, ledger); 92 | } 93 | 94 | 95 | // Trace forward following control flow to see if the flags set by the 'start' instruction are clobbered 96 | // before they are used by a conditional. 97 | // 98 | // This itself clobberes bit 31 in block_t::visited. 99 | // 100 | template 101 | bool flags_clobbered_before_use(routine_t& routine, block_it_t start_block, inst_it_t start_inst, xed_flag_set_t ledger) 102 | { 103 | routine.reset_visited_bit(31); 104 | 105 | //xed_flag_set_t ledger; 106 | //auto start_flags = xed_decoded_inst_get_rflags_info(&start_inst->decoded_inst); 107 | //ledger.flat = (xed_simple_flag_get_written_flag_set(start_flags)->flat | xed_simple_flag_get_undefined_flag_set(start_flags)->flat); 108 | 109 | // This first loop iterates to the end of the current block, without setting its visited bit so that the recursion can 110 | // visit it and trace to the start instruction. 111 | // 112 | for (auto cur_inst = start_inst; cur_inst != start_block->instructions.end(); ++cur_inst) 113 | { 114 | auto cur_inst_flags = xed_decoded_inst_get_rflags_info(&cur_inst->decoded_inst); 115 | 116 | if (cur_inst_flags) 117 | { 118 | if (ledger.flat & xed_simple_flag_get_read_flag_set(cur_inst_flags)->flat) 119 | return false; 120 | 121 | ledger.flat &= ~(xed_simple_flag_get_written_flag_set(cur_inst_flags)->flat | xed_simple_flag_get_undefined_flag_set(cur_inst_flags)->flat); 122 | 123 | if (ledger.flat == 0) 124 | return true; 125 | } 126 | } 127 | 128 | return start_block->invoke_for_next_check_bool(flags_clobbered_before_use_recursion, start_block, start_inst, ledger); 129 | } 130 | 131 | } 132 | 133 | -------------------------------------------------------------------------------- /BDASM/inst.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | 6 | #include "encoder.h" 7 | #include "traits.h" 8 | #include "addr_width.h" 9 | #include "symbol.h" 10 | #include "pex.h" 11 | #include "linker.h" 12 | 13 | namespace dasm 14 | { 15 | 16 | namespace inst_flag 17 | { 18 | typedef uint32_t type; 19 | constexpr type none = 0; 20 | 21 | // Patch types 22 | // 23 | constexpr type rel_br = (1 << 0); 24 | constexpr type disp = (1 << 1); 25 | 26 | // Patch a 32 bit immediate with an rva inside the binary 27 | // 28 | constexpr type rva_imm32 = (1 << 2); 29 | 30 | // Patch a 32 bit immediate with a disp calculated like so be careful this does not calculate 31 | // based on rip. 32 | // rva - ilen + disp 33 | // disp = dest_link - (my_link - ilen) 34 | // 35 | constexpr type disp_imm32 = (1 << 3); 36 | 37 | // This is for instructions that have relocs inside of them do these even exist? 38 | // Seems that encoding mov rax,[64b] is valid instruction so i assume so? 39 | // used_link is for the rva they pointed to in the original binary 40 | // 41 | constexpr type reloc_disp = (1 << 6); // Form: mov rax,[base+rva] 42 | constexpr type reloc_imm = (1 << 7); // Form: movabs rax,base+rva 43 | 44 | constexpr type uses_symbol = (rel_br | disp | reloc_disp | reloc_imm); 45 | 46 | // This is so we know what instructions are vital for block termination 47 | // 48 | constexpr type block_terminator = (1 << 8); 49 | 50 | // This is for things like a ret or undetermined unconditional jumps. Pretty much 51 | // anything that exits/finishes the current routine. 52 | // 53 | constexpr type routine_terminator = (1 << 9); 54 | } 55 | 56 | template 57 | class inst_t 58 | { 59 | public: 60 | inst_flag::type flags; 61 | 62 | // This actually has a purpose. if zero, then this was an inserted instruction and we might not want 63 | // to apply obfuscation techniques on it. 64 | // 65 | union 66 | { 67 | uint32_t original_rva; 68 | uint32_t visited; 69 | }; 70 | 71 | // Link this instruction is responsible for setting the RVA of. 72 | // 73 | uint32_t my_link; 74 | 75 | // Link of target, used for calcuating deltas. 76 | // 77 | uint32_t used_link; 78 | 79 | // Tells the state of the following xed_decoded_inst_t 80 | // 81 | bool is_encoder_request; 82 | 83 | xed_decoded_inst_t decoded_inst; 84 | 85 | union inst_additional_data_t 86 | { 87 | struct reloc_data_t 88 | { 89 | uint8_t offset_in_inst; 90 | uint8_t type; 91 | uint32_t original_rva; 92 | }reloc; 93 | }additional_data; 94 | 95 | 96 | // Data used when encoding. Shame this has to be here. Feels hacky 97 | // 98 | struct post_encode_data_t 99 | { 100 | uint8_t bytes[XED_MAX_INSTRUCTION_BYTES]; 101 | 102 | int32_t additional_disp; 103 | }encode_data; 104 | 105 | // Custom encoder called instead of the default one. decoded_inst is in encoder_inst format 106 | // 107 | std::function*, pex::binary_t*, linker_t*, uint8_t*)> custom_encoder; 108 | 109 | // This is called after the instruction is encoded 110 | // Unused in favor of custom encoder now 111 | // 112 | //std::function*, uint8_t*, linker_t*, pex::binary_t*)> encode_callback; 113 | 114 | 115 | explicit inst_t() 116 | : flags(0) 117 | , original_rva(0) 118 | , my_link(linker_t::invalid_link_value) 119 | , used_link(linker_t::invalid_link_value) 120 | , is_encoder_request(false) 121 | , custom_encoder(nullptr) 122 | { 123 | encode_data.additional_disp = 0; 124 | } 125 | 126 | template 127 | explicit inst_t(xed_iclass_enum_t iclass, xed_uint_t effective_operand_width, Operands... operands) 128 | : flags(0) 129 | , original_rva(0) 130 | , my_link(linker_t::invalid_link_value) 131 | , used_link(linker_t::invalid_link_value) 132 | , is_encoder_request(false) 133 | , custom_encoder(nullptr) 134 | { 135 | encode_data.additional_disp = 0; 136 | 137 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 138 | 139 | decode(buffer, encode_inst_in_place(buffer, addr_width::machine_state::value, iclass, effective_operand_width, operands...)); 140 | } 141 | 142 | explicit inst_t(inst_t const& to_copy) 143 | : flags(to_copy.flags) 144 | , my_link(to_copy.my_link) 145 | , used_link(to_copy.used_link) 146 | , is_encoder_request(to_copy.is_encoder_request) 147 | , decoded_inst(to_copy.decoded_inst) 148 | , custom_encoder(to_copy.custom_encoder) 149 | { 150 | encode_data.additional_disp = to_copy.encode_data.additional_disp; 151 | std::memcpy(&additional_data, &to_copy.additional_data, sizeof inst_additional_data_t); 152 | for (uint32_t i = 0; i < XED_MAX_INSTRUCTION_BYTES; ++i) 153 | encode_data.bytes[i] = to_copy.encode_data.bytes[i]; 154 | } 155 | 156 | void zero_and_set_mode() 157 | { 158 | xed_decoded_inst_zero_set_mode(&decoded_inst, &addr_width::machine_state::value); 159 | is_encoder_request = false; 160 | } 161 | 162 | // Initial decode routine 163 | // 164 | uint32_t decode(uint8_t* itext, uint32_t max_size) 165 | { 166 | zero_and_set_mode(); 167 | 168 | xed_error_enum_t err = xed_decode(&decoded_inst, itext, max_size); 169 | if (XED_ERROR_NONE != err) 170 | { 171 | return 0; 172 | } 173 | 174 | return xed_decoded_inst_get_length(&decoded_inst); 175 | } 176 | 177 | // Redecodes the current inst to make sure it represents the most up to date settings. 178 | // Is there a better way to do this? Say I xed_decoded_inst_set_disp_width or something... 179 | // That doesnt update xed_decoded_inst_get_length; 180 | // 181 | bool redecode() 182 | { 183 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 184 | 185 | if (!is_encoder_request) 186 | xed_encoder_request_init_from_decode(&decoded_inst); 187 | 188 | uint32_t out_size = 0; 189 | xed_error_enum_t err = xed_encode(&decoded_inst, buffer, XED_MAX_INSTRUCTION_BYTES, &out_size); 190 | if (XED_ERROR_NONE != err) 191 | { 192 | return false; 193 | } 194 | 195 | zero_and_set_mode(); 196 | 197 | err = xed_decode(&decoded_inst, buffer, XED_MAX_INSTRUCTION_BYTES); 198 | if (XED_ERROR_NONE != err) 199 | { 200 | return 0; 201 | } 202 | return true; 203 | } 204 | 205 | // Readys the inst for encoding. 206 | // 207 | void to_encoder_request() 208 | { 209 | xed_encoder_request_init_from_decode(&decoded_inst); 210 | is_encoder_request = true; 211 | } 212 | 213 | // Encode the instruction to a place, assumes enough space. 214 | // 215 | uint32_t dumb_encode(uint8_t* target) 216 | { 217 | if (!is_encoder_request) 218 | to_encoder_request(); 219 | 220 | uint32_t out_size = 0; 221 | xed_error_enum_t err = xed_encode(&decoded_inst, target, XED_MAX_INSTRUCTION_BYTES, &out_size); 222 | if (XED_ERROR_NONE != err) 223 | { 224 | return 0; 225 | } 226 | return out_size; 227 | } 228 | finline bool resolve_deltas(pex::binary_t* binary, linker_t* linker, uint8_t* dest, uint32_t expected_length) 229 | { 230 | if (flags & inst_flag::rel_br) 231 | { 232 | int64_t ip = dest - binary->mapped_image + expected_length; 233 | int64_t br_disp = (int64_t)linker->get_link_addr(used_link) - ip + encode_data.additional_disp; 234 | 235 | xed_decoded_inst_set_branch_displacement_bits(&decoded_inst, br_disp, xed_decoded_inst_get_branch_displacement_width_bits(&decoded_inst)); 236 | } 237 | else if (flags & inst_flag::disp) 238 | { 239 | int64_t ip = dest - binary->mapped_image + expected_length; 240 | int64_t mem_disp = (int64_t)linker->get_link_addr(used_link) - ip + encode_data.additional_disp; 241 | 242 | xed_decoded_inst_set_memory_displacement_bits(&decoded_inst, mem_disp, xed_decoded_inst_get_memory_displacement_width_bits(&decoded_inst, 0)); 243 | } 244 | else if (flags & inst_flag::rva_imm32) 245 | { 246 | if (xed_decoded_inst_get_immediate_is_signed(&decoded_inst)) 247 | { 248 | xed_decoded_inst_set_immediate_signed_bits(&decoded_inst, linker->get_link_addr(used_link) + encode_data.additional_disp, 32); 249 | } 250 | else 251 | { 252 | xed_decoded_inst_set_immediate_unsigned_bits(&decoded_inst, linker->get_link_addr(used_link) + encode_data.additional_disp, 32); 253 | } 254 | } 255 | else if (flags & inst_flag::reloc_disp) 256 | { 257 | /*typename addr_width::storage::type abs_addr = binary->optional_header.get_image_base() + static_cast::type>(linker->get_link_addr(used_link)); 258 | if (!xed_patch_disp(&decoded_inst, dest, xed_disp(abs_addr, addr_width::bits::value))) 259 | { 260 | std::printf("Failed to patch reloc displacement at %X\n", dest - binary->mapped_image); 261 | } 262 | binary->remap_reloc(additional_data.reloc.original_rva, dest - binary->mapped_image + additional_data.reloc.offset_in_inst, additional_data.reloc.type);*/ 263 | 264 | printf("reloc not supported.\n"); 265 | return false; 266 | } 267 | else if (flags & inst_flag::reloc_imm) 268 | { 269 | /*typename addr_width::storage::type abs_addr = binary->optional_header.get_image_base() + static_cast::type>(linker->get_link_addr(used_link)); 270 | if (!xed_patch_imm0(&decoded_inst, dest, xed_imm0(abs_addr, addr_width::bits::value))) 271 | { 272 | std::printf("Failed to patch reloc imm at %X\n", dest - binary->mapped_image); 273 | } 274 | binary->remap_reloc(additional_data.reloc.original_rva, dest - binary->mapped_image + additional_data.reloc.offset_in_inst, additional_data.reloc.type);*/ 275 | 276 | printf("reloc not supported.\n"); 277 | return false; 278 | } 279 | // TODO: make these^ manipulate the reloc vector inside of the binary. 280 | 281 | return true; 282 | } 283 | uint32_t encode_to_binary(pex::binary_t* binary, linker_t* linker, uint8_t* dest) 284 | { 285 | if (!is_encoder_request) 286 | to_encoder_request(); 287 | 288 | if (custom_encoder) 289 | return custom_encoder(this, binary, linker, dest); 290 | 291 | uint32_t expected_length = length(); 292 | 293 | if (!resolve_deltas(binary, linker, dest, expected_length)) 294 | return 0; 295 | 296 | uint32_t ilen = 0; 297 | xed_error_enum_t err = xed_encode(&decoded_inst, dest, XED_MAX_INSTRUCTION_BYTES, &ilen); 298 | if (XED_ERROR_NONE != err) 299 | { 300 | return 0; 301 | } 302 | 303 | if (ilen != expected_length) 304 | { 305 | printf("Encoded inst length did not match what was expected.\n"); 306 | return 0; 307 | } 308 | 309 | return ilen; 310 | } 311 | 312 | finline uint32_t length() const 313 | { 314 | return xed_decoded_inst_get_length(&decoded_inst); 315 | } 316 | 317 | finline uint32_t noperands() const 318 | { 319 | return xed_decoded_inst_noperands(&decoded_inst); 320 | } 321 | 322 | finline uint32_t num_explicit_operands() const 323 | { 324 | auto _inst = inst(); 325 | auto _noperands = noperands(); 326 | uint32_t explicit_operands = 0; 327 | for (uint32_t i = 0; i < _noperands; ++i) 328 | { 329 | if (XED_OPVIS_EXPLICIT == xed_operand_operand_visibility(xed_inst_operand(_inst, i))) 330 | ++explicit_operands; 331 | } 332 | return explicit_operands; 333 | } 334 | 335 | finline const xed_inst_t* inst() const 336 | { 337 | return xed_decoded_inst_inst(&decoded_inst); 338 | } 339 | 340 | finline xed_iclass_enum_t iclass() const 341 | { 342 | return xed_decoded_inst_get_iclass(&decoded_inst); 343 | } 344 | 345 | finline xed_iform_enum_t iform() const 346 | { 347 | return xed_decoded_inst_get_iform_enum(&decoded_inst); 348 | } 349 | 350 | // I think this will always hold true... 351 | // 352 | finline uint8_t calc_reloc_offset() const 353 | { 354 | return length() - addr_width::bytes::value; 355 | } 356 | 357 | finline uint32_t effective_operand_width() const 358 | { 359 | return xed_operand_values_get_effective_operand_width(xed_decoded_inst_operands_const(&decoded_inst)); 360 | } 361 | 362 | finline xed_reg_enum_t get_reg(xed_operand_enum_t operand_name) const 363 | { 364 | return xed_decoded_inst_get_reg(&decoded_inst, operand_name); 365 | } 366 | 367 | finline xed_reg_enum_t get_base_reg(uint32_t mem_idx) const 368 | { 369 | return xed_decoded_inst_get_base_reg(&decoded_inst, mem_idx); 370 | } 371 | 372 | finline xed_reg_enum_t get_index_reg(uint32_t mem_idx) const 373 | { 374 | return xed_decoded_inst_get_index_reg(&decoded_inst, mem_idx); 375 | } 376 | 377 | finline uint32_t get_scale(uint32_t mem_idx) const 378 | { 379 | return xed_decoded_inst_get_scale(&decoded_inst, mem_idx); 380 | } 381 | 382 | finline long long get_memory_displacement(uint32_t mem_idx) const 383 | { 384 | return xed_decoded_inst_get_memory_displacement(&decoded_inst, mem_idx); 385 | } 386 | 387 | finline int get_signed_immediate() const 388 | { 389 | return xed_decoded_inst_get_signed_immediate(&decoded_inst); 390 | } 391 | 392 | finline int get_unsigned_immediate() const 393 | { 394 | return xed_decoded_inst_get_unsigned_immediate(&decoded_inst); 395 | } 396 | 397 | finline unsigned int operand_length(uint32_t operand_idx) const 398 | { 399 | return xed_decoded_inst_operand_length(&decoded_inst, operand_idx); 400 | } 401 | 402 | finline void common_edit(uint32_t mlink, uint32_t ulink, inst_flag::type flg) 403 | { 404 | my_link = mlink; 405 | used_link = ulink; 406 | flags |= flg; 407 | } 408 | 409 | }; 410 | 411 | using inst32_t = inst_t; 412 | using inst64_t = inst_t; 413 | 414 | template 415 | using inst_list_t = std::list>; 416 | 417 | template 418 | using inst_it_t = inst_list_t::iterator; 419 | 420 | using inst_list32_t = inst_list_t; 421 | using inst_list64_t = inst_list_t; 422 | 423 | using inst_it32_t = inst_list32_t::iterator; 424 | using inst_it64_t = inst_list64_t::iterator; 425 | 426 | template 427 | uint32_t calc_inst_list_size(inst_list_tconst& list) 428 | { 429 | uint32_t size = 0; 430 | for (auto const& inst : list) 431 | size += inst.length(); 432 | return size; 433 | } 434 | 435 | template 436 | uint8_t* dumb_encoder(inst_list_t& list, uint32_t& size) 437 | { 438 | size = calc_inst_list_size(list); 439 | 440 | uint8_t* res = new uint8_t[size]; 441 | uint8_t* base = res; 442 | 443 | for (auto& inst : list) 444 | { 445 | inst.to_encoder_request(); 446 | auto meme = inst.dumb_encode(res); 447 | res += meme; 448 | } 449 | 450 | return base; 451 | } 452 | } 453 | 454 | -------------------------------------------------------------------------------- /BDASM/ir.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "linker.h" 9 | 10 | // Going to use the same linker scheme as dasm 11 | // 12 | 13 | enum class operand_type_t : uint8_t 14 | { 15 | imm, 16 | reg, 17 | link, 18 | }; 19 | 20 | enum class operand_width_t : uint8_t 21 | { 22 | b8, 23 | b16, 24 | b32, 25 | b64, 26 | b128, 27 | b256, 28 | b512, 29 | }; 30 | 31 | 32 | enum class reg_id_t : uint64_t 33 | { 34 | // Instruction counter, 64 bit wide 35 | // 36 | ip, 37 | 38 | // Standard 64 bit gprs 39 | // 40 | r0, r1, r2, r3, r4, r5, r6, r7, 41 | r8, r9, r10, r11, r12, r13, r14, r15, 42 | 43 | // rt0-7 which are needed to lift 64bit gpr using insts 44 | // 45 | rt0, rt1, rt2, rt3, rt4, rt5, rt6, rt7, 46 | 47 | // SSE/AVX registers 48 | // 49 | f0, f1, f2, f3, f4, f5, f6, f7, 50 | f8, f9, f10, f11, f12, f13, f14, f15, 51 | f16, f17, f18, f19, f20, f21, f22, f23, 52 | f24, f25, f26, f27, f28, f29, f31, f31, 53 | 54 | // ft0-7 which are needed to lift these larger register using insts 55 | // 56 | ft0, ft1, ft2, ft3, ft4, ft5, ft6, ft7, 57 | 58 | 59 | // x87? O_O 60 | }; 61 | 62 | enum class ir_class_t : uint32_t 63 | { 64 | irc_nop, 65 | irc_mov, 66 | irc_ld, 67 | irc_st, 68 | irc_add, 69 | irc_sub, 70 | irc_mul, 71 | irc_div, 72 | irc_or, 73 | irc_and, 74 | irc_xor, 75 | irc_nand, 76 | irc_not, 77 | irc_jl, 78 | }; 79 | 80 | // Immediates have size 8 to 64 only 81 | // 82 | union ir_immediate_t 83 | { 84 | int8_t i8; 85 | int16_t i16; 86 | int32_t i32; 87 | int64_t i64; 88 | 89 | uint8_t u8; 90 | uint16_t u16; 91 | uint32_t u32; 92 | uint64_t u64; 93 | }; 94 | 95 | struct ir_operand_t 96 | { 97 | operand_type_t type; 98 | operand_width_t width; 99 | uint16_t flags; // Just a pad atm 100 | union 101 | { 102 | ir_immediate_t imm; 103 | reg_id_t reg; 104 | uint32_t link; // displacement/relbr 105 | uint64_t raw; 106 | }data; 107 | }; 108 | 109 | class ir_inst_t 110 | { 111 | ir_class_t inst_class; 112 | ir_operand_t operands[3]; 113 | 114 | bool validate() { return false; } 115 | void print() { std::printf("Instruction.\n"); } 116 | }; 117 | 118 | class ir_block_t 119 | { 120 | uint32_t link; 121 | std::list insts; 122 | }; 123 | 124 | union lifter_gpr_state_t 125 | { 126 | uint32_t a, b, c, d, sp, bp, si, di, 127 | r8, r9, r10, r11, r12, r13, r14, r15; 128 | uint32_t raw[16]; 129 | constexpr lifter_gpr_state_t() 130 | { 131 | for (uint32_t i = 0; i < 16; ++i) 132 | raw[i] = i; 133 | } 134 | }; 135 | 136 | void lift_instruction(ir_block_t* block, lifter_gpr_state_t* vars) 137 | { 138 | // Take for example the instruction xor rax,rbx 139 | // 140 | // in the ir it would be this. xor ++vars.a, vars.a, vars.b 141 | // 142 | // 143 | 144 | } 145 | 146 | 147 | void memes() 148 | { 149 | 150 | } 151 | 152 | -------------------------------------------------------------------------------- /BDASM/linker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | // This file is responsible for forming links between instructions 11 | // It does so by providing a common place for the instructions to look 12 | // for data based on an index into a table. The basic idea is that one 13 | // instruction sets the data in an initial placement pass, then the data 14 | // can be read and used by other instructions in an assembly pass. 15 | // 16 | namespace dasm 17 | { 18 | struct link_t 19 | { 20 | uint64_t addr; 21 | link_t() 22 | { 23 | addr = 0; 24 | } 25 | }; 26 | 27 | class linker_t 28 | { 29 | std::vector m_table; 30 | 31 | // Switch to a spinlock 32 | std::mutex m_lock; 33 | public: 34 | static constexpr uint32_t invalid_link_value = 0xFFFFFFFF; 35 | 36 | linker_t(uint32_t binary_size, uint32_t reserve_size = 0x1000) 37 | { 38 | m_table.reserve(binary_size + reserve_size); 39 | m_table.resize(binary_size); 40 | for (uint32_t i = 0; i < binary_size; i++) 41 | m_table[i].addr = i; 42 | } 43 | 44 | // Locking routine to allocate a certain amount of symbols 45 | // returns the min and max+1 value 46 | // 47 | std::pair get_link_bundle(uint32_t count) 48 | { 49 | std::lock_guard g(m_lock); 50 | uint32_t min = m_table.size(); 51 | m_table.resize(m_table.size() + count); 52 | return { min, min + count }; 53 | } 54 | 55 | uint32_t get_link_bundle_base(uint32_t count) 56 | { 57 | std::lock_guard g(m_lock); 58 | uint32_t min = m_table.size(); 59 | m_table.resize(m_table.size() + count); 60 | return min; 61 | } 62 | 63 | uint32_t allocate_link() 64 | { 65 | std::lock_guard g(m_lock); 66 | auto index = m_table.size(); 67 | m_table.emplace_back(); 68 | return index; 69 | } 70 | 71 | uint32_t allocate_link_no_lock() 72 | { 73 | auto index = m_table.size(); 74 | m_table.emplace_back(); 75 | return index; 76 | } 77 | 78 | finline link_t& get_link(uint32_t link_index) 79 | { 80 | return m_table[link_index]; 81 | } 82 | 83 | finline void set_link_addr(uint32_t link_index, uint64_t address) 84 | { 85 | /*if (link_index == 0) 86 | { 87 | printf("Setting 0th index to %p\n", address); 88 | }*/ 89 | m_table[link_index].addr = address; 90 | } 91 | finline uint64_t get_link_addr(uint32_t link_index) 92 | { 93 | /*if (m_table[link_index].addr == 0) 94 | { 95 | printf("Accessing a 0 addr.\n"); 96 | }*/ 97 | return m_table[link_index].addr; 98 | } 99 | }; 100 | 101 | } 102 | -------------------------------------------------------------------------------- /BDASM/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Problems: 4 | * - Seems as though the execption handlers are not found. Probably because 5 | * there is no direct jump into them. Maybe can ignore this for now... 6 | */ 7 | #include 8 | #include 9 | #include 10 | 11 | #include "inst.h" 12 | #include "sff.h" 13 | #include "symbol.h" 14 | #include "dasm.h" 15 | #include "pex.h" 16 | 17 | #include "dpattern.h" 18 | 19 | #include "obf.h" 20 | 21 | // Passes 22 | // 23 | #include "mba.h" 24 | #include "pi_blocks.h" 25 | #include "stack_allocation.h" 26 | #include "opaques.h" 27 | #include "original.h" 28 | #include "encrypted_blocks.h" 29 | #include "encrypted_routines.h" 30 | #include "flat_control.h" 31 | #include "constant_encryption.h" 32 | #include "virtual_operands.h" 33 | 34 | 35 | 36 | //uint8_t bytes[] = { 0xFF, 0x15, 0x00 ,0x30 ,0x40 ,0x00 }; 37 | //uint8_t bytes[] = { 0x48,0xFF ,0x15 ,0x39 ,0x6C ,0xC3 ,0xFF }; 38 | 39 | //#define image_name "C:\\$Fanta\\FntaDrvr\\x64\\Release\\ShellcodeMaker.exe" 40 | //#define image_name "C:\\Users\\Iizerd\\Desktop\\revers windas\\ntoskrnl.exe" 41 | //#define image_name "C:\\Users\\Iizerd\\Desktop\\revers windas\\dxgkrnl.sys" 42 | //#define image_name "C:\\$Fanta\\CV2\\x64\\Release\\CV2.exe" 43 | 44 | //#ifdef _DEBUG 45 | //#define image_name "C:\\$Work\\BDASM\\x64\\Debug\\TestExe.exe" 46 | //#define image_out "C:\\$Work\\BDASM\\x64\\Debug\\TestExe2.exe" 47 | //#else 48 | //#define image_name "C:\\@\\Work\\BDASM\\x64\\Release\\TestExe.exe" 49 | 50 | #define image_name "C:\\$Work\\BDASM\\x64\\Release\\TestExe.exe" 51 | 52 | //#define image_name "C:\\$Work\\CrackmeTest\\x64\\Release\\CrackmeTest.exe" 53 | 54 | //#define image_name "C:\\Users\\James\\Desktop\\Reverse Windas\\dxgkrnl.sys" 55 | #define image_out "C:\\$Work\\BDASM\\x64\\Release\\TestExe4.exe" 56 | //#endif 57 | 58 | //#define image_name "C:\\$Fanta\\sballizerdware\\x64\\Release\\FantaShellcode.exe" 59 | 60 | 61 | int main(int argc, char** argv) 62 | { 63 | srand(time(nullptr)); 64 | xed_tables_init(); 65 | 66 | 67 | dasm::linker_t linker(0x1000); 68 | std::list> blocks; 69 | auto& block = blocks.emplace_front(blocks.end()); 70 | //dasm::block_t<> block(blocks.end()); 71 | 72 | block.instructions.emplace_back( 73 | XED_ICLASS_MOV, 74 | 64, 75 | xed_reg(XED_REG_RAX), 76 | xed_reg(XED_REG_RBX) 77 | ); 78 | 79 | block.instructions.emplace_back( 80 | XED_ICLASS_ADD, 81 | 64, 82 | xed_reg(XED_REG_RAX), 83 | xed_reg(XED_REG_RBX) 84 | ); 85 | virtual_operands_t<>::routine_t routine; 86 | virtual_operands_t<>::convert_basic_block(linker, routine, blocks.begin()); 87 | 88 | for (auto& inst : routine.blocks.front().insts) 89 | { 90 | printf("Inst: %u\n", inst.flags); 91 | } 92 | 93 | printf("converted count %u\n", routine.blocks.begin()->insts.size()); 94 | 95 | system("pause"); 96 | 97 | return 1; 98 | 99 | /*uint32_t len = 0; 100 | obf::obf_t obf; 101 | obf.linker = new dasm::linker_t(0); 102 | 103 | virtual_operands_t::initialize_tables(); 104 | auto list = virtual_operands_t::build_vmenter(obf, 0, 0); 105 | auto res = dasm::dumb_encoder(list, len); 106 | 107 | for (uint32_t i = 0; i < len; i++) 108 | { 109 | std::printf("%02X ", res[i]); 110 | } 111 | printf("\n"); 112 | system("pause"); 113 | return 1;*/ 114 | 115 | 116 | obf::obf_t obfuscator; 117 | 118 | obfuscator.load_file(image_name); 119 | 120 | obfuscator.register_single_pass(); 121 | //obfuscator.register_single_pass(); 122 | //obfuscator.register_single_pass(); 123 | obfuscator.register_single_pass(); 124 | //obfuscator.register_single_pass(); 125 | //obfuscator.register_single_pass(0x100); 126 | //obfuscator.register_single_pass(); 127 | //obfuscator.register_single_pass(); 128 | //obfuscator.register_single_pass(); 129 | 130 | obfuscator.run_single_passes(); 131 | 132 | printf("staritng placement.\n"); 133 | //obfuscator.encode(obfuscator.place()); 134 | obfuscator.compile(); 135 | 136 | obfuscator.save_file(image_out); 137 | system("pause"); 138 | return 1; 139 | 140 | 141 | //uint8_t memes[] = { 0x48, 0x81, 0xEC, 0xB8, 0x22, 0x00, 0x00 }; 142 | 143 | //dasm::inst64_t inst; 144 | //inst.decode(memes, sizeof(memes)); 145 | //std::printf("iform is %s\n", xed_iform_enum_t2str(xed_decoded_inst_get_iform_enum(&inst.decoded_inst))); 146 | //std::printf("signed = %d\n", xed_decoded_inst_get_immediate_is_signed(&inst.decoded_inst)); 147 | 148 | //return 1; 149 | std::string binary_path = image_name; 150 | 151 | if (argc == 2) 152 | binary_path = argv[1]; 153 | 154 | addr_width::type width = pex::binary_t<>::deduce_address_width(binary_path); 155 | //printf("image size %u %u\n", address_width_to_bits(width), address_width_to_bytes(width)); 156 | 157 | std::ifstream SffFile(binary_path, std::ios::binary); 158 | SffFile.seekg(0, std::ios::end); 159 | size_t FileLength = SffFile.tellg(); 160 | SffFile.seekg(0, std::ios::beg); 161 | uint8_t* FileBuffer = (uint8_t*)malloc(FileLength); 162 | if (!FileBuffer) 163 | return 1; 164 | SffFile.read((PCHAR)FileBuffer, FileLength); 165 | SffFile.close(); 166 | 167 | 168 | 169 | if (width == addr_width::x86) 170 | { 171 | pex::binary_t binary; 172 | if (!binary.map_image(FileBuffer, FileLength)) 173 | printf("failed.\n"); 174 | } 175 | else if (width == addr_width::x64) 176 | { 177 | pex::binary_t binary; 178 | if (!binary.map_image(FileBuffer, FileLength)) 179 | printf("failed.\n"); 180 | 181 | printf("Entry point %X\n", binary.optional_header.get_address_of_entry_point()); 182 | 183 | dasm::decoder_context_t context(&binary); 184 | context.settings.recurse_calls = true; 185 | context.linker = new dasm::linker_t(binary.optional_header.get_size_of_image(), 0x10000); 186 | 187 | dasm::dasm_t disassembler(&context); 188 | 189 | disassembler.add_routine(binary.optional_header.get_address_of_entry_point()); 190 | 191 | 192 | for (auto& exp : binary.m_exports.entries) 193 | { 194 | disassembler.add_routine(exp.rva); 195 | } 196 | 197 | uint32_t count = 0; 198 | auto addr = binary.mapped_image + binary.optional_header.get_data_directory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).get_virtual_address(); 199 | for (pex::image_runtime_function_it_t m_runtime_functions(reinterpret_cast(addr)); 200 | !m_runtime_functions.is_null(); ++m_runtime_functions) 201 | { 202 | if (binary.is_rva_in_executable_section(m_runtime_functions.get_begin_address())) 203 | disassembler.add_routine(m_runtime_functions.get_begin_address()); 204 | count++; 205 | } 206 | printf("added %u runtime functions\n", count); 207 | auto start_time = std::chrono::high_resolution_clock::now(); 208 | disassembler.run(); 209 | disassembler.wait_for_completion(); 210 | 211 | auto time = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start_time); 212 | 213 | printf("Took %ums\n", time.count()); 214 | 215 | printf("Found %llu routines.\n", disassembler.completed_routines.size()); 216 | 217 | uint32_t block_count = 0; 218 | uint32_t block_max = 0; 219 | uint32_t rva_of_max; 220 | for (auto& rou : disassembler.completed_routines) 221 | { 222 | /*for (auto& block : rou.blocks) 223 | { 224 | if (block.termination_type == dasm::termination_type_t::invalid) 225 | std::printf("block terminatn invalid at %X %X\n", block.rva_start, block.rva_end); 226 | }*/ 227 | block_count += rou.blocks.size(); 228 | if (rou.blocks.size() > block_max) 229 | { 230 | block_max = rou.blocks.size(); 231 | rva_of_max = rou.entry_link; 232 | } 233 | } 234 | 235 | std::printf("Found %u blocks. %u was the max in one func(%X)\n", block_count, block_max, rva_of_max); 236 | 237 | std::set rvaset; 238 | 239 | /*for (auto& rou : disassembler.completed_routines) 240 | { 241 | rvaset.insert(rou.original_entry_rva); 242 | } 243 | 244 | std::ifstream filememe2("C:\\@\\Work\\BDASM\\x64\\Release\\test.txt"); 245 | std::string temp = ""; 246 | while (filememe2 >> temp) 247 | { 248 | rvaset.erase(std::stoull(temp, nullptr, 16)); 249 | }*/ 250 | 251 | 252 | //std::ifstream filememe2("C:\\@\\Work\\BDASM\\x64\\Release\\test.txt"); 253 | //std::string temp = ""; 254 | //while (filememe2 >> temp) 255 | //{ 256 | // rvaset.insert(std::stoull(temp, nullptr, 16)); 257 | //} 258 | 259 | //std::vector sorted_rvas; 260 | //for (auto& rou : disassembler.completed_routines) 261 | //{ 262 | // sorted_rvas.push_back(rou.entry_link); 263 | // rvaset.erase(rou.entry_link); 264 | //} 265 | 266 | 267 | //std::sort(std::begin(sorted_rvas), end(sorted_rvas)); 268 | //std::ofstream rvasfile("C:\\@\\Work\\BDASM\\x64\\Release\\rvas.txt"); 269 | //for (auto const rva : sorted_rvas) 270 | // rvasfile << "0x" << std::hex << rva << "\n"; 271 | //rvasfile.close(); 272 | 273 | 274 | /*for (auto rva : rvaset) 275 | { 276 | std::printf("Rva: %X\n", rva); 277 | }*/ 278 | 279 | printf("total: %llu\n", rvaset.size()); 280 | 281 | /*for (auto& rou : disassembler.completed_routines) 282 | { 283 | if (rou.entry_link == 0x1030) 284 | { 285 | rou.blocks.sort([](dasm::block_t const& l, dasm::block_t const& r) 286 | { 287 | return (l.rva_start < r.rva_start); 288 | }); 289 | printf("Found main:\n"); 290 | for (auto& blo : rou.blocks) 291 | { 292 | std::printf("Block: %X\n", blo.rva_start, blo.rva_end); 293 | for (auto& inst : blo.instructions) 294 | std::printf("\t%s\n", xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(&inst.decoded_inst))); 295 | if (blo.fallthrough_block != rou.blocks.end()) 296 | std::printf("Fallthrough %X\n", blo.fallthrough_block->rva_start); 297 | } 298 | } 299 | }*/ 300 | 301 | auto& routine = disassembler.completed_routines.front(); 302 | 303 | routine.blocks.sort([](dasm::block_t const& l, dasm::block_t const& r) 304 | { 305 | return (l.rva_start < r.rva_start); 306 | }); 307 | printf("Found main:\n"); 308 | //routine.print_blocks(); 309 | uint32_t i = 0; 310 | 311 | //routine.blocks.front().clear(); 312 | //std::next(routine.blocks.begin())->clear(); 313 | //std::prev(routine.blocks.end())->clear(); 314 | //for (auto it = routine.begin(); it != routine.end(); ++it) 315 | //{ 316 | // i++; 317 | // printf("IClass %s\n", xed_iclass_enum_t2str(xed_decoded_inst_get_iclass(&it->decoded_inst))); 318 | //} 319 | system("pause"); 320 | for (auto& block : routine.blocks) 321 | for (auto& inst : block.instructions) 322 | i++; 323 | // SHOULD SEE 98 instructions 324 | printf("%u instructions at %X\n", i, routine.entry_link); 325 | 326 | } 327 | else 328 | printf("invalid addr width."); 329 | 330 | 331 | system("pause"); 332 | } 333 | 334 | 335 | 336 | //uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 337 | 338 | //dasm::inst_t inst( 339 | // XED_ICLASS_NOP, 340 | // 32 341 | //); 342 | 343 | ///*dasm::inst_t inst; 344 | 345 | // 346 | 347 | //auto len = encode_inst_in_place(buffer, addr_width::machine_state::value, 348 | // XED_ICLASS_XCHG, 349 | // 8, 350 | // xed_mem_bd( 351 | // max_reg_width::value, 352 | // xed_disp(0, 32), 353 | // 8 354 | // ), 355 | // xed_reg(XED_REG_AL) 356 | //);*/ 357 | 358 | 359 | //inst.dumb_encode(buffer); 360 | 361 | //for (auto i = 0; i < inst.length(); i++) 362 | //{ 363 | // std::printf("%02X ", buffer[i]); 364 | //} 365 | //std::printf("\n"); 366 | 367 | //return 1; 368 | 369 | /* 370 | auto rand_val = ((0x24121 << 4) | (1 << 0)); 371 | 372 | auto addr = 0xC00023; 373 | auto temp = addr; 374 | do 375 | { 376 | addr += rand_val; 377 | } while (addr & 0xF); 378 | 379 | do 380 | { 381 | addr -= (rand_val - 1); 382 | } while (temp < addr); 383 | 384 | addr += (rand_val - 1); 385 | 386 | printf("Results are %X %X\n", addr, rand_val, temp); 387 | */ 388 | 389 | 390 | 391 | 392 | 393 | //// for writeup 394 | // 395 | // 396 | //template 397 | //uint32_t get_len_of_mov_reg_imm() 398 | //{ 399 | // uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 400 | // return encode_inst_in_place( 401 | // buffer, 402 | // addr_width::machine_state::value, // Machine state template 403 | // XED_ICLASS_MOV, // Instruction Class 404 | // addr_width::bits::value, // Effective operand width template 405 | // max_reg_width::value, // Equates to max size of a given register based on address width 406 | // xed_imm0( // Creates an immediate value of size 32 or 64 based on '' 407 | // 0xABBA, 408 | // addr_width::bits::value, 409 | // ) 410 | // ); 411 | //} -------------------------------------------------------------------------------- /BDASM/mba.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /* 4 | NAND: 5 | AND A,B 6 | NOT A 7 | 8 | 9 | 10 | ADD: 11 | A + B == ~A - ~B 12 | 13 | SUB: 14 | A - B == ~A + ~B 15 | 16 | OR: 17 | 18 | 19 | NOT: 20 | ~A == A ^ ~0 21 | */ 22 | 23 | #include "obf.h" 24 | 25 | struct mba_t 26 | { 27 | //template 28 | //class expression_t 29 | //{ 30 | // // Emit as instructions 31 | // virtual dasm::inst_list_t emit() = 0; 32 | //}; 33 | 34 | 35 | // percent_chance: 0-100 chance to mutate a possible inst 36 | // min_count: minimum number of instructions to mutate 37 | // red_space_store: store variables in unallocated stack memory 38 | // 39 | template 40 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx, uint32_t percent_chance, uint32_t min_count, bool red_space_store = false) 41 | { 42 | 43 | } 44 | }; 45 | 46 | -------------------------------------------------------------------------------- /BDASM/obf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "align.h" 7 | #include "dasm.h" 8 | #include "flags.h" 9 | 10 | namespace obf 11 | { 12 | enum class pass_status_t 13 | { 14 | // Complete and total failure that means we need to scrub the whole process 15 | // 16 | critical_failure, 17 | 18 | // Failure but its ok, the routine is still intact and we can proceed with other routines 19 | // 20 | failure, 21 | 22 | // 23 | // 24 | success, 25 | }; 26 | 27 | 28 | /*template 29 | class routine_t;*/ 30 | 31 | template 32 | class obf_t; 33 | 34 | //template 35 | //struct context_t 36 | //{ 37 | // dasm::linker_t& linker; 38 | // pex::binary_t& bin; 39 | // std::list>& obf_routines; 40 | // std::list>& additional_routines; 41 | //}; 42 | 43 | template 44 | class routine_t 45 | { 46 | public: 47 | dasm::routine_t& m_routine; 48 | 49 | // Space the original function occupied, how much we have to place a jump 50 | // 51 | uint32_t original_space; 52 | public: 53 | 54 | routine_t(dasm::routine_t& routine, uint32_t space) 55 | : m_routine(routine) 56 | , original_space(space) 57 | {} 58 | 59 | template 60 | pass_status_t mutation_pass(obf_t& ctx, Params... params) 61 | { 62 | return Pass_type::pass(m_routine, ctx, params...); 63 | } 64 | }; 65 | 66 | namespace data_flag 67 | { 68 | typedef uint32_t type; 69 | constexpr type none = 0; 70 | 71 | // data = rva(link1) 72 | constexpr type rva_32 = (1 << 0); 73 | constexpr type rva_64 = (1 << 1); 74 | 75 | // data = rva(link2) - rva(link1) 76 | constexpr type disp_32 = (1 << 3); 77 | 78 | // data = rva(link1) - link2 79 | // This is used by the virtualized to resolve rip relative displacements. 80 | // Treats link2 as an adjustment(displacement in virt inst wont be at rip) 81 | // 82 | constexpr type disp_from_me_32 = (1 << 4); 83 | 84 | } 85 | 86 | template 87 | class data_chunk_t 88 | { 89 | std::vector> patches; 90 | 91 | std::vector> links; 92 | public: 93 | std::vector raw_data; 94 | 95 | void add_patch(uint32_t offset, data_flag::type flags, uint32_t link1, uint32_t link2) 96 | { 97 | patches.emplace_back(offset, flags, link1, link2); 98 | } 99 | 100 | void add_link(uint32_t link, uint32_t offset) 101 | { 102 | links.emplace_back(link, offset); 103 | } 104 | 105 | // For the placement pass 106 | // 107 | void place_in_binary(uint64_t& rva, dasm::linker_t* linker) 108 | { 109 | for (auto [link, offset] : links) 110 | { 111 | linker->set_link_addr(link, rva + offset); 112 | } 113 | rva += raw_data.size(); 114 | } 115 | 116 | // For the encode/write pass. using memcpy because of possible unaligned writes 117 | // 118 | void write_to_binary(uint8_t* data, dasm::linker_t* linker) 119 | { 120 | for (auto [offset, flags, link1, link2] : patches) 121 | { 122 | if (flags & data_flag::rva_32) 123 | { 124 | uint32_t rva = linker->get_link_addr(link1); 125 | std::memcpy(data + offset, &rva, sizeof uint32_t); 126 | } 127 | else if (flags & data_flag::rva_64) 128 | { 129 | uint64_t rva = linker->get_link_addr(link1); 130 | std::memcpy(data + offset, &rva, sizeof uint64_t); 131 | } 132 | else if (flags & data_flag::disp_32) 133 | { 134 | int64_t dest = linker->get_link_addr(link2); 135 | int64_t source = linker->get_link_addr(link1); 136 | int32_t disp = dest - source; 137 | std::memcpy(data + offset, &disp, sizeof(int32_t)); 138 | } 139 | } 140 | } 141 | }; 142 | 143 | //https://www.youtube.com/watch?v=pXwbj_ZPKwg&ab_channel=VvporTV 144 | // 145 | template 146 | class obf_t 147 | { 148 | std::vector&, obf_t&)>> single_passes; 149 | 150 | dasm::decoder_context_t* m_decoder_context; 151 | 152 | uint32_t func_alignment; 153 | 154 | uint32_t block_alignment; 155 | public: 156 | dasm::linker_t* linker; 157 | 158 | dasm::dasm_t* dasm; 159 | 160 | pex::binary_t* bin; 161 | 162 | std::list> obf_routines; 163 | 164 | std::list> data_chunks; 165 | 166 | // These are routines that are added after the fact and we dont want to apply obfuscation passes to. 167 | // 168 | std::list> additional_routines; 169 | 170 | obf_t() 171 | : dasm(nullptr) 172 | , m_decoder_context(nullptr) 173 | , linker(nullptr) 174 | , bin(new pex::binary_t) 175 | , func_alignment(1) 176 | , block_alignment(1) 177 | {} 178 | 179 | ~obf_t() 180 | { 181 | if (dasm) 182 | delete dasm; 183 | if (m_decoder_context) 184 | delete m_decoder_context; 185 | if (linker) 186 | delete linker; 187 | 188 | delete bin; 189 | } 190 | 191 | 192 | bool set_func_alignment(uint32_t new_alignment) 193 | { 194 | if (func_alignment == 1) 195 | { 196 | func_alignment = new_alignment; 197 | return true; 198 | } 199 | return false; 200 | } 201 | 202 | bool set_block_alignment(uint32_t new_alignment) 203 | { 204 | if (block_alignment == 1) 205 | { 206 | block_alignment = new_alignment; 207 | return true; 208 | } 209 | return false; 210 | } 211 | 212 | bool routine_analysis(dasm::routine_t& routine, uint32_t& start_size) 213 | { 214 | uint32_t start = routine.entry_block->rva_start; 215 | uint32_t end = routine.entry_block->rva_end; 216 | start_size = end - start; 217 | 218 | std::vector*> blocks; 219 | for (auto& block : routine.blocks) 220 | blocks.emplace_back(&block); 221 | 222 | for (uint32_t i = 0; i < blocks.size();) 223 | { 224 | if (blocks[i]->termination_type == dasm::termination_type_t::invalid) 225 | { 226 | printf("Invalid block at [%X:%X]\n", blocks[i]->rva_start, blocks[i]->rva_end); 227 | return false; 228 | } 229 | if (blocks[i]->rva_start == end) 230 | { 231 | end = blocks[i]->rva_end; 232 | std::swap(blocks[i], blocks[blocks.size() - 1]); 233 | blocks.pop_back(); 234 | i = 0; 235 | } 236 | else 237 | ++i; 238 | } 239 | 240 | start_size = end - start; 241 | 242 | return true; 243 | } 244 | 245 | bool load_file(std::string const& file_path) 246 | { 247 | std::ifstream file(file_path, std::ios::binary); 248 | if (!file.good()) 249 | return false; 250 | 251 | file.seekg(0, std::ios::end); 252 | size_t file_length = file.tellg(); 253 | file.seekg(0, std::ios::beg); 254 | uint8_t* file_buffer = (uint8_t*)malloc(file_length); 255 | if (!file_buffer) 256 | return false; 257 | file.read((PCHAR)file_buffer, file_length); 258 | file.close(); 259 | 260 | if (!bin->map_image(file_buffer, file_length)) 261 | return false; 262 | 263 | linker = new dasm::linker_t(bin->optional_header.get_size_of_image(), 0x10000); 264 | 265 | m_decoder_context = new dasm::decoder_context_t(bin); 266 | m_decoder_context->settings.recurse_calls = true; 267 | m_decoder_context->linker = linker; 268 | 269 | dasm = new dasm::dasm_t(m_decoder_context); 270 | 271 | // First we add all runtime func as possible entries 272 | // 273 | /*auto addr = bin->mapped_image + bin->optional_header.get_data_directory(IMAGE_DIRECTORY_ENTRY_EXCEPTION).get_virtual_address(); 274 | for (pex::image_runtime_function_it_t m_runtime_functions(reinterpret_cast(addr)); 275 | !m_runtime_functions.is_null(); ++m_runtime_functions) 276 | { 277 | dasm->add_routine(m_runtime_functions.get_begin_address()); 278 | }*/ 279 | 280 | 281 | // Add all exports, which we are SURE make functions 282 | // 283 | for (auto& exprt : bin->m_exports.entries) 284 | { 285 | dasm->add_routine(exprt.rva, true); 286 | } 287 | 288 | // Finally we add the entry point 289 | // 290 | if (auto entry = bin->optional_header.get_address_of_entry_point(); entry) 291 | dasm->add_routine(entry, true); 292 | 293 | 294 | dasm->run(); 295 | 296 | dasm->wait_for_completion(); 297 | 298 | for (auto& routine : dasm->completed_routines) 299 | { 300 | if (uint32_t size = 0; routine_analysis(routine, size) && size > 5) 301 | { 302 | routine.promote_relbrs(); 303 | obf_routines.emplace_back(routine, size); 304 | } 305 | } 306 | } 307 | 308 | void save_file(std::string const& file_path) 309 | { 310 | uint32_t data_size = 0; 311 | auto data = bin->unmap_image(data_size); 312 | 313 | std::ofstream file(file_path, std::ios::binary); 314 | file.write(reinterpret_cast(data), data_size); 315 | file.close(); 316 | } 317 | 318 | 319 | template 320 | pass_status_t group_pass(Params... params) 321 | { 322 | return Pass_type::pass(*this, params...); 323 | } 324 | 325 | template 326 | void register_single_pass(Params... params) 327 | { 328 | single_passes.push_back(std::bind(&Pass_type::template pass, std::placeholders::_1, std::placeholders::_2, params...)); 329 | } 330 | 331 | void run_single_passes() 332 | { 333 | //context_t context = { *linker, *bin, obf_routines, additional_routines }; 334 | 335 | for (auto& routine : obf_routines) 336 | { 337 | for (auto& block : routine.m_routine.blocks) 338 | for (auto& inst : block.instructions) 339 | inst.redecode(); 340 | 341 | /*routine.m_routine.blocks.sort([](dasm::block_t& left, dasm::block_t& right) 342 | { 343 | return left.rva_start < right.rva_start; 344 | });*/ 345 | 346 | for (auto pass : single_passes) 347 | { 348 | pass(routine.m_routine, *this); 349 | } 350 | 351 | /*for (auto block_it = routine.m_routine.blocks.begin(); block_it != routine.m_routine.blocks.end(); ++block_it) 352 | { 353 | for (auto inst_it = block_it->instructions.begin(); inst_it != block_it->instructions.end(); ++inst_it) 354 | { 355 | auto cat = xed_decoded_inst_get_category(&inst_it->decoded_inst); 356 | 357 | if (cat == XED_CATEGORY_COND_BR) 358 | { 359 | if (!(inst_it->flags & dasm::inst_flag::block_terminator)) 360 | { 361 | std::printf("was not block terminator. %X\n", inst_it->original_rva); 362 | } 363 | if (std::next(inst_it) != block_it->instructions.end()) 364 | { 365 | std::printf("was not last instruction. %X\n", inst_it->original_rva); 366 | } 367 | } 368 | } 369 | }*/ 370 | } 371 | 372 | } 373 | 374 | // These two functions REQUIRE that the order is not changed between their calls 375 | // Must be called one after the other 376 | // 377 | uint64_t place_routines() 378 | { 379 | uint64_t rva = bin->next_section_rva(); 380 | auto base = rva; 381 | for (auto& routine : obf_routines) 382 | { 383 | 384 | for (auto block_it = routine.m_routine.blocks.begin(); block_it != routine.m_routine.blocks.end(); ++block_it) 385 | { 386 | if (block_it == routine.m_routine.entry_block) 387 | linker->set_link_addr(routine.m_routine.entry_link, rva); 388 | 389 | block_it->place_in_binary(rva, linker); 390 | 391 | rva = align_up(rva, block_alignment); 392 | } 393 | 394 | rva = align_up(rva, func_alignment); 395 | } 396 | 397 | for (auto& routine : additional_routines) 398 | { 399 | 400 | for (auto block_it = routine.blocks.begin(); block_it != routine.blocks.end(); ++block_it) 401 | { 402 | if (block_it == routine.entry_block) 403 | linker->set_link_addr(routine.entry_link, rva); 404 | 405 | block_it->place_in_binary(rva, linker); 406 | 407 | rva = align_up(rva, block_alignment); 408 | } 409 | 410 | rva = align_up(rva, func_alignment); 411 | } 412 | 413 | return bin->append_section(".OBFCODE", rva - base, IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_WRITE, true); 414 | } 415 | void encode_routines(uint64_t rva) 416 | { 417 | //uint64_t rva = bin->append_section(".TEST", section_size, IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_WRITE, true); 418 | auto dest = bin->mapped_image + rva; 419 | for (auto& routine : obf_routines) 420 | { 421 | for (auto& block : routine.m_routine.blocks) 422 | { 423 | block.encode_in_binary(bin, linker, &dest); 424 | 425 | dest = align_up_ptr(dest, block_alignment); 426 | } 427 | 428 | dest = align_up_ptr(dest, func_alignment); 429 | 430 | if (0 && routine.original_space >= 15) 431 | { 432 | int32_t random = rand() % 0xFFFF; 433 | uint32_t rva = routine.m_routine.entry_block->rva_start; 434 | uint32_t off = encode_inst_in_place( 435 | bin->mapped_image + rva, 436 | addr_width::machine_state::value, 437 | XED_ICLASS_LEA, 438 | addr_width::bits::value, 439 | xed_reg(max_reg_width::value), 440 | xed_mem_bd( 441 | max_reg_width::value, 442 | xed_disp(-static_cast(rva + 7) + random, 32), 443 | addr_width::bits::value 444 | ) 445 | ); 446 | off += encode_inst_in_place( 447 | bin->mapped_image + rva + off, 448 | addr_width::machine_state::value, 449 | XED_ICLASS_ADD, 450 | addr_width::bits::value, 451 | xed_reg(max_reg_width::value), 452 | xed_simm0(linker->get_link_addr(routine.m_routine.entry_block->link) - random, 32) 453 | ); 454 | encode_inst_in_place( 455 | bin->mapped_image + rva + off, 456 | addr_width::machine_state::value, 457 | XED_ICLASS_JMP, 458 | addr_width::bits::value, 459 | xed_reg(max_reg_width::value) 460 | ); 461 | 462 | } 463 | else 464 | { 465 | 466 | // Put a jump at the location of the original function, in case we didnt disassemble something 467 | // 468 | int32_t disp = linker->get_link_addr(routine.m_routine.entry_block->link) - routine.m_routine.entry_block->rva_start - 5; 469 | encode_inst_in_place( 470 | bin->mapped_image + routine.m_routine.entry_block->rva_start, 471 | addr_width::machine_state::value, 472 | XED_ICLASS_JMP, 473 | 32, 474 | xed_relbr(disp, 32) 475 | ); 476 | } 477 | } 478 | 479 | for (auto& routine : additional_routines) 480 | { 481 | for (auto& block : routine.blocks) 482 | { 483 | block.encode_in_binary(bin, linker, &dest); 484 | 485 | dest = align_up_ptr(dest, block_alignment); 486 | } 487 | 488 | dest = align_up_ptr(dest, block_alignment); 489 | 490 | dest = align_up_ptr(dest, func_alignment); 491 | } 492 | 493 | } 494 | 495 | uint64_t place_data() 496 | { 497 | uint64_t rva = bin->next_section_rva(); 498 | auto base = rva; 499 | for (auto& data_chunk : data_chunks) 500 | { 501 | data_chunk.place_in_binary(rva, linker); 502 | rva = align_up(rva, 0x8); 503 | } 504 | return bin->append_section(".OBFDATA", rva - base, IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_WRITE, true); 505 | } 506 | void write_data(uint64_t rva) 507 | { 508 | auto dest = bin->mapped_image + rva; 509 | for (auto& data_chunk : data_chunks) 510 | { 511 | data_chunk.write_to_binary(dest, linker); 512 | dest = align_up_ptr(dest, 0x8); 513 | } 514 | } 515 | 516 | void compile() 517 | { 518 | uint64_t data_rva = 0; 519 | auto code_rva = place_routines(); 520 | 521 | if (data_chunks.size()) 522 | data_rva = place_data(); 523 | 524 | encode_routines(code_rva); 525 | 526 | if (data_chunks.size()) 527 | write_data(data_rva); 528 | } 529 | }; 530 | } 531 | 532 | 533 | //void meme() 534 | //{ 535 | // dasm::routine_t routine; 536 | // obf::routine_t obfr(routine); 537 | // obf::obf_t ctx; 538 | // ctx.bin = nullptr; 539 | // ctx.linker = nullptr; 540 | // obfr.mutation_pass>(ctx); 541 | //} -------------------------------------------------------------------------------- /BDASM/opaques.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #include "obf.h" 5 | #include "flags.h" 6 | 7 | // Locate places where we know the state of certain flags, then jump based on them 8 | // Example1: trace forward the flag used by a jcc, find where its written to again, and right before then place an opaque 9 | // Example2: find places where constant values are moved into registers, trace forward until they are potentially invalidated and 10 | // place an opaque right before 11 | // 12 | // 13 | // 14 | 15 | // Trace flags after a previous conditional jump until it is written to, then insert a branch before that 16 | // using the known flag value 17 | // 18 | struct opaque_from_flags_t 19 | { 20 | // Will be using bitwise on the visited member here beacuse we need to differentiate 21 | // 22 | 23 | constexpr static uint32_t visited_1 = (1 << 0); 24 | constexpr static uint32_t visited_2 = (1 << 1); 25 | 26 | template 27 | struct my_context 28 | { 29 | dasm::routine_t& routine; 30 | obf::obf_t& ctx; 31 | my_context(dasm::routine_t& r, obf::obf_t& context) 32 | : routine(r) 33 | , ctx(context) 34 | {} 35 | }; 36 | 37 | template 38 | static bool multiple_references(my_context& ctx, dasm::block_it_t check_block) 39 | { 40 | if (check_block == ctx.routine.blocks.end()) 41 | return false; 42 | uint32_t count = 0; 43 | for (auto& block : ctx.routine.blocks) 44 | { 45 | if (block.fallthrough_block == check_block || block.taken_block == check_block) 46 | ++count; 47 | } 48 | return count > 1; 49 | } 50 | 51 | static xed_iclass_enum_t invert_jcc(xed_iclass_enum_t jcc) 52 | { 53 | switch (jcc) 54 | { 55 | case XED_ICLASS_JB: return XED_ICLASS_JNB; 56 | case XED_ICLASS_JBE: return XED_ICLASS_JNBE; 57 | case XED_ICLASS_JL: return XED_ICLASS_JNL; 58 | case XED_ICLASS_JLE: return XED_ICLASS_JNLE; 59 | case XED_ICLASS_JNB: return XED_ICLASS_JB; 60 | case XED_ICLASS_JNBE: return XED_ICLASS_JBE; 61 | case XED_ICLASS_JNL: return XED_ICLASS_JL; 62 | case XED_ICLASS_JNLE: return XED_ICLASS_JLE; 63 | case XED_ICLASS_JNO: return XED_ICLASS_JO; 64 | case XED_ICLASS_JNP: return XED_ICLASS_JP; 65 | case XED_ICLASS_JNS: return XED_ICLASS_JS; 66 | case XED_ICLASS_JNZ: return XED_ICLASS_JZ; 67 | case XED_ICLASS_JO: return XED_ICLASS_JNO; 68 | case XED_ICLASS_JP: return XED_ICLASS_JNP; 69 | case XED_ICLASS_JS: return XED_ICLASS_JNS; 70 | case XED_ICLASS_JZ: return XED_ICLASS_JNZ; 71 | default: return XED_ICLASS_INVALID; 72 | } 73 | } 74 | 75 | static bool is_bad_iclass(xed_iclass_enum_t iclass) 76 | { 77 | switch (iclass) 78 | { 79 | case XED_ICLASS_CALL_NEAR: 80 | case XED_ICLASS_SYSCALL: 81 | case XED_ICLASS_RET_NEAR: 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | template 88 | static void reset_visited_2(dasm::routine_t& routine) 89 | { 90 | for (auto& block : routine.blocks) 91 | { 92 | block.visited &= ~visited_2; 93 | } 94 | } 95 | 96 | template 97 | static uint32_t find_random_link(my_context& ctx) 98 | { 99 | auto routine_it = ctx.ctx.obf_routines.begin(); 100 | std::advance(routine_it, rand() % ctx.ctx.obf_routines.size()); 101 | 102 | auto block_it_t = routine_it->m_routine.blocks.begin(); 103 | std::advance(block_it_t, rand() % routine_it->m_routine.blocks.size()); 104 | 105 | auto inst_it = block_it_t->instructions.begin(); 106 | std::advance(inst_it, rand() % block_it_t->instructions.size()); 107 | 108 | return inst_it->my_link; 109 | } 110 | 111 | 112 | template 113 | static void recursive_trace_and_place(dasm::block_it_t block, my_context& ctx, xed_iclass_enum_t iclass, const xed_flag_set_t* flag_set, bool taken) 114 | { 115 | if (block->visited & visited_2) 116 | return; 117 | 118 | auto place_jcc = [&](dasm::inst_it_t inst_it) 119 | { 120 | //printf("opaqued.\n"); 121 | 122 | if (taken) 123 | iclass = invert_jcc(iclass); 124 | 125 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 126 | 127 | auto jcc = block->instructions.emplace(inst_it); 128 | jcc->decode( 129 | buffer, 130 | encode_inst_in_place( 131 | buffer, 132 | addr_width::machine_state::value, 133 | iclass, 134 | 32, 135 | xed_relbr(0, 32) 136 | ) 137 | ); 138 | jcc->my_link = ctx.ctx.linker->allocate_link(); 139 | jcc->used_link = find_random_link(ctx); 140 | jcc->original_rva = 0; 141 | jcc->flags |= dasm::inst_flag::rel_br; 142 | 143 | }; 144 | 145 | for (auto inst_it = block->instructions.begin(); inst_it != block->instructions.end(); ++inst_it) 146 | { 147 | auto simple_flag = xed_decoded_inst_get_rflags_info(&inst_it->decoded_inst); 148 | if (is_bad_iclass(inst_it->iclass()) || (simple_flag && (flag_set->flat & (xed_simple_flag_get_undefined_flag_set(simple_flag)->flat | xed_simple_flag_get_written_flag_set(simple_flag)->flat)))) 149 | { 150 | place_jcc(inst_it); 151 | 152 | return; 153 | } 154 | } 155 | 156 | 157 | /* block->visited |= visited_2; 158 | if (!multiple_references(ctx, block->fallthrough_block) && !multiple_references(ctx, block->taken_block)) 159 | block->invoke_for_next(recursive_trace_and_place, ctx, iclass, flag_set, taken); 160 | */ 161 | 162 | 163 | switch (block->termination_type) 164 | { 165 | case dasm::termination_type_t::invalid: 166 | case dasm::termination_type_t::returns: 167 | break; 168 | 169 | case dasm::termination_type_t::unconditional_br: 170 | if (!multiple_references(ctx, block->taken_block)) 171 | recursive_trace_and_place(block->taken_block, ctx, iclass, flag_set, taken); 172 | else 173 | place_jcc(std::prev(block->instructions.end())); 174 | break; 175 | 176 | case dasm::termination_type_t::conditional_br: 177 | if (!multiple_references(ctx, block->taken_block) && !multiple_references(ctx, block->fallthrough_block)) 178 | { 179 | recursive_trace_and_place(block->taken_block, ctx, iclass, flag_set, taken); 180 | recursive_trace_and_place(block->fallthrough_block, ctx, iclass, flag_set, taken); 181 | } 182 | else 183 | place_jcc(std::prev(block->instructions.end())); 184 | break; 185 | case dasm::termination_type_t::fallthrough: 186 | if (!multiple_references(ctx, block->fallthrough_block)) 187 | recursive_trace_and_place(block->fallthrough_block, ctx, iclass, flag_set, taken); 188 | else 189 | place_jcc(block->instructions.end()); 190 | break; 191 | case dasm::termination_type_t::undetermined_unconditional_br: 192 | place_jcc(std::prev(block->instructions.end())); 193 | break; 194 | case dasm::termination_type_t::unknown_logic: 195 | break; 196 | } 197 | } 198 | 199 | template 200 | static void recursive_application(dasm::block_it_t block, my_context& ctx) 201 | { 202 | if (block->visited & visited_1) 203 | return; 204 | 205 | 206 | if (block->termination_type == dasm::termination_type_t::conditional_br) 207 | { 208 | auto simple_flag = xed_decoded_inst_get_rflags_info(&block->instructions.back().decoded_inst); 209 | auto read_flags = xed_simple_flag_get_read_flag_set(simple_flag); 210 | auto iclass = block->instructions.back().iclass(); 211 | 212 | 213 | ctx.routine.reset_visited_bit(1); 214 | if (!multiple_references(ctx, block->taken_block)) 215 | recursive_trace_and_place(block->taken_block, ctx, iclass, read_flags, true); 216 | 217 | 218 | ctx.routine.reset_visited_bit(1); 219 | if (!multiple_references(ctx, block->fallthrough_block)) 220 | recursive_trace_and_place(block->fallthrough_block, ctx, iclass, read_flags, false); 221 | 222 | } 223 | 224 | 225 | block->visited |= visited_1; 226 | block->invoke_for_next(recursive_application, ctx); 227 | } 228 | 229 | 230 | template 231 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 232 | { 233 | routine.reset_visited(); 234 | 235 | my_context my_context = { routine, ctx }; 236 | 237 | recursive_application(routine.entry_block, my_context); 238 | 239 | return obf::pass_status_t::success; 240 | } 241 | }; 242 | 243 | // Search for known values of zero or nonzero. Trace forward until its written to and place a test and jcc 244 | // right before. make sure flags are clobbered so they dont need to be preserved. 245 | // Examples: 246 | // mov reg,nonzero ; 247 | // or reg,nonzero ; 248 | // mov [reg],val ; reg couldnt be zero 249 | // mov reg2,[reg1] ; reg1 couldnt be zero 250 | // xor reg,reg ; reg is zero 251 | // 252 | // Sadly this one is mostly useless and there is an error with the pointer ones. 253 | // 254 | struct opaque_from_const_t 255 | { 256 | template 257 | static uint32_t random_block_link(dasm::routine_t& routine) 258 | { 259 | auto block_it = routine.blocks.begin(); 260 | std::advance(block_it, rand() % routine.blocks.size()); 261 | return block_it->link; 262 | } 263 | 264 | // Returns true if a certain value can be assured of a register 265 | // 266 | template 267 | static bool assures_value(dasm::inst_it_t inst_it, bool& is_zero, xed_reg_enum_t& reg) 268 | { 269 | uint32_t num_operands = inst_it->noperands(); 270 | auto inst = inst_it->inst(); 271 | 272 | /*for (uint32_t i = 0; i < num_operands; ++i) 273 | { 274 | if (XED_OPERAND_MEM0 == xed_operand_name(xed_inst_operand(inst, i))) 275 | { 276 | is_zero = false; 277 | reg = xed_decoded_inst_get_base_reg(&inst_it->decoded_inst, 0); 278 | if (reg != max_reg_width::value && 279 | reg != XED_REG_INVALID && 280 | reg != max_reg_width::value 281 | ) 282 | return true; 283 | } 284 | }*/ 285 | 286 | switch (inst_it->iform()) 287 | { 288 | case XED_IFORM_MOV_GPRv_IMMv: 289 | case XED_IFORM_MOV_GPRv_IMMz: 290 | case XED_IFORM_OR_GPRv_IMMb: 291 | case XED_IFORM_OR_GPRv_IMMz: 292 | { 293 | // This is kinda a meme to find the reg we write to that isnt flags 294 | uint32_t operand_reg = XED_OPERAND_REG0; 295 | while (true) 296 | { 297 | reg = xed_decoded_inst_get_reg(&inst_it->decoded_inst, static_cast(operand_reg)); 298 | if (reg != max_reg_width::value) 299 | break; 300 | ++operand_reg; 301 | } 302 | 303 | if (xed_decoded_inst_get_immediate_is_signed(&inst_it->decoded_inst)) 304 | is_zero = (xed_decoded_inst_get_signed_immediate(&inst_it->decoded_inst) == 0); 305 | else 306 | is_zero = (xed_decoded_inst_get_unsigned_immediate(&inst_it->decoded_inst) == 0); 307 | return true; 308 | } 309 | /*case XED_IFORM_XOR_GPRv_GPRv_31: 310 | case XED_IFORM_XOR_GPRv_GPRv_33: 311 | { 312 | is_zero = true; 313 | xed_reg_enum_t left_reg = XED_REG_INVALID; 314 | for (uint32_t i = 0; i < num_operands; ++i) 315 | { 316 | if (auto operand_name = xed_operand_name(xed_inst_operand(inst, i)); 317 | xed_operand_is_register(operand_name)) 318 | { 319 | auto cur_reg = xed_decoded_inst_get_reg(&inst_it->decoded_inst, operand_name); 320 | if (cur_reg != max_reg_width::value) 321 | { 322 | if (left_reg == XED_REG_INVALID) 323 | left_reg = cur_reg; 324 | else 325 | return (left_reg == cur_reg); 326 | } 327 | } 328 | } 329 | 330 | return false; 331 | }*/ 332 | } 333 | 334 | return false; 335 | } 336 | 337 | template 338 | static bool is_register_clobbered(dasm::inst_it_t inst_it, xed_reg_enum_t reg) 339 | { 340 | if (XED_CATEGORY_CALL == xed_decoded_inst_get_category(&inst_it->decoded_inst)) 341 | return true; 342 | 343 | uint32_t num_operands = inst_it->noperands(); 344 | auto inst = inst_it->inst(); 345 | 346 | for (uint32_t i = 0; i < num_operands; ++i) 347 | { 348 | if (auto operand = xed_inst_operand(inst, i); xed_operand_written(operand)) 349 | { 350 | if (auto operand_name = xed_operand_name(operand); xed_operand_is_register(operand_name) && 351 | xed_decoded_inst_get_reg(&inst_it->decoded_inst, operand_name) == reg) 352 | { 353 | return true; 354 | } 355 | } 356 | } 357 | 358 | return false; 359 | } 360 | 361 | template 362 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 363 | { 364 | for (auto block_it = routine.blocks.begin(); block_it != routine.blocks.end(); ++block_it) 365 | { 366 | for (auto inst_it = block_it->instructions.begin(); inst_it != block_it->instructions.end() && !(inst_it->flags & dasm::inst_flag::block_terminator); ++inst_it) 367 | { 368 | bool is_zero; 369 | xed_reg_enum_t reg; 370 | 371 | if (assures_value(inst_it, is_zero, reg)) 372 | { 373 | auto inst_it2 = std::next(inst_it); 374 | for (;inst_it2 != block_it->instructions.end(); ++inst_it2) 375 | { 376 | if (is_register_clobbered(inst_it2, reg) || (inst_it2->flags & dasm::inst_flag::block_terminator)) 377 | break; 378 | } 379 | 380 | // Setup a ledger of the flags that a test inst would set 381 | // 382 | xed_flag_set_t ledger; 383 | ledger.flat = 0; 384 | ledger.s.of = 1; 385 | ledger.s.cf = 1; 386 | ledger.s.sf = 1; 387 | ledger.s.zf = 1; 388 | ledger.s.pf = 1; 389 | 390 | // Now we know that we could potentially place a test and false jump right before this thing 391 | // 392 | while (!dasm::flags_clobbered_before_use(routine, block_it, inst_it2, ledger)) 393 | { 394 | if (inst_it2 == inst_it) 395 | goto continue_block_loop; 396 | 397 | --inst_it2; 398 | } 399 | 400 | auto reg_as_8 = change_reg_width(reg, register_width::byte); 401 | 402 | printf("reg is %s %X\n", xed_reg_enum_t2str(reg_as_8), inst_it->original_rva); 403 | 404 | block_it->instructions.emplace(inst_it2, 405 | XED_ICLASS_TEST, 406 | 8, 407 | xed_reg(reg_as_8), 408 | xed_reg(reg_as_8) 409 | )->common_edit(ctx.linker->allocate_link(), 0, 0); 410 | 411 | if (is_zero) 412 | { 413 | block_it->instructions.emplace(inst_it2, 414 | XED_ICLASS_JNZ, 415 | 32, 416 | xed_relbr(0xABBA, 32) 417 | )->common_edit(ctx.linker->allocate_link(), random_block_link(routine), dasm::inst_flag::rel_br); 418 | } 419 | else 420 | { 421 | block_it->instructions.emplace(inst_it2, 422 | XED_ICLASS_JZ, 423 | 32, 424 | xed_relbr(0xABBA, 32) 425 | )->common_edit(ctx.linker->allocate_link(), random_block_link(routine), dasm::inst_flag::rel_br); 426 | } 427 | 428 | goto go_to_next_block; 429 | } 430 | 431 | continue_block_loop: 432 | continue; 433 | } 434 | 435 | go_to_next_block: 436 | continue; 437 | } 438 | } 439 | }; 440 | 441 | 442 | // also kinda stupid 443 | // Similar to the opaque_from_const_t in that we use known values to determine the jump 444 | // I think this will work better because its data access which ida cant know will be a certain value 445 | // 446 | // push rax 447 | // 448 | // lea (al)(ax)(eax)(rax),[rip+offset] 449 | // or 450 | // mov al,[rip+offset] 451 | // 452 | // wrap around other insts that dont touch al 453 | // 454 | // test al,al 455 | // or 456 | // cmp al,0 457 | // pop rax 458 | // jz 459 | // 460 | // 461 | struct opaque_from_rip_t 462 | { 463 | template 464 | static dasm::inst_it_t find_random_inst(obf::obf_t& ctx) 465 | { 466 | auto routine_it = ctx.obf_routines.begin(); 467 | std::advance(routine_it, rand() % ctx.obf_routines.size()); 468 | 469 | auto block_it_t = routine_it->m_routine.blocks.begin(); 470 | std::advance(block_it_t, rand() % routine_it->m_routine.blocks.size()); 471 | 472 | auto inst_it = block_it_t->instructions.begin(); 473 | std::advance(inst_it, rand() % block_it_t->instructions.size()); 474 | 475 | return inst_it; 476 | } 477 | 478 | template 479 | static uint32_t find_random_link(obf::obf_t& ctx) 480 | { 481 | auto routine_it = ctx.obf_routines.begin(); 482 | std::advance(routine_it, rand() % ctx.obf_routines.size()); 483 | 484 | auto block_it_t = routine_it->m_routine.blocks.begin(); 485 | std::advance(block_it_t, rand() % routine_it->m_routine.blocks.size()); 486 | 487 | auto inst_it = block_it_t->instructions.begin(); 488 | std::advance(inst_it, rand() % block_it_t->instructions.size()); 489 | 490 | return inst_it->my_link; 491 | } 492 | 493 | template 494 | static dasm::inst_list_t gen(obf::obf_t& ctx) 495 | { 496 | uint32_t target_link = 0; 497 | 498 | // Add instructions can have opcode of zero 499 | // 500 | auto inst = find_random_inst(ctx); 501 | target_link = inst->my_link; 502 | /*while (XED_ICLASS_ADD != xed_decoded_inst_get_iclass(&inst->decoded_inst)) 503 | { 504 | inst = find_random_inst(ctx); 505 | target_link = inst->my_link; 506 | }*/ 507 | 508 | dasm::inst_list_t result; 509 | 510 | result.emplace_back( 511 | XED_ICLASS_PUSH, 512 | addr_width::bits::value, 513 | xed_reg(max_reg_width::value) 514 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 515 | 516 | result.emplace_back( 517 | XED_ICLASS_MOV, 518 | 8, 519 | xed_reg(XED_REG_AL), 520 | xed_mem_bd( 521 | max_reg_width::value, 522 | xed_disp(0, 32), 523 | 8 524 | ) 525 | ).common_edit(ctx.linker->allocate_link(), target_link, dasm::inst_flag::disp); 526 | 527 | result.emplace_back( 528 | XED_ICLASS_TEST, 529 | 8, 530 | xed_reg(XED_REG_AL), 531 | xed_reg(XED_REG_AL) 532 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 533 | 534 | result.emplace_back( 535 | XED_ICLASS_JZ, 536 | 32, 537 | xed_relbr(0, 32) 538 | ).common_edit(ctx.linker->allocate_link(), find_random_link(ctx), dasm::inst_flag::rel_br); 539 | 540 | result.emplace_back( 541 | XED_ICLASS_POP, 542 | addr_width::bits::value, 543 | xed_reg(max_reg_width::value) 544 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 545 | 546 | return result; 547 | } 548 | 549 | template 550 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 551 | { 552 | for (auto block_it = routine.blocks.begin(); block_it != routine.blocks.end(); ++block_it) 553 | { 554 | if (block_it->instructions.size() > 5) 555 | { 556 | auto it = block_it->instructions.begin(); 557 | std::advance(it, rand() % (block_it->instructions.size() - 3)); 558 | 559 | xed_flag_set_t ledger; 560 | ledger.flat = 0; 561 | ledger.s.of = 1; 562 | ledger.s.cf = 1; 563 | ledger.s.sf = 1; 564 | ledger.s.zf = 1; 565 | ledger.s.pf = 1; 566 | 567 | // Now we know that we could potentially place a test and false jump right before this thing 568 | // 569 | if (dasm::flags_clobbered_before_use(routine, block_it, it, ledger)) 570 | { 571 | printf("placed one.\n"); 572 | block_it->instructions.splice(it, gen(ctx)); 573 | } 574 | } 575 | } 576 | 577 | return obf::pass_status_t::success; 578 | } 579 | }; 580 | 581 | struct opaque_code_copy_t 582 | { 583 | template 584 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 585 | { 586 | 587 | } 588 | }; -------------------------------------------------------------------------------- /BDASM/original.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | 5 | // These are all the passes that play around with the original memory of the function 6 | // 7 | 8 | // It's required that this pass be run before any that might alter the start and end rvas set in the 9 | // disassembly process 10 | // 11 | struct pad_original_t 12 | { 13 | template 14 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 15 | { 16 | for (auto& block : routine.blocks) 17 | { 18 | memset(ctx.bin->mapped_image + block.rva_start, 0xCC, block.rva_end - block.rva_start); 19 | } 20 | 21 | return obf::pass_status_t::success; 22 | } 23 | }; 24 | 25 | // Add one here that obfuscates the jumps 26 | // -------------------------------------------------------------------------------- /BDASM/other_vm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ovm 6 | { 7 | namespace vinst_fmt 8 | { 9 | #pragma pack(push,1) 10 | 11 | // Describes a max of 2 registers of any size 12 | // Reg1 = Base & 0x3F 13 | // Reg2 = Base >> 6 14 | // 15 | struct two_reg_t 16 | { 17 | uint16_t reg1 : 6; 18 | uint16_t reg2 : 6; 19 | uint16_t pad : 4; 20 | }; 21 | static_assert(sizeof(two_reg_t) == 2); 22 | 23 | // Describes an index scale combo 24 | // index = Base & 0xF 25 | // scale = Base >> 4 26 | // 27 | struct index_scale_t 28 | { 29 | uint8_t index : 4; 30 | uint8_t scale : 2; 31 | uint8_t pad : 2; 32 | }; 33 | static_assert(sizeof(index_scale_t) == 1); 34 | 35 | //struct imm 36 | 37 | 38 | #pragma pack(pop) 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /BDASM/pi_blocks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | #include "encoder.h" 5 | 6 | // Make all blocks of a routine position independent inside the binary by appending 7 | // an absolute jump onto the end of blocks that feature a fallthrough. 8 | // 9 | 10 | struct position_independent_blocks_t 11 | { 12 | template 13 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx) 14 | { 15 | for (auto& block : routine.blocks) 16 | { 17 | switch (block.termination_type) 18 | { 19 | case dasm::termination_type_t::invalid: 20 | std::printf("Invalid block termination type in block [%08X:%08X]\n", block.rva_start, block.rva_end); [[fallthrough]]; 21 | return obf::pass_status_t::critical_failure; [[fallthrough]]; 22 | case dasm::termination_type_t::returns: [[fallthrough]]; 23 | case dasm::termination_type_t::unconditional_br: 24 | break; 25 | 26 | // These two termination types have fallthroughs and need to have an absolute 27 | // jump patched onto the end to make them position independent. 28 | // 29 | case dasm::termination_type_t::conditional_br: [[fallthrough]]; 30 | case dasm::termination_type_t::fallthrough: 31 | 32 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 33 | 34 | block.instructions.emplace_back( 35 | XED_ICLASS_JMP, 36 | 32, 37 | xed_relbr(0, 32) 38 | ).common_edit(ctx.linker->allocate_link(), block.fallthrough_block->link, dasm::inst_flag::rel_br | dasm::inst_flag::block_terminator); 39 | block.instructions.back().original_rva = 0; 40 | 41 | break; 42 | case dasm::termination_type_t::undetermined_unconditional_br: [[fallthrough]]; 43 | case dasm::termination_type_t::unknown_logic: 44 | break; 45 | default: 46 | std::printf("Unknown block termination type.\n"); 47 | return obf::pass_status_t::critical_failure; 48 | } 49 | } 50 | return obf::pass_status_t::success; 51 | } 52 | }; -------------------------------------------------------------------------------- /BDASM/sff.h: -------------------------------------------------------------------------------- 1 | #ifndef __SHELLCODE_FILE_FORMAT_H 2 | #define __SHELLCODE_FILE_FORMAT_H 3 | 4 | #include 5 | #include 6 | 7 | #define SHELLCODE_FILE_MAGIC 'lCcS' 8 | 9 | // Structures for dissassembling the shellcode file. 10 | typedef struct _CLASS_DESCRIPTOR 11 | { 12 | ULONG Magic; 13 | ULONG FunctionCount; 14 | ULONG TotalFileSize; 15 | } CLASS_DESCRIPTOR, * PCLASS_DESCRIPTOR; 16 | 17 | typedef struct _SHELLCODE_FUNC_DESCRIPTOR 18 | { 19 | ULONG Offset; 20 | ULONG Size; 21 | } SHELLCODE_FUNC_DESCRIPTOR, * PSHELLCODE_FUNC_DESCRIPTOR; 22 | 23 | typedef struct _DECOMP_FILE 24 | { 25 | CLASS_DESCRIPTOR Class; 26 | SHELLCODE_FUNC_DESCRIPTOR Functions[1]; 27 | } DECOMP_FILE, * PDECOMP_FILE; 28 | 29 | inline BOOLEAN SffVerify(PDECOMP_FILE File) 30 | { 31 | return (File->Class.Magic == SHELLCODE_FILE_MAGIC); 32 | } 33 | 34 | inline VOID SffDbgPrint(PDECOMP_FILE File) 35 | { 36 | printf("Magic: \'%c%c%c%c\'\n", 37 | ((PCHAR)&File->Class.Magic)[0], 38 | ((PCHAR)&File->Class.Magic)[1], 39 | ((PCHAR)&File->Class.Magic)[2], 40 | ((PCHAR)&File->Class.Magic)[3]); 41 | 42 | printf("FunctionCount: %u\n", File->Class.FunctionCount); 43 | printf("File Size: 0x%X\n", File->Class.TotalFileSize); 44 | 45 | for (int i = 0; i < File->Class.FunctionCount; i++) 46 | { 47 | printf(" Function[%d]:\n", i); 48 | printf("\tSize: 0x%X\n", File->Functions[i].Size); 49 | printf("\tOffset: 0x%X\n", File->Functions[i].Offset); 50 | } 51 | } 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /BDASM/size_casting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | extern "C" 4 | { 5 | #include 6 | } 7 | 8 | #include "addr_width.h" 9 | 10 | enum class register_width : uint8_t 11 | { 12 | byte, 13 | word, 14 | dword, 15 | qword, 16 | }; 17 | 18 | constexpr xed_reg_enum_t __reg_size_map[] = { 19 | XED_REG_AL, XED_REG_AX, XED_REG_EAX, XED_REG_RAX, 20 | XED_REG_BL, XED_REG_BX, XED_REG_EBX, XED_REG_RBX, 21 | XED_REG_CL, XED_REG_CX, XED_REG_ECX, XED_REG_RCX, 22 | XED_REG_DL, XED_REG_DX, XED_REG_EDX, XED_REG_RDX, 23 | 24 | XED_REG_SIL, XED_REG_SI, XED_REG_ESI, XED_REG_RSI, 25 | XED_REG_DIL, XED_REG_DI, XED_REG_EDI, XED_REG_RDI, 26 | XED_REG_BPL, XED_REG_BP, XED_REG_EBP, XED_REG_RBP, 27 | XED_REG_SPL, XED_REG_SP, XED_REG_ESP, XED_REG_RSP, 28 | 29 | XED_REG_R8B, XED_REG_R8W, XED_REG_R8D, XED_REG_R8, 30 | XED_REG_R9B, XED_REG_R9W, XED_REG_R9D, XED_REG_R9, 31 | XED_REG_R10B, XED_REG_R10W, XED_REG_R10D, XED_REG_R10, 32 | XED_REG_R11B, XED_REG_R11W, XED_REG_R11D, XED_REG_R11, 33 | XED_REG_R12B, XED_REG_R12W, XED_REG_R12D, XED_REG_R12, 34 | XED_REG_R13B, XED_REG_R13W, XED_REG_R13D, XED_REG_R13, 35 | XED_REG_R14B, XED_REG_R14W, XED_REG_R14D, XED_REG_R14, 36 | XED_REG_R15B, XED_REG_R15W, XED_REG_R15D, XED_REG_R15, 37 | 38 | XED_REG_INVALID, XED_REG_IP, XED_REG_EIP, XED_REG_RIP, 39 | 40 | XED_REG_INVALID, XED_REG_FLAGS, XED_REG_EFLAGS, XED_REG_RFLAGS, 41 | }; 42 | 43 | constexpr uint32_t __reg_enum_to_internal_id(xed_reg_enum_t reg) 44 | { 45 | switch (reg) 46 | { 47 | case XED_REG_AL: case XED_REG_AX: case XED_REG_EAX: case XED_REG_RAX: return 0; 48 | case XED_REG_BL: case XED_REG_BX: case XED_REG_EBX: case XED_REG_RBX: return 1; 49 | case XED_REG_CL: case XED_REG_CX: case XED_REG_ECX: case XED_REG_RCX: return 2; 50 | case XED_REG_DL: case XED_REG_DX: case XED_REG_EDX: case XED_REG_RDX: return 3; 51 | 52 | case XED_REG_SIL: case XED_REG_SI: case XED_REG_ESI: case XED_REG_RSI: return 4; 53 | case XED_REG_DIL: case XED_REG_DI: case XED_REG_EDI: case XED_REG_RDI: return 5; 54 | case XED_REG_BPL: case XED_REG_BP: case XED_REG_EBP: case XED_REG_RBP: return 6; 55 | case XED_REG_SPL: case XED_REG_SP: case XED_REG_ESP: case XED_REG_RSP: return 7; 56 | 57 | case XED_REG_R8B: case XED_REG_R8W: case XED_REG_R8D: case XED_REG_R8: return 8; 58 | case XED_REG_R9B: case XED_REG_R9W: case XED_REG_R9D: case XED_REG_R9: return 9; 59 | case XED_REG_R10B: case XED_REG_R10W: case XED_REG_R10D: case XED_REG_R10: return 10; 60 | case XED_REG_R11B: case XED_REG_R11W: case XED_REG_R11D: case XED_REG_R11: return 11; 61 | case XED_REG_R12B: case XED_REG_R12W: case XED_REG_R12D: case XED_REG_R12: return 12; 62 | case XED_REG_R13B: case XED_REG_R13W: case XED_REG_R13D: case XED_REG_R13: return 13; 63 | case XED_REG_R14B: case XED_REG_R14W: case XED_REG_R14D: case XED_REG_R14: return 14; 64 | case XED_REG_R15B: case XED_REG_R15W: case XED_REG_R15D: case XED_REG_R15: return 15; 65 | 66 | case XED_REG_IP: case XED_REG_EIP: case XED_REG_RIP: return 16; 67 | case XED_REG_INVALID: case XED_REG_FLAGS: case XED_REG_EFLAGS: case XED_REG_RFLAGS: return 17; 68 | default: 69 | return XED_REG_INVALID; 70 | } 71 | } 72 | 73 | namespace addr_width 74 | { 75 | template struct reg_width; 76 | template<> struct reg_width { inline constexpr static register_width value = register_width::dword; }; 77 | template<> struct reg_width { inline constexpr static register_width value = register_width::qword; }; 78 | } 79 | 80 | xed_reg_enum_t change_reg_width(xed_reg_enum_t reg, register_width width) 81 | { 82 | return __reg_size_map[__reg_enum_to_internal_id(reg) * 4 + static_cast(width)]; 83 | } 84 | 85 | template 86 | struct reg_as_width 87 | { 88 | inline constexpr static xed_reg_enum_t value = __reg_size_map[__reg_enum_to_internal_id(Register_enum) * 4 + static_cast(Register_width)]; 89 | }; 90 | 91 | template 92 | struct max_reg_width 93 | { 94 | inline constexpr static xed_reg_enum_t value = __reg_size_map[__reg_enum_to_internal_id(Register_enum) * 4 + static_cast(aw) + 2]; 95 | }; 96 | 97 | 98 | -------------------------------------------------------------------------------- /BDASM/stack_allocation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | #include "encoder.h" 5 | #include "backtrace.h" 6 | 7 | // I can actually handle the special stack deallocators... i just need to trace back to where the reg moved into rsp is used 8 | // see if its a lea reg,[rsp+stack_allocation] then adjust accordingly. 9 | // 10 | 11 | // write func to perform complete stack analysis with blocks that have references to the other blocks blah blah blah 12 | // use iterators for the references 13 | // 14 | struct stack_allocation_t 15 | { 16 | template 17 | struct my_context_t 18 | { 19 | obf::obf_t& ctx; 20 | 21 | // The visited value to check for when visiting a block 22 | // 23 | uint32_t visited; 24 | 25 | // Size we need to edit allocator/deallocator by 26 | // 27 | int32_t additional_alloc; 28 | 29 | // Size of the original allocation. Zero for funcs that did not allocate 30 | // 31 | int32_t sp_allocation; 32 | 33 | // How far into new memory bp is, because it could be different from sp 34 | // 35 | int32_t bp_allocation; 36 | 37 | // Bp based memory access also needs to be adjusted 38 | // 39 | bool bp_based; 40 | 41 | // This is when this happens 42 | // 43 | // lea rbp,[rsp+-const] 44 | // sub rsp,const 45 | bool lea_to_bp; 46 | 47 | bool custom_alloc_possible; 48 | 49 | my_context_t(obf::obf_t& context, uint32_t vis, int32_t alloc_size) 50 | : ctx(context) 51 | , visited(vis) 52 | , additional_alloc(alloc_size) 53 | , sp_allocation(0) 54 | , bp_allocation(0) 55 | , bp_based(false) 56 | , lea_to_bp(false) 57 | , custom_alloc_possible(true) 58 | {} 59 | }; 60 | 61 | // Sometimes msvc decides to randomly move rsp into rax or some other reg, this will tracebackwards from a lea 62 | // searching for a 'mov rax,rsp' to see if that is the case 63 | // 64 | template 65 | static bool does_reg_equal_sp(xed_reg_enum_t reg, dasm::block_it_t block, dasm::inst_it_t inst) 66 | { 67 | if (reg == max_reg_width::value) 68 | return true; 69 | 70 | // Otherwise, we trace backwards in the current block looking for a place where 'reg' might be set to sp 71 | // 72 | for (auto rev = std::make_reverse_iterator(inst); rev != block->instructions.rend(); ++rev) 73 | { 74 | if (auto iform = rev->iform(); 75 | (iform == XED_IFORM_MOV_GPRv_GPRv_89 || iform == XED_IFORM_MOV_GPRv_GPRv_8B) && 76 | reg == xed_decoded_inst_get_reg(&rev->decoded_inst, XED_OPERAND_REG0) && 77 | max_reg_width::value == xed_decoded_inst_get_reg(&rev->decoded_inst, XED_OPERAND_REG1)) 78 | { 79 | return true; 80 | } 81 | 82 | // We will check all operands of the instruction to see if this reg we are looking at is clobbered 83 | // if it is and we havnt found that sp was moved into it yet, then it couldnt possibly equal sp at 84 | // the place we need it to. 85 | // 86 | auto inst = rev->inst(); 87 | auto num_operands = rev->noperands(); 88 | 89 | for (uint32_t i = 0; i < num_operands; ++i) 90 | { 91 | auto operand = xed_inst_operand(inst, i); 92 | if (xed_operand_written(operand)) 93 | { 94 | auto operand_name = xed_operand_name(operand); 95 | if (xed_operand_is_register(operand_name)) 96 | { 97 | if (reg == xed_decoded_inst_get_reg(&rev->decoded_inst, operand_name)) 98 | return false; 99 | } 100 | } 101 | } 102 | } 103 | 104 | return false; 105 | } 106 | 107 | // returns true if the function is a candidate for a custom allocation 108 | // No calls or undetermined jumps 109 | // 110 | template 111 | static bool run_stack_analysis(my_context_t& ctx, dasm::routine_t& routine) 112 | { 113 | for (auto block_it = routine.blocks.begin(); block_it != routine.blocks.end(); ++block_it) 114 | { 115 | bool found_standard_deallocator = false; 116 | for (auto inst_it = block_it->instructions.begin(); inst_it != block_it->instructions.end(); ++inst_it) 117 | { 118 | auto iform = inst_it->iform(); 119 | if (iform == XED_IFORM_SUB_GPRv_IMMz || iform == XED_IFORM_SUB_GPRv_IMMb && 120 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0)) 121 | { 122 | if (ctx.sp_allocation) 123 | return false; 124 | ctx.sp_allocation = xed_decoded_inst_get_signed_immediate(&inst_it->decoded_inst); 125 | } 126 | if (iform == XED_IFORM_ADD_GPRv_IMMz || iform == XED_IFORM_ADD_GPRv_IMMb && 127 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0)) 128 | { 129 | found_standard_deallocator = true; 130 | } 131 | else if ((iform == XED_IFORM_MOV_GPRv_GPRv_89 || iform == XED_IFORM_MOV_GPRv_GPRv_8B) && 132 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0) && 133 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG1)) 134 | { 135 | ctx.bp_based = true; 136 | ctx.lea_to_bp = false; 137 | ctx.bp_allocation = ctx.sp_allocation; 138 | //printf("------MOV BP. %X\n", inst_it->original_rva); 139 | } 140 | else if ((iform == XED_IFORM_LEA_GPRv_AGEN) && 141 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0) && 142 | does_reg_equal_sp(xed_decoded_inst_get_base_reg(&inst_it->decoded_inst, 0), block_it, inst_it)) 143 | { 144 | // If bp gets moved around a lot then we cant reliably track it with this 145 | // 146 | if (ctx.bp_based) 147 | return false; 148 | 149 | ctx.bp_based = true; 150 | ctx.lea_to_bp = true; 151 | ctx.bp_allocation = (-xed_decoded_inst_get_memory_displacement(&inst_it->decoded_inst, 0)) + ctx.sp_allocation; 152 | //printf("-----LEA BP. %X\n", inst_it->original_rva); 153 | } 154 | else if (auto icat = xed_decoded_inst_get_category(&inst_it->decoded_inst); 155 | icat == XED_CATEGORY_CALL) 156 | { 157 | ctx.custom_alloc_possible = false; 158 | } 159 | } 160 | 161 | if (block_it->termination_type == dasm::termination_type_t::undetermined_unconditional_br) 162 | ctx.custom_alloc_possible = false; 163 | 164 | if (block_it->termination_type == dasm::termination_type_t::returns && found_standard_deallocator == false) 165 | return false; 166 | } 167 | return true; 168 | } 169 | 170 | template 171 | static void recursive_disp_fixup(dasm::block_it_t block, my_context_t& ctx, bool in_allocation) 172 | { 173 | // Dont continue because we have already touched this block 174 | // 175 | if (block->visited == ctx.visited) 176 | return; 177 | 178 | for (auto inst_it = block->instructions.begin(); inst_it != block->instructions.end(); ++inst_it) 179 | { 180 | auto iform = inst_it->iform(); 181 | if (iform == XED_IFORM_SUB_GPRv_IMMz || iform == XED_IFORM_SUB_GPRv_IMMb && 182 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0)) 183 | { 184 | //printf("Found allocator. %X\n", ctx.sp_allocation + ctx.additional_alloc); 185 | xed_decoded_inst_set_immediate_signed_bits(&inst_it->decoded_inst, ctx.sp_allocation + ctx.additional_alloc, 32); 186 | in_allocation = true; 187 | } 188 | else if (iform == XED_IFORM_ADD_GPRv_IMMz || XED_IFORM_ADD_GPRv_IMMb && 189 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0)) 190 | { 191 | //printf("Found deallocator. %X\n", ctx.sp_allocation + ctx.additional_alloc); 192 | 193 | xed_decoded_inst_set_immediate_signed_bits(&inst_it->decoded_inst, ctx.sp_allocation + ctx.additional_alloc, 32); 194 | in_allocation = false; 195 | } 196 | else if (ctx.bp_based && iform == XED_IFORM_LEA_GPRv_AGEN && 197 | max_reg_width::value == xed_decoded_inst_get_reg(&inst_it->decoded_inst, XED_OPERAND_REG0) && 198 | does_reg_equal_sp(xed_decoded_inst_get_base_reg(&inst_it->decoded_inst, 0), block, inst_it)) 199 | { 200 | //printf("found lea to do allocation on %X\n", inst_it->original_rva); 201 | auto disp = xed_decoded_inst_get_memory_displacement(&inst_it->decoded_inst, 0); 202 | xed_decoded_inst_set_memory_displacement_bits(&inst_it->decoded_inst, disp - ctx.additional_alloc, 32); 203 | inst_it->redecode(); 204 | } 205 | else if (in_allocation) 206 | { 207 | auto inst = inst_it->inst(); 208 | auto num_operands = inst_it->noperands(); 209 | 210 | for (uint32_t i = 0; i < num_operands; ++i) 211 | { 212 | auto operand = xed_inst_operand(inst, i); 213 | auto operand_name = xed_operand_name(operand); 214 | if (operand_name == XED_OPERAND_MEM0 || operand_name == XED_OPERAND_AGEN) 215 | { 216 | //printf("found one to patch. %X\n", inst_it->original_rva); 217 | if (max_reg_width::value == 218 | xed_decoded_inst_get_base_reg(&inst_it->decoded_inst, 0)) 219 | { 220 | auto disp = xed_decoded_inst_get_memory_displacement(&inst_it->decoded_inst, 0); 221 | // If our disp is less than the allocation size, we are accessing data in the allocation 222 | // Otherwise we are accessing data in args, home space, or return addr 223 | // 224 | if (disp > ctx.sp_allocation) 225 | { 226 | xed_decoded_inst_set_memory_displacement(&inst_it->decoded_inst, disp + ctx.additional_alloc, 4); 227 | } 228 | inst_it->redecode(); 229 | } 230 | else if (ctx.bp_based && 231 | max_reg_width::value == 232 | xed_decoded_inst_get_base_reg(&inst_it->decoded_inst, 0)) 233 | { 234 | auto disp = xed_decoded_inst_get_memory_displacement(&inst_it->decoded_inst, 0); 235 | 236 | // This logic needs to get checked... 237 | // 238 | if (ctx.bp_allocation != 0 && disp >= ctx.bp_allocation) 239 | { 240 | xed_decoded_inst_set_memory_displacement_bits(&inst_it->decoded_inst, disp + ctx.additional_alloc, 32); 241 | } 242 | else if (ctx.bp_allocation == 0 && disp < 0) 243 | { 244 | xed_decoded_inst_set_memory_displacement_bits(&inst_it->decoded_inst, disp - ctx.additional_alloc, 32); 245 | } 246 | inst_it->redecode(); 247 | } 248 | } 249 | } 250 | } 251 | } 252 | 253 | ++block->visited; 254 | block->invoke_for_next(recursive_disp_fixup, ctx, in_allocation); 255 | } 256 | 257 | template 258 | static void insert_deallocators(dasm::block_it_t block, my_context_t& ctx) 259 | { 260 | if (block->visited == ctx.visited) 261 | return; 262 | 263 | if (block->termination_type == dasm::termination_type_t::returns || 264 | block->termination_type == dasm::termination_type_t::undetermined_unconditional_br) 265 | { 266 | // Allocate and place the deallocator before the last terminating instruction 267 | // 268 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 269 | block->instructions.emplace(std::prev(block->instructions.end()), 270 | XED_ICLASS_ADD, 271 | addr_width::bits::value, 272 | xed_reg(max_reg_width::value), 273 | xed_simm0( 274 | ctx.additional_alloc, 275 | 32 276 | ) 277 | )->common_edit(ctx.ctx.linker->allocate_link(), 0, 0); 278 | } 279 | 280 | ++block->visited; 281 | block->invoke_for_next(insert_deallocators, ctx); 282 | } 283 | 284 | 285 | // Puts the rsp offset where our data starts into allocation_size 286 | // 287 | template 288 | static obf::pass_status_t pass(dasm::routine_t& routine, obf::obf_t& ctx, int32_t& allocation_size) 289 | { 290 | /*if (routine.entry_block->rva_start >= 0x1B71) 291 | return obf::pass_status_t::failure;*/ 292 | 293 | routine.reset_visited(); 294 | my_context_t my_ctx = { ctx, 1, allocation_size }; 295 | 296 | if (!run_stack_analysis(my_ctx, routine)) 297 | return obf::pass_status_t::failure; 298 | 299 | // If there wasnt any stack allocation originally, we insert one if possible 300 | // 301 | if (!my_ctx.sp_allocation) 302 | { 303 | return obf::pass_status_t::failure; 304 | 305 | if (my_ctx.custom_alloc_possible) 306 | { 307 | // Create custom stack allocators 308 | // 309 | uint8_t buffer[XED_MAX_INSTRUCTION_BYTES]; 310 | 311 | routine.entry_block->instructions.emplace_front( 312 | XED_ICLASS_SUB, 313 | addr_width::bits::value, 314 | xed_reg(max_reg_width::value), 315 | xed_simm0( 316 | allocation_size, 317 | 32 318 | ) 319 | ).common_edit(ctx.linker->allocate_link(), 0, 0); 320 | 321 | insert_deallocators(routine.entry_block, my_ctx); 322 | routine.reset_visited(); 323 | } 324 | else 325 | return obf::pass_status_t::failure; 326 | } 327 | 328 | //if (my_ctx.bp_based) 329 | // return obf::pass_status_t::failure; 330 | 331 | recursive_disp_fixup(routine.entry_block, my_ctx, false); 332 | return obf::pass_status_t::success; 333 | } 334 | }; -------------------------------------------------------------------------------- /BDASM/substitution.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "obf.h" 4 | #include "encoder.h" 5 | 6 | // The goal of this is to substitute instructions with other harder to understand 7 | // instruction combinations. Very similar to MBA but i thought it deserved its own 8 | // pass because its not really related to math. See as follows 9 | // 10 | // MOV A,B 11 | // OR A,B 12 | // AND A,B 13 | // 14 | // 15 | 16 | namespace obf 17 | { 18 | struct substitution_t 19 | { 20 | template 21 | static bool pass(dasm::routine_t& routine, context_t& ctx, uint32_t percent_chance, uint32_t min_count, bool red_space_store = false) 22 | { 23 | 24 | } 25 | }; 26 | } -------------------------------------------------------------------------------- /BDASM/symbol.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "traits.h" 9 | 10 | namespace bin_data_flag 11 | { 12 | typedef uint64_t type; 13 | constexpr type none = 0; 14 | 15 | constexpr type base = (1 << 0); 16 | 17 | // This symbol was placed and given an updated rva 18 | // 19 | constexpr type placed = (1 << 1); 20 | 21 | 22 | // Sections where things are found are marked like this... 23 | // 24 | constexpr type data = (1 << 2); 25 | constexpr type executable = (1 << 3); 26 | 27 | 28 | constexpr type function_start = (1 << 4); 29 | 30 | constexpr type is_export = (1 << 5); 31 | 32 | 33 | constexpr type reloc = (1 << 6); 34 | constexpr type reloc_type_shift = 7; 35 | constexpr type reloc_type_mask = (0xF << reloc_type_shift); 36 | 37 | constexpr type func_data = (1 << 12); 38 | constexpr type func_data_shift = 13; 39 | constexpr type func_data_mask = (0xFFFF << func_data_shift); //imposes upper limit on function count of 2^16 40 | 41 | constexpr type mask = 0xffffffffffffffff; 42 | }; 43 | 44 | // These symbols are basically an intermediate between two things. For example an instruction and another isntruction 45 | // One instruction sets the rva once its placed in its final destination, and the other reads the rva to calculate a needed delta 46 | // 47 | class bin_data_t 48 | { 49 | public: 50 | 51 | // Some rva that represents where the symbol isa. Set once its placed. 52 | // 53 | //uint64_t address; 54 | 55 | // 56 | // 57 | bin_data_flag::type flags; 58 | 59 | explicit bin_data_t(bin_data_flag::type flags = 0, uint64_t raw_address = 0) 60 | : flags(flags) {} 61 | 62 | explicit bin_data_t(bin_data_t const& to_copy) 63 | : flags(to_copy.flags) {} 64 | 65 | finline bin_data_t& set_flag(bin_data_flag::type value) 66 | { 67 | flags |= value; 68 | return *this; 69 | } 70 | finline bin_data_t& remove_flag(bin_data_flag::type value) 71 | { 72 | flags &= ~value; 73 | return *this; 74 | } 75 | finline bin_data_t& set_flag_abs(bin_data_flag::type new_flags) 76 | { 77 | flags = new_flags; 78 | return *this; 79 | } 80 | finline void mark_as_reloc(uint8_t reloc_type) 81 | { 82 | flags |= bin_data_flag::reloc; 83 | flags = ((flags & ~bin_data_flag::reloc_type_mask) | (static_cast(reloc_type & 0xF) << bin_data_flag::reloc_type_shift)); 84 | } 85 | finline uint8_t get_reloc_type() 86 | { 87 | return ((flags & bin_data_flag::reloc_type_mask) >> bin_data_flag::reloc_type_shift); 88 | } 89 | 90 | // Accessing function data 91 | // 92 | finline bool has_func_data() 93 | { 94 | return (flags & bin_data_flag::func_data); 95 | } 96 | finline uint16_t get_func_data_idx() 97 | { 98 | return ((flags & bin_data_flag::func_data_mask) >> bin_data_flag::func_data_shift); 99 | } 100 | finline void set_func_data_idx(uint16_t idx) 101 | { 102 | flags = ((flags & ~bin_data_flag::func_data_mask) | (static_cast(idx) << bin_data_flag::func_data_shift)); 103 | } 104 | }; 105 | 106 | struct func_sym_data_t 107 | { 108 | uint32_t runtime_function_rva; 109 | func_sym_data_t(uint32_t rva) 110 | : runtime_function_rva(rva) 111 | {} 112 | func_sym_data_t(func_sym_data_t const& to_copy) 113 | : runtime_function_rva(to_copy.runtime_function_rva) 114 | {} 115 | }; 116 | 117 | class bin_data_table_t 118 | { 119 | uint32_t m_image_size; 120 | 121 | bin_data_t* m_image_table; 122 | 123 | std::vector m_func_data; 124 | 125 | public: 126 | 127 | bin_data_table_t(uint32_t image_size, uint32_t arbitrary_table_start_size = 1000) 128 | : m_image_size(image_size) 129 | { 130 | m_image_table = new bin_data_t[image_size]; 131 | } 132 | ~bin_data_table_t() 133 | { 134 | delete[] m_image_table; 135 | } 136 | 137 | void resize_image_table(uint32_t new_image_size) 138 | { 139 | bin_data_t* new_image_table = new bin_data_t[new_image_size]; 140 | uint32_t copy_size = new_image_size; 141 | if (m_image_size < new_image_size) 142 | copy_size = m_image_size; 143 | 144 | for (uint32_t i = 0; i < copy_size; i++) 145 | new_image_table[i] = m_image_table[i]; 146 | 147 | delete[] m_image_table; 148 | m_image_table = new_image_table; 149 | m_image_size = new_image_size; 150 | } 151 | 152 | 153 | finline bool is_executable(uint32_t symbol_index) 154 | { 155 | return (m_image_table[symbol_index].flags & bin_data_flag::executable); 156 | } 157 | 158 | finline bool inst_uses_reloc(uint32_t inst_rva, uint32_t inst_len, uint8_t& offset, uint8_t& type) 159 | { 160 | for (uint32_t i = inst_rva; i < inst_rva + inst_len; ++i) 161 | if (m_image_table[i].flags & bin_data_flag::reloc) 162 | { 163 | type = m_image_table[i].get_reloc_type(); 164 | offset = i; 165 | return true; 166 | } 167 | return false; 168 | } 169 | 170 | finline bool has_func_data(uint32_t inst_rva) 171 | { 172 | return m_image_table[inst_rva].flags & bin_data_flag::func_data; 173 | } 174 | 175 | finline func_sym_data_t& get_func_data(uint32_t inst_rva) 176 | { 177 | return m_func_data[m_image_table[inst_rva].get_func_data_idx()]; 178 | } 179 | 180 | finline void set_func_data_and_start(uint32_t inst_rva, uint32_t runtime_func_rva) 181 | { 182 | auto& sym = m_image_table[inst_rva]; 183 | sym.flags |= bin_data_flag::function_start; 184 | if (sym.flags & bin_data_flag::func_data) 185 | { 186 | m_func_data[sym.get_func_data_idx()] = { runtime_func_rva }; 187 | } 188 | else 189 | { 190 | auto idx = m_func_data.size(); 191 | m_func_data.emplace_back(runtime_func_rva); 192 | sym.set_func_data_idx(idx); 193 | sym.set_flag(bin_data_flag::func_data); 194 | } 195 | } 196 | 197 | 198 | void unsafe_mark_range_as(uint32_t start, uint32_t size, bin_data_flag::type flag) 199 | { 200 | uint32_t end = start + size; 201 | for (uint32_t i = start; i < end; i++) 202 | m_image_table[i].flags |= flag; 203 | } 204 | 205 | 206 | // If we are in the binary itself then these are always valid so no need for more time with if 207 | // 208 | ndiscard finline uint32_t unsafe_get_symbol_index_for_rva(uint64_t address, bin_data_flag::type flags = bin_data_flag::none) 209 | { 210 | m_image_table[address].set_flag(flags); 211 | return address; 212 | } 213 | 214 | // Access symbols within the binary bounds without a check to make sure 215 | // 216 | ndiscard finline bin_data_t& unsafe_get_symbol_for_rva(uint32_t symbol_index) 217 | { 218 | return m_image_table[symbol_index]; 219 | } 220 | 221 | 222 | }; -------------------------------------------------------------------------------- /BDASM/traits.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | #define finline __forceinline 5 | #define ndiscard [[nodiscard]] 6 | #define mexport __declspec(dllexport) 7 | 8 | 9 | -------------------------------------------------------------------------------- /BDASM/x64/Debug/BDASM.ilk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iizerd/BDASM/c58f6be5ae3207f027d083e60899989f32e2c0a5/BDASM/x64/Debug/BDASM.ilk -------------------------------------------------------------------------------- /BDASM/x64/Debug/vc143.idb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iizerd/BDASM/c58f6be5ae3207f027d083e60899989f32e2c0a5/BDASM/x64/Debug/vc143.idb -------------------------------------------------------------------------------- /BDASM/x64/Release/BDASM.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iizerd/BDASM/c58f6be5ae3207f027d083e60899989f32e2c0a5/BDASM/x64/Release/BDASM.vcxproj.FileListAbsolute.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BDASM 2 | **BDASM** = **B**inary **D**is**AS**se**M**bler 3 | 4 | Reach into the bowels of the pe. 5 | 6 | ![alt text](https://i.imgur.com/fJXItld.png) 7 | 8 | -------------------------------------------------------------------------------- /TestExe/TestExe.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | Win32Proj 24 | {4006c556-e4cf-4562-8d04-1f3abb594571} 25 | TestExe 26 | 10.0 27 | 28 | 29 | 30 | Application 31 | true 32 | v143 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v143 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v143 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v143 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | true 77 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | true 79 | 80 | 81 | Console 82 | true 83 | 84 | 85 | 86 | 87 | Level3 88 | true 89 | true 90 | true 91 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 92 | true 93 | 94 | 95 | Console 96 | true 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | true 105 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 106 | true 107 | $(SolutionDir); 108 | 109 | 110 | Console 111 | true 112 | 113 | 114 | 115 | 116 | Level3 117 | false 118 | true 119 | true 120 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 121 | true 122 | $(SolutionDir); 123 | MinSpace 124 | false 125 | false 126 | AnySuitable 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /TestExe/TestExe.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /TestExe/TestExe.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /TestExe/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | 5 | 6 | #include "sdk.h" 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | 14 | //holy christ im such a beast. 15 | __declspec(noinline) int other_routine() 16 | { 17 | //BDASM_Begin(MARKER_ATTRIBUTE_EXTEND_TO_FUNC_START, 0); 18 | printf("this is the other routine.\n"); 19 | //BDASM_End(); 20 | 21 | //BDASM_Begin(MARKER_ATTRIBUTE_EXTEND_TO_FUNC_END, 0); 22 | printf("this is the other routine.2\n"); 23 | //BDASM_End(); 24 | 25 | return 12; 26 | } 27 | 28 | #include 29 | #include 30 | 31 | int main(int argc, char** argv) 32 | { 33 | std::string input; 34 | while (true) 35 | { 36 | std::cout << "Enter the password: "; 37 | std::cin >> input; 38 | if (input == "password") 39 | { 40 | std::cout << "Correct\n"; 41 | break; 42 | } 43 | else 44 | std::cout << "Innorrect\n"; 45 | } 46 | 47 | system("pause"); 48 | return 1; 49 | 50 | 51 | //std::cout << input << '\n'; 52 | //while (true) 53 | //{ 54 | // std::cout << "Enter the password: "; 55 | // std::cin >> input; 56 | // /*if (input == "password") 57 | // { 58 | // std::cout << "Correct.\n"; 59 | // break; 60 | // } 61 | // else 62 | // std::cout << "Incorrect.\n";*/ 63 | // std::cout << input << '\n'; 64 | //} 65 | 66 | 67 | /*printf("it was 1.\n"); 68 | system("pause"); 69 | return 1;*/ 70 | 71 | /*auto start = std::chrono::high_resolution_clock::now(); 72 | 73 | uint64_t count = 0; 74 | for (uint32_t i = 0; i < 0xFFFFF; ++i) 75 | { 76 | count += i; 77 | } 78 | 79 | std::printf("it tool %llu.\n", std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start).count()); 80 | 81 | system("pause"); 82 | return 1;*/ 83 | /*if (argc == 1) 84 | { 85 | printf("it was 1.\n"); 86 | } 87 | printf("it was 1.\n"); 88 | system("pause"); 89 | return 1;*/ 90 | 91 | /*int memes = rand() % 3; 92 | if (argc == 1) 93 | { 94 | memes = 1776 + 34; 95 | printf("it was 1. %X %X\n", argc + 2, memes); 96 | } 97 | else 98 | { 99 | memes = 19912 + 12; 100 | printf("it wasnt 1. %X %X\n", argc + 3, memes); 101 | } 102 | 103 | argc = rand() % 2; 104 | printf("hello there. %X %X\n", argc, memes); 105 | 106 | other_routine(); 107 | other_routine(); 108 | 109 | system("pause"); 110 | return 12;*/ 111 | 112 | 113 | 114 | 115 | ////BDASM_Begin(MARKER_ATTRIBUTE_ENTIRE_FUNCTION, 0); 116 | 117 | //printf("Hello Test. %llu\n", 0xFFEACC0DEF); 118 | //int meme = other_routine(); 119 | 120 | //printf("Result was %d\n", meme); 121 | //system("pause"); 122 | 123 | /*__try 124 | { 125 | for (int i = 0; i < 10; i++) 126 | { 127 | printf("Heres an int %d\n", i); 128 | } 129 | } 130 | __except (EXCEPTION_EXECUTE_HANDLER) 131 | { 132 | printf("here lies our exception handler.\n"); 133 | }*/ 134 | 135 | return 1; 136 | } -------------------------------------------------------------------------------- /TestExe/x64/Release/TestExe.vcxproj.FileListAbsolute.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Iizerd/BDASM/c58f6be5ae3207f027d083e60899989f32e2c0a5/TestExe/x64/Release/TestExe.vcxproj.FileListAbsolute.txt -------------------------------------------------------------------------------- /sdk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Tells the obfuscator that it can generate instructions that modify 6 | // themselves or others in the current group. 7 | // 8 | #define MARKER_ATTRIBUTE_SINGLE_THREAD (1 << 0) 9 | 10 | // Tells the obfuscator that the code is only executed once, and can 11 | // be destroyed after executed. Probably done with rip relative instructions. 12 | // This implies MARKER_ATTRIBUTE_SINGLE_THREAD 13 | // 14 | #define MARKER_ATTRIBUTE_EXECUTED_ONCE ((1 << 1) | MARKER_ATTRIBUTE_SINGLE_THREAD) 15 | 16 | 17 | #define BDASM_MARKER_INST_COUNT 5 18 | #define BDASM_Mark( \ 19 | MarkerAttributes \ 20 | ) \ 21 | { \ 22 | _xabort(0xFF); \ 23 | __nop(); \ 24 | _xabort(MarkerAttributes); \ 25 | _xabort(0xFF); \ 26 | } 27 | 28 | 29 | 30 | 31 | 32 | 33 | // Tells the obfuscator that it is to extend the group backwards until the 34 | // start of the current function. This is useful because the markers will 35 | // appear in code AFTER the prologue, meaning they would not be within the 36 | // group. 37 | // 38 | #define MARKER_ATTRIBUTE_EXTEND_TO_FUNC_START (1 << 2) 39 | 40 | // Same as above, but extends the group to the end of the function instead. 41 | // 42 | #define MARKER_ATTRIBUTE_EXTEND_TO_FUNC_END (1 << 3) 43 | 44 | // Tells the obfuscator that the entire function the BDASM_Begin appears 45 | // in is to be treated as one group and obfuscated. 46 | // This will ignore BDASM_End macros so you dont need to place one. 47 | // Implies MARKER_ATTRIBUTE_EXTEND_TO_FUNC_START and MARKER_ATTRIBUTE_EXTEND_TO_FUNC_END 48 | // 49 | #define MARKER_ATTRIBUTE_ENTIRE_FUNCTION (MARKER_ATTRIBUTE_EXTEND_TO_FUNC_START | MARKER_ATTRIBUTE_EXTEND_TO_FUNC_END) 50 | 51 | 52 | 53 | 54 | //#define BDASM_END_INST_COUNT 4 55 | //#define BDASM_End() \ 56 | // { \ 57 | // _xabort(0xFF); \ 58 | // __nop(); \ 59 | // __nop(); \ 60 | // _xabort(0xFF); \ 61 | // } 62 | 63 | 64 | 65 | --------------------------------------------------------------------------------