feat: implement encryption
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
|||||||
[submodule "tinyriscv"]
|
[submodule "tinyriscv"]
|
||||||
path = tinyriscv
|
path = tinyriscv
|
||||||
url = ssh://git@ssh.git.xn--k-0fa.se:222/sas2026/tinyriscv.git
|
url = ssh://git@ssh.git.xn--k-0fa.se:222/sas2026/tinyriscv.git
|
||||||
|
[submodule "tiny-AES-c"]
|
||||||
|
path = tiny-AES-c
|
||||||
|
url = git@github.com:kokke/tiny-AES-c.git
|
||||||
|
|||||||
36
Makefile
36
Makefile
@@ -16,10 +16,14 @@ HOST_LDFLAGS ?= -Wl,-s
|
|||||||
EMU_SRC_FILES := $(wildcard src/emulated/*.c)
|
EMU_SRC_FILES := $(wildcard src/emulated/*.c)
|
||||||
EMU_OBJ_FILES := $(EMU_SRC_FILES:src/emulated/%.c=build/%.riscv.o)
|
EMU_OBJ_FILES := $(EMU_SRC_FILES:src/emulated/%.c=build/%.riscv.o)
|
||||||
EMU_OBJ := build/emulated.riscv.elf
|
EMU_OBJ := build/emulated.riscv.elf
|
||||||
|
EMU_OBJ_LICENSE := build/license
|
||||||
|
|
||||||
GENERATED := build/include/generated.h
|
GENERATED := build/include/generated.h
|
||||||
|
|
||||||
HOST_SRC := src/main.c src/elf.c
|
HOST_SRC_EXTRA := src/elf.c src/hwinfo.c src/util.c tiny-AES-c/aes.c
|
||||||
|
HOST_SRC := src/main.c $(HOST_SRC_EXTRA)
|
||||||
|
HOST_SRC_ENCRYPTOR := src/encryptor.c $(HOST_SRC_EXTRA)
|
||||||
|
HOST_INCLUDE := -I src -I tinyriscv/src -I tiny-AES-c
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
ifeq ($(OS),Windows_NT)
|
||||||
HOST_EXE := build/main.exe
|
HOST_EXE := build/main.exe
|
||||||
@@ -27,6 +31,13 @@ else
|
|||||||
HOST_EXE := build/main
|
HOST_EXE := build/main
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OS),Windows_NT)
|
||||||
|
HOST_EXE_ENCRYPTOR := build/encryptor.exe
|
||||||
|
else
|
||||||
|
HOST_EXE_ENCRYPTOR := build/encryptor
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Disassembly
|
# Disassembly
|
||||||
RISCV_OBJDUMP ?= $(patsubst %-gcc,%-objdump,$(RISCV_CC))
|
RISCV_OBJDUMP ?= $(patsubst %-gcc,%-objdump,$(RISCV_CC))
|
||||||
_DISAS_TARGETS := $(filter disas-%,$(MAKECMDGOALS))
|
_DISAS_TARGETS := $(filter disas-%,$(MAKECMDGOALS))
|
||||||
@@ -36,18 +47,29 @@ _DISAS_FILES := $(if $(_DISAS_TARGETS),$(filter %.elf %.o,$(MAKECMDGOALS)))
|
|||||||
|
|
||||||
.PHONY: all emulated-riscv host clean disas-risc
|
.PHONY: all emulated-riscv host clean disas-risc
|
||||||
|
|
||||||
all: $(HOST_EXE) $(EMU_OBJ)
|
all: $(HOST_EXE) $(EMU_OBJ_LICENSE) $(HOST_EXE_ENCRYPTOR)
|
||||||
|
|
||||||
emulated-riscv: $(EMU_OBJ)
|
emulated-riscv: $(EMU_OBJ_LICENSE)
|
||||||
|
|
||||||
host: $(HOST_EXE)
|
host: $(HOST_EXE) $(HOST_EXE_ENCRYPTOR)
|
||||||
|
|
||||||
$(HOST_EXE): $(HOST_SRC) tinyriscv/src/tinyriscv.h src/config.h src/elf.h | build
|
$(HOST_EXE): $(HOST_SRC) | build
|
||||||
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -I src -I tinyriscv/src $(HOST_SRC) -o $@
|
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC) -o $@
|
||||||
|
|
||||||
build/%.riscv.o: src/emulated/%.c $(GENERATED) | build
|
$(HOST_EXE_ENCRYPTOR): $(HOST_SRC_ENCRYPTOR) | build
|
||||||
|
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(HOST_INCLUDE) $(HOST_SRC_ENCRYPTOR) -o $@
|
||||||
|
|
||||||
|
build/%.riscv.o: src/emulated/%.c $(GENERATED) $(HOST_EXE_ENCRYPTOR) | build
|
||||||
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -I $(dir $(GENERATED)) -I src/emulated -c $< -o $@
|
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -I $(dir $(GENERATED)) -I src/emulated -c $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
EMU_OBJ_LICENSE_IF_EXISTS := $(wildcard $(EMU_OBJ_LICENSE))
|
||||||
|
$(EMU_OBJ_LICENSE): $(EMU_OBJ) | build
|
||||||
|
ifneq ($(EMU_OBJ_LICENSE_IF_EXISTS),)
|
||||||
|
rm $(EMU_OBJ_LICENSE_IF_EXISTS)
|
||||||
|
endif
|
||||||
|
$(HOST_EXE_ENCRYPTOR) $(EMU_OBJ) $@
|
||||||
|
|
||||||
$(EMU_OBJ): $(EMU_OBJ_FILES) | build
|
$(EMU_OBJ): $(EMU_OBJ_FILES) | build
|
||||||
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -nostdlib -Wl,-e,entry -Wl,-Ttext=0 -Wl,--emit-relocs $(EMU_OBJ_FILES) -o $@
|
$(RISCV_CC) $(RISCV_ARCH_FLAGS) -nostdlib -Wl,-e,entry -Wl,-Ttext=0 -Wl,--emit-relocs $(EMU_OBJ_FILES) -o $@
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define EMU_MEM_SIZE 16384u
|
#define EMU_MEM_SIZE 16384u
|
||||||
#define EMU_PROGRAM_PATH "build/emulated.riscv.elf"
|
#define EMU_PROGRAM_PATH "build/license"
|
||||||
#define EMU_ENTRY_SYMBOL "entry"
|
#define EMU_ENTRY_SYMBOL "entry"
|
||||||
|
|
||||||
#define STACK_SIZE 1024
|
#define STACK_SIZE 1024
|
||||||
|
|||||||
38
src/elf.c
38
src/elf.c
@@ -8,45 +8,41 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
static int read_file_bytes(const char* path, uint8_t** out_buf, size_t* out_size) {
|
static int read_file_bytes(FILE* f, uint8_t** out_buf, size_t* out_size) {
|
||||||
FILE* f = fopen(path, "rb");
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
fprintf(stderr, "Failed to open object file: %s (%s)\n", path, strerror(errno));
|
fprintf(stderr, "Failed to open object file: (%s)\n", strerror(errno));
|
||||||
return LOAD_ERR_OPEN;
|
return LOAD_ERR_OPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
if (fseek(f, 0, SEEK_END) != 0) {
|
if (fseek(f, 0, SEEK_END) != 0) {
|
||||||
fclose(f);
|
fprintf(stderr, "Failed to seek object file\n");
|
||||||
fprintf(stderr, "Failed to seek object file: %s\n", path);
|
|
||||||
return LOAD_ERR_SMALL_FILE;
|
return LOAD_ERR_SMALL_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
long file_size = ftell(f);
|
long file_size = ftell(f);
|
||||||
if (file_size < 0) {
|
if (file_size < 0) {
|
||||||
fclose(f);
|
fprintf(stderr, "Failed to read object file size\n");
|
||||||
fprintf(stderr, "Failed to read object file size: %s\n", path);
|
|
||||||
return LOAD_ERR_SMALL_FILE;
|
return LOAD_ERR_SMALL_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fseek(f, 0, SEEK_SET) != 0) {
|
if (fseek(f, 0, SEEK_SET) != 0) {
|
||||||
fclose(f);
|
fprintf(stderr, "Failed to rewind object file\n");
|
||||||
fprintf(stderr, "Failed to rewind object file: %s\n", path);
|
|
||||||
return LOAD_ERR_SMALL_FILE;
|
return LOAD_ERR_SMALL_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* file_buf = (uint8_t*)malloc((size_t)file_size);
|
uint8_t* file_buf = (uint8_t*)malloc((size_t)file_size);
|
||||||
if (!file_buf) {
|
if (!file_buf) {
|
||||||
fclose(f);
|
|
||||||
fprintf(stderr, "Failed to allocate %ld bytes for object file\n", file_size);
|
fprintf(stderr, "Failed to allocate %ld bytes for object file\n", file_size);
|
||||||
return LOAD_ERR_OOM;
|
return LOAD_ERR_OOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t read_count = fread(file_buf, 1, (size_t)file_size, f);
|
size_t read_count = fread(file_buf, 1, (size_t)file_size, f);
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
if (read_count != (size_t)file_size) {
|
if (read_count != (size_t)file_size) {
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
fprintf(stderr, "Object file too small or unreadable: %s\n", path);
|
fprintf(stderr, "Object file too small or unreadable\n");
|
||||||
return LOAD_ERR_SMALL_FILE;
|
return LOAD_ERR_SMALL_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,29 +263,29 @@ static int apply_relocations(const uint8_t* file_buf, size_t bytes, uint8_t* mem
|
|||||||
return LOAD_OK;
|
return LOAD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_elf_object_sections(const char* path, uint8_t* memory, uint32_t mem_size) {
|
int load_elf_object_sections(FILE* f, uint8_t* memory, uint32_t mem_size) {
|
||||||
uint8_t* file_buf = NULL;
|
uint8_t* file_buf = NULL;
|
||||||
size_t bytes = 0u;
|
size_t bytes = 0u;
|
||||||
int file_status = read_file_bytes(path, &file_buf, &bytes);
|
int file_status = read_file_bytes(f, &file_buf, &bytes);
|
||||||
if (file_status != LOAD_OK) {
|
if (file_status != LOAD_OK) {
|
||||||
return file_status;
|
return file_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes < 52u) {
|
if (bytes < 52u) {
|
||||||
fprintf(stderr, "Object file too small or unreadable: %s\n", path);
|
fprintf(stderr, "Object file too small or unreadable\n");
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
return LOAD_ERR_SMALL_FILE;
|
return LOAD_ERR_SMALL_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_buf[0] != ELF_MAGIC_0 || file_buf[1] != ELF_MAGIC_1
|
if (file_buf[0] != ELF_MAGIC_0 || file_buf[1] != ELF_MAGIC_1
|
||||||
|| file_buf[2] != ELF_MAGIC_2 || file_buf[3] != ELF_MAGIC_3) {
|
|| file_buf[2] != ELF_MAGIC_2 || file_buf[3] != ELF_MAGIC_3) {
|
||||||
fprintf(stderr, "Not an ELF file: %s\n", path);
|
fprintf(stderr, "Not an ELF file\n");
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
return LOAD_ERR_NOT_ELF;
|
return LOAD_ERR_NOT_ELF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_buf[4] != ELFCLASS32 || file_buf[5] != ELFDATA2LSB) {
|
if (file_buf[4] != ELFCLASS32 || file_buf[5] != ELFDATA2LSB) {
|
||||||
fprintf(stderr, "Unsupported ELF format in %s (need 32-bit little-endian)\n", path);
|
fprintf(stderr, "Unsupported ELF format (need 32-bit little-endian)\n");
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
return LOAD_ERR_UNSUPPORTED_FORMAT;
|
return LOAD_ERR_UNSUPPORTED_FORMAT;
|
||||||
}
|
}
|
||||||
@@ -299,13 +295,13 @@ int load_elf_object_sections(const char* path, uint8_t* memory, uint32_t mem_siz
|
|||||||
uint16_t e_shnum = read_u16_le(file_buf + 48);
|
uint16_t e_shnum = read_u16_le(file_buf + 48);
|
||||||
|
|
||||||
if (e_shoff >= bytes || e_shentsize == 0u) {
|
if (e_shoff >= bytes || e_shentsize == 0u) {
|
||||||
fprintf(stderr, "Invalid section header table in %s\n", path);
|
fprintf(stderr, "Invalid section header table\n");
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
return LOAD_ERR_INVALID_SHT;
|
return LOAD_ERR_INVALID_SHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uint32_t)e_shoff + (uint32_t)e_shentsize * (uint32_t)e_shnum > bytes) {
|
if ((uint32_t)e_shoff + (uint32_t)e_shentsize * (uint32_t)e_shnum > bytes) {
|
||||||
fprintf(stderr, "Section headers out of file bounds in %s\n", path);
|
fprintf(stderr, "Section headers out of file bounds\n");
|
||||||
free(file_buf);
|
free(file_buf);
|
||||||
return LOAD_ERR_SHT_OUT_OF_BOUNDS;
|
return LOAD_ERR_SHT_OUT_OF_BOUNDS;
|
||||||
}
|
}
|
||||||
@@ -389,11 +385,11 @@ int load_elf_object_sections(const char* path, uint8_t* memory, uint32_t mem_siz
|
|||||||
return reloc_status;
|
return reloc_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int resolve_elf_symbol_memory_offset(const char* path, const char* symbol_name,
|
int resolve_elf_symbol_memory_offset(FILE* f, const char* symbol_name,
|
||||||
uint32_t mem_size, uint32_t* out_offset) {
|
uint32_t mem_size, uint32_t* out_offset) {
|
||||||
uint8_t* file_buf = NULL;
|
uint8_t* file_buf = NULL;
|
||||||
size_t bytes = 0u;
|
size_t bytes = 0u;
|
||||||
int file_status = read_file_bytes(path, &file_buf, &bytes);
|
int file_status = read_file_bytes(f, &file_buf, &bytes);
|
||||||
if (file_status != LOAD_OK) {
|
if (file_status != LOAD_OK) {
|
||||||
return file_status;
|
return file_status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#define R_RISCV_RELAX 51u
|
#define R_RISCV_RELAX 51u
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
LOAD_OK = 1,
|
LOAD_OK = 1,
|
||||||
@@ -48,7 +49,7 @@ enum {
|
|||||||
uint16_t read_u16_le(const uint8_t* data);
|
uint16_t read_u16_le(const uint8_t* data);
|
||||||
uint32_t read_u32_le(const uint8_t* data);
|
uint32_t read_u32_le(const uint8_t* data);
|
||||||
uint32_t align_up(uint32_t value, uint32_t align);
|
uint32_t align_up(uint32_t value, uint32_t align);
|
||||||
int load_elf_object_sections(const char* path, uint8_t* memory, uint32_t mem_size);
|
int load_elf_object_sections(FILE* f, uint8_t* memory, uint32_t mem_size);
|
||||||
int resolve_elf_symbol_memory_offset(const char* path, const char* symbol_name,
|
int resolve_elf_symbol_memory_offset(FILE* f, const char* symbol_name,
|
||||||
uint32_t mem_size, uint32_t* out_offset);
|
uint32_t mem_size, uint32_t* out_offset);
|
||||||
|
|
||||||
|
|||||||
61
src/encryptor.c
Normal file
61
src/encryptor.c
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <aes.h>
|
||||||
|
|
||||||
|
#include "hwinfo.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
if (argc != 3) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* input = argv[1];
|
||||||
|
char* output = argv[2];
|
||||||
|
|
||||||
|
hw_info_t hwinfo = {0};
|
||||||
|
if(get_hw_info(&hwinfo) != 0){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* key = hwinfo_to_key(hwinfo);
|
||||||
|
|
||||||
|
if(key == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "HWINFO: %s\n", hw_info_flatten(hwinfo));
|
||||||
|
|
||||||
|
fprintf(stderr, "Key: ");
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
fprintf(stderr, "%02X", key[i]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
uint8_t nonce[16] = {0};
|
||||||
|
|
||||||
|
FILE* license = fopen(input, "rb");
|
||||||
|
long data_start = ftell(license);
|
||||||
|
fseek(license, 0, SEEK_END);
|
||||||
|
int license_size = ftell(license) - data_start;
|
||||||
|
fseek(license, data_start, SEEK_SET);
|
||||||
|
uint8_t* buf = malloc(license_size);
|
||||||
|
fread(buf, 1, license_size, license);
|
||||||
|
|
||||||
|
|
||||||
|
AES_init_ctx(&ctx, key);
|
||||||
|
AES_init_ctx_iv(&ctx, key, nonce);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, buf, license_size);
|
||||||
|
|
||||||
|
FILE* encrypted_license = fopen(output, "wb+");
|
||||||
|
fwrite(&nonce, 1, sizeof(nonce), encrypted_license);
|
||||||
|
fwrite(buf, 1, license_size, encrypted_license);
|
||||||
|
|
||||||
|
fclose(license);
|
||||||
|
fclose(encrypted_license);
|
||||||
|
|
||||||
|
fprintf(stderr, "Wrote encrypted license file to %s\n", output);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
77
src/hwinfo.c
Normal file
77
src/hwinfo.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include "hwinfo.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
char* hw_info_flatten(hw_info_t hwinfo) {
|
||||||
|
int bufsize = strlen(hwinfo.vendor_id) +
|
||||||
|
strlen(hwinfo.model_name) +
|
||||||
|
strlen(hwinfo.os_version) +
|
||||||
|
strlen(hwinfo.mem_total) +
|
||||||
|
1;
|
||||||
|
|
||||||
|
char* hw_info_flat = malloc(bufsize);
|
||||||
|
|
||||||
|
if(hw_info_flat == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(hw_info_flat, 0, bufsize);
|
||||||
|
|
||||||
|
strcat(hw_info_flat, hwinfo.vendor_id);
|
||||||
|
strcat(hw_info_flat, hwinfo.model_name);
|
||||||
|
strcat(hw_info_flat, hwinfo.os_version);
|
||||||
|
strcat(hw_info_flat, hwinfo.mem_total);
|
||||||
|
|
||||||
|
return hw_info_flat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void read_cpu_info(FILE* file, hw_info_t* hwinfo) {
|
||||||
|
char line[256];
|
||||||
|
while(fgets(line, sizeof(line), file)) {
|
||||||
|
if (strncmp(line, "vendor_id", 9) == 0) {
|
||||||
|
hwinfo->vendor_id = strdup(strchr(line, ':') + 2);
|
||||||
|
hwinfo->vendor_id[strcspn(hwinfo->vendor_id, "\r\n")] = 0; // Remove newline
|
||||||
|
} else if (strncmp(line, "model name", 10) == 0) {
|
||||||
|
hwinfo->model_name = strdup(strchr(line, ':') + 2);
|
||||||
|
hwinfo->model_name[strcspn(hwinfo->model_name, "\r\n")] = 0; // Remove newline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_os_version(FILE* file, hw_info_t* hwinfo) {
|
||||||
|
char line[256];
|
||||||
|
if(!fgets(line, sizeof(line), file)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hwinfo->os_version = strdup(strchr(strchr(line, ' ') + 1, ' ') + 1);
|
||||||
|
hwinfo->os_version[strcspn(hwinfo->os_version, " \r\n")] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_mem_info(FILE* file, hw_info_t* hwinfo) {
|
||||||
|
char line[256];
|
||||||
|
while(fgets(line, sizeof(line), file)) {
|
||||||
|
if(strncmp(line, "MemTotal", 8) == 0) {
|
||||||
|
hwinfo->mem_total = strchr(line, ':') + 1;
|
||||||
|
hwinfo->mem_total = strdup(hwinfo->mem_total + strspn(hwinfo->mem_total, " "));
|
||||||
|
*strrchr(hwinfo->mem_total, ' ') = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_hw_info(hw_info_t* hwinfo) {
|
||||||
|
FILE* f_cpuinfo = fopen("/proc/cpuinfo", "rb");
|
||||||
|
FILE* f_osversion = fopen("/proc/version", "rb");
|
||||||
|
FILE* f_meminfo = fopen("/proc/meminfo", "rb");
|
||||||
|
|
||||||
|
|
||||||
|
if(!f_cpuinfo || !f_osversion || !f_meminfo) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_cpu_info(f_cpuinfo, hwinfo);
|
||||||
|
read_os_version(f_osversion, hwinfo);
|
||||||
|
read_mem_info(f_meminfo, hwinfo);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
19
src/hwinfo.h
Normal file
19
src/hwinfo.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct HWInfo {
|
||||||
|
char* vendor_id;
|
||||||
|
char* model_name;
|
||||||
|
char* os_version;
|
||||||
|
char* mem_total;
|
||||||
|
} hw_info_t;
|
||||||
|
|
||||||
|
char* hw_info_flatten(hw_info_t hwinfo);
|
||||||
|
|
||||||
|
void read_cpu_info(FILE* file, hw_info_t* hwinfo);
|
||||||
|
void read_os_version(FILE* file, hw_info_t* hwinfo);
|
||||||
|
void read_mem_info(FILE* file, hw_info_t* hwinfo);
|
||||||
|
|
||||||
|
int get_hw_info(hw_info_t* hwinfo);
|
||||||
72
src/main.c
72
src/main.c
@@ -1,18 +1,78 @@
|
|||||||
#define TINYRISCV_M
|
#define TINYRISCV_M
|
||||||
|
|
||||||
#include "tinyriscv.h"
|
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
#include "hwinfo.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "aes.h"
|
||||||
|
#include "tinyriscv.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_STEPS 1024u
|
#define MAX_STEPS 1024u
|
||||||
|
|
||||||
|
|
||||||
int main(){
|
int main(){
|
||||||
|
hw_info_t hwinfo = {0};
|
||||||
|
if(get_hw_info(&hwinfo) != 0){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* key = hwinfo_to_key(hwinfo);
|
||||||
|
|
||||||
|
if(key == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "HWINFO: %s\n", hw_info_flatten(hwinfo));
|
||||||
|
|
||||||
|
fprintf(stderr, "Key: ");
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
fprintf(stderr, "%02X", key[i]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct AES_ctx ctx;
|
||||||
|
uint8_t nonce[16] = {0};
|
||||||
|
|
||||||
|
FILE* license = fopen(EMU_PROGRAM_PATH, "rb");
|
||||||
|
fread(nonce, 16, 1, license);
|
||||||
|
long data_start = ftell(license);
|
||||||
|
fseek(license, 0, SEEK_END);
|
||||||
|
int license_size = ftell(license) - data_start;
|
||||||
|
fseek(license, data_start, SEEK_SET);
|
||||||
|
uint8_t* buf = malloc(license_size);
|
||||||
|
fread(buf, 1, license_size, license);
|
||||||
|
|
||||||
|
|
||||||
|
// void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||||
|
// void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||||
|
// void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, size_t length);
|
||||||
|
|
||||||
|
AES_init_ctx(&ctx, key);
|
||||||
|
AES_init_ctx_iv(&ctx, key, nonce);
|
||||||
|
AES_CTR_xcrypt_buffer(&ctx, buf, license_size);
|
||||||
|
|
||||||
|
FILE* decrypted_license = tmpfile();
|
||||||
|
fwrite(buf, 1, license_size, decrypted_license);
|
||||||
|
rewind(decrypted_license);
|
||||||
|
|
||||||
|
char begin[8] = {0};
|
||||||
|
char expected[] = {0x7F, 'E', 'L', 'F', 1, 1, 1, 0};
|
||||||
|
fread(begin, 1, sizeof(begin), decrypted_license);
|
||||||
|
if(memcmp(begin, expected, sizeof(begin)) != 0) {
|
||||||
|
// This happens when decryption fails
|
||||||
|
printf("You are not authorized to use this software!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const int maxninput = 255;
|
const int maxninput = 255;
|
||||||
printf("Please enter the flag: ");
|
printf("Please enter the flag: ");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -34,9 +94,9 @@ int main(){
|
|||||||
memcpy(memory + SECTION_USERDATA + 1, userinput, real_len);
|
memcpy(memory + SECTION_USERDATA + 1, userinput, real_len);
|
||||||
|
|
||||||
// Load elf, keep 512 bytes as safe buffer
|
// Load elf, keep 512 bytes as safe buffer
|
||||||
int load_status = load_elf_object_sections(EMU_PROGRAM_PATH, memory, cpu.mem_size - SIZE_USERDATA);
|
int load_status = load_elf_object_sections(decrypted_license, memory, cpu.mem_size - SIZE_USERDATA);
|
||||||
if (load_status != LOAD_OK) {
|
if (load_status != LOAD_OK) {
|
||||||
fprintf(stderr, "ELF load failed with code %d for '%s'\n", load_status, EMU_PROGRAM_PATH);
|
fprintf(stderr, "ELF load failed with code %d for decrypted license\n", load_status);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
printf("ELF load failed with code %d\n", load_status);
|
printf("ELF load failed with code %d\n", load_status);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
@@ -45,7 +105,7 @@ int main(){
|
|||||||
|
|
||||||
uint32_t entry_offset = 0u;
|
uint32_t entry_offset = 0u;
|
||||||
int symbol_status = resolve_elf_symbol_memory_offset(
|
int symbol_status = resolve_elf_symbol_memory_offset(
|
||||||
EMU_PROGRAM_PATH, EMU_ENTRY_SYMBOL, cpu.mem_size, &entry_offset);
|
decrypted_license, EMU_ENTRY_SYMBOL, cpu.mem_size, &entry_offset);
|
||||||
if (symbol_status != LOAD_OK) {
|
if (symbol_status != LOAD_OK) {
|
||||||
fprintf(stderr, "Entry symbol '%s' resolve failed with code %d for '%s'\n",
|
fprintf(stderr, "Entry symbol '%s' resolve failed with code %d for '%s'\n",
|
||||||
EMU_ENTRY_SYMBOL, symbol_status, EMU_PROGRAM_PATH);
|
EMU_ENTRY_SYMBOL, symbol_status, EMU_PROGRAM_PATH);
|
||||||
@@ -72,9 +132,9 @@ int main(){
|
|||||||
uint32_t result = (uint32_t)cpu.x[10];
|
uint32_t result = (uint32_t)cpu.x[10];
|
||||||
|
|
||||||
if(result == 1) {
|
if(result == 1) {
|
||||||
printf("Congrats! That's the flag!");
|
printf("Congrats! That's the flag!\n");
|
||||||
} else {
|
} else {
|
||||||
printf("Nope, sorry, that's incorrect!");
|
printf("Nope, sorry, that's incorrect!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
44
src/util.c
Normal file
44
src/util.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
We do the following algorithm twice
|
||||||
|
|
||||||
|
algorithm fnv-1a is
|
||||||
|
hash := FNV_offset_basis
|
||||||
|
|
||||||
|
for each byte_of_data to be hashed do
|
||||||
|
hash := hash XOR byte_of_data
|
||||||
|
hash := hash × FNV_prime
|
||||||
|
|
||||||
|
return hash
|
||||||
|
*/
|
||||||
|
void dual_fnv_hash(char* input, uint8_t key[16]) {
|
||||||
|
uint64_t lower = 0xcbf29ce484222325;
|
||||||
|
uint64_t upper = 0xcbf29ce484222325 + 0xC0010FF5E7; // add a made-up constant
|
||||||
|
|
||||||
|
while(*input != 0) {
|
||||||
|
lower = (lower ^ *input) * FNV_PRIME;
|
||||||
|
upper = (upper ^ *input) * FNV_PRIME;
|
||||||
|
|
||||||
|
input += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key, &lower, 8);
|
||||||
|
memcpy(key + 8, &upper, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t* hwinfo_to_key(hw_info_t hwinfo) {
|
||||||
|
char* hw_info_flat = hw_info_flatten(hwinfo);
|
||||||
|
|
||||||
|
if (hw_info_flat == NULL){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t* key = malloc(16);
|
||||||
|
dual_fnv_hash(hw_info_flat, key);
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
15
src/util.h
Normal file
15
src/util.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hwinfo.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FNV_PRIME 0x00000100000001b3
|
||||||
|
|
||||||
|
// Generate an aes key by hashing the input
|
||||||
|
// This hash is not safe in any way
|
||||||
|
// But it is fast and easy to implement!
|
||||||
|
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
|
||||||
|
void dual_fnv_hash(char* input, uint8_t key[16]);
|
||||||
|
|
||||||
|
uint8_t* hwinfo_to_key(hw_info_t hwinfo);
|
||||||
1
tiny-AES-c
Submodule
1
tiny-AES-c
Submodule
Submodule tiny-AES-c added at 23856752fb
Reference in New Issue
Block a user