Skip to content
PoC for a taint based attack on VMProtect
Branch: master
Clone or download
Latest commit 880f14b Jul 3, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Source Initial Commit Jul 3, 2019
README.md Update README.md Jul 3, 2019

README.md

UniTaint

Quick PoC for a taint based attack on VMProtect

Takes a protected x64 binary, traces the vmprotected function with unicorn and taints the input using bea disassembler and a custom tainter

Tested on simple functions without any branches.

Example

Protected C Function

__declspec(dllexport) uint64_t DoXor(uint64_t a, uint64_t b) { return a ^ b; }

Tainted instructions during trace

T push r8 // 4FC0
T push rcx // 4F80
T push rdx // 4F70
T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4F70
T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E58 1: 2222222222221111
T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4F80
T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E38 1: 1111111111111111
T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FC0
T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E48 1: 777
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 5E 1: 4E58
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF8 1: 2222222222221111
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 0 1: 4E58
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 2222222222221111
T mov r10, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FF0
T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF8
T not r10 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF
T not r15 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF
T and r10, r15 // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: DDDDDDDDDDDDEEEE
T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: DDDDDDDDDDDDEEEE
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 5D330000 1: 4E38
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 1111111111111111
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 808E31 1: 4E38
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE8 1: 1111111111111111
T mov r11, qword ptr [r13] // RSP 4DE0 0: 5000 1: 4FE8
T mov rdx, qword ptr [r13 + 8] // RSP 4DE0 0: 2FCF8 1: 4FF0
T not r11 // RSP 4DE0 0: 1111111111111111 1: DEADBEEF
T not rdx // RSP 4DE0 0: 1111111111111111 1: DEADBEEF
T or r11, rdx // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: EEEEEEEEEEEEEEEE
T mov qword ptr [r13 + 8], r11 // RSP 4DE0 0: 4FF0 1: EEEEEEEEEEEEEEEE
T mov r10, qword ptr [r13] // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: 4FF0
T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF8
T not r10 // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: DEADBEEF
T not r15 // RSP 4DE0 0: DDDDDDDDDDDDEEEE 1: DEADBEEF
T and r10, r15 // RSP 4DE0 0: 1111111111111111 1: 2222222222221111
T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: 1111
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 2A220000 1: 4E58
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FF0 1: 2222222222221111
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 4A00 1: 4E38
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE8 1: 1111111111111111
T mov r10, qword ptr [r13] // RSP 4DE0 0: 1111 1: 4FE8
T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: 4F20 1: 4FF0
T not r10 // RSP 4DE0 0: 1111111111111111 1: DEADBEEF
T not r15 // RSP 4DE0 0: 2222222222221111 1: DEADBEEF
T and r10, r15 // RSP 4DE0 0: EEEEEEEEEEEEEEEE 1: DDDDDDDDDDDDEEEE
T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF0 1: CCCCCCCCCCCCEEEE
T mov r10, qword ptr [r13] // RSP 4DE0 0: CCCCCCCCCCCCEEEE 1: 4FF0
T mov r15, qword ptr [r13 + 8] // RSP 4DE0 0: DDDDDDDDDDDDEE00 1: 4FF8
T not r10 // RSP 4DE0 0: CCCCCCCCCCCCEEEE 1: DEADBEEF
T not r15 // RSP 4DE0 0: 1111 1: DEADBEEF
T and r10, r15 // RSP 4DE0 0: 3333333333331111 1: FFFFFFFFFFFFEEEE
T mov qword ptr [r13 + 8], r10 // RSP 4DE0 0: 4FF8 1: 3333333333330000
T mov rbx, qword ptr [r13] // RSP 4DE0 0: 4 1: 4FF8
T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4E68 1: 3333333333330000
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: EE250AB7 1: 4E68
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FE0 1: 3333333333330000
T mov r11, qword ptr [r13 + 8] // RSP 4DE0 0: EEEEEEEEEEEEEE00 1: 4FE0
T add rsi, r11 // RSP 4DE0 0: 23523 1: 3333333333330000
T mov qword ptr [r13 + 8], rsi // RSP 4DE0 0: 4FE0 1: 3333333333353523
T cmp r8, r11 // RSP 4DE0 0: 1400DCD67 1: 3333333333330000
// Not implemented opcode : cmp
T push r8 // 4DD8
T mov rbx, qword ptr [r13] // RSP 4DE0 0: 0 1: 4FE0
T mov qword ptr [rsp + r14], rbx // RSP 4DE0 0: 4DF0 1: 3333333333353523
T cmp r11, rsi // RSP 4DE0 0: 3333333333330000 1: 3333333333353523
// Not implemented opcode : cmp
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 0 1: 4E48
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FD0 1: 777
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 8000000 1: 4DF0
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4FB8 1: 3333333333353523
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 3F260AB7 1: 4E68
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4F90 1: 3333333333330000
T mov r15, qword ptr [rsp + r14] // RSP 4DE0 0: 35D7 1: 4E58
T mov qword ptr [r13], r15 // RSP 4DE0 0: 4F80 1: 2222222222221111
T cmp r11, rsi // RSP 4DE0 0: 3333333333330000 1: 3333333333353523
// Not implemented opcode : cmp
T pop rdx //4F80 V: 2222222222221111
T pop rcx //4F90 V: 3333333333330000
T pop rax //4FB8 V: 3333333333353523
T pop r8 //4FD0 V: 777
Result (RAX) = 3333333333353523
Result (R8)  = 777

