add flag computer wp temp

This commit is contained in:
breakingdevil
2020-11-02 20:36:26 +08:00
parent cdeff494d2
commit 6a22c4626f
38 changed files with 1100 additions and 0 deletions
Vendored
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+52
View File
@@ -1 +1,53 @@
# Flag 计算机
此题目基于 [https://github.com/skeeto/dosdefender-ld31](https://github.com/skeeto/dosdefender-ld31) 修改而成。
```
由于我太菜了,所以引入了一个 BUG 导致题目下线修改后上线。给大家带来了不便,十分抱歉。
```
这道题主要想展现的效果是在 DOS 和 Windows 上都能运行的程序。在 Windows 上运行将弹出一个对话框。
![](./pics/1.png)
这和我们在 DOS 上运行 Windows PE 程序在 DOS 中输出"This program cannot be run in DOS mode"相照应。如果我们把程序载入 010editor就会发现一些猫腻。
![](pics/2.png)
我们会发现原来的 DOS stub 充满了代码。实际上我是先编译了一个 COM 可执行文件,然后手动为 COM 文件加上 DOS 头。所以在此过程中 DOS 中的一些值是手工进行设置的。
然后我将能够运行的 DOS 可执行文件设置为 visual studio 2019 中的 exe 的 DOS stub。最终编译成了你们现在看到的样子。
## 逆向分析
我们将它拖入ida
![](pics/3.png)
我们选择让 IDA 分析 MS-DOS executeble。
然后我们观察 start 函数。
![](pics/4.png)
我们发现它调用了一个函数,然后执行了 DOS exit 中断,IDA 已经将其标注了出来。
```
这里用了一个 CPU 指令前缀的编译方法,使得我们的 80386 能够在实模式使用 32 位操作数。0x66
:它属于 Prefix group 3Operand-size override prefix。
```
有了这样一个 opcode 会有怎么样的行为呢?
![](pics/5.png)
可以看到 operand size 变为了 32bit。
我们分析 102f 这个函数。
![](pics/6.png)
可以看到使用了大量使用这个技巧的痕迹,这就是为什么我们能在实模式使用 32bit 寄存器的原因。
```
asm (".code16gcc\n"
"call dosmain\n"
"mov $0x4C,%ah\n"
"int $0x21\n");
```
最先展开的 include 项目中有我们的 init.h 。
这个文件中的一个伪指令 ".code16cc" 代表着让gcc生成 16bit realmode 模式的汇编指令。所以这是为什么大量指令前都有 0x66 的原因。当我们的操作数是类似于 uint32 声明时,0x66 就会起作用。
逆向的核心过程就是明白程序干了哪些事情,橙色的操作数代表着地址,我们将鼠标悬停在上面,然后右键把它类型转换一下。
![](pics/7.png)
IDA 就能识别字符串了。
ps: 作为一个CTF玩家,我最喜欢的事情就是按 F5 ,hackergame 是为了让人能学到东西,而不是千篇一律的难题,不是为了难而难。所以我程序在 realmode 下,IDA 失效了,这样大家都能从 “0” 接触汇编。
显而易见的是,参数是字符串的一般就是我们的类似的 printf 函数。只不过这里是 vga 的输出而已。
![](pics/8.png)
我们看整个控制流,发现程序并不复杂,大多数都是控制显示的逻辑。
大家可以对着源代码再看一遍,这个函数就是对应的 main 函数。
下面讲下程序的核心逻辑。
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.
@@ -0,0 +1,2 @@
*.com
*.o
@@ -0,0 +1,20 @@
CC = gcc
DOS = dosbox
CFLAGS = -std=gnu99 -w -O0 -nostdlib -m32 -march=i386 \
-Wno-unused-function \
-ffreestanding -fomit-frame-pointer -fwrapv -fno-strict-aliasing \
-fno-leading-underscore -fno-pic -fno-stack-protector \
-Wl,--nmagic,-static,-Tcom.ld
dosdef.com : dosdef.c *.h
.PHONY : all clean test
clean :
$(RM) *.com
test : dosdef.com
$(DOS) $^
%.com : %.c
$(CC) -o $@ $(CFLAGS) $<
@@ -0,0 +1,14 @@
---
enabled: true
name: Flag 计算机
category: binary
url: files/get_flag_system.exe
index: 270
flags:
- name: ''
score: 300
type: text
flag: flag{g3tfl4g_0p3r4t1ng_syst3m}
---
一个玄学的 flag 计算机,平常的时候只会摸鱼,但如果在**合适的时间**运行它的话,它就可以告诉你真正的 flag。
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
@@ -0,0 +1,23 @@
#ifndef ALLOC_H
#define ALLOC_H
#include "int.h"
extern char _heap;
static char *hbreak = &_heap;
static void *sbrk(size_t size)
{
char *ptr = hbreak;
for (size_t i = 0; i < size; i++)
ptr[i] = 0;
hbreak += size;
return ptr;
}
static void free(void)
{
hbreak = &_heap;
}
#endif
@@ -0,0 +1,16 @@
OUTPUT_FORMAT(binary)
SECTIONS
{
. = 0x0100;
.text :
{
*(.text);
}
.data :
{
*(.data);
*(.bss);
*(.rodata);
}
_heap = ALIGN(4);
}
+10
View File
@@ -0,0 +1,10 @@
# Suggested DOSBox configuration for DOS Defender
# Usage: dosbox -conf dosbox.conf dosdef.com
[sdl]
output=opengl
windowresolution=1280x800
[cpu]
core=dynamic
cycles=max
@@ -0,0 +1,261 @@
#include "init.h"
#include "print.h"
#include "joystick.h"
#include "vga.h"
#include "rand.h"
#include "time.h"
#include "alloc.h"
#include "keyboard.h"
#include "speaker.h"
#define SCALE 1000
#define BACKGROUND 17
#define PLAYER 14
#define BULLET_SPEED 3
#define PARTICLE_MAX_AGE 50
#define MAX_PLAYERS 2
typedef unsigned int tick_t;
typedef void (*ai_t)(int id);
typedef void (*power_t)(int id);
static tick_t ticks;
static unsigned score;
static unsigned best_score;
static struct speaker speaker;
struct ship {
int32_t x, y, dx, dy;
tick_t last_fire;
ai_t ai;
struct sample *fx_fire;
uint16_t score;
uint16_t hp, hp_max;
uint8_t radius;
uint8_t fire_delay;
uint8_t fire_damage;
uint8_t drop_rate;
uint8_t color_a, color_b;
bool is_player;
union {
int target_ship;
struct {
uint32_t x, y;
} target_position;
};
};
struct bullet {
int32_t x, y, dx, dy;
tick_t birthtick;
uint8_t color;
uint8_t damage;
bool alive;
};
struct particle {
int32_t x, y;
tick_t birthtick;
bool alive;
};
struct powerup {
int32_t x, y;
tick_t birthtick;
power_t power;
bool alive;
uint8_t color;
};
static struct bullet *bullets;
static size_t bullets_max = 32;
static struct particle *particles;
static size_t particles_max = 64;
static struct ship *ships;
static size_t ships_max = 12;
static struct powerup *powerups;
static size_t powerups_max = 8;
static bool joystick_detected()
{
struct joystick joystick;
joystick_read(&joystick);
return joystick.axis[0] != 0 || joystick.axis[1] != 0;
}
static void burn(int32_t x, int32_t y);
static void ship_draw(int id, bool clear);
static void powerup_random(int id);
// #define VGA_PWIDTH 320
// #define VGA_PHEIGHT 200
// 53 character a line
static unsigned short strlen(const char * in)
{
short ret=0;
while(in[ret] != 0)
{
ret++;
}
return ret;
}
static unsigned short str_line_middle(unsigned short length)
{
return (53 - length) / 2 * 6;
}
static void delay()
{
for(unsigned short i = 0; i<0xf;i++)
{
usleep(800);
}
}
// static uint32_t rand_seed = 375226057;
// static uint32_t rand(void)
// {
// rand_seed = rand_seed * 1103515245 + 12345;
// return rand_seed;
// }
// static uint32_t randn(uint32_t n)
// {
// return (rand() >> 7) % n;
// }
uint32_t a,x0,b;
static uint32_t gen_random_a()
{
a = get_time() % 58379;
// a = 26141;
x0 = 1103515245;
}
static uint32_t myrand(void)
{
x0 = x0 * a + 12345678;
return x0;
}
// flag{g3tfl4g_0p3r4t1ng_syst3m}
uint32_t get_matrix[15];
uint32_t my_matrix[15*15]={20597,19141,29258,17804,29076,28746,24890,28979,26196,31833,26624,24774,18916,29028,24033,22913,23436,25750,26539,21652,31296,22446,16506,21949,22761,30221,29477,29617,16497,23022,23179,30781,23877,29171,31665,26534,32159,22583,27525,28708,31216,17158,31988,32190,23747,21272,21278,24727,29984,25303,23445,23119,23155,26346,26389,30747,28948,31418,21323,31758,30911,18790,21312,25099,22348,25409,29357,22180,23588,28794,18133,25624,21972,23401,24821,31369,25187,31517,19840,28836,20794,20239,24523,30814,24016,17954,21227,16691,30290,23391,20482,24822,31968,30651,27908,22690,30875,31003,31747,19978,25482,18563,30143,27788,26658,26295,23244,27086,26456,24251,28647,22783,27460,19187,23252,24078,19203,26251,18113,19542,24533,16666,24038,32744,28670,30438,26379,18591,30109,26509,20947,27696,22945,27542,32128,25416,21675,19389,27085,29380,20163,21102,30936,30862,18230,21904,16938,16579,20641,27551,22740,24666,16836,23306,27661,26506,28623,29816,20166,29405,23982,30046,19365,24926,19029,32448,17567,17156,18678,28594,19769,28631,25769,31309,24457,30625,21825,29811,17112,31370,25345,24333,24005,31606,30942,21441,30599,22894,18015,19994,27901,26868,21948,27614,23449,21289,19588,19955,28133,16696,31509,26219,19946,27895,28760,28547,28315,16614,26006,17129,24769,24608,17714,17682,18532,17597,29247,28789,27011,29841,32640,17508,27662,23548,29514};
int dosmain(void)
{
vga_on();
vga_clear(BACKGROUND);
vga_vsync();
vga_print((struct point){str_line_middle(strlen("WWWWWWWWWWWWWOOOOOOOOOOWWWWWOO OOOOOOOWWWWWWWWWWWWWWW")), 14}, MAGENTA, "WWWWWWWWWWWWWOOOOOOOOOOWWWWWOO OOOOOOOWWWWWWWWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWWWWOOO OONWWWWWOOO OOOWWWWWWWWWW")), 23}, MAGENTA, "WWWWWWWWOOO OONWWWWWOOO OOOWWWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWWOOO OOOdOOWWWWMMWOOdOOO OdOWWWWWWWW")), 32}, MAGENTA, "WWWWWWOOO OOOdOOWWWWMMWOOdOOO OdOWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWOO OOdONWOOOdOOOOOdOOOWNOOO OOWWWWWWW")), 41}, MAGENTA, "WWWWWOO OOdONWOOOdOOOOOdOOOWNOOO OOWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWNOO OONWOOOOO OOOOOWOOO OOWWWWWW")), 50}, MAGENTA, "WWWNOO OONWOOOOO OOOOOWOOO OOWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWOO OOOWOOO OdOWOOO OOWWWWW")), 59}, MAGENTA, "WWWOO OOOWOOO OdOWOOO OOWWWWW");
vga_print((struct point){str_line_middle(strlen("WWOO OONWOO OOWNdO OOWWWW")), 68}, MAGENTA, "WWOO OONWOO OOWNdO OOWWWW");
vga_print((struct point){str_line_middle(strlen("WNO OONWOO OOWNOO OONWWW")), 77}, MAGENTA, "WNO OONWOO OOWNOO OONWWW");
vga_print((struct point){str_line_middle(strlen("WOO OOWOO OOWOO OOMWW")), 86}, MAGENTA, "WOO OOWOO OOWOO OOMWW");
vga_print((struct point){str_line_middle(strlen("WOO OOMOO OOWOO OOWWW")), 95}, MAGENTA, "WOO OOMOO OOWOO OOWWW");
vga_print((struct point){str_line_middle(strlen("WOO OOWNdO OOWWOO ONMWO")), 104}, MAGENTA, "WOO OOWNdO OOWWOO ONMWO");
vga_print((struct point){str_line_middle(strlen("WWOO OOWOOO OdNWOO OOWWWO")), 113}, MAGENTA, "WWOO OOWOOO OdNWOO OOWWWO");
vga_print((struct point){str_line_middle(strlen("WWNOO OOWNOO OOOWNOO OdNMWWW")), 122}, MAGENTA, "WWNOO OOWNOO OOOWNOO OdNMWWW");
vga_print((struct point){str_line_middle(strlen("WWWOOO OOOWOOOO OOONWOOO OONWWWWW")), 131}, MAGENTA, "WWWOOO OOOWOOOO OOONWOOO OONWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWOdO OOONWOOdOOOOOOOOOdOOWNOOO OdNWWWWWW")), 140}, MAGENTA, "WWWWOdO OOONWOOdOOOOOOOOOdOOWNOOO OdNWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWNOOO OOOOOOWWNNNNWWNOOOOOO OOOWWWWWWWW")), 149}, MAGENTA, "WWWWWNOOO OOOOOOWWNNNNWWNOOOOOO OOOWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWWWOOOO OOdNWWWWMNdOO OOONWWWWWWWWW")), 158}, MAGENTA, "WWWWWWWOOOO OOdNWWWWMNdOO OOONWWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWWWWWWWWOOOOOO OOMWWWWOO OOOOOOWWWWWMWWWWWWWW")), 167}, MAGENTA, "WWWWWWWWWWWWOOOOOO OOMWWWWOO OOOOOOWWWWWMWWWWWWWW");
vga_print((struct point){str_line_middle(strlen("WWWWWWWWWWWWWWWNOOOOOONWWWWWNOOdOOONWWWWWWWWWWWWWWWWW")), 176}, MAGENTA, "WWWWWWWWWWWWWWWNOOOOOONWWWWWNOOdOOONWWWWWWWWWWWWWWWWW");
delay();
vga_clear(BACKGROUND);
gen_random_a();
uint32_t rand_gen[15];
for(uint32_t i=0;i<15;i++)
{
rand_gen[i] = myrand();
}
for(uint32_t i=0;i<15;i++)
{
for(uint32_t j=0;j<15;j++)
{
get_matrix[i] += (my_matrix[i*15+j] * rand_gen[j]) & (0xffff);
get_matrix[i] = get_matrix[i] & 0xffff;
vga_clear(BACKGROUND);
vga_print((struct point){str_line_middle(strlen("GETFLAG OPERATING SYSTEM")), 5}, MAGENTA, "GETFLAG OPERATING SYSTEM");
vga_print((struct point){0, 15}, MAGENTA, "OPERATING SYSTEM USE AI TECH");
vga_print((struct point){0, 25}, MAGENTA, "SETTING A RANDOM FLAG SEED");
vga_print((struct point){0, 35}, RED, "CHECKED YOU ARE PLAYING USTC HACKERGAME");
vga_print((struct point){0, 45}, MAGENTA, "LET ME COMPUTE FLAG FOR YOU");
vga_print((struct point){0, 55}, MAGENTA, "IF I FIND THE FLAG I WILL PRINT IT");
for(short k=0; k<0xff;k++)
{
vga_print((struct point){0, 65}, RED, "COMPUTING PLEASE WAIT");
usleep(800);
vga_print((struct point){0, 65}, BLACK, "COMPUTING PLEASE WAIT");
usleep(800);
}
}
}
vga_clear(BACKGROUND);
vga_print((struct point){str_line_middle(strlen("GETFLAG OPERATING SYSTEM")), 5}, MAGENTA, "GETFLAG OPERATING SYSTEM");
vga_print((struct point){0, 15}, MAGENTA, "FOUND A SOLUTION");
vga_print((struct point){0, 25}, MAGENTA, "FLAG IS IN PRINTABLE FORMAT");
vga_print((struct point){0, 35}, MAGENTA, "THE SYSTEM MAY GET WRONG SEED");
vga_print((struct point){0, 45}, MAGENTA, "YOU SHOULD RESET IT");
for(int i=0; i < 0xff; i++)
{
for(int j=0; j < 0xa0; j++)
{
}
}
delay();
vga_off();
// 187 49114 12533 39320 44039 25566 22160 10990 15801 27249 45757 55153 58050 7065 14228
// printl(get_matrix[0]);
// printl(get_matrix[1]);
// printl(get_matrix[2]);
// printl(get_matrix[3]);
// printl(get_matrix[4]);
// printl(get_matrix[5]);
// printl(get_matrix[6]);
// printl(get_matrix[7]);
// printl(get_matrix[8]);
// printl(get_matrix[9]);
// printl(get_matrix[10]);
// printl(get_matrix[11]);
// printl(get_matrix[12]);
// printl(get_matrix[13]);
// printl(get_matrix[14]);
char out[40];
out[30] = '$';
out[31] = '$';
out[32] = '$';
out[33] = '$';
print("\nYOU SHOULD CHECK PRINT OUT STRING ASCII$$");
print("\nDOS ONLY PRINT UPPERCASE LETTERS$$");
print("\n$$$$");
unsigned short aim[30]={221, 49078, 12436, 39423, 44156, 25529, 22179, 10906, 15839, 27165, 45705, 55062, 58013, 7081, 14308, 136, 49064, 12481, 39404, 44086, 25520, 22263, 10929, 15818, 27144, 45774, 55045, 58097, 7156, 14313};
for(short i=0; i<30;i++)
{
out[i] = (char)(aim[i] ^ get_matrix[i%15]);
}
print(out);
return 0;
}
@@ -0,0 +1,5 @@
/* NOTICE: This must be included first! */
asm (".code16gcc\n"
"call dosmain\n"
"mov $0x4C,%ah\n"
"int $0x21\n");
@@ -0,0 +1,18 @@
#ifndef INT_H
#define INT_H
typedef unsigned char uint8_t;
typedef char int8_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned long int uint32_t;
typedef long int int32_t;
typedef unsigned long long int uint64_t;
typedef long long int int64_t;
typedef unsigned short size_t;
#define true 1
#define false 0
typedef char bool;
#endif
@@ -0,0 +1,88 @@
#include "math.h"
#include "int.h"
struct joystick {
uint16_t axis[4];
bool button[4];
};
struct joystick_config {
uint16_t min[4];
uint16_t max[4];
uint16_t center[4];
};
static struct joystick_config joystick_config = {
{0xffff, 0xffff, 0xffff, 0xffff},
{0x0000, 0x0000, 0x0000, 0x0000},
{0x0000, 0x0000, 0x0000, 0x0000},
};
static void joystick_read(struct joystick *joystick)
{
asm volatile ("mov $0x84, %%ah\n"
"mov $1, %%dx\n"
"int $0x15\n"
: "=a"(joystick->axis[0]), "=b"(joystick->axis[1]),
"=c"(joystick->axis[2]), "=d"(joystick->axis[3]));
for (int i = 0; i < 4; i++) {
joystick_config.min[i] =
min(joystick_config.min[i], joystick->axis[i]);
joystick_config.max[i] =
max(joystick_config.max[i], joystick->axis[i]);
}
uint16_t buttons = 0;
asm volatile ("mov $0x84, %%ah\n"
"mov $0, %%dx\n"
"int $0x15\n"
: "=a"(buttons)
: /**/
: "bx", "cx", "dx");
for (int i = 0; i < 4; i++)
joystick->button[i] = !(buttons & (1 << (i + 4)));
}
#include "vga.h"
#include "vga_font.h"
static void joystick_crosshair(struct point c, uint8_t color)
{
vga_line((struct point){c.x - 2, c.y},
(struct point){c.x + 2, c.y}, color);
vga_line((struct point){c.x, c.y - 2},
(struct point){c.x, c.y + 2}, color);
}
static void joystick_calibrate()
{
vga_clear(BLUE);
int32_t scaled[4] = {};
struct joystick joy;
do {
vga_vsync();
joystick_crosshair((struct point){scaled[0], scaled[1]}, BLUE);
joystick_crosshair((struct point){scaled[2], scaled[3]}, BLUE);
joystick_read(&joy);
for (int i = 0; i < 4; i++) {
int32_t scale = joystick_config.max[i] - joystick_config.min[i];
if (scale != 0) {
scaled[i] = joy.axis[i] - joystick_config.min[i];
scaled[i] *= (i & 0x01) ? VGA_PHEIGHT : VGA_PWIDTH;
scaled[i] /= scale;
}
}
joystick_crosshair((struct point){scaled[0], scaled[1]}, WHITE);
joystick_crosshair((struct point){scaled[2], scaled[3]}, YELLOW);
vga_print((struct point){55, 80}, YELLOW,
"MOVE JOYSTICK AROUND ITS FULL RANGE");
vga_print((struct point){43, 113}, YELLOW,
"THEN CENTER JOYSTICK AND PRESS BUTTON A");
vga_pixel((struct point){VGA_PWIDTH / 2, VGA_PHEIGHT / 2}, BLACK);
} while (!joy.button[0]);
for (int i = 0; i < 4; i++)
joystick_config.center[i] = joy.axis[i];
vga_clear(LIGHT_BLUE);
do
joystick_read(&joy);
while (joy.button[0]);
}
@@ -0,0 +1,33 @@
#include "int.h"
static bool kbhit()
{
bool result;
asm volatile ("mov $1, %%ah\n"
"int $0x16\n"
"jnz set%=\n"
"mov $0, %0\n"
"jmp done%=\n"
"set%=:\n"
"mov $1, %0\n"
"done%=:\n"
: "=rm"(result));
return result;
}
static uint16_t kb_read()
{
uint16_t key;
asm volatile ("mov $1, %%ah\n"
"int $0x16\n"
"jnz get%=\n"
"mov $0, %%ax\n"
"jmp done%=\n"
"get%=:\n"
"mov $0, %%ah\n"
"int $0x16\n"
"jmp done%=\n"
"done%=:\n"
: "=a"(key));
return key;
}
@@ -0,0 +1,19 @@
#ifndef MATH_H
#define MATH_H
static inline int abs(int x)
{
return x < 0 ? -x : x;
}
static inline int max(int a, int b)
{
return a < b ? b : a;
}
static inline int min(int a, int b)
{
return b < a ? b : a;
}
#endif
@@ -0,0 +1 @@
20597,19141,29258,17804,29076,28746,24890,28979,26196,31833,26624,24774,18916,29028,24033,22913,23436,25750,26539,21652,31296,22446,16506,21949,22761,30221,29477,29617,16497,23022,23179,30781,23877,29171,31665,26534,32159,22583,27525,28708,31216,17158,31988,32190,23747,21272,21278,24727,29984,25303,23445,23119,23155,26346,26389,30747,28948,31418,21323,31758,30911,18790,21312,25099,22348,25409,29357,22180,23588,28794,18133,25624,21972,23401,24821,31369,25187,31517,19840,28836,20794,20239,24523,30814,24016,17954,21227,16691,30290,23391,20482,24822,31968,30651,27908,22690,30875,31003,31747,19978,25482,18563,30143,27788,26658,26295,23244,27086,26456,24251,28647,22783,27460,19187,23252,24078,19203,26251,18113,19542,24533,16666,24038,32744,28670,30438,26379,18591,30109,26509,20947,27696,22945,27542,32128,25416,21675,19389,27085,29380,20163,21102,30936,30862,18230,21904,16938,16579,20641,27551,22740,24666,16836,23306,27661,26506,28623,29816,20166,29405,23982,30046,19365,24926,19029,32448,17567,17156,18678,28594,19769,28631,25769,31309,24457,30625,21825,29811,17112,31370,25345,24333,24005,31606,30942,21441,30599,22894,18015,19994,27901,26868,21948,27614,23449,21289,19588,19955,28133,16696,31509,26219,19946,27895,28760,28547,28315,16614,26006,17129,24769,24608,17714,17682,18532,17597,29247,28789,27011,29841,32640,17508,27662,23548,29514,
@@ -0,0 +1,22 @@
#ifndef PORT_H
#define PORT_H
#include "int.h"
static inline int16_t inportb(int16_t port)
{
volatile uint8_t value;
asm volatile ("in %%dx, %%ax\n"
: "=a"(value)
: "d"(port));
return value;
}
static inline void outportb(int16_t port, uint8_t value)
{
asm volatile ("out %%al, %%dx\n"
: /* no output */
: "d"(port), "a"(value));
}
#endif
@@ -0,0 +1,21 @@
static void print(char *string)
{
asm volatile ("mov $0x09, %%ah\n"
"int $0x21\n"
: /* no output */
: "d"(string)
: "ah");
}
static void printl(unsigned long n)
{
volatile char buffer[12];
int i = sizeof(buffer);
buffer[--i] = '$';
if (n == 0)
buffer[--i] = '0';
else
for (; n > 0; n /= 10)
buffer[--i] = '0' + (n % 10);
print((char *) buffer + i);
}
@@ -0,0 +1,21 @@
#ifndef RANDOM_H
#define RANDOM_H
#include "int.h"
#define RAND_MAX 4294967295
static uint32_t rand_seed = 375226057;
static uint32_t rand(void)
{
rand_seed = rand_seed * 1103515245 + 12345;
return rand_seed;
}
static uint32_t randn(uint32_t n)
{
return (rand() >> 7) % n;
}
#endif
@@ -0,0 +1,229 @@
#pragma once
#include "int.h"
#include "tone.h"
struct note {
unsigned frequency;
uint16_t length;
};
struct sample {
int priority;
size_t length;
struct note notes[];
};
struct sample fx_menu_toggle = {
.priority = 50,
.length = 3,
{
{600, 2},
{1000, 1},
{700, 2}
}
};
struct sample fx_menu_select = {
.priority = 55,
.length = 4,
{
{800, 2},
{900, 3},
{1000, 4},
{0, 10}
}
};
struct sample fx_intro_music = {
.priority = 100,
.length = 11,
{
{262, 10},
{247, 10},
{220, 10},
{196, 10},
{247, 10},
{220, 10},
{196, 10},
{247, 10},
{220, 10},
{0, 10},
{110, 20},
}
};
struct sample fx_end_music = {
.priority = 200,
.length = 15,
{
{62, 50},
{0, 2},
{62, 50},
{0, 2},
{62, 50},
{0, 2},
{73, 25},
{0, 2},
{65, 20},
{0, 2},
{62, 50},
{0, 2},
{55, 50},
{0, 2},
{62, 100},
}
};
struct sample fx_explode = {
.priority = 10,
.length = 11,
{
{62, 1},
{47, 1},
{20, 1},
{96, 1},
{47, 1},
{20, 1},
{96, 1},
{47, 1},
{20, 1},
{89, 1},
{60, 1},
}
};
struct sample fx_fire0 = {
.priority = 0,
.length = 4,
{
{200, 1},
{190, 1},
{180, 1},
{170, 1}
}
};
struct sample fx_fire1 = {
.priority = -10,
.length = 5,
{
{150, 1},
{120, 1},
{100, 1},
{120, 1},
{135, 1}
}
};
struct sample fx_fire2 = {
.priority = -5,
.length = 5,
{
{300, 1},
{320, 1},
{330, 1},
{335, 1},
{340, 1}
}
};
struct sample fx_fire3 = {
.priority = 1,
.length = 14,
{
{50, 7},
{75, 7},
{100, 7},
{150, 7},
{200, 1},
{250, 1},
{300, 1},
{370, 1},
{360, 1},
{350, 1},
{340, 1},
{330, 1},
{320, 1},
{310, 1}
}
};
struct sample fx_hit = {
.priority = 5,
.length = 5,
{
{120, 3},
{130, 3},
{140, 3},
{150, 3},
{160, 3}
}
};
struct sample fx_powerup = {
.priority = 50,
.length = 2,
{
{800, 3},
{900, 3}
}
};
struct sample fx_boss = {
.priority = 500,
.length = 13,
{
{110, 15},
{0, 2},
{110, 15},
{0, 2},
{110, 5},
{175, 30},
{0, 2},
{175, 15},
{0, 2},
{175, 15},
{0, 2},
{175, 5},
{110, 30},
}
};
struct speaker {
struct sample *sample;
int index, step;
};
void speaker_play(struct speaker *speaker, struct sample *sample)
{
if (!speaker->sample || speaker->sample->priority < sample->priority) {
speaker->sample = sample;
speaker->index = -1;
speaker->step = 0;
}
}
void speaker_step(struct speaker *speaker)
{
if (speaker->sample) {
if (speaker->step) {
speaker->step--;
} else {
speaker->index++;
if (speaker->index >= speaker->sample->length) {
speaker->sample = 0;
tone_off();
} else {
struct note note = speaker->sample->notes[speaker->index];
if (note.frequency == 0)
tone_off();
else {
tone(note.frequency);
tone_on();
}
speaker->step = note.length;
}
}
}
}
@@ -0,0 +1,54 @@
#ifndef TIME_H
#define TIME_H
static uint32_t get_tick()
{
unsigned long result;
asm volatile ("push %%es\n"
"mov $0,%%bx\n"
"mov %%bx,%%es\n"
"mov $0x046C,%%bx\n"
"mov %%es:(%%bx),%%eax\n"
"pop %%es\n"
: "=a"(result)
: /* no inputs */
: "bx");
return result;
}
static uint32_t get_time()
{
uint16_t high, low;
asm volatile ("mov $0x2C, %%ah\n"
"int $0x21\n"
: "=c"(high), "=d"(low)
:
: "ah");
return (((uint32_t) high) << 16) | low;
}
/* Granularity of 976 usec and doesn't work in DOSBox. */
static void usleep(uint32_t us)
{
asm volatile ("mov $0x86, %%ah\n"
"int $0x15\n"
: /* no outputs */
: "c"(us >> 16), "d"(us & 0x16)
: "ah", "flags");
}
/* Granularity of 55 msec. */
static void msleep(int ms)
{
uint32_t count = ms / 54; // 18.2 Hz
uint32_t last = get_tick();
while (count) {
uint32_t now = get_tick();
if (now != last) {
last = now;
count--;
}
}
}
#endif
@@ -0,0 +1,18 @@
#include "port.h"
static void tone_on()
{
outportb(0x61, inportb(0x61) | 0x03);
}
static void tone_off()
{
outportb(0x61, inportb(0x61) & ~0x03);
}
static void tone(unsigned frequency)
{
uint16_t period = 1193180 / frequency;
outportb(0x42, period & 0xff);
outportb(0x42, period >> 8);
}
@@ -0,0 +1,117 @@
#ifndef VGA_H
#define VGA_H
#include "math.h"
#define VGA_PWIDTH 320
#define VGA_PHEIGHT 200
enum VGA_COLOR {
BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHT_GRAY, DARK_GRAY,
LIGHT_BLUE, LIGHT_GREEN, LIGHT_CYAN, LIGHT_RED, LIGHT_MAGENTA,
YELLOW, WHITE
};
struct point {
short x, y;
};
struct rect {
struct point tl, br;
};
/* Switch to VGA mode 13 and set ES. */
static void vga_on()
{
asm volatile ("mov $0x0013, %%ax\n"
"int $0x10\n"
"mov $0xA000, %%ax\n"
"mov %%ax, %%es\n"
: /* no outputs */
: /* no inputs */
: "ax");
}
static void vga_off()
{
asm volatile ("mov $0x0003, %%ax\n"
"int $0x10\n"
"mov $0xA000, %%dx\n"
"mov %%dx, %%es\n"
: /* no outputs */
: /* no inputs */
: "ax", "dx");
}
static void vga_pixel(volatile struct point p, uint8_t color)
{
if (p.x >= 0 && p.x < VGA_PWIDTH && p.y >= 0 && p.y < VGA_PHEIGHT)
asm volatile ("imul $320, %%bx\n"
"add %%ax, %%bx\n"
"mov %%cl, %%es:(%%bx)\n"
: /* no outputs */
: "a"(p.x), "b"(p.y), "c"(color)
: "dx");
}
static void vga_clear(char color)
{
asm volatile ("mov %%al, %%ah\n"
"mov $0, %%di\n"
"push %%ax\n"
"shl $16, %%eax\n"
"pop %%ax\n"
"mov $16000, %%cx\n"
"rep\n"
"stosl\n"
: /* no outputs */
: "a"(color)
: "cx", "di");
}
static void vga_line(struct point a, struct point b, uint8_t color)
{
int dx = abs(b.x - a.x), sx = a.x < b.x ? 1 : -1;
int dy = abs(b.y - a.y), sy = a.y < b.y ? 1 : -1;
int err = (dx > dy ? dx : -dy) / 2, e2;
for(;;) {
vga_pixel(a, color);
if (a.x == b.x && a.y == b.y)
break;
e2 = err;
if (e2 > -dx) {
err -= dy;
a.x += sx;
}
if (e2 < dy) {
err += dx;
a.y += sy;
}
}
}
static void vga_rect(struct rect r, uint8_t color)
{
vga_line(r.tl, (struct point){r.br.x, r.tl.y}, color);
vga_line(r.tl, (struct point){r.tl.x, r.br.y}, color);
vga_line(r.br, (struct point){r.br.x, r.tl.y}, color);
vga_line(r.br, (struct point){r.tl.x, r.br.y}, color);
}
static void vga_vsync()
{
asm volatile ("mov $0x03DA, %%dx\n"
"current%=:"
"in %%dx, %%al\n"
"and $0x8, %%al\n"
"jnz current%=\n"
"restart%=:"
"in %%dx, %%al\n"
"and $0x8, %%al\n"
"jz restart%=\n"
: /* no outputs */
: /* no inputs */
: "al", "dx");
}
#endif
@@ -0,0 +1,32 @@
#include "int.h"
#include "vga.h"
/* Letters are 7 pixels tall and 5 pixels wide. */
/* http://redd.it/2ba3g3 */
static const char LINES[] = "BCDEIKOPQRSTUVYZ\\_`";
static const char LETTERS[] =
"DFJSJJJRJJRJJRGJIIIJGRJJJJJRSIIRIISSIIRIIIHIILJJHJJJSJJJGDDDD"
"DGAAAAAJHJKMOMKJIIIIIISJQNJJJJJJPNLJJGJJJJJGRJJRIIIGJJJNGCRJJ"
"RMKJGJIGAJGSDDDDDDJJJJJJGJJJJJFDJJJNQJJJJFDFJJJJFDDDDSABDEIS";
static int vga_font_line(int c, int row) {
return c == ' ' ? 0 : LINES[LETTERS[(c - 'A') * 7 + row] - 'A'] - 'A';
}
static void vga_print(struct point p, uint8_t color, const char *message)
{
for (int y = 0; y < 7; y++) {
for (int x = 0; message[x]; x++) {
int c = message[x];
int line = vga_font_line(c, y);
for (int i = 0; i < 5; i++) {
if ((line >> i) & 0x01) {
int dx = p.x + x * 6 + (4 - i);
int dy = p.y + y;
vga_pixel((struct point){dx, dy}, color);
}
}
}
}
}