├── README.md └── Source ├── CS_Reg_Mapping.h ├── UniTaint.h ├── UniTranslator.h └── main.cpp /README.md: -------------------------------------------------------------------------------- 1 | # UniTaint 2 | 3 | Quick PoC for a taint based attack on VMProtect 4 | 5 | Takes a protected x64 binary, traces the vmprotected function with unicorn and taints the input using bea disassembler and a custom tainter 6 | 7 | Tested on simple functions without any branches. 8 | 9 | # Example 10 | 11 | # Protected C Function 12 | 13 | __declspec(dllexport) uint64_t DoXor(uint64_t a, uint64_t b) { 14 | return a ^ b; 15 | } 16 | 17 | 18 | # Tainted instructions during trace 19 | ``` 20 | T push r8 // 4FC0 21 | T push rcx // 4F80 22 | T push rdx // 4F70 23 | T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4F70 24 | T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E58 1: 2222222222221111 25 | T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4F80 26 | T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E38 1: 1111111111111111 27 | T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FC0 28 | T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E48 1: 777 29 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 5E 1: 4E58 30 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF8 1: 2222222222221111 31 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 0 1: 4E58 32 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 2222222222221111 33 | T mov r10, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FF0 34 | T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF8 35 | T not r10 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF 36 | T not r15 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF 37 | T and r10, r15 // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: DDDDDDDDDDDDEEEE 38 | T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: DDDDDDDDDDDDEEEE 39 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 5D330000 1: 4E38 40 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 1111111111111111 41 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 808E31 1: 4E38 42 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE8 1: 1111111111111111 43 | T mov r11, qword ptr [r13] // RSP 4DE0 0: 5000 1: 4FE8 44 | T mov rdx, qword ptr [r13 + 8] // RSP 4DE0 0: 2FCF8 1: 4FF0 45 | T not r11 // RSP 4DE0 0: 1111111111111111 1: DEADBEEF 46 | T not rdx // RSP 4DE0 0: 1111111111111111 1: DEADBEEF 47 | T or r11, rdx // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: EEEEEEEEEEEEEEEE 48 | T mov qword ptr [r13 + 8], r11 // RSP 4DE0 0: 4FF0 1: EEEEEEEEEEEEEEEE 49 | T mov r10, qword ptr [r13] // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: 4FF0 50 | T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF8 51 | T not r10 // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: DEADBEEF 52 | T not r15 // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: DEADBEEF 53 | T and r10, r15 // RSP 4DE0 0: 1111111111111111 1: 2222222222221111 54 | T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: 1111 55 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 2A220000 1: 4E58 56 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 2222222222221111 57 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 4A00 1: 4E38 58 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE8 1: 1111111111111111 59 | T mov r10, qword ptr [r13] // RSP 4DE0 0: 1111 1: 4FE8 60 | T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF0 61 | T not r10 // RSP 4DE0 0: 1111111111111111 1: DEADBEEF 62 | T not r15 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF 63 | T and r10, r15 // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: DDDDDDDDDDDDEEEE 64 | T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF0 1: CCCCCCCCCCCCEEEE 65 | T mov r10, qword ptr [r13] // RSP 4DE0 0: CCCCCCCCCCCCEEEE 1: 4FF0 66 | T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: DDDDDDDDDDDDEE00 1: 4FF8 67 | T not r10 // RSP 4DE0 0: CCCCCCCCCCCCEEEE 1: DEADBEEF 68 | T not r15 // RSP 4DE0 0: 1111 1: DEADBEEF 69 | T and r10, r15 // RSP 4DE0 0: 3333333333331111 1: FFFFFFFFFFFFEEEE 70 | T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: 3333333333330000 71 | T mov rbx, qword ptr [r13] // RSP 4DE0 0: 4 1: 4FF8 72 | T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E68 1: 3333333333330000 73 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: EE250AB7 1: 4E68 74 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE0 1: 3333333333330000 75 | T mov r11, qword ptr [r13 + 8] // RSP 4DE0 0: EEEEEEEEEEEEEE00 1: 4FE0 76 | T add rsi, r11 // RSP 4DE0 0: 23523 1: 3333333333330000 77 | T mov qword ptr [r13 + 8], rsi // RSP 4DE0 0: 4FE0 1: 3333333333353523 78 | T cmp r8, r11 // RSP 4DE0 0: 1400DCD67 1: 3333333333330000 79 | // Not implemented opcode : cmp 80 | T push r8 // 4DD8 81 | T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FE0 82 | T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4DF0 1: 3333333333353523 83 | T cmp r11, rsi // RSP 4DE0 0: 3333333333330000 1: 3333333333353523 84 | // Not implemented opcode : cmp 85 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 0 1: 4E48 86 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FD0 1: 777 87 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 8000000 1: 4DF0 88 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FB8 1: 3333333333353523 89 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 3F260AB7 1: 4E68 90 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4F90 1: 3333333333330000 91 | T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 35D7 1: 4E58 92 | T mov qword ptr [r13], r15 // RSP 4DE0 0: 4F80 1: 2222222222221111 93 | T cmp r11, rsi // RSP 4DE0 0: 3333333333330000 1: 3333333333353523 94 | // Not implemented opcode : cmp 95 | T pop rdx //4F80 V: 2222222222221111 96 | T pop rcx //4F90 V: 3333333333330000 97 | T pop rax //4FB8 V: 3333333333353523 98 | T pop r8 //4FD0 V: 777 99 | Result (RAX) = 3333333333353523 100 | Result (R8) = 777 101 | ``` 102 | 103 | # Translated instruction into C code 104 | 105 | ```c 106 | uint64_t S_0; 107 | uint64_t S_1; 108 | uint64_t S_2; 109 | uint64_t S_3; 110 | uint64_t S_4; 111 | uint64_t S_5; 112 | uint64_t S_6; 113 | uint64_t S_7; 114 | uint64_t S_8; 115 | uint64_t S_9; 116 | uint64_t S_10; 117 | uint64_t S_11; 118 | uint64_t S_12; 119 | uint64_t S_13; 120 | uint64_t S_14; 121 | uint64_t S_15; 122 | S_0 = r8; 123 | S_1 = rcx; 124 | S_2 = rdx; 125 | rbx = S_2; 126 | S_3 = rbx; 127 | rbx = S_1; 128 | S_4 = rbx; 129 | rbx = S_0; 130 | S_5 = rbx; 131 | r15 = S_3; 132 | S_6 = r15; 133 | r15 = S_3; 134 | S_7 = r15; 135 | r10 = S_7; 136 | r15 = S_6; 137 | r10 = ~r10; 138 | r15 = ~r15; 139 | r10 = r10 & r15; 140 | S_6 = r10; 141 | r15 = S_4; 142 | S_7 = r15; 143 | r15 = S_4; 144 | S_8 = r15; 145 | r11 = S_8; 146 | rdx = S_7; 147 | r11 = ~r11; 148 | rdx = ~rdx; 149 | r11 = r11 | rdx; 150 | S_7 = r11; 151 | r10 = S_7; 152 | r15 = S_6; 153 | r10 = ~r10; 154 | r15 = ~r15; 155 | r10 = r10 & r15; 156 | S_6 = r10; 157 | r15 = S_3; 158 | S_7 = r15; 159 | r15 = S_4; 160 | S_8 = r15; 161 | r10 = S_8; 162 | r15 = S_7; 163 | r10 = ~r10; 164 | r15 = ~r15; 165 | r10 = r10 & r15; 166 | S_7 = r10; 167 | r10 = S_7; 168 | r15 = S_6; 169 | r10 = ~r10; 170 | r15 = ~r15; 171 | r10 = r10 & r15; 172 | S_6 = r10; 173 | rbx = S_6; 174 | S_9 = rbx; 175 | r15 = S_9; 176 | S_10 = r15; 177 | r11 = S_10; 178 | rsi = rsi + r11; 179 | S_10 = rsi; 180 | S_11 = r8; 181 | rbx = S_10; 182 | S_12 = rbx; 183 | r15 = S_5; 184 | S_13 = r15; 185 | r15 = S_12; 186 | S_14 = r15; 187 | r15 = S_9; 188 | S_15 = r15; 189 | r15 = S_3; 190 | S_1 = r15; 191 | rdx = S_1; 192 | rcx = S_15; 193 | rax = S_14; 194 | r8 = S_13; 195 | ``` 196 | 197 | # Compile and optimize with Clang and O3 198 | 199 | ```c 200 | #include 201 | #include 202 | 203 | uint64_t rax; 204 | uint64_t rbx; 205 | uint64_t rcx; 206 | uint64_t rdx; 207 | uint64_t rbp; 208 | uint64_t rsp; 209 | uint64_t rsi; 210 | uint64_t rdi; 211 | uint64_t r8; 212 | uint64_t r9; 213 | uint64_t r10; 214 | uint64_t r11; 215 | uint64_t r12; 216 | uint64_t r13; 217 | uint64_t r14; 218 | uint64_t r15; 219 | 220 | __declspec(dllexport) void RXor() { 221 | uint64_t S_0; 222 | uint64_t S_1; 223 | uint64_t S_2; 224 | uint64_t S_3; 225 | uint64_t S_4; 226 | uint64_t S_5; 227 | uint64_t S_6; 228 | uint64_t S_7; 229 | uint64_t S_8; 230 | uint64_t S_9; 231 | uint64_t S_10; 232 | uint64_t S_11; 233 | uint64_t S_12; 234 | uint64_t S_13; 235 | uint64_t S_14; 236 | uint64_t S_15; 237 | 238 | S_0 = r8; 239 | S_1 = rcx; 240 | S_2 = rdx; 241 | rbx = S_2; 242 | S_3 = rbx; 243 | rbx = S_1; 244 | S_4 = rbx; 245 | rbx = S_0; 246 | S_5 = rbx; 247 | r15 = S_3; 248 | S_6 = r15; 249 | r15 = S_3; 250 | S_7 = r15; 251 | r10 = S_7; 252 | r15 = S_6; 253 | r10 = ~r10; 254 | r15 = ~r15; 255 | r10 = r10 & r15; 256 | S_6 = r10; 257 | r15 = S_4; 258 | S_7 = r15; 259 | r15 = S_4; 260 | S_8 = r15; 261 | r11 = S_8; 262 | rdx = S_7; 263 | r11 = ~r11; 264 | rdx = ~rdx; 265 | r11 = r11 | rdx; 266 | S_7 = r11; 267 | r10 = S_7; 268 | r15 = S_6; 269 | r10 = ~r10; 270 | r15 = ~r15; 271 | r10 = r10 & r15; 272 | S_6 = r10; 273 | r15 = S_3; 274 | S_7 = r15; 275 | r15 = S_4; 276 | S_8 = r15; 277 | r10 = S_8; 278 | r15 = S_7; 279 | r10 = ~r10; 280 | r15 = ~r15; 281 | r10 = r10 & r15; 282 | S_7 = r10; 283 | r10 = S_7; 284 | r15 = S_6; 285 | r10 = ~r10; 286 | r15 = ~r15; 287 | r10 = r10 & r15; 288 | S_6 = r10; 289 | rbx = S_6; 290 | S_9 = rbx; 291 | r15 = S_9; 292 | S_10 = r15; 293 | r11 = S_10; 294 | rsi = rsi + r11; 295 | S_10 = rsi; 296 | S_11 = r8; 297 | rbx = S_10; 298 | S_12 = rbx; 299 | r15 = S_5; 300 | S_13 = r15; 301 | r15 = S_12; 302 | S_14 = r15; 303 | r15 = S_9; 304 | S_15 = r15; 305 | r15 = S_3; 306 | S_1 = r15; 307 | rdx = S_1; 308 | rcx = S_15; 309 | rax = S_14; 310 | r8 = S_13; 311 | } 312 | 313 | int main() { 314 | rcx = 0x1111222200000000; 315 | rdx = 0x0000000033334444; 316 | 317 | RXor(); 318 | printf("RXor: %016llX\n", rax); 319 | 320 | return 0; 321 | } 322 | ``` 323 | 324 | # Output LLVM IR 325 | 326 | ``` 327 | ; Function Attrs: norecurse nounwind uwtable 328 | define dso_local void @_Z4RXorv() local_unnamed_addr #0 { 329 | %1 = load i64, i64* @rcx, align 8, !tbaa !2 330 | %2 = load i64, i64* @rdx, align 8, !tbaa !2 331 | %3 = xor i64 %2, %1 332 | store i64 %3, i64* @r10, align 8, !tbaa !2 333 | store i64 %3, i64* @r11, align 8, !tbaa !2 334 | %4 = load i64, i64* @rsi, align 8, !tbaa !2 335 | %5 = add i64 %4, %3 336 | store i64 %5, i64* @rsi, align 8, !tbaa !2 337 | store i64 %5, i64* @rbx, align 8, !tbaa !2 338 | store i64 %2, i64* @r15, align 8, !tbaa !2 339 | store i64 %2, i64* @rdx, align 8, !tbaa !2 340 | store i64 %3, i64* @rcx, align 8, !tbaa !2 341 | store i64 %5, i64* @rax, align 8, !tbaa !2 342 | ret void 343 | ``` 344 | -------------------------------------------------------------------------------- /Source/CS_Reg_Mapping.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | static std::map CS_x86_Reg_Map = { 7 | { X86_REG_INVALID, "Invalid" }, 8 | 9 | { X86_REG_AH, "ah" }, 10 | { X86_REG_AL, "al" }, 11 | { X86_REG_AX, "ax" }, 12 | { X86_REG_BH, "bh" }, 13 | { X86_REG_BL, "bl" }, 14 | { X86_REG_BP, "bp" }, 15 | { X86_REG_BPL, "bpl" }, 16 | { X86_REG_BX, "bx" }, 17 | { X86_REG_CH, "ch" }, 18 | { X86_REG_CL, "cl" }, 19 | { X86_REG_CS, "cs" }, 20 | { X86_REG_CX, "cx" }, 21 | { X86_REG_DH, "dh" }, 22 | { X86_REG_DI, "di" }, 23 | { X86_REG_DIL, "dil" }, 24 | { X86_REG_DL, "dl" }, 25 | { X86_REG_DS, "ds" }, 26 | { X86_REG_DX, "dx" }, 27 | { X86_REG_EAX, "eax" }, 28 | { X86_REG_EBP, "ebp" }, 29 | { X86_REG_EBX, "ebx" }, 30 | { X86_REG_ECX, "ecx" }, 31 | { X86_REG_EDI, "edi" }, 32 | { X86_REG_EDX, "edx" }, 33 | { X86_REG_EFLAGS, "flags" }, 34 | { X86_REG_EIP, "eip" }, 35 | { X86_REG_EIZ, "eiz" }, 36 | { X86_REG_ES, "es" }, 37 | { X86_REG_ESI, "esi" }, 38 | { X86_REG_ESP, "esp" }, 39 | { X86_REG_FPSW, "fpsw" }, 40 | { X86_REG_FS, "fs" }, 41 | { X86_REG_GS, "gs" }, 42 | { X86_REG_IP, "ip" }, 43 | { X86_REG_RAX, "rax" }, 44 | { X86_REG_RBP, "rbp" }, 45 | { X86_REG_RBX, "rbx" }, 46 | { X86_REG_RCX, "rcx" }, 47 | { X86_REG_RDI, "rdi" }, 48 | { X86_REG_RDX, "rdx" }, 49 | { X86_REG_RIP, "rip" }, 50 | { X86_REG_RIZ, "riz" }, 51 | { X86_REG_RSI, "rsi" }, 52 | { X86_REG_RSP, "rsp" }, 53 | { X86_REG_SI, "si" }, 54 | { X86_REG_SIL, "sil" }, 55 | { X86_REG_SP, "sp" }, 56 | { X86_REG_SPL, "spl" }, 57 | { X86_REG_SS, "ss" }, 58 | { X86_REG_CR0, "cr0" }, 59 | { X86_REG_CR1, "cr1" }, 60 | { X86_REG_CR2, "cr2" }, 61 | { X86_REG_CR3, "cr3" }, 62 | { X86_REG_CR4, "cr4" }, 63 | { X86_REG_CR5, "cr5" }, 64 | { X86_REG_CR6, "cr6" }, 65 | { X86_REG_CR7, "cr7" }, 66 | { X86_REG_CR8, "cr8" }, 67 | { X86_REG_CR9, "cr9" }, 68 | { X86_REG_CR10, "cr10" }, 69 | { X86_REG_CR11, "cr11" }, 70 | { X86_REG_CR12, "cr12" }, 71 | { X86_REG_CR13, "cr13" }, 72 | { X86_REG_CR14, "cr14" }, 73 | { X86_REG_CR15, "cr15" }, 74 | { X86_REG_DR0, "dr0" }, 75 | { X86_REG_DR1, "dr1" }, 76 | { X86_REG_DR2, "dr2" }, 77 | { X86_REG_DR3, "dr3" }, 78 | { X86_REG_DR4, "dr4" }, 79 | { X86_REG_DR5, "dr5" }, 80 | { X86_REG_DR6, "dr6" }, 81 | { X86_REG_DR7, "dr7" }, 82 | { X86_REG_FP0, "fp0" }, 83 | { X86_REG_FP1, "fp1" }, 84 | { X86_REG_FP2, "fp2" }, 85 | { X86_REG_FP3, "fp3" }, 86 | { X86_REG_FP4, "fp4" }, 87 | { X86_REG_FP5, "fp5" }, 88 | { X86_REG_FP6, "fp6" }, 89 | { X86_REG_FP7, "fp7" }, 90 | { X86_REG_K0, "k0" }, 91 | { X86_REG_K1, "k1" }, 92 | { X86_REG_K2, "k2" }, 93 | { X86_REG_K3, "k3" }, 94 | { X86_REG_K4, "k4" }, 95 | { X86_REG_K5, "k5" }, 96 | { X86_REG_K6, "k6" }, 97 | { X86_REG_K7, "k7" }, 98 | { X86_REG_MM0, "mm0" }, 99 | { X86_REG_MM1, "mm1" }, 100 | { X86_REG_MM2, "mm2" }, 101 | { X86_REG_MM3, "mm3" }, 102 | { X86_REG_MM4, "mm4" }, 103 | { X86_REG_MM5, "mm5" }, 104 | { X86_REG_MM6, "mm6" }, 105 | { X86_REG_MM7, "mm7" }, 106 | { X86_REG_R8, "r8" }, 107 | { X86_REG_R9, "r9" }, 108 | { X86_REG_R10, "r10" }, 109 | { X86_REG_R11, "r11" }, 110 | { X86_REG_R12, "r12" }, 111 | { X86_REG_R13, "r13" }, 112 | { X86_REG_R14, "r14" }, 113 | { X86_REG_R15, "r15" }, 114 | { X86_REG_ST0, "st(0" }, 115 | { X86_REG_ST1, "st(1)" }, 116 | { X86_REG_ST2, "st(2)" }, 117 | { X86_REG_ST3, "st(3)" }, 118 | { X86_REG_ST4, "st(4)" }, 119 | { X86_REG_ST5, "st(5)" }, 120 | { X86_REG_ST6, "st(6)" }, 121 | { X86_REG_ST7, "st(7)" }, 122 | { X86_REG_XMM0, "xmm0" }, 123 | { X86_REG_XMM1, "xmm1" }, 124 | { X86_REG_XMM2, "xmm2" }, 125 | { X86_REG_XMM3, "xmm3" }, 126 | { X86_REG_XMM4, "xmm4" }, 127 | { X86_REG_XMM5, "xmm5" }, 128 | { X86_REG_XMM6, "xmm6" }, 129 | { X86_REG_XMM7, "xmm7" }, 130 | { X86_REG_XMM8, "xmm8" }, 131 | { X86_REG_XMM9, "xmm9" }, 132 | { X86_REG_XMM10, "xmm10" }, 133 | { X86_REG_XMM11, "xmm11" }, 134 | { X86_REG_XMM12, "xmm12" }, 135 | { X86_REG_XMM13, "xmm13" }, 136 | { X86_REG_XMM14, "xmm14" }, 137 | { X86_REG_XMM15, "xmm15" }, 138 | { X86_REG_XMM16, "xmm16" }, 139 | { X86_REG_XMM17, "xmm17" }, 140 | { X86_REG_XMM18, "xmm18" }, 141 | { X86_REG_XMM19, "xmm19" }, 142 | { X86_REG_XMM20, "xmm20" }, 143 | { X86_REG_XMM21, "xmm21" }, 144 | { X86_REG_XMM22, "xmm22" }, 145 | { X86_REG_XMM23, "xmm23" }, 146 | { X86_REG_XMM24, "xmm24" }, 147 | { X86_REG_XMM25, "xmm25" }, 148 | { X86_REG_XMM26, "xmm26" }, 149 | { X86_REG_XMM27, "xmm27" }, 150 | { X86_REG_XMM28, "xmm28" }, 151 | { X86_REG_XMM29, "xmm29" }, 152 | { X86_REG_XMM30, "xmm30" }, 153 | { X86_REG_XMM31, "xmm31" }, 154 | { X86_REG_YMM0, "ymm0" }, 155 | { X86_REG_YMM1, "ymm1" }, 156 | { X86_REG_YMM2, "ymm2" }, 157 | { X86_REG_YMM3, "ymm3" }, 158 | { X86_REG_YMM4, "ymm4" }, 159 | { X86_REG_YMM5, "ymm5" }, 160 | { X86_REG_YMM6, "ymm6" }, 161 | { X86_REG_YMM7, "ymm7" }, 162 | { X86_REG_YMM8, "ymm8" }, 163 | { X86_REG_YMM9, "ymm9" }, 164 | { X86_REG_YMM10, "ymm10" }, 165 | { X86_REG_YMM11, "ymm11" }, 166 | { X86_REG_YMM12, "ymm12" }, 167 | { X86_REG_YMM13, "ymm13" }, 168 | { X86_REG_YMM14, "ymm14" }, 169 | { X86_REG_YMM15, "ymm15" }, 170 | { X86_REG_YMM16, "ymm16" }, 171 | { X86_REG_YMM17, "ymm17" }, 172 | { X86_REG_YMM18, "ymm18" }, 173 | { X86_REG_YMM19, "ymm19" }, 174 | { X86_REG_YMM20, "ymm20" }, 175 | { X86_REG_YMM21, "ymm21" }, 176 | { X86_REG_YMM22, "ymm22" }, 177 | { X86_REG_YMM23, "ymm23" }, 178 | { X86_REG_YMM24, "ymm24" }, 179 | { X86_REG_YMM25, "ymm25" }, 180 | { X86_REG_YMM26, "ymm26" }, 181 | { X86_REG_YMM27, "ymm27" }, 182 | { X86_REG_YMM28, "ymm28" }, 183 | { X86_REG_YMM29, "ymm29" }, 184 | { X86_REG_YMM30, "ymm30" }, 185 | { X86_REG_YMM31, "ymm31" }, 186 | { X86_REG_ZMM0, "zmm0" }, 187 | { X86_REG_ZMM1, "zmm1" }, 188 | { X86_REG_ZMM2, "zmm2" }, 189 | { X86_REG_ZMM3, "zmm3" }, 190 | { X86_REG_ZMM4, "zmm4" }, 191 | { X86_REG_ZMM5, "zmm5" }, 192 | { X86_REG_ZMM6, "zmm6" }, 193 | { X86_REG_ZMM7, "zmm7" }, 194 | { X86_REG_ZMM8, "zmm8" }, 195 | { X86_REG_ZMM9, "zmm9" }, 196 | { X86_REG_ZMM10, "zmm10" }, 197 | { X86_REG_ZMM11, "zmm11" }, 198 | { X86_REG_ZMM12, "zmm12" }, 199 | { X86_REG_ZMM13, "zmm13" }, 200 | { X86_REG_ZMM14, "zmm14" }, 201 | { X86_REG_ZMM15, "zmm15" }, 202 | { X86_REG_ZMM16, "zmm16" }, 203 | { X86_REG_ZMM17, "zmm17" }, 204 | { X86_REG_ZMM18, "zmm18" }, 205 | { X86_REG_ZMM19, "zmm19" }, 206 | { X86_REG_ZMM20, "zmm20" }, 207 | { X86_REG_ZMM21, "zmm21" }, 208 | { X86_REG_ZMM22, "zmm22" }, 209 | { X86_REG_ZMM23, "zmm23" }, 210 | { X86_REG_ZMM24, "zmm24" }, 211 | { X86_REG_ZMM25, "zmm25" }, 212 | { X86_REG_ZMM26, "zmm26" }, 213 | { X86_REG_ZMM27, "zmm27" }, 214 | { X86_REG_ZMM28, "zmm28" }, 215 | { X86_REG_ZMM29, "zmm29" }, 216 | { X86_REG_ZMM30, "zmm30" }, 217 | { X86_REG_ZMM31, "zmm31" }, 218 | { X86_REG_R8B, "r8b" }, 219 | { X86_REG_R9B, "r9b" }, 220 | { X86_REG_R10B, "r10b" }, 221 | { X86_REG_R11B, "r11b" }, 222 | { X86_REG_R12B, "r12b" }, 223 | { X86_REG_R13B, "r13b" }, 224 | { X86_REG_R14B, "r14b" }, 225 | { X86_REG_R15B, "r15b" }, 226 | { X86_REG_R8D, "r8d" }, 227 | { X86_REG_R9D, "r9d" }, 228 | { X86_REG_R10D, "r10d" }, 229 | { X86_REG_R11D, "r11d" }, 230 | { X86_REG_R12D, "r12d" }, 231 | { X86_REG_R13D, "r13d" }, 232 | { X86_REG_R14D, "r14d" }, 233 | { X86_REG_R15D, "r15d" }, 234 | { X86_REG_R8W, "r8w" }, 235 | { X86_REG_R9W, "r9w" }, 236 | { X86_REG_R10W, "r10w" }, 237 | { X86_REG_R11W, "r11w" }, 238 | { X86_REG_R12W, "r12w" }, 239 | { X86_REG_R13W, "r13w" }, 240 | { X86_REG_R14W, "r14w" }, 241 | { X86_REG_R15W, "r15w" }, 242 | }; -------------------------------------------------------------------------------- /Source/UniTaint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "UniTranslator.h" 12 | 13 | 14 | namespace Uni { 15 | 16 | int X86Regs[][5] = { 17 | {X86_REG_RAX, X86_REG_EAX, X86_REG_AX, X86_REG_AH, X86_REG_AL}, 18 | {X86_REG_RBX, X86_REG_EBX, X86_REG_BX, X86_REG_BH, X86_REG_BL}, 19 | {X86_REG_RCX, X86_REG_ECX, X86_REG_CX, X86_REG_CH, X86_REG_CL}, 20 | {X86_REG_RDX, X86_REG_EDX, X86_REG_DX, X86_REG_DH, X86_REG_DL}, 21 | {X86_REG_RSI, X86_REG_ESI, X86_REG_SI, X86_REG_SIL, 0}, 22 | {X86_REG_RDI, X86_REG_EDI, X86_REG_DI, X86_REG_DIL, 0}, 23 | {X86_REG_RBP, X86_REG_EBP, X86_REG_BP, 0, 0}, 24 | {X86_REG_RSP, X86_REG_ESP, X86_REG_SP, 0, 0}, 25 | {X86_REG_R8, X86_REG_R8D, X86_REG_R8W, X86_REG_R8B, 0}, 26 | {X86_REG_R9, X86_REG_R9D, X86_REG_R9W, X86_REG_R9B, 0}, 27 | {X86_REG_R10, X86_REG_R10D, X86_REG_R10W, X86_REG_R10B, 0}, 28 | {X86_REG_R11, X86_REG_R11D, X86_REG_R11W, X86_REG_R11B, 0}, 29 | {X86_REG_R12, X86_REG_R12D, X86_REG_R12W, X86_REG_R12B, 0}, 30 | {X86_REG_R13, X86_REG_R13D, X86_REG_R13W, X86_REG_R13B, 0}, 31 | {X86_REG_R14, X86_REG_R14D, X86_REG_R14W, X86_REG_R14B, 0}, 32 | {X86_REG_R15, X86_REG_R15D, X86_REG_R15W, X86_REG_R15B, 0}, 33 | }; 34 | 35 | enum TType { 36 | Reg = 1, 37 | Memory = 2 38 | }; 39 | 40 | class TValue { 41 | public: 42 | virtual TType getType() { 43 | return Type; 44 | } 45 | 46 | TType Type; 47 | }; 48 | 49 | class TReg : TValue { 50 | public: 51 | TReg(int Register) { 52 | this->Register = Register; 53 | this->Type = TType::Reg; 54 | } 55 | 56 | int getRegister() { 57 | return Register; 58 | } 59 | private: 60 | int Register; 61 | }; 62 | 63 | class TMemory : TValue { 64 | public: 65 | TMemory(uint64_t Offset) { 66 | this->Offset = Offset; 67 | this->Type = TType::Memory; 68 | } 69 | 70 | uint64_t getOffset() { 71 | return Offset; 72 | } 73 | private: 74 | uint64_t Offset; 75 | }; 76 | 77 | class UniTaint { 78 | public: 79 | UniTaint(uc_engine *uc, uint64_t RSP_Base, uint64_t EntryPointVA) : UT(uc, RSP_Base, EntryPointVA) { 80 | this->uc = uc; 81 | TaintAll = false; 82 | 83 | cs_err err = cs_open(CS_ARCH_X86, CS_MODE_64, &this->HCapstone); 84 | if (err) { 85 | printf("Failed on cs_open() with error returned: %u\n", err); 86 | exit(0); 87 | } 88 | 89 | // Set detail option 90 | cs_option(this->HCapstone, CS_OPT_DETAIL, CS_OPT_ON); 91 | }; 92 | ~UniTaint() {}; 93 | 94 | bool isTaintedReg(int Reg) { 95 | if (TaintAll == true) { 96 | return true; 97 | } 98 | for (auto Iter = TaintedValues.begin(); Iter != TaintedValues.end(); ++Iter) { 99 | if ((*Iter)->getType() == TType::Reg) { 100 | TReg *R = (TReg *)*Iter; 101 | if (R->getRegister() == Reg) { 102 | return true; 103 | } 104 | } 105 | } 106 | return false; 107 | } 108 | 109 | bool isTaintedMemory(uint64_t Offset) { 110 | if (TaintAll == true) { 111 | return true; 112 | } 113 | for (auto Iter = TaintedValues.begin(); Iter != TaintedValues.end(); ++Iter) { 114 | if ((*Iter)->getType() == TType::Memory) { 115 | TMemory *M = (TMemory *)*Iter; 116 | if (M->getOffset() == Offset) { 117 | return true; 118 | } 119 | } 120 | } 121 | return false; 122 | } 123 | 124 | /* 125 | int getFullReg(int Reg) { 126 | // Some test 127 | return Reg; 128 | 129 | int FullReg = 0; 130 | for (int i = 0; i < 16; i++) { 131 | for (int j = 0; j < 5; j++) { 132 | if (X86Regs[i][j] == 0) 133 | break; 134 | 135 | if (X86Regs[i][j] == Reg) 136 | return X86Regs[i][0]; 137 | } 138 | } 139 | 140 | assert(FullReg == 0 && "Full register not found!"); 141 | } 142 | */ 143 | 144 | void addReg(int Reg) { 145 | if (this->isTaintedReg(Reg) == false) { 146 | TaintedValues.push_back((TValue *) new TReg(Reg)); 147 | } 148 | } 149 | 150 | void removeReg(int Reg) { 151 | for (auto Iter = TaintedValues.begin(); Iter != TaintedValues.end(); ++Iter) { 152 | if ((*Iter)->getType() == TType::Reg) { 153 | TReg *R = (TReg *)*Iter; 154 | if (R->getRegister() == Reg) { 155 | TaintedValues.erase(Iter); 156 | return; 157 | } 158 | } 159 | } 160 | } 161 | 162 | 163 | void addMemory(uint64_t Offset) { 164 | if (this->isTaintedMemory(Offset) == false) { 165 | TaintedValues.push_back((TValue *) new TMemory(Offset)); 166 | } 167 | } 168 | 169 | void removeMemory(uint64_t Offset) { 170 | for (auto Iter = TaintedValues.begin(); Iter != TaintedValues.end(); ++Iter) { 171 | if ((*Iter)->getType() == TType::Memory) { 172 | TMemory *M = (TMemory *)*Iter; 173 | if (M->getOffset() == Offset) { 174 | TaintedValues.erase(Iter); 175 | return; 176 | } 177 | } 178 | } 179 | } 180 | 181 | void addEPTaint(int Reg) { 182 | if (this->isTaintedReg(Reg) == false) { 183 | TaintedValues.push_back((TValue *) new TReg(Reg)); 184 | EPTaintedValues.insert(Reg); 185 | } 186 | } 187 | 188 | void setTaintAllMode() { 189 | this->TaintAll = true; 190 | } 191 | 192 | void setTaint(uc_engine *uc, cs_x86_op &Op) { 193 | switch (Op.type) { 194 | case CS_OP_REG: { 195 | this->addReg(Op.reg); 196 | } 197 | break; 198 | case CS_OP_MEM: { 199 | uint64_t MemPtr = this->getAbsoluteAddress(uc, Op.mem); 200 | this->addMemory(MemPtr); 201 | } 202 | break; 203 | default: 204 | assert("setTaint Unknown type!\n"); 205 | } 206 | } 207 | 208 | void removeTaint(uc_engine *uc, cs_x86_op &Op) { 209 | switch (Op.type) { 210 | case CS_OP_REG: { 211 | this->removeReg(Op.reg); 212 | } 213 | break; 214 | case CS_OP_MEM: { 215 | uint64_t MemPtr = this->getAbsoluteAddress(uc, Op.mem); 216 | this->removeMemory(MemPtr); 217 | } 218 | break; 219 | default: 220 | assert("setTaint Unknown type!\n"); 221 | } 222 | } 223 | 224 | bool isPush(cs_insn &Instruction) { 225 | if (!strncmp(Instruction.mnemonic, "push", 4)) { 226 | return true; 227 | } 228 | return false; 229 | } 230 | 231 | bool isPop(cs_insn &Instruction) { 232 | if (!strncmp(Instruction.mnemonic, "pop", 3)) { 233 | return true; 234 | } 235 | return false; 236 | } 237 | 238 | bool isRead(cs_x86_op &Op) { 239 | return Op.access & CS_AC_READ; 240 | } 241 | 242 | bool isWrite(cs_x86_op &Op) { 243 | return Op.access & CS_AC_WRITE; 244 | } 245 | 246 | bool isPushed(int Reg) { 247 | // Check if reg is tainted at the EP 248 | if (EPTaintedValues.find(Reg) == EPTaintedValues.end()) { 249 | // Then always ok to use it 250 | return true; 251 | } 252 | 253 | if (PushedRegs.find(Reg) == PushedRegs.end()) { 254 | return false; 255 | } 256 | 257 | return true; 258 | } 259 | 260 | bool isEPTaintedSlot(uint64_t Addr) { 261 | if (this->EPTaintedValuesSlots.find(Addr) != this->EPTaintedValuesSlots.end()) 262 | return true; 263 | 264 | return false; 265 | } 266 | 267 | int isValidOperation(DISASM &pDisAsm, bool AllowData = false) { 268 | if (pDisAsm.Instruction.Category | GENERAL_PURPOSE_INSTRUCTION) { 269 | int Cat = pDisAsm.Instruction.Category & 0xFFFF; 270 | if (Cat == DATA_TRANSFER) { 271 | if (AllowData) 272 | return 1; 273 | return 0; 274 | } 275 | 276 | if (Cat == ARITHMETIC_INSTRUCTION) 277 | return 1; 278 | if (Cat == LOGICAL_INSTRUCTION) 279 | return 1; 280 | if (Cat == SHIFT_ROTATE) 281 | return 1; 282 | if (Cat == BIT_UInt8) 283 | return 2; 284 | if (Cat == CONTROL_TRANSFER) 285 | return 1; 286 | if (Cat == STRING_INSTRUCTION) 287 | return 1; 288 | 289 | assert("Not handled Instructio Catagory!"); 290 | } 291 | 292 | return false; 293 | } 294 | 295 | uint64_t getAbsoluteAddress(uc_engine *uc, x86_op_mem &Mem) { 296 | uint64_t Addr = 0; 297 | if (Mem.base != X86_REG_INVALID) { 298 | uc_reg_read(uc, Mem.base, &Addr); 299 | } 300 | 301 | if (Mem.index != X86_REG_INVALID) { 302 | uint64_t Index; 303 | uc_reg_read(uc, Mem.index, &Index); 304 | Addr = Addr + Index * Mem.scale; 305 | } 306 | 307 | Addr += Mem.disp; 308 | 309 | return Addr; 310 | } 311 | 312 | uint64_t getOperandValue(uc_engine *uc, cs_x86_op &Op, bool Read=false) { 313 | uint64_t V = 0; 314 | 315 | switch (Op.type) { 316 | case CS_OP_REG: { 317 | uc_reg_read(uc, Op.reg, &V); 318 | } 319 | break; 320 | case CS_OP_MEM: { 321 | V = this->getAbsoluteAddress(uc, Op.mem); 322 | if (Read) { 323 | uc_mem_read(uc, V, &V, 8); 324 | } 325 | } 326 | break; 327 | case CS_OPT_INVALID: { 328 | V = 0xDEADBEEF; 329 | } 330 | break; 331 | default: 332 | assert("Unknown operand type!\n"); 333 | } 334 | 335 | return V; 336 | } 337 | 338 | std::vector getTaintType(cs_x86_op *Ops, int Count) { 339 | std::vector TaintType; 340 | 341 | for (int i = 0; i < Count; i++) { 342 | switch (Ops[i].type) { 343 | case CS_OP_REG: { 344 | if (isTaintedReg(Ops[i].reg)) { 345 | // Tainted reg 346 | TaintType.push_back('T'); 347 | } else { 348 | // Const 349 | TaintType.push_back('C'); 350 | } 351 | } 352 | break; 353 | case CS_OP_MEM: { 354 | uint64_t V = this->getAbsoluteAddress(uc, Ops[i].mem); 355 | if (isTaintedMemory(V)) { 356 | TaintType.push_back('T'); 357 | } 358 | else { 359 | TaintType.push_back('C'); 360 | } 361 | } 362 | break; 363 | default: 364 | TaintType.push_back('N'); 365 | } 366 | } 367 | 368 | return TaintType; 369 | } 370 | 371 | void translateInstructionRemill(uint64_t Address, const uint8_t *Code, int Size, size_t Count) { 372 | cs_insn *Instructions; 373 | int count = cs_disasm(this->HCapstone, Code, Size, Address, 1, &Instructions); 374 | 375 | this->UT.translateInstructionLLVM(Instructions[0]); 376 | 377 | // Clean up 378 | if (count) { 379 | cs_free(Instructions, count); 380 | } 381 | } 382 | 383 | void processInstructions(uc_engine *uc, uint64_t Address, const uint8_t *Code, int Size, size_t Count, uint64_t RSP) { 384 | cs_insn *Instructions; 385 | size_t next_ins = 0; 386 | 387 | //capstone 388 | int count = cs_disasm(this->HCapstone, Code, Size, Address, 1, &Instructions); 389 | 390 | //BEA 391 | DISASM BeaIns; 392 | memset(&BeaIns, 0, sizeof(DISASM)); 393 | 394 | BeaIns.Archi = 64; 395 | BeaIns.EIP = (UIntPtr) Code; 396 | BeaIns.VirtualAddr = Address; 397 | int OpLen = Disasm(&BeaIns); 398 | 399 | 400 | cs_insn &Ins = Instructions[0]; 401 | cs_detail *Detail = Ins.detail; 402 | cs_x86 &X86 = Detail->x86; 403 | int OpcodeLen = Ins.size; 404 | bool Handled = false; 405 | 406 | 407 | //printf("%08llX: %s %s // RSP %X 0: %llX 1: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, getOperandValue(uc, X86.operands[0]), getOperandValue(uc, X86.operands[1])); 408 | 409 | // Handle push / pop first 410 | if (isPush(Ins)) { 411 | switch (X86.operands[0].type) { 412 | case CS_OP_REG: { 413 | int RReg = X86.operands[0].reg; 414 | if (this->isTaintedReg(RReg)) { 415 | this->addMemory(RSP - 8); 416 | printf("%08llX: T %s %s // %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP - 8); 417 | 418 | // Translate 419 | auto TT = getTaintType(X86.operands, X86.op_count); 420 | this->UT.translateInstruction(Ins, TT); 421 | 422 | this->PushedRegs.insert(RReg); 423 | this->EPTaintedValuesSlots.insert(RSP - 8); 424 | 425 | // Test: Remove taint on register after push 426 | this->removeReg(RReg); 427 | } 428 | else { 429 | // Check if memory is tainted 430 | if (this->isTaintedMemory(RSP - 8)) { 431 | this->removeMemory(RSP - 8); 432 | } 433 | } 434 | Handled = true; 435 | } 436 | break; 437 | case CS_OP_MEM: { 438 | int64_t MemPtr = X86.operands[0].mem.disp; 439 | if (this->isTaintedMemory(MemPtr)) { 440 | this->addMemory(RSP - 8); 441 | printf("%08llX: T %s %s //%X\n", Address, Ins.mnemonic, Ins.op_str, RSP - 8); 442 | 443 | // Translate 444 | auto TT = getTaintType(X86.operands, X86.op_count); 445 | this->UT.translateInstruction(Ins, TT); 446 | 447 | } else { 448 | // Check if memory is tainted 449 | if (this->isTaintedMemory(RSP - 8)) { 450 | this->removeMemory(RSP - 8); 451 | } 452 | } 453 | Handled = true; 454 | } 455 | break; 456 | } 457 | } 458 | 459 | if (isPop(Ins)) { 460 | switch (X86.operands[0].type) { 461 | case CS_OP_REG: { 462 | int RReg = X86.operands[0].reg; 463 | if (this->isTaintedMemory(RSP)) { 464 | this->addReg(RReg); 465 | 466 | uint64_t V = 0; 467 | uc_mem_read(uc, RSP, &V, 8); 468 | printf("%08llX: T %s %s //%X V: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, V); 469 | 470 | // Translate 471 | auto TT = getTaintType(X86.operands, X86.op_count); 472 | this->UT.translateInstruction(Ins, TT); 473 | 474 | // Test: Remove taint on memory after pop 475 | this->removeMemory(RSP); 476 | } else if (this->isTaintedReg(RReg)) { 477 | // Check if reg is tainted and remove taint 478 | this->removeReg(RReg); 479 | } 480 | // Mark as handled 481 | Handled = true; 482 | } 483 | break; 484 | case CS_OP_MEM: { 485 | uint64_t Addr = this->getAbsoluteAddress(uc, X86.operands[0].mem); 486 | if (this->isTaintedMemory(RSP)) { 487 | // Remove taint on RSP and taint dest 488 | printf("%08llX: T %s %s // %X %X\n", Address, Ins.mnemonic, Ins.op_str, RSP, Addr); 489 | 490 | // Translate 491 | auto TT = getTaintType(X86.operands, X86.op_count); 492 | this->UT.translateInstruction(Ins, TT); 493 | 494 | this->removeMemory(RSP); 495 | this->addMemory(Addr); 496 | } else if (this->isTaintedMemory(Addr)) { 497 | // Unknown SRC so remove taint on Addr 498 | this->removeMemory(Addr); 499 | } 500 | Handled = true; 501 | } 502 | break; 503 | } 504 | } 505 | 506 | // Check if operands are tainted 507 | for (int i = 0; i < X86.op_count; i++) { 508 | // If (push/pop/pushfq/popfq) then its already handled 509 | if (Handled) 510 | break; 511 | 512 | // Parse operands 513 | switch (X86.operands[i].type) { 514 | case CS_OP_REG: 515 | { 516 | int RReg = X86.operands[i].reg; 517 | uint64_t RValue = 0; 518 | uc_reg_read(uc, RReg, &RValue); 519 | if (this->isPushed(RReg) && this->isTaintedReg(RReg)) { 520 | if (isWrite(X86.operands[i])) { 521 | // Check if this is an arithmetic operation 522 | int VOPType = isValidOperation(BeaIns); 523 | if (VOPType == 1) { 524 | printf("%08llX: T %s %s // RSP %X 0: %llX 1: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, getOperandValue(uc, X86.operands[0]), getOperandValue(uc, X86.operands[1])); 525 | 526 | // Translate 527 | auto TT = getTaintType(X86.operands, X86.op_count); 528 | this->UT.translateInstruction(Ins, TT); 529 | 530 | Handled = true; 531 | break; 532 | } 533 | else if (VOPType == 2) { 534 | // Ignore for now ... (TODO) 535 | // No cases where this instructions were needed so far 536 | } else { 537 | // else untaint 538 | this->removeReg(RReg); 539 | break; 540 | } 541 | } 542 | else if (isRead(X86.operands[i])) { 543 | int VOpType = isValidOperation(BeaIns, true); 544 | if (VOpType == 1) { 545 | // then we are ok 546 | printf("%08llX: T %s %s // RSP %X 0: %llX 1: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, getOperandValue(uc, X86.operands[0]), getOperandValue(uc, X86.operands[1])); 547 | 548 | // Translate 549 | auto TT = getTaintType(X86.operands, X86.op_count); 550 | this->UT.translateInstruction(Ins, TT); 551 | 552 | // taint the destination 553 | this->setTaint(uc, X86.operands[0]); 554 | 555 | // Test: remove taint on stored reg in mem 556 | if (X86.operands[0].type == CS_OP_MEM) { 557 | this->removeReg(RReg); 558 | } 559 | } 560 | else if (VOpType == 2) { 561 | // Ignore 562 | } else { 563 | // untaint 564 | this->removeReg(RReg); 565 | } 566 | Handled = true; 567 | break; 568 | } 569 | } 570 | } 571 | break; 572 | case CS_OP_MEM: 573 | { 574 | uint64_t MemPtr = this->getAbsoluteAddress(uc, X86.operands[i].mem); 575 | if (this->isTaintedMemory(MemPtr)) { 576 | // ReadMem 577 | uint64_t Value = 0; 578 | uc_mem_read(uc, MemPtr, &Value, 8); 579 | 580 | // Memory is the destination => write 581 | if (this->isWrite(X86.operands[i])) { 582 | int RReg = X86.operands[1].reg; 583 | uint64_t RValue = 0; 584 | uc_reg_read(uc, RReg, &RValue); 585 | 586 | // Check if source is tainted 587 | if (this->isTaintedReg(RReg)) { 588 | // Log instruction 589 | printf("%08llX: T %s %s // RSP %X 0: %llX 1: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, getOperandValue(uc, X86.operands[0]), getOperandValue(uc, X86.operands[1])); 590 | 591 | // Translate 592 | auto TT = getTaintType(X86.operands, X86.op_count); 593 | this->UT.translateInstruction(Ins, TT); 594 | 595 | // Todo: 596 | // We assume that this is a store and the reg is not used anymore after that ... 597 | this->removeReg(RReg); 598 | } 599 | else { 600 | // unknown reg 601 | // remove taint on memory slot 602 | this->removeMemory(MemPtr); 603 | } 604 | 605 | // Remove taint on Reg 606 | // strange disabled for now 607 | //this->removeReg(RReg); 608 | } 609 | else { // must be a read 610 | // Log instruction 611 | printf("%08llX: T %s %s // RSP %X 0: %llX 1: %llX\n", Address, Ins.mnemonic, Ins.op_str, RSP, getOperandValue(uc, X86.operands[0]), getOperandValue(uc, X86.operands[1])); 612 | 613 | // Translate 614 | auto TT = getTaintType(X86.operands, X86.op_count); 615 | this->UT.translateInstruction(Ins, TT); 616 | 617 | // taint the destination 618 | this->setTaint(uc, X86.operands[0]); 619 | 620 | // (Wrong) remove taint on src 621 | // Keep the taint otherwise until it get written by something we don't know, otherwise we miss some access 622 | //this->removeTaint(uc, X86.operands[i]); 623 | } 624 | 625 | Handled = true; 626 | break; 627 | } 628 | } 629 | break; 630 | case CS_OP_IMM: { 631 | // Not interessting 632 | // So far we don't have any cases to handle this one 633 | //printf("Please implement CS_OP_IMM for operand! %i\n", X86.operands[i].type); 634 | } 635 | break; 636 | default: 637 | printf("Please implement the missing operand! %i\n", X86.operands[i].type); 638 | } 639 | } 640 | 641 | // Clean up 642 | if (count) { 643 | cs_free(Instructions, count); 644 | } 645 | } 646 | 647 | void dumpLLVMTranslation(std::string OutputPath) { 648 | this->UT.finishLLVMTranslation(OutputPath); 649 | } 650 | 651 | private: 652 | uc_engine *uc; 653 | UniTranslator UT; 654 | bool TaintAll; 655 | 656 | std::set PushedRegs; 657 | std::vector TaintedValues; 658 | std::set EPTaintedValues; 659 | std::set EPTaintedValuesSlots; 660 | std::vector TaintedInstructions; 661 | 662 | csh HCapstone; 663 | }; 664 | 665 | }; -------------------------------------------------------------------------------- /Source/UniTranslator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "CS_Reg_Mapping.h" 14 | 15 | class UniTranslator { 16 | public: 17 | UniTranslator(uc_engine *uc, uint64_t RSP_Base, uint64_t EntryPointVA) { 18 | this->uc = uc; 19 | this->CurrentSlot = 0; 20 | this->RSP_Base = RSP_Base; 21 | }; 22 | 23 | ~UniTranslator() { 24 | this->uc = nullptr; 25 | this->printTranslation(); 26 | } 27 | 28 | void printTranslation() { 29 | // Create Slots 30 | for (int i = 0; i < this->CurrentSlot; i++) { 31 | printf("uint64_t S_%d;\n", i); 32 | } 33 | printf("\n"); 34 | 35 | std::cout << this->LoggedInstructions; 36 | } 37 | 38 | uint64_t getAbsoluteAddress(x86_op_mem &Mem) { 39 | uint64_t Addr = 0; 40 | if (Mem.base != X86_REG_INVALID) { 41 | uc_reg_read(uc, Mem.base, &Addr); 42 | } 43 | 44 | if (Mem.index != X86_REG_INVALID) { 45 | uint64_t Index; 46 | uc_reg_read(uc, Mem.index, &Index); 47 | Addr = Addr + Index * Mem.scale; 48 | } 49 | 50 | Addr += Mem.disp; 51 | 52 | return Addr; 53 | } 54 | 55 | uint64_t getOperandValue(cs_x86_op &Op, bool Read = false) { 56 | uint64_t V = 0; 57 | 58 | switch (Op.type) { 59 | case CS_OP_REG: { 60 | int RReg = Op.reg; 61 | uc_reg_read(uc, RReg, &V); 62 | } 63 | break; 64 | case CS_OP_MEM: { 65 | V = this->getAbsoluteAddress(Op.mem); 66 | if (Read) { 67 | uc_mem_read(uc, V, &V, 8); 68 | } 69 | } 70 | break; 71 | case CS_OPT_INVALID: { 72 | V = 0xDEADBEEF; 73 | } 74 | break; 75 | default: 76 | assert("Unknown operand type!\n"); 77 | } 78 | 79 | return V; 80 | } 81 | 82 | uint64_t getRSP() { 83 | uint64_t V = 0; 84 | uc_reg_read(uc, UC_X86_REG_RSP, &V); 85 | 86 | return V; 87 | } 88 | 89 | std::string getOperandAsString(cs_x86_op &Op, char TaintType = 'N') { 90 | switch (Op.type) { 91 | case CS_OP_REG: { 92 | if (TaintType == 'C') { 93 | uint64_t V; 94 | uc_reg_read(this->uc, Op.reg, &V); 95 | return std::to_string(V); 96 | } 97 | else { 98 | auto &StrReg = CS_x86_Reg_Map[Op.reg]; 99 | return StrReg; 100 | } 101 | } 102 | break; 103 | case CS_OP_MEM: { 104 | auto Addr = this->getAbsoluteAddress(Op.mem); 105 | std::string StrAddr = "S_" + std::to_string(getSlot(Addr)); 106 | return StrAddr; 107 | } 108 | break; 109 | default: 110 | assert("Unknown operand type!\n"); 111 | } 112 | 113 | return ""; 114 | } 115 | 116 | std::string getOperandAsStringRemill(cs_x86_op &Op) { 117 | switch (Op.type) { 118 | case CS_OP_REG: { 119 | auto &StrReg = CS_x86_Reg_Map[Op.reg]; 120 | return StrReg; 121 | } 122 | break; 123 | case CS_OP_MEM: { 124 | auto Addr = this->getAbsoluteAddress(Op.mem); 125 | 126 | Addr = RSP_Base - Addr; 127 | 128 | //std::string StrAddr = "qword ptr [" + std::to_string(getSlot(Addr) * 8) + "] "; 129 | std::string StrAddr = "qword ptr [RSP - " + std::to_string(Addr) + "] "; 130 | return StrAddr; 131 | } 132 | break; 133 | default: 134 | assert("Unknown operand type!\n"); 135 | } 136 | } 137 | 138 | std::string rewriteInstruction(cs_insn &Inst) { 139 | std::string NewInst = Inst.mnemonic; 140 | if (Inst.detail->x86.op_count > 0) { 141 | NewInst += " "; 142 | NewInst += getOperandAsStringRemill(Inst.detail->x86.operands[0]); 143 | } 144 | 145 | if (Inst.detail->x86.op_count > 1) { 146 | NewInst += " , "; 147 | NewInst += getOperandAsStringRemill(Inst.detail->x86.operands[1]); 148 | } 149 | 150 | // assemble 151 | ks_engine *ks; 152 | ks_err err; 153 | size_t size; 154 | unsigned char *encode; 155 | size_t count; 156 | 157 | err = ks_open(KS_ARCH_X86, KS_MODE_64, &ks); 158 | 159 | ks_asm(ks, NewInst.c_str(), 0, &encode, &size, &count); 160 | 161 | // NOTE: free encode after usage to avoid leaking memory 162 | ks_free(encode); 163 | 164 | // close Keystone instance when done 165 | ks_close(ks); 166 | 167 | return NewInst; 168 | } 169 | 170 | void translateInstruction(cs_insn &Inst, std::vector &TT) { 171 | //LLVM test 172 | //translateInstructionLLVM(Inst); 173 | 174 | return; 175 | 176 | // We need to do it a little bit smarter ;) 177 | std::string NInst = rewriteInstruction(Inst); 178 | 179 | std::stringstream SS; 180 | 181 | cs_detail *Detail = Inst.detail; 182 | cs_x86 &X86 = Detail->x86; 183 | int OpcodeLen = Inst.size; 184 | 185 | std::string Op = Inst.mnemonic; 186 | if (Op == "push") { 187 | uint64_t RSP = getRSP(); 188 | uint64_t Slot = getSlot(RSP - 8); 189 | 190 | SS << "S_" << Slot << " = " << getOperandAsString(X86.operands[0], TT[0]) << ";\n"; 191 | this->LoggedInstructions += SS.str(); 192 | } 193 | else if (Op == "pop") { 194 | uint64_t RSP = getRSP(); 195 | int64_t Slot = getSlot(RSP); 196 | 197 | SS << getOperandAsString(X86.operands[0]) << " = " << "S_" << Slot << ";\n"; 198 | this->LoggedInstructions += SS.str(); 199 | } 200 | else if (Op == "mov") { 201 | SS << getOperandAsString(X86.operands[0]) << " = " << getOperandAsString(X86.operands[1], TT[1]) << ";\n"; 202 | this->LoggedInstructions += SS.str(); 203 | } 204 | else if (Op == "imul") { 205 | // needs more work 206 | SS << "rax = rax * " << getOperandAsString(X86.operands[0], TT[0]) << ";\n"; 207 | this->LoggedInstructions += SS.str(); 208 | } 209 | else if (Op == "not") { 210 | SS << getOperandAsString(X86.operands[0]) << " = " << "~" << getOperandAsString(X86.operands[0], TT[0]) << ";\n"; 211 | this->LoggedInstructions += SS.str(); 212 | } 213 | else if (Op == "or") { 214 | SS << getOperandAsString(X86.operands[0]) << " = " << getOperandAsString(X86.operands[0], TT[0]) << " | " << getOperandAsString(X86.operands[1], TT[1]) << ";\n"; 215 | this->LoggedInstructions += SS.str(); 216 | } 217 | else if (Op == "and") { 218 | SS << getOperandAsString(X86.operands[0]) << " = " << getOperandAsString(X86.operands[0], TT[0]) << " & " << getOperandAsString(X86.operands[1], TT[1]) << ";\n"; 219 | this->LoggedInstructions += SS.str(); 220 | } 221 | else if (Op == "add") { 222 | SS << getOperandAsString(X86.operands[0]) << " = " << getOperandAsString(X86.operands[0], TT[0]) << " + " << getOperandAsString(X86.operands[1], TT[1]) << ";\n"; 223 | this->LoggedInstructions += SS.str(); 224 | } 225 | else { 226 | // Not implemented so far 227 | int j = 2; 228 | printf("// Not implemented opcode : %s\n", Op.c_str()); 229 | } 230 | } 231 | 232 | int getSlot(uint64_t VA) { 233 | auto S = Slots.find(VA); 234 | if (S != Slots.end()) { 235 | return SlotMap[VA]; 236 | } 237 | 238 | Slots.insert(VA); 239 | SlotMap[VA] = CurrentSlot; 240 | 241 | return CurrentSlot++; 242 | } 243 | 244 | llvm::Value *getSlotRemill(uint64_t VA) { 245 | auto S = Slots.find(VA); 246 | if (S != Slots.end()) { 247 | return SlotMapLLVM[VA]; 248 | } 249 | 250 | Slots.insert(VA); 251 | SlotMap[VA] = CurrentSlot; 252 | CurrentSlot++; 253 | 254 | return SlotMapLLVM[VA]; 255 | } 256 | 257 | private: 258 | uc_engine *uc; 259 | 260 | uint64_t RSP_Base; 261 | 262 | int CurrentSlot; 263 | std::set Slots; 264 | std::map SlotMap; 265 | std::map SlotMapLLVM; 266 | 267 | std::string LoggedInstructions; 268 | }; -------------------------------------------------------------------------------- /Source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "UniTaint.h" 6 | #include "UniTranslator.h" 7 | 8 | using namespace Uni; 9 | 10 | #include 11 | 12 | typedef struct { 13 | uint64_t EntryPoint; 14 | uint64_t ImageBase; 15 | uint64_t ImageSize; 16 | uint64_t ImportTableVA; 17 | uint8_t *VirtualImage; 18 | PIMAGE_DOS_HEADER DosHeader; 19 | PIMAGE_NT_HEADERS64 NTHeader; 20 | std::vector Sections; 21 | uint8_t *Buffer; 22 | } *PSPEImage, SPEImage; 23 | 24 | SPEImage PEImage; 25 | 26 | bool ParsePE64(char *FilePath) { 27 | FILE *fp = fopen(FilePath, "rb"); 28 | if (!fp) { 29 | printf("Could not open file %s !\n", FilePath); 30 | return 0; 31 | } 32 | 33 | // Get FileSize 34 | fseek(fp, 0, SEEK_END); 35 | size_t FileSize = ftell(fp); 36 | fseek(fp, 0, SEEK_SET); 37 | 38 | // Alloc Mem 39 | uint8_t *FileMem = (uint8_t *)calloc(1, FileSize); 40 | 41 | // Read and close 42 | fread(FileMem, 1, FileSize, fp); 43 | fclose(fp); 44 | 45 | PEImage.DosHeader = (PIMAGE_DOS_HEADER)FileMem; 46 | PEImage.NTHeader = (PIMAGE_NT_HEADERS64)(((BYTE *)PEImage.DosHeader) + (PEImage.DosHeader->e_lfanew)); 47 | 48 | // Get ImageBase 49 | PEImage.EntryPoint = PEImage.NTHeader->OptionalHeader.AddressOfEntryPoint; 50 | 51 | //Fill return struct 52 | PEImage.ImageBase = PEImage.NTHeader->OptionalHeader.ImageBase; 53 | PEImage.ImageSize = PEImage.NTHeader->OptionalHeader.SizeOfImage; 54 | PEImage.EntryPoint = PEImage.EntryPoint + PEImage.ImageBase; 55 | PEImage.ImportTableVA = PEImage.NTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; 56 | 57 | // Check if we can relocate the image 58 | uint64_t PreferredAddress = 0; 59 | if ((PEImage.NTHeader->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) == 0) { 60 | //Cant't load without this 61 | printf("Image has no dynamic base! Trying to load at the specific base\n"); 62 | PreferredAddress = PEImage.NTHeader->OptionalHeader.ImageBase; 63 | } 64 | 65 | // Allocate Virtual Image Read/Write only to raise an exception if a thread/code gets started and we miss to catch it 66 | uint8_t *VImage = (uint8_t *)VirtualAlloc((void *)PreferredAddress, PEImage.NTHeader->OptionalHeader.SizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); 67 | if (!VImage) { 68 | printf("Could not allocate memory @ %llX\n", PreferredAddress); 69 | return false; 70 | } 71 | memset(VImage, 0, PEImage.NTHeader->OptionalHeader.SizeOfImage); 72 | PEImage.VirtualImage = VImage; 73 | 74 | // Parse the sections and load image into memory 75 | PIMAGE_SECTION_HEADER psectionheader = (PIMAGE_SECTION_HEADER)(PEImage.NTHeader + 1); 76 | for (int i = 0; i < PEImage.NTHeader->FileHeader.NumberOfSections; i++) { 77 | uint64_t SectionVA = psectionheader->VirtualAddress; 78 | uint64_t SectionSize = psectionheader->Misc.VirtualSize; 79 | uint64_t RawOffset = psectionheader->PointerToRawData; 80 | uint64_t RawSize = psectionheader->SizeOfRawData; 81 | 82 | //printf("%s Page %08llX %08llX\n", psectionheader->Name, SectionVA, SectionSize); 83 | 84 | // Add image 85 | PEImage.Sections.push_back(psectionheader); 86 | 87 | //copy information 88 | memcpy(VImage + SectionVA, FileMem + RawOffset, (size_t)RawSize); 89 | 90 | //Copy the header 91 | if (i == 0) { 92 | memcpy(VImage, FileMem, (size_t)RawOffset); 93 | } 94 | 95 | psectionheader++; 96 | } 97 | 98 | return true; 99 | } 100 | 101 | uint64_t RawToVA(uint64_t RawAddress) { 102 | for (auto S : PEImage.Sections) { 103 | if (RawAddress >= S->PointerToRawData && RawAddress < (S->PointerToRawData + S->SizeOfRawData)) { 104 | return RawAddress - S->PointerToRawData + S->VirtualAddress; 105 | } 106 | } 107 | 108 | std::exception("RawAddress not found!"); 109 | } 110 | 111 | uint64_t VaToRaw(uint64_t VA) { 112 | for (auto S : PEImage.Sections) { 113 | if (VA >= S->VirtualAddress && VA < (S->VirtualAddress + S->Misc.VirtualSize)) { 114 | return VA - S->VirtualAddress + S->PointerToRawData; 115 | } 116 | } 117 | 118 | std::exception("VA not found!"); 119 | } 120 | 121 | 122 | // callback for tracing instruction 123 | bool hook_Segment_error(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { 124 | switch (type) { 125 | case UC_MEM_READ_UNMAPPED: 126 | case UC_MEM_WRITE_UNMAPPED: 127 | { 128 | //Like in code 129 | uint64_t RIP; 130 | uc_reg_read(uc, UC_X86_REG_RIP, &RIP); 131 | 132 | uint64_t RSP; 133 | uc_reg_read(uc, UC_X86_REG_RIP, &RSP); 134 | 135 | // Disable logging 136 | printf("Missing memory @ 0x%08llX [%08llX] RSP[%08llX]\n", RIP, address, *(uint64_t *) RSP); 137 | 138 | //printX64Regs(uc); 139 | 140 | return true; 141 | } 142 | case UC_MEM_FETCH_UNMAPPED: 143 | { 144 | uint64_t RIP; 145 | uc_reg_read(uc, UC_X86_REG_RIP, &RIP); 146 | 147 | uint64_t RSP; 148 | uc_reg_read(uc, UC_X86_REG_RSP, &RSP); 149 | 150 | printf("0x%08llX External code: Return to 0x%08llX\n", RIP, *(uint64_t *)RSP); 151 | 152 | return true; 153 | } 154 | default: 155 | // return false to indicate we want to stop emulation 156 | printf("Failed hook_Segment_error!\n"); 157 | return false; 158 | } 159 | } 160 | 161 | 162 | typedef struct { 163 | uint64_t VA; 164 | uint8_t Opcode[16]; 165 | } Entry; 166 | 167 | int main(int argc, char **argv) { 168 | uc_engine *uc; 169 | uc_err err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); 170 | if (err != UC_ERR_OK) { 171 | printf("Failed on uc_open() with error returned: %u\n", err); 172 | } 173 | 174 | // RSP Stack base 175 | uint64_t CurrentVA = 0x146EA48E5; // PEImage.EntryPoint; 176 | uint64_t OriginalRSP = 0x5000; 177 | 178 | // init UniTaint 179 | UniTaint UT(uc, OriginalRSP, CurrentVA); 180 | 181 | // map test 182 | /* 183 | uint64_t Code = 0x1000; 184 | err = uc_mem_map(uc, Code, 0x1000, UC_PROT_ALL); 185 | err = uc_mem_write(uc, Code, Test1, sizeof(Test1)); 186 | */ 187 | // Parse binary 188 | ParsePE64(argv[1]); 189 | 190 | // map pe into unicorn 191 | err = uc_mem_map(uc, (uint64_t)PEImage.ImageBase, (size_t)PEImage.ImageSize, UC_PROT_ALL); 192 | err = uc_mem_write(uc, PEImage.ImageBase, PEImage.VirtualImage, PEImage.ImageSize); 193 | if (err) { 194 | printf("MapPEIntoUnicorn failed! %i\n", err); 195 | return false; 196 | } 197 | 198 | // Setup hooks 199 | uc_hook SegmentError; 200 | uc_hook Interrupt; 201 | 202 | // tracing all instruction by having @begin > @end 203 | err = uc_hook_add(uc, &SegmentError, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_FETCH_UNMAPPED, (void *)hook_Segment_error, 0, 1, 0); 204 | if (err) { 205 | printf("Failed on uc_hook_add() with error returned: %s\n", uc_strerror(err)); 206 | } 207 | 208 | // Taint registers 209 | UT.addEPTaint(X86_REG_RAX); 210 | UT.addEPTaint(X86_REG_RBX); 211 | UT.addEPTaint(X86_REG_RCX); 212 | UT.addEPTaint(X86_REG_RDX); 213 | UT.addEPTaint(X86_REG_R8); 214 | UT.addEPTaint(X86_REG_RSI); 215 | UT.addEPTaint(X86_REG_RDI); 216 | UT.addEPTaint(X86_REG_RBP); 217 | UT.addEPTaint(X86_REG_R8); 218 | UT.addEPTaint(X86_REG_R9); 219 | UT.addEPTaint(X86_REG_R10); 220 | UT.addEPTaint(X86_REG_R11); 221 | UT.addEPTaint(X86_REG_R12); 222 | UT.addEPTaint(X86_REG_R13); 223 | UT.addEPTaint(X86_REG_R14); 224 | UT.addEPTaint(X86_REG_R15); 225 | 226 | // Create stack 227 | err = uc_mem_map(uc, OriginalRSP-0x1000, 0x1000, UC_PROT_ALL); 228 | 229 | uint64_t CurrentRSP = OriginalRSP; 230 | uc_reg_write(uc, UC_X86_REG_RSP, &CurrentRSP); 231 | 232 | uint64_t RCX = 0x1111111111111111; 233 | uint64_t RDX = 0x2222222222221111; 234 | uint64_t R8 = 0x777; 235 | uint64_t RAX = 0; 236 | uc_reg_write(uc, UC_X86_REG_RCX, &RCX); 237 | uc_reg_write(uc, UC_X86_REG_RDX, &RDX); 238 | uc_reg_write(uc, UC_X86_REG_R8, &R8); 239 | 240 | // Test 241 | /* 242 | uint8_t RTest[] = { 0x48, 0xC7, 0xC0, 0x11, 0x11, 0x11, 0x11, 0x48, 0xC7, 0xC0, 0x22, 0x22, 0x22, 0x22 }; 243 | UT.translateInstructionRemill(CurrentVA, RTest, 16, 1); 244 | UT.translateInstructionRemill(CurrentVA, RTest + 7, 16, 1); 245 | */ 246 | std::vector TraceLog; 247 | 248 | do { 249 | uint8_t Opcode[16]; 250 | uc_mem_read(uc, CurrentVA, Opcode, 16); 251 | 252 | Entry E; 253 | E.VA = CurrentVA; 254 | memcpy(E.Opcode, Opcode, 16); 255 | TraceLog.push_back(E); 256 | 257 | //UT.processInstructions(uc, CurrentVA, Opcode, 16, 1, CurrentRSP); 258 | UT.translateInstructionRemill(CurrentVA, Opcode, 16, 1); 259 | 260 | err = uc_emu_start(uc, CurrentVA, -1, 0, 1); 261 | 262 | uc_reg_read(uc, UC_X86_REG_RIP, &CurrentVA); 263 | uc_reg_read(uc, UC_X86_REG_RSP, &CurrentRSP); 264 | } while (CurrentVA != -1 && err == UC_ERR_OK); 265 | 266 | // Print if there was an error 267 | /* 268 | if (err != UC_ERR_OK) { 269 | std::cout << "UC Error: " << uc_strerror(err) << "\n"; 270 | return 1; 271 | } 272 | */ 273 | 274 | // Write log file 275 | FILE *fp = fopen("trace.bin", "wb"); 276 | uint64_t S = TraceLog.size(); 277 | fwrite(&S, sizeof(uint64_t), 1, fp); 278 | 279 | for (auto &E : TraceLog) { 280 | fwrite(&E, sizeof(Entry), 1, fp); 281 | } 282 | 283 | fclose(fp); 284 | 285 | uc_reg_read(uc, UC_X86_REG_RAX, &RAX); 286 | printf("Result (RAX) = %llX\n", RAX); 287 | uc_reg_read(uc, UC_X86_REG_R8, &RAX); 288 | printf("Result (R8) = %llX\n", RAX); 289 | 290 | // Finish llvm translation 291 | UT.dumpLLVMTranslation("VMP_llvm.ll"); 292 | 293 | return 0; 294 | } --------------------------------------------------------------------------------