Translated instruction into C code

uint64_t S_0;
uint64_t S_1;
uint64_t S_2;
uint64_t S_3;
uint64_t S_4;
uint64_t S_5;
uint64_t S_6;
uint64_t S_7;
uint64_t S_8;
uint64_t S_9;
uint64_t S_10;
uint64_t S_11;
uint64_t S_12;
uint64_t S_13;
uint64_t S_14;
uint64_t S_15;
S_0 = r8;
S_1 = rcx;
S_2 = rdx;
rbx = S_2;
S_3 = rbx;
rbx = S_1;
S_4 = rbx;
rbx = S_0;
S_5 = rbx;
r15 = S_3;
S_6 = r15;
r15 = S_3;
S_7 = r15;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
r15 = S_4;
S_7 = r15;
r15 = S_4;
S_8 = r15;
r11 = S_8;
rdx = S_7;
r11 = ~r11;
rdx = ~rdx;
r11 = r11 | rdx;
S_7 = r11;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
r15 = S_3;
S_7 = r15;
r15 = S_4;
S_8 = r15;
r10 = S_8;
r15 = S_7;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_7 = r10;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
rbx = S_6;
S_9 = rbx;
r15 = S_9;
S_10 = r15;
r11 = S_10;
rsi = rsi + r11;
S_10 = rsi;
S_11 = r8;
rbx = S_10;
S_12 = rbx;
r15 = S_5;
S_13 = r15;
r15 = S_12;
S_14 = r15;
r15 = S_9;
S_15 = r15;
r15 = S_3;
S_1 = r15;
rdx = S_1;
rcx = S_15;
rax = S_14;
r8 = S_13;

Compile and optimize with Clang and O3

#include <stdio.h>
#include <stdint.h>

uint64_t rax;
uint64_t rbx;
uint64_t rcx;	
uint64_t rdx;
uint64_t rbp;
uint64_t rsp;
uint64_t rsi;
uint64_t rdi;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;

__declspec(dllexport) void RXor() {
uint64_t S_0;
uint64_t S_1;
uint64_t S_2;
uint64_t S_3;
uint64_t S_4;
uint64_t S_5;
uint64_t S_6;
uint64_t S_7;
uint64_t S_8;
uint64_t S_9;
uint64_t S_10;
uint64_t S_11;
uint64_t S_12;
uint64_t S_13;
uint64_t S_14;
uint64_t S_15;

S_0 = r8;
S_1 = rcx;
S_2 = rdx;
rbx = S_2;
S_3 = rbx;
rbx = S_1;
S_4 = rbx;
rbx = S_0;
S_5 = rbx;
r15 = S_3;
S_6 = r15;
r15 = S_3;
S_7 = r15;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
r15 = S_4;
S_7 = r15;
r15 = S_4;
S_8 = r15;
r11 = S_8;
rdx = S_7;
r11 = ~r11;
rdx = ~rdx;
r11 = r11 | rdx;
S_7 = r11;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
r15 = S_3;
S_7 = r15;
r15 = S_4;
S_8 = r15;
r10 = S_8;
r15 = S_7;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_7 = r10;
r10 = S_7;
r15 = S_6;
r10 = ~r10;
r15 = ~r15;
r10 = r10 & r15;
S_6 = r10;
rbx = S_6;
S_9 = rbx;
r15 = S_9;
S_10 = r15;
r11 = S_10;
rsi = rsi + r11;
S_10 = rsi;
S_11 = r8;
rbx = S_10;
S_12 = rbx;
r15 = S_5;
S_13 = r15;
r15 = S_12;
S_14 = r15;
r15 = S_9;
S_15 = r15;
r15 = S_3;
S_1 = r15;
rdx = S_1;
rcx = S_15;
rax = S_14;
r8 = S_13;
}

int main() {
	rcx = 0x1111222200000000;
	rdx = 0x0000000033334444;

	RXor();
	printf("RXor: %016llX\n", rax);

	return 0;
}

Output LLVM IR

; Function Attrs: norecurse nounwind uwtable
define dso_local void @_Z4RXorv() local_unnamed_addr #0 {
  %1 = load i64, i64* @rcx, align 8, !tbaa !2
  %2 = load i64, i64* @rdx, align 8, !tbaa !2
  %3 = xor i64 %2, %1
  store i64 %3, i64* @r10, align 8, !tbaa !2
  store i64 %3, i64* @r11, align 8, !tbaa !2
  %4 = load i64, i64* @rsi, align 8, !tbaa !2
  %5 = add i64 %4, %3
  store i64 %5, i64* @rsi, align 8, !tbaa !2
  store i64 %5, i64* @rbx, align 8, !tbaa !2
  store i64 %2, i64* @r15, align 8, !tbaa !2
  store i64 %2, i64* @rdx, align 8, !tbaa !2
  store i64 %3, i64* @rcx, align 8, !tbaa !2
  store i64 %5, i64* @rax, align 8, !tbaa !2
  ret void
You can’t perform that action at this time.