├── .gitignore ├── Stage-3 ├── Server-Files │ ├── flag.txt │ └── Dockerfile ├── Challenge-Files │ ├── Makefile │ ├── tacOS-base.bin │ └── part-3-server.py ├── solve.asm ├── Source-Files │ └── Makefile └── readme.md ├── Stage-2 ├── solve.txt └── readme.md ├── Stage-1 ├── Challenge-Files │ ├── stage-2.bin │ ├── Makefile │ └── stage-1.asm ├── solve.txt ├── Source-Files │ ├── Makefile │ ├── flaggen.py │ └── stage-2.asm ├── Server-Files │ ├── Dockerfile │ └── stage-1-server.py └── readme.md └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | Part-1/Source-Files/flag.txt 2 | 3 | -------------------------------------------------------------------------------- /Stage-3/Server-Files/flag.txt: -------------------------------------------------------------------------------- 1 | flag{tacOShell_cod3_t4cOSm3ll_c0de} 2 | -------------------------------------------------------------------------------- /Stage-2/solve.txt: -------------------------------------------------------------------------------- 1 | Change the last jmp command, `jmp LOAD_ADDR` to `jmp LOAD_ADDR + 1`, compile and run. 2 | -------------------------------------------------------------------------------- /Stage-1/Challenge-Files/stage-2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ElykDeer/A-Walk-Through-x86/HEAD/Stage-1/Challenge-Files/stage-2.bin -------------------------------------------------------------------------------- /Stage-3/Challenge-Files/Makefile: -------------------------------------------------------------------------------- 1 | tacOS.bin: 2 | dd bs=512 if=tacOS-base.bin of=tacOS.bin 3 | dd bs=512 if=untrusted-code.bin >> tacOS.bin 4 | -------------------------------------------------------------------------------- /Stage-3/Challenge-Files/tacOS-base.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ElykDeer/A-Walk-Through-x86/HEAD/Stage-3/Challenge-Files/tacOS-base.bin -------------------------------------------------------------------------------- /Stage-1/solve.txt: -------------------------------------------------------------------------------- 1 | Answer Key: 2 | 3 | Question 1: "0x00" 4 | Question 2: "0x00" 5 | Question 3: "0x0000" 6 | Question 4: "0x0e74" 7 | Question 5: "0x0e61" 8 | Question 6: "0x9000" 9 | Question 7: "0xaaa0" 10 | Question 8: "0xaaaa" 11 | 12 | -------------------------------------------------------------------------------- /Stage-1/Source-Files/Makefile: -------------------------------------------------------------------------------- 1 | all: stage-2.bin clean 2 | 3 | 4 | stage-2.bin: stage-2.asm flag.txt 5 | nasm -Wall -D STAGE_1_2 -f bin -o ../Challenge-Files/stage-2.bin stage-2.asm 6 | 7 | flag.txt: flaggen.py 8 | python2 flaggen.py flag{on3_5m0l1_JMP_f0r_x86_0ne_m4s5!ve_L33P_5_YOU} 9 | 10 | clean: 11 | rm -f flag.txt 12 | -------------------------------------------------------------------------------- /Stage-1/Server-Files/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update && apt-get upgrade -y 4 | RUN apt-get install -y socat python3 5 | 6 | RUN useradd -ms /bin/sh x86 7 | COPY stage-1-server.py /home/x86 8 | 9 | WORKDIR /home/x86 10 | 11 | ADD . / 12 | 13 | USER x86 14 | CMD ["socat", "-T300", "TCP-LISTEN:8000,reuseaddr,fork", "EXEC:/usr/bin/timeout 300 /home/x86/stage-1-server.py"] 15 | -------------------------------------------------------------------------------- /Stage-3/Server-Files/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN apt-get update && apt-get upgrade -y && apt-get install build-essential qemu python3-dev -y 4 | RUN apt-get install -y socat nasm 5 | 6 | COPY Challenge-Files/part-3-server.py Challenge-Files/Makefile Challenge-Files/tacOS-base.bin Server-Files/flag.txt / 7 | RUN chmod +x /part-3-server.py 8 | 9 | CMD ["socat", "-T60", "TCP-LISTEN:8000,reuseaddr,fork", "EXEC:./part-3-server.py"] 10 | -------------------------------------------------------------------------------- /Stage-3/solve.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | mov rdi, 0x00b8000 ; Graphics Buffer 4 | 5 | call get_ip 6 | mov rsi, rax 7 | add rsi, 2 8 | 9 | xor rax, rax 10 | 11 | print_loop: 12 | mov al, [rsi] 13 | mov ah, 0x1f 14 | inc rsi 15 | 16 | cmp ax, 0x1f00 17 | je .end 18 | 19 | mov word [rdi], ax 20 | add rdi, 2 21 | 22 | jmp print_loop 23 | 24 | .end: 25 | jmp .end 26 | 27 | get_ip: 28 | call next_line 29 | next_line: 30 | pop rax 31 | ret 32 | 33 | ; This complies to: 34 | ; bf00800b00e8220000004889c64883c6024831c08a06b41f48ffc6663d001f74096689074883c702ebeaebfee80000000058c3 35 | -------------------------------------------------------------------------------- /Stage-1/Challenge-Files/Makefile: -------------------------------------------------------------------------------- 1 | all: tacOS.bin clean-extra 2 | 3 | tacOS.bin: stage-1.asm stage-2.bin 4 | $(eval num_sectors := $(shell BLOCKSIZE=512 du stage-2.bin | cut -f1)) 5 | nasm -Wall -D NUM_SECTORS=$(num_sectors) -f bin -o stage-1.bin stage-1.asm 6 | dd bs=512 if=stage-1.bin of=tacOS.bin 7 | dd bs=512 seek=1 if=stage-2.bin of=tacOS.bin 8 | 9 | run: tacOS.bin clean-extra 10 | $(eval num_kb := $(shell du -k tacOS.bin | cut -f1)) 11 | @echo "Binary is $(num_kb) KB long" 12 | qemu-system-x86_64 -serial stdio -d guest_errors -drive format=raw,file=tacOS.bin 13 | 14 | clean-extra: 15 | rm -f stage-1.bin 16 | 17 | clean: clean-extra 18 | rm -f tacOS.bin -------------------------------------------------------------------------------- /Stage-1/Source-Files/flaggen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | import sys 4 | 5 | xor_key = (ord('E') | ord('l')) & (ord('y') | ord('k')) 6 | 7 | if len(sys.argv) != 2: 8 | print("Usage: ./flaggen.py 'flag'") 9 | exit(1) 10 | 11 | flag = sys.argv[1] 12 | 13 | encrypted = "" 14 | for c in flag: 15 | encrypted += chr((ord(c) << 1) ^ xor_key) 16 | # print(repr(encrypted)) # Proof it works 17 | 18 | decrypted = "" 19 | for c in encrypted: 20 | decrypted += chr((ord(c) ^ xor_key) >> 1) 21 | # print(decrypted) # Proof it works 22 | 23 | nasmString = '' 24 | for c in encrypted: 25 | nasmString += hex(ord(c)) + ', 0x1f, ' 26 | 27 | nasmString = nasmString[:-2] 28 | 29 | with open("flag.txt", 'w') as f: 30 | f.write("db " + nasmString + "\n") -------------------------------------------------------------------------------- /Stage-3/Source-Files/Makefile: -------------------------------------------------------------------------------- 1 | all: tacOS-base.bin clean 2 | 3 | 4 | tacOS-base.bin: flag.txt ../../Stage-1/Challenge-Files/stage-1.asm stage-2.bin 5 | $(eval num_sectors := $(shell BLOCKSIZE=512 du $(realpath stage-2.bin) | cut -f1)) 6 | nasm -Wall -D NUM_SECTORS=$(num_sectors) -D STAGE_3 -f bin -o stage-1.bin ../../Stage-1/Challenge-Files/stage-1.asm 7 | dd bs=512 if=stage-1.bin of=../Challenge-Files/tacOS-base.bin 8 | dd bs=512 seek=1 if=stage-2.bin of=../Challenge-Files/tacOS-base.bin 9 | 10 | flag.txt: 11 | ../../Stage-1/Source-Files/flaggen.py flag{fake_flag} 12 | 13 | stage-2.bin: ../../Stage-1/Source-Files/stage-2.asm 14 | nasm -Wall -f bin -o stage-2.bin ../../Stage-1/Source-Files/stage-2.asm 15 | 16 | clean: 17 | rm flag.txt stage-1.bin stage-2.bin 18 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | This is series of challenges that I wrote for CSAW 2018 Quals. 2 | 3 | The intended purpose of this challenge is to impart on people who know very little to nothing about x86 or general "reverse engineering" a working understanding of these topics. 4 | 5 | This is a three-part series designed to get you comfortable with x86 assembly, covering 16, 32, and 64 bit code (part two containing all three, though part one is 16 bit and part three is designed to be 64 bit): 6 | In part one, you will employ static analysis techniques (which sounds scarier than it is) against the assembly source code to answer a short quiz. 7 | In part two, you will need a disassembler to allow you to read a compiled program, analyze what happens when it is executed, and determine a workaround for the problem that may become evident. 8 | In part three, you will need to write and compile some assembly of your own to send to a server for it to run such that it prints the flag. 9 | -------------------------------------------------------------------------------- /Stage-1/readme.md: -------------------------------------------------------------------------------- 1 | The provided Dockerfile deploys a server that the quiz is hosted on such that people can test their answers and potentially get the flag. 2 | 3 | To test the program locally, run `make run` in the `Challenge-Files` directory. This will compile tacOS (the small bootloader/OS I've made) and run it through QEMU. 4 | 5 | The flag that is granted from the server for the proper solutions to stage 1 is in `Server-Files/stage-1-server.py`. 6 | 7 | People solving the challenge should be provided with the three files located in `Challenge-Files`: 8 | `stage-1.asm` 9 | `stage-2.bin` 10 | `Makefile` 11 | 12 | Description to be provided to people trying to solve the challenge: 13 | ``` 14 | N3WBS 0NLY!!! 15 | 16 | Your first lesson in assembly is in 'stage-1.asm', so read it down! 17 | 18 | To run the code, run `make run`; this will compile tacOS (the small bootloader/OS I've made) and run it through QEMU. 19 | 20 | To solve the challenge, you'll need to connect to the quiz server and answer some questions about the source code. 21 | 22 | nc 23 | ``` 24 | -------------------------------------------------------------------------------- /Stage-2/readme.md: -------------------------------------------------------------------------------- 1 | This stage required no external server, as this is considered to fall into the category of reverse engineering problems reffered to as "crack-me's", which normally means that the flag is somehow creatively stored in the binary and there is some method by which the program recovers the flag, it is up to you to discover how the program recovers the flag and determine the right way to interact with the program such that the flag's recovery happens (or otherwise extract the mechanism and implement it better, for some challenges). 2 | 3 | The flag that is printed by the program is stored in `../Part-1/Source-Files/Makefile`. 4 | 5 | People solving the challenge should be provided with the same three files as the last part, located in `../Part-1/Challenge-Files`: 6 | `stage-1.asm` 7 | `stage-2.bin` 8 | `Makefile` 9 | 10 | Description to be provided to people trying to solve the challenge: 11 | ``` 12 | Stage twooooooooooooooooooooooooooooooooooooooooooooooo! 13 | 14 | This time the code that's important is compiled... 15 | Can you figure out what's going wrong in stage-2.bin? 16 | And more importantly, can you work your way around it??? 17 | 18 | (Same files as the last part) 19 | ``` 20 | -------------------------------------------------------------------------------- /Stage-3/readme.md: -------------------------------------------------------------------------------- 1 | The provided Dockerfile deploys a server that the the competitors need to interact with to solve the challenge. 2 | 3 | To prepare this challenge: 4 | ``` 5 | docker build -t=stage-3 -f Server-Files/Dockerfile . 6 | docker run -d --restart always -p 9004:8000 -p 5900-6100:5900-6100 stage-3 7 | ``` 8 | 9 | To test the challenge `nc localhost 9004` and paste the solution from solve.asm... Then connect to the VNC server to see that it actually worked. 10 | 11 | The flag that the competitors have to print with the code they submit is stored in `Sever-Files/flag.txt`. 12 | 13 | People solving the challenge should be provided with the three files located in `Challenge-Files`: 14 | `tacOS-base.bin` (which can be rebuilt by running make in `Source-Files`) 15 | `part-3-server.py` 16 | `Makefile` 17 | 18 | Description to be provided to people trying to solve the challenge: 19 | ``` 20 | The final boss! 21 | 22 | Time to pull together your knowledge of Bash, Python, and stupidly-low-level assembly!! 23 | 24 | This time you have to write some assembly that I am going to run.. You'll see the output of your code through VNC for 60 seconds. 25 | 26 | Objective: Print the flag. 27 | 28 | What to know: 29 | 30 | Strings need to be alternating between the character you want to print and '0x1f' (0x1f611f611f611f61 for four 'a's). 31 | 32 | To print a string you need to write those alternating bytes to the frame buffer (starting at 0x00b8000...just do it). Increment your pointer to move through this buffer. 33 | 34 | If you're having difficulty figuring out where the flag is stored in memory, this code snippet might help you out: 35 | 36 | ~~~ 37 | get_ip: 38 | call next_line 39 | next_line: 40 | pop rax 41 | ret 42 | ~~~ 43 | 44 | That'll put the address of `pop rax` into rax. 45 | 46 | Call serves as an alias for `push rip` (the instruction pointer - where we are in code) followed by `jmp _____` where whatever is next to the call fills in the blank. 47 | 48 | And in case this comes up, you shouldn't need to know where you are loaded in memory if you use that above snippet... 49 | 50 | Happy Reversing!! 51 | 52 | - Elyk 53 | ``` 54 | -------------------------------------------------------------------------------- /Stage-3/Challenge-Files/part-3-server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import subprocess 3 | import socket 4 | import binascii 5 | import random 6 | import tempfile 7 | import os 8 | import random 9 | 10 | dump = input("Pls give datas like \"90909090\" for four nops:\n") 11 | 12 | if len(dump) >= 1000: 13 | print("Too long!!", flush=True) 14 | exit() 15 | 16 | dumpList = [dump[i:i+2] for i in range(0, len(dump), 2)] 17 | 18 | hexList = [] 19 | 20 | for b in dumpList: 21 | try: 22 | hexList += binascii.unhexlify(b) 23 | except: 24 | print("Even-Byte Hex only!!", flush=True) 25 | exit() 26 | 27 | def port_open(port): 28 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 29 | result = sock.connect_ex(('localhost', port)) 30 | if result == 0: 31 | return False 32 | else: 33 | return True 34 | 35 | flag = open("flag.txt", 'r').readline().strip().encode('charmap') 36 | null = open("/dev/null", 'w') 37 | 38 | # with tempfile.TemporaryDirectory() as workdir: 39 | # for fn in ["Makefile", "tacOS-base.bin"]: 40 | # os.symlink(os.path.join(os.path.dirname(os.path.realpath(__file__)), fn), os.path.join(workdir, fn)) 41 | 42 | workdir = "./" 43 | with open(os.path.join(workdir, "untrusted-code.bin"), 'wb') as f: 44 | f.write(bytearray(hexList) + flag + b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') 45 | 46 | subprocess.run(["make"], cwd=workdir, stdout=null, stderr=null) 47 | 48 | displays = list(range(200)) 49 | random.shuffle(displays) 50 | for p in displays: 51 | if port_open(p + 5900): 52 | print("Connect with VNC to port", p + 5900, flush=True) 53 | subprocess.run([ 54 | "timeout", 55 | "-s", "KILL", 56 | "15", 57 | "qemu-system-x86_64", 58 | "-m", "16", 59 | "-drive", "format=raw,file=" + os.path.join(workdir, "tacOS.bin"), 60 | "-vnc", ":" + str(p) 61 | ], stdout=null, stderr=null) 62 | break 63 | else: 64 | print("Servers busy, try again later", flush=True) 65 | 66 | # workdir is auto cleaned by leaving ctxt 67 | -------------------------------------------------------------------------------- /Stage-1/Server-Files/stage-1-server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from time import sleep 3 | 4 | 5 | def input_answer(prompt, answer): 6 | user_input = input(prompt) 7 | if user_input == answer: 8 | return 1 9 | else: 10 | return 0 11 | 12 | 13 | def main(): 14 | # Question 1 15 | if not input_answer("What is the value of dh after line 129 executes? (Answer with a one-byte hex value, prefixed with '0x')\n", "0x00"): 16 | return 0 17 | 18 | # Question 2 19 | if not input_answer("\nWhat is the value of gs after line 145 executes? (Answer with a one-byte hex value, prefixed with '0x')\n", "0x00"): 20 | return 0 21 | 22 | # Question 3 23 | if not input_answer("\nWhat is the value of si after line 151 executes? (Answer with a two-byte hex value, prefixed with '0x')\n", "0x0000"): 24 | return 0 25 | 26 | # Question 4 27 | if not input_answer("\nWhat is the value of ax after line 169 executes? (Answer with a two-byte hex value, prefixed with '0x')\n", "0x0e74"): 28 | return 0 29 | 30 | # Question 5 31 | if not input_answer("\nWhat is the value of ax after line 199 executes for the first time? (Answer with a two-byte hex value, prefixed with '0x')\n", "0x0e61"): 32 | return 0 33 | 34 | # Question 6 35 | if not input_answer("\If the value of bp at line 313 is 0x9000 what is the value of bp after line 335 executes? (Answer with a two-byte hex value, prefixed with '0x')\n", "0x9000"): 36 | return 0 37 | 38 | # Question 7 39 | if not input_answer("\If the value of sp at line 313 is 0xaaaa what is the value of sp after line 335 executes? (Answer with a two-byte hex value, prefixed with '0x')\n", "0xaaa0"): 40 | return 0 41 | 42 | # Question 8 43 | if not input_answer("\If the value of sp at line 313 is 0xaaaa what is the value of sp after line 335 executes? (Answer with a two-byte hex value, prefixed with '0x')\n", "0xaaaa"): 44 | return 0 45 | 46 | return 1 47 | 48 | 49 | if __name__ == "__main__": 50 | print("\nWelcome!\n") 51 | 52 | if(main()): 53 | print("flag{reeeeeee3333eeally_go0d_job_solv1ng_your_fir5t_rev_reee33334eeeeeecrui7!}") 54 | else: 55 | print("Sorry, try again!") 56 | -------------------------------------------------------------------------------- /Stage-1/Source-Files/stage-2.asm: -------------------------------------------------------------------------------- 1 | bits 16 2 | org 0x6000 3 | 4 | %ifdef STAGE_1_2 5 | hlt 6 | %endif 7 | 8 | main: 9 | .a_20: 10 | in al, 0x92 11 | or al, 2 12 | out 0x92, al 13 | 14 | .init: 15 | xor ax, ax 16 | ; Set up segment registers. 17 | mov ss, ax 18 | ; Set up stack so that it starts below Main. 19 | mov sp, main 20 | 21 | mov ds, ax 22 | mov es, ax 23 | mov fs, ax 24 | mov gs, ax 25 | cld 26 | 27 | mov edi, 0 28 | jmp SwitchToLongMode 29 | 30 | %define PAGE_PRESENT (1 << 0) 31 | %define PAGE_WRITE (1 << 1) 32 | 33 | %define CODE_SEG 0x0008 34 | %define DATA_SEG 0x0010 35 | 36 | ALIGN 4 37 | ; Interupt Descriptor Table 38 | IDT: 39 | .Length dw 0 40 | .Base dd 0 41 | 42 | SwitchToLongMode: 43 | ; Zero out the 16KiB buffer. 44 | ; Since we are doing a rep stosd, count should be bytes/4. 45 | push di ; REP STOSD alters DI. 46 | mov ecx, 0x1000 47 | xor eax, eax 48 | cld 49 | rep stosd 50 | pop di ; Get DI back. 51 | 52 | ; Build the Page Map Level 4. 53 | ; es:di points to the Page Map Level 4 table. 54 | lea eax, [es:di + 0x1000] ; Put the address of the Page Directory Pointer Table in to EAX. 55 | or eax, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writable flag. 56 | mov [es:di], eax ; Store the value of EAX as the first PML4E. 57 | 58 | ; Build the Page Directory Pointer Table. 59 | lea eax, [es:di + 0x2000] ; Put the address of the Page Directory in to EAX. 60 | or eax, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writable flag. 61 | mov [es:di + 0x1000], eax ; Store the value of EAX as the first PDPTE. 62 | 63 | ; Build the Page Directory. 64 | lea eax, [es:di + 0x3000] ; Put the address of the Page Table in to EAX. 65 | or eax, PAGE_PRESENT | PAGE_WRITE ; Or EAX with the flags - present flag, writeable flag. 66 | mov [es:di + 0x2000], eax ; Store to value of EAX as the first PDE. 67 | 68 | push di ; Save DI for the time being. 69 | lea di, [di + 0x3000] ; Point DI to the page table. 70 | mov eax, PAGE_PRESENT | PAGE_WRITE ; Move the flags into EAX - and point it to 0x0000. 71 | 72 | ; Build the Page Table. 73 | .LoopPageTable: 74 | mov [es:di], eax 75 | add eax, 0x1000 76 | add di, 8 77 | cmp eax, 0x200000 ; If we did all 2MiB, end. 78 | jb .LoopPageTable 79 | 80 | pop di ; Restore DI. 81 | 82 | ; Disable IRQs 83 | mov al, 0xFF ; Out 0xFF to 0xA1 and 0x21 to disable all IRQs. 84 | out 0xA1, al 85 | out 0x21, al 86 | 87 | nop 88 | nop 89 | 90 | lidt [IDT] ; Load a zero length IDT so that any NMI causes a triple fault. 91 | 92 | ; Enter long mode. 93 | mov eax, 10100000b ; Set the PAE and PGE bit. 94 | mov cr4, eax 95 | 96 | mov edx, edi ; Point CR3 at the PML4. 97 | mov cr3, edx 98 | 99 | mov ecx, 0xC0000080 ; Read from the EFER MSR. 100 | rdmsr 101 | or eax, 0x00000100 ; Set the LME bit. 102 | wrmsr 103 | 104 | mov ebx, cr0 ; Activate long mode 105 | or ebx,0x80000001 ; - by enabling paging and protection simultaneously. 106 | mov cr0, ebx 107 | 108 | lgdt [GDT.Pointer] ; Load GDT.Pointer defined below. 109 | 110 | jmp CODE_SEG:LongMode ; Load CS with 64 bit segment and flush the instruction cache 111 | 112 | ; Global Descriptor Table 113 | GDT: 114 | .Null: 115 | dq 0x0000000000000000 ; Null Descriptor - should be present. 116 | .Code: 117 | dq 0x00209A0000000000 ; 64-bit code descriptor (exec/read). 118 | dq 0x0000920000000000 ; 64-bit data descriptor (read/write). 119 | ALIGN 4 120 | dw 0 ; Padding to make the "address of the GDT" field aligned on a 4-byte boundary 121 | .Pointer: 122 | dw $ - GDT - 1 ; 16-bit Size (Limit) of GDT. 123 | dd GDT ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit) 124 | 125 | flag: 126 | %include "flag.txt" 127 | dq 0x00, 0x00 ; Null-double-quadword terminated string because why tf not 128 | 129 | bits 64 130 | LongMode: 131 | mov ax, DATA_SEG 132 | mov ds, ax 133 | mov es, ax 134 | mov fs, ax 135 | mov gs, ax 136 | mov ss, ax 137 | 138 | ; Blank out the screen to a blue color. 139 | mov edi, 0xB8000 140 | mov rcx, 500 ; Since we are clearing uint64_t over here, we put the count as Count/4. 141 | mov rax, 0x1F201F201F201F20 ; Set the value to set the screen to: Blue background, white foreground, blank spaces. 142 | rep stosq ; Clear the entire screen. 143 | 144 | mov edi, 0x00b8000 ; Graphics Buffer 145 | 146 | xor rax, rax 147 | xor rbx, rbx 148 | xor rcx, rcx 149 | xor rdx, rdx 150 | 151 | mov dl, 'E' 152 | or dl, 'l' 153 | mov dh, 'y' 154 | or dh, 'k' 155 | and dl, dh 156 | mov dh, 0 157 | 158 | mov rsi, flag 159 | .print_loop: 160 | cmp qword [rsi+rax], 0 161 | je .end 162 | 163 | mov rcx, 4 164 | .dec_loop: 165 | mov bl, [rsi+rax] 166 | xor bl, dl 167 | shr bl, 1 168 | mov [rsi+rax], bl 169 | add rax, 2 170 | loop .dec_loop 171 | sub rax, 8 172 | 173 | mov rcx, [rsi+rax] 174 | mov [rdi+rax], rcx 175 | 176 | add rax, 8 177 | jmp .print_loop 178 | 179 | .end: 180 | %ifdef STAGE_1_2 181 | jmp .end 182 | %endif 183 | -------------------------------------------------------------------------------- /Stage-1/Challenge-Files/stage-1.asm: -------------------------------------------------------------------------------- 1 | ; Welcome to CSAW! And, presumably, welcome to reverse engineering. 2 | ; This challenge is for N3WbS ONLY, so if you know what you're doing, then put one of your freshmen on this challenge..if you don't have any freshmen, then you need to recruit harder - for now just go steal one. Come back when you're ready with some fresh blood, or go work on some harder challenges! 3 | 4 | ; Rule # ONE : 5 | ; Since this problem is designed to introduce newbies to reverse engineering, I've designed this source document such that you can hopefully read it straight down and come to a reasonable understanding of this nonsense... 6 | ; Reverse engineering is the dissection and understanding of SYSTEMS, not of CODE.. As such, you won't need to read and understand every single line so long as you can understand what is general occurring and build a working intuition of what the system is doing. 7 | ; For example, if you see a call to `print("input: ")` then a call to `password = inputPassword()`, I would sincerely hope that you could deduce that you're being asked to input the weight of an average-sized giraffe. (that's a joke...I do those..ask on IRC if you get caught up on something you think might be a joke..though we can't really help you during the competition..we can help clear up misunderstandings as a result of me not being an english major, but not too much beyond that) 8 | 9 | ; Alright. 10 | ; So if you're still here then you're about to learn the coolest shit ever. 11 | ; This is assembly. This is a human-readable representation of what is as close as reasonable (and still READABLE) to what the actual processor on your computer runs. 12 | ; It's worth mentioning that assembly is a dense topic, there's a lot here to understand... You should probably go take a course on this and read some book and--- WAIT!! NO!! THIS IS CSAW!!! WE LEARN THIS THE FUN WAY; MISGUIDEDLY DIVING IN HEAD FIRST AND BREAKING SHIT ALONG THE WAY. 13 | ; So here we go. 14 | 15 | ; To start, I am not going to give you a hello world world program as is standard - that would be far too complicated a program to parse. Let's instead write a basic operating system. Much easier, right? *eye twitch* 16 | ; Here's the bill of materials you're going to want for this challenge, and most of your future hacking/building/programing/life.... .-. 17 | ; 1. Linux, of some sort - I'm running Ubuntu 18.04 myself, and that's what a lot of other CTF problems are made to target, but there are plenty of versions of Linux out there... You'll have to reinstall whatever you setup about a million times before you actually figure out how this Unix-like shit works, so don't worry about it too much and just go install any one of them. 18 | ; You might wish to use a Virtual Machine for this. That would be okay. 19 | ; If you really want, you could even containerise this. That'd be cool... But not needed. 20 | ; If you are on Windows, the Linux Subssytem for Windows is really nice.. I like it a lot. 21 | ; 22 | ; 2. NASM - How we convert the text below into the stuff the computer can actually read. 23 | ; Yeah, so, uhhh, the bad news is that a computer can't understand text very well. The good news is that it's pretty easy to make the text machine-readable: each line of ode below translates to somewhere between 1 and 15 bytes that the computer can understand perfectly - but we can only recognize as a collection of random numbers. 24 | ; (On Ubuntu, that's a simple `sudo apt install nasm`) 25 | ; 26 | ; 3. QEMU - How we're going to run the operating system we're making 27 | ; (On Ubuntu, that's a simple `sudo apt install qemu`) 28 | ; 29 | ; 4. Probably a text editor. To this edit text (to solve part two). I like VisualStudioCode.. It has some 'asm' extentions. 30 | ; 31 | ; 5. A T3rMiNaL! They're useful. You type things in them and make stuff happen... This should almost go without saying, but that's how we're going to interact with the tool's we are using for this challenge, and many other challenges. 32 | ; Don't be scared though, there are many nice graphical tools you'll end up using along the way. 33 | ; 34 | ; 6. To practically advance in reverse engineering, and to advance past the first stage of this "Tour Of x86", you'll need a disassembler. 35 | ; A disassembler takes that collection of seemingly random numbers and translates it into something a human can understand. 36 | ; The nice disassemblers also do some extra analysis on these programs, which allow for it to more accurate disassemble the program, like BinaryNinja!! <- the best one ever. :) And no I'm not contractually obligated to say that. I'm also not stuck in a box. I also don't miss the large death laser in the sky. The death laser was mean to me. 37 | 38 | ; Damn, that was boring. 39 | 40 | ; Time for the really cool stuff! x86 assembly! 41 | ; It's worth mentioning that there are lots of different assembly languages; since there are many different kinds of computers that have different design goals and use-cases, and "the processor" is the brain of all of these devices, there has developd a healthy handful of different assembly languages to control these different processors. 42 | ; Two of these use-cases might include a low-power environment like your phone (where you want it to work all day), and a computationally intensive device like a server or a gaming computer... The phone would use something that was designed with low power usage in mind, like the ARM processors, whereas the desktop might use something that is more powerful/faster/has more features such as Intel's and AMD's own x86! Which is what we'll look at because most services you'll exploit 'in their natural habitat' will be running on a heavy-duty x86 computer - tangentially, since it's designed to be more robust it is a LOT more complicated and there are sometimes glitches, which we call vulnerabilities, in the implementation of the processors' instruction that might allow us to do things that were not intended in the design - possibly leaking data. 43 | 44 | ; First things first, don't read these next three lines of code 45 | 46 | ; Tell the text to machine-code machine, NASM, where in memory our code is going to be loaded. Hexadecimal. Legacy BS. 47 | org 7C00h 48 | ; Tell Mr. Machine that we're using 16-bit assembly 49 | bits 16 50 | 51 | ; Setting up two defines for later so we don't have magic numbers laying around. 52 | %define LOAD_ADDR 0x6000 53 | 54 | ; Got you - I bet you even read those lines. Ugh. 55 | 56 | ; Every program needs to start somewhere, why not start at the `_start`? 57 | _start: ; This is a label... It's not an instruction. It is simply a marker for us humans. We put it here so we can reference it later, such that ff we later specify `_start` in our code, NASM will know we're referencing the element immediately following the label. 58 | cli ; This is not an instruction you normally see... So don't worry about it. Makes it so, like, plugging in a usb doesn't scare the processor away from us. 59 | 60 | ; Important: Assembly gives you a set number of variables. These variables are called registers. They are not variables, but you can think of them like that. They're really fast and depending on the name you reference them by, you get different sizes of them (16 bits vs 8 bits vs 64, etc.) - they're fixed-sized slots for us to store _data_. 61 | ; I'm going to go ahead and clear all of the registers we have 'general' access to (and that won't cause our code to die) just so you can see what they are.. There are tons more, but these are the meat-and-gravy of what we'll use to store and manipulate data. 62 | 63 | mov ah, 0 64 | mov al, 0 65 | mov ax, 0 66 | 67 | ; Okay I'll stop myself right here. Let's break this line down into its component parts. 68 | ; `mov` - the first word that you see is called the "opcode" - the "operation code" - the short word that represent and operation performed by your code on the processor of the computer. This one is move. It moves stuff. 69 | ; `ah` - one of those registers I mentioned (the 'a' register...there's also 'b', 'c', 'd', and more). It's 8 bits large... It's the smallest register size we have. 70 | ; `0` - it's.... zero. What do you want from meee? 71 | ; 72 | ; So in a syntax you're probably more used to: 73 | ; `mov ah, 0` means `ah = 0` 74 | ; since we're moving data from the right to the left... Setting ah hold the value zero. 75 | ; We're doing the same to `al` and `ax`, al is another 8-bit register, and ax is 16 bits... They're all related by the `A`, though.. They're different parts of the same register: 76 | ; 77 | ; 16 bits (separated for visual effect in eight-bit chunks): 78 | ; 79 | ; -------- -------- 80 | ; 81 | ; These are slots for 0's and ones.. Could look like: 82 | ; 83 | ; 00000000 00000000 84 | ; 85 | ; Or whatever other binary value we set it to. 86 | ; 87 | ; The most significant digits in the number are on the left, like we're used to. As such, and as I have, we can separate these 16-bits into two separate halves and label them `high` (h) and `low` (l)... The higher 8-bits being the more-significant digits. 88 | ; We can manipulate each of these halfs independently, for convenience. We simply need to know how to reference them. 89 | ; 90 | ; -------- -------- 91 | ; AH AL 92 | ; 93 | ; And the whole thing is called AX. 94 | ; 95 | ; This is important, so, to restate... If you want to change any part of the `A` register, you need to reference which part of it you want to change. The 16 bits, or the lower 8-bits, or the higher 8-bits. Be "specif-bits" (specific..I know, I'm hilarious). 96 | ; 97 | ; We have registers A, B, C, and D that are the same.. Later we'll also have 8 through 15, that are similar, but we'll get to them when we get to them. 98 | 99 | ; Let's keep clearing our registers... Just to makes sure they're all zero when we're starting out and to show you what they all look like 100 | 101 | mov bh, 0 102 | mov bl, 0 103 | mov bx, 0 ; Realize that this one is pointless and redundant. 104 | 105 | mov ch, 1 106 | mov cl, 1 107 | mov cx, 0 ; The other two values get overwritten regardless, the value of ch and cl (the two components that make up cx) after this instruction are both 0, not 1. 108 | 109 | ; To prove that last comment, let's introduce a quick comparison... `cmp` 110 | cmp ch, 1 ; Many instructions act on more than their explicitly stated operands, in this case it sets some of the bits in a register known as the `flags` registers.. Each bit of the flags register is used as a boolean value. You don't need to memorize what each bit holds a bool for, though, since we have other opcodes that will read and parse the flags register for us. 111 | ; This instruction looks at the register ch and the absolute value of "one" and sets the various field in `flags` based on the attributes that it recognizes - less than, greater than, equal, etc. 112 | 113 | je .death ; read as "jump equal", if the two values previously compared were equal at the time of the comparison, then we will jump to the _label_ (remember... `_start`?) specified as the sole operand. This instruction also acts on a register not explicitly stated... The "instructions pointer", which effectively holds the count of which instruction in the program we are next to execute (it really holds a pointer to the instruction loaded in memory, but pedantics...) 114 | jmp .next_test ; Since the two values were not equal and did not satisfy the jump condition, it instead just falls through to the next instruction, this one, which skips the death block via a unconditional jump 115 | 116 | .death: 117 | hlt ; "Halt and catch fire" - stop executing code. Immediately. Die. Never come back. It's all over. The death laser in the sky got you. Etc. 118 | 119 | .next_test: ;One note, I'm using NASM as a assembler (which is fairly standard), and it provides a lot of nice preprocessor things, much like `#include`s in C++ and the like. 120 | ; One of the things that NASM provides is 'local labels', so any label with a dot (".") in font of it, is considered local to a function (the previous label without a dot in front of it), so you can have the same label across your codebase within larger labels (tentatively called functions), just for convenience. 121 | cmp cl, 0 122 | je .success ; If cl is indeed zero, skip the death! 123 | 124 | hlt ; pls no 125 | 126 | .success: ; Whitespace is ignored, btw...just like me 127 | 128 | ; There are other ways to make a register be set to zero... I hope you know your binary operators (and, or, not, xor, compliments) 129 | xor dh, dh ; <- Question 1 130 | and dl, 0 131 | mov dx, 0xffff ; Hexadecimal 132 | not dx 133 | 134 | cmp dx, 0 135 | jne .death ; This time jumping backwards to a label we passed... Saves duplicate code. 136 | 137 | ; Alright, recruits! New registers! 138 | ; These are called segment registers and are all 16-bits only. 139 | ; ...Yeah... 140 | ; Fuckin' useless. 141 | 142 | mov ds, ax ; Oh yeah so this time since 143 | mov es, bx ; the other registers are 144 | mov fs, cx ; already zero, I'm just going 145 | mov gs, dx ; to use them to help me clear <- Question 2 146 | mov ss, ax ; these registers out. 147 | 148 | ; Many of these registers actually have names, but they're mostly irrelevant and just legacy. 149 | mov sp, cx ; Stack Pointer 150 | mov bp, dx ; Base Pointer 151 | mov si, sp ; Source Index <- Question 3 152 | mov di, bp ; Destination Index 153 | ; Remember, those were just a `ds = ax; ex = bx;` etc. What values were the registers on the right? 154 | 155 | ; So now we've covered just about all the registers we can, let's start doing some things. 156 | 157 | ; New function 158 | new_function: 159 | ; As you can see, it's not really a new function... Since whitespace and labels are effectively ignored, I'm just labeling a new spot in the source file. 160 | 161 | ; Goal: Let's print some text! 162 | 163 | ; First things first, we need to setup the screen such that it will allow us to display text.. 164 | mov ax, 0x0003 165 | int 0x10 ; AH! Something new! 166 | 167 | ; Step two, a problem: we can only print one letter at a time, like so: 168 | mov al, 't' 169 | mov ah, 0x0e ; <- question 4 170 | int 0x10 ; The same new thing. Scawy! 171 | 172 | ; `int` is an interrupt. To step back and think in terms of what the code we programmers write can do, there is nothing the code can do except for manipulate data and make decisions (branching). 173 | ; If we want any code we write to have meaning impact though, we need to interact with the environment - to manifest the data we manipulate in the code such that it is useful for the end user. 174 | ; This means we have call into the API of the system our code is running on. In the of this code, we need to interact with the motherboard's system - the BIOS - and ask it to interact with, on our behalf, the screen (and later maybe other things like USB drives and such). 175 | ; The interrupt we are using here is interrupt 0x10. You can read about all the things it does [here](https://en.wikipedia.org/wiki/INT_10H) But, effectively, there are a number of different things this interrupt can do depending on the value of AH. AH + 0x0e allows us to print the 8-bit ASCII letter stored in the low 8-bit portion of the a register: al. 176 | 177 | ; But this is kinda useless for us. It only prints one letter. We can do better. 178 | 179 | ; First let's define a string to print, but remember...now we're defining junk data in the middle of code, so we need to jump around it so there's no attempt to decode our text string 180 | mov ax, .string_to_print 181 | jmp print_string 182 | .string_to_print: db "acOS", 0x0a, 0x0d, " by Elyk", 0x00 ; label: 183 | ; db stands for define-bytes, there's db, dw, dd, dq, dt, do, dy, and dz. I just learned that three of those exist. It's not really assembly-specific knowledge. It's okay. https://www.nasm.us/doc/nasmdoc3.html 184 | ; The array can be in the form of a "string" or comma,separate,values,. 185 | 186 | ; Now let's make a whole 'function' that prints a string 187 | print_string: 188 | .init: 189 | mov si, ax ; We have no syntactic way of passing parameters, so I'm just going to pass the first argument of a function through ax - the string to print. 190 | 191 | .print_char_loop: 192 | cmp byte [si], 0 ; The brackets around an expression is interpreted as "the address of" whatever that expression is.. It's exactly the same as the dereference operator in C-like languages 193 | ; So in this case, si is a pointer (which is a copy of the pointer from ax (line 183), which is the first "argument" to this "function", which is the pointer to the string we are trying to print) 194 | ; If we are currently pointing at a null-byte, we have the end of the string... Using null-terminated strings (the zero at the end of the string definition at line 178) 195 | je .end 196 | 197 | mov al, [si] ; Since this is treated as a dereference of si, we are getting the BYTE AT si... `al = *si` 198 | 199 | mov ah, 0x0e ; <- Question 5! 200 | int 0x10 ; Actually print the character 201 | 202 | inc si ; Increment the pointer, get to the next character 203 | jmp .print_char_loop 204 | .end: 205 | 206 | print_string_right: 207 | ; Print strings the right way 208 | 209 | jmp .past_data ; Reminder: Locally-defined lable, also remember: jumping past junk data below 210 | .important_string_to_print: db "lol kek ", 0 211 | .past_data: 212 | 213 | mov bp, .important_string_to_print ; Pointer to string 214 | mov dh, 3 ; Row to start print on 215 | mov dl, 15 ; Col to start print on 216 | mov cx, 0x0007 ; String length 217 | mov bx, 0000000000001111b ; White text on black background 218 | 219 | mov ax, 0x1301 ; This one prints a whole string! (also clearing all but the low bit...the coloring mode) 220 | int 0x10 ; Do the thing 221 | 222 | ; Although to be entirely honest I kinda like printing letter-by-letter more... It's more aesthetic. Plus you could use interrupt 0x15 to sleep a little bit between each layer and make it look cool... 223 | 224 | load_second_stage: 225 | ; This bit calls another interrupt that uses a file-descriptor-like thing, a daps, to find a load a file from disk. 226 | ; Load the rest of the bootloader 227 | mov si, daps ; disk packet address 228 | mov ah, 0x42 ; al unused 229 | mov dl, 0x80 ; what to copy 230 | int 0x13 ; do it (the interrupt takes care of the file loading) 231 | 232 | ; There's one more thing I have to show you before actually leaving here on a good concious : the stack 233 | ; Let's make a print-number function real quick (and skip over it to the code that uses it) 234 | jmp stack_example 235 | 236 | ; This function should print the number stored in AX...this is a non-trivial task, it turns out 237 | newline: 238 | db 0x0d, 0x0a 239 | print_buf: 240 | resb 5 241 | db ' ', 0 242 | print_ax: 243 | ; our strategy is to build the string of numbers from right to left, using modulo by 10 math, so we're getting to the end of our buffer 244 | lea si, [print_buf + 4] 245 | ; I guess it's also worth mentioning what this magical `lea` opcode does... It's sorta witchcraft. 246 | ; Inside of `[...]` you can have at worst `[reg_1+reg_2*const_1*const_2]` 247 | ; Where `reg_1` is called the `base` 248 | ; Where `reg_2` is called the `index` 249 | ; Where `const_1` is called the `offset` 250 | ; Where `const_2` is called the `scale` 251 | ; Whereas most of the time, the brackets serve as a dereference, `lea` explicitly instead just grabs the result of the operation inside the brackets.. Can be used as a shortcut/not having to call `add` 252 | ; Basically `r9 = print_buf + 18` 253 | 254 | mov di, si ; copy the address of the last character 255 | mov bx, 10 ; As I said before, we'll be dividing by 10 (which I'm just storing in the B register) to get each lowest digit 256 | 257 | .div_loop: 258 | ; Division is a little weird in assembly.. But also really nice. 259 | ; The command to divide is simply `div opcode_1`, where it divides the value in the a register implicitly 260 | ; The result of the division is stored in rax, and the remainder is stored in rdx. rdx needs to be cleared before we can actually perform the division, though. 261 | xor dx, dx ; zero rdx for div 262 | div bx ; rax:rdx (result:remainder) = rax / rbx 263 | add dx, 0x30 ; convert binary digit to ascii (0x30 = '0') 264 | mov byte [si], dl ; save remainder 265 | dec si ; decrement the buffer address, go to the "next" character 266 | cmp ax, 0 ; if rax == 0 exit the loop...if we have exhausted the numberspace 267 | jz .check_buf 268 | jmp .div_loop 269 | 270 | .check_buf: 271 | cmp si, di ; Compare what we were using as the pointer into our buffer to the saved last byte (check if we did any work) 272 | jne .print_buf 273 | mov byte [si], '0' ; place a zero into the buffer if we didn't do anything else to the buffer 274 | dec si 275 | 276 | .print_buf: 277 | ; Initialize Registers 278 | inc si ; address of last digit saved to buffer 279 | 280 | .print_char_loop: 281 | cmp byte [si], 0 ; Check if we are at the end of the buffer 282 | je .end 283 | 284 | ; sleep between outputs because I'm 3dGY and C00l 285 | push cx ; I'll explain this push/pop stuff in a moment 286 | push dx 287 | push ax 288 | xor cx, cx 289 | mov dx, 0xffff 290 | mov ah, 0x86 291 | int 0x15 292 | pop ax 293 | pop dx 294 | pop cx 295 | 296 | mov al, [si] ; Go to the next character 297 | 298 | mov ah, 0x0e ; Actually print the character 299 | int 0x10 300 | 301 | inc si 302 | jmp .print_char_loop 303 | .end: 304 | ret 305 | 306 | print_info: 307 | mov ax, bp ; Print stack registers 308 | call print_ax 309 | mov ax, sp 310 | call print_ax 311 | ret 312 | 313 | stack_example: 314 | mov ax, 1 315 | push ax ; Pushes the value onto the stack, saving it 316 | call print_ax ; Oh yeah BTW we DO have functions! And this is how you call them... It saves `ip`, the instruction pointer that I mentioned earlier, such that it may be recovered later and we can pick up from right after this call (via the use of a RET opcode) 317 | call print_info ; Watch the two values of printed in print_info... One stays the same while the other changes. 318 | 319 | mov ax, 2 320 | push ax 321 | call print_ax 322 | call print_info ; The BP register, or base pointer isn't changing 323 | 324 | mov ax, 3 325 | push ax 326 | call print_ax 327 | call print_info ; The SP register, or stack pointer, however is changing 328 | 329 | mov ax, 4 330 | push ax 331 | call print_ax 332 | call print_info 333 | 334 | mov ax, 5 335 | push ax ; <- Question 6 & 7! 336 | call print_ax 337 | call print_info 338 | 339 | pop ax ; Restores the last value from the stack (First-in-last-out) 340 | call print_ax 341 | call print_info ; And as we take things back off the stack, the sp goes back to what it was! 342 | 343 | pop ax 344 | call print_ax 345 | call print_info 346 | 347 | pop ax 348 | call print_ax 349 | call print_info ; One can use this distance - between bp and sp - to set up a local "frame" in the stack to store variables. This is called a stack frame. It's a good way to store extra values. 350 | 351 | pop ax 352 | call print_ax 353 | call print_info ; As a matter of fact, compilers store all of a function's local variables in the stack. 354 | 355 | pop ax ; <- Question 8! 356 | call print_ax 357 | call print_info 358 | 359 | 360 | end: 361 | ; Before we leave this stage, and the w0dERful souRCE cod3 I've WRItten bY HanD, I want to thank you for coming to CSAW and reading this.. 362 | ; I hope that you enjoy the rest of the game, and come to find a deep love for assembly, reverse engineering, and -w-i-s-h-i-n-g- -y-o-u- -n-e-v-e-r- -h-a-d- -e-y-e-s-. 363 | ; Remember: Google, Stack-Overflow, Manuals, Reference Docs, Wikipedia, etc are all your friend.. This in particular might be helpful: nasm.us/doc/nasmdoci.html (documentation for the assembler I'm using, NASM... Has a nice guide to all this in there) 364 | 365 | ; Now time to scale up our system from 16-bit mode to 64! We're gonna see a couple changes. The biggest is that we have new registers: 366 | ; 367 | ; The A-D registers are extended to 64, but only gives you access to either the whole thing or the LOW 32 bits (in addition to what we already have) 368 | ; RAX = all 64 bits of A 369 | ; EAX = Low 32 bits of A 370 | ; AX = Low 16 bits of A 371 | ; AL = Low 8 bits of A 372 | ; AH = 8 bits of A, 8 bits up from the bottom 373 | ; Modifying any of these affects the rest, with the caveat that `mov eax, __` also clears the high 32 bits. 374 | ; 375 | ; We also get r8-r15 376 | ; R8 = all 64 bits of A 377 | ; R8D = Low 32 bits of A 378 | ; R8W = Low 16 bits of A 379 | ; R8B = Low 8 bits of A 380 | ; No access to the 8 bits that live 8 bits from the bottom of the register. 381 | 382 | ; Yeah BTW you're gonna need a disassembler now.......I recommend BinaryNinja. 383 | 384 | ; Jump into the second stage of the bootloader/challenge progression 385 | jmp LOAD_ADDR 386 | 387 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 388 | ;; Data Section ;; 389 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 390 | align 16 391 | 392 | ; disk address packet structure 393 | daps: 394 | .size: db 0x10 395 | db 0 ; always 0 396 | 397 | ; NUM_SECTORS comes from the environment, see the makefile (+2 in stage three to account for user data) 398 | %ifdef STAGE_3 399 | .num_sectors: dw NUM_SECTORS + 2 400 | %else 401 | .num_sectors: dw NUM_SECTORS 402 | %endif 403 | 404 | .transfer_buffer: dd LOAD_ADDR 405 | .lba_lower: dd 0x1 406 | .lba_upper: dd 0x0 407 | 408 | times 0200h - 2 - ($ - $$) db 0 ; Zerofill up to 510 bytes 409 | dw 0AA55h ; Boot Sector signature <- need this for the disk to load --------------------------------------------------------------------------------