From 3a4d87073098fd42fc5133a4b5ad6e4b6d2c9aed Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 10 Dec 2018 00:16:23 -0800 Subject: 4864 Our first buffer overflow! --- html/subx/059read-byte.subx.html | 479 ++++++++++++++++++++++----------------- 1 file changed, 266 insertions(+), 213 deletions(-) (limited to 'html/subx') diff --git a/html/subx/059read-byte.subx.html b/html/subx/059read-byte.subx.html index 6e2f5855..7c5b55fa 100644 --- a/html/subx/059read-byte.subx.html +++ b/html/subx/059read-byte.subx.html @@ -100,219 +100,272 @@ if ('onhashchange' in window) { 34 # main: 35 e8/call run-tests/disp32 # 'run-tests' is a function created automatically by SubX. It calls all functions that start with 'test-'. 36 #? e8/call test-read-byte-multiple/disp32 - 37 # syscall(exit, Num-test-failures) - 38 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX - 39 b8/copy-to-EAX 1/imm32 - 40 cd/syscall 0x80/imm8 - 41 - 42 # return next byte value in EAX, with top 3 bytes cleared. - 43 # On EOF, return 0xffffffff. - 44 read-byte: # f : (address buffered-file) -> byte-or-eof/EAX - 45 # . prolog - 46 55/push-EBP - 47 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP - 48 # . save registers - 49 51/push-ECX - 50 56/push-ESI - 51 # ESI = f - 52 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI - 53 # ECX = f->read - 54 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX - 55 # if (f->read >= f->write) populate stream from file - 56 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) - 57 7c/jump-if-lesser $read-byte:from-stream/disp8 - 58 # . clear-stream(stream = f+4) - 59 # . . push args - 60 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX - 61 50/push-EAX - 62 # . . call - 63 e8/call clear-stream/disp32 - 64 # . . discard args - 65 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP - 66 # . EAX = read(f->fd, stream = f+4) - 67 # . . push args - 68 50/push-EAX - 69 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI - 70 # . . call - 71 e8/call read/disp32 - 72 # . . discard args - 73 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP - 74 # if EAX = 0 return 0xffffffff - 75 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX - 76 75/jump-if-not-equal $read-byte:from-stream/disp8 - 77 b8/copy-to-EAX 0xffffffff/imm32 - 78 eb/jump $read-byte:end/disp8 - 79 $read-byte:from-stream: - 80 # read byte from stream - 81 # AL = f->data[f->read] - 82 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX - 83 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy byte at *(ESI+ECX+16) to AL - 84 # ++f->read - 85 ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8) - 86 $read-byte:end: - 87 # . restore registers - 88 5e/pop-to-ESI - 89 59/pop-to-ECX - 90 # . epilog - 91 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP - 92 5d/pop-to-EBP - 93 c3/return - 94 - 95 # - tests - 96 - 97 test-read-byte-single: - 98 # - check that read-byte returns first byte of 'file' - 99 # setup -100 # . clear-stream(_test-stream) -101 # . . push args -102 68/push _test-stream/imm32 -103 # . . call -104 e8/call clear-stream/disp32 -105 # . . discard args -106 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -107 # . clear-stream(_test-buffered-file+4) -108 # . . push args -109 b8/copy-to-EAX _test-buffered-file/imm32 -110 05/add-to-EAX 4/imm32 -111 50/push-EAX -112 # . . call -113 e8/call clear-stream/disp32 -114 # . . discard args -115 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -116 # . write(_test-stream, "Ab") -117 # . . push args -118 68/push "Ab"/imm32 -119 68/push _test-stream/imm32 -120 # . . call -121 e8/call write/disp32 -122 # . . discard args -123 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -124 # read-byte(_test-buffered-file) -125 # . . push args -126 68/push _test-buffered-file/imm32 -127 # . . call -128 e8/call read-byte/disp32 -129 # . . discard args -130 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -131 # check-ints-equal(EAX, 'A', msg) -132 # . . push args -133 68/push "F - test-read-byte-single"/imm32 -134 68/push 0x41/imm32 -135 50/push-EAX -136 # . . call -137 e8/call check-ints-equal/disp32 -138 # . . discard args -139 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -140 # . end -141 c3/return -142 -143 test-read-byte-multiple: -144 # - call read-byte twice, check that second call returns second byte -145 # setup -146 # . clear-stream(_test-stream) -147 # . . push args -148 68/push _test-stream/imm32 -149 # . . call -150 e8/call clear-stream/disp32 -151 # . . discard args -152 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -153 # . clear-stream(_test-buffered-file+4) -154 # . . push args -155 b8/copy-to-EAX _test-buffered-file/imm32 -156 05/add-to-EAX 4/imm32 -157 50/push-EAX -158 # . . call -159 e8/call clear-stream/disp32 -160 # . . discard args -161 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -162 # . write(_test-stream, "Ab") -163 # . . push args -164 68/push "Ab"/imm32 -165 68/push _test-stream/imm32 -166 # . . call -167 e8/call write/disp32 -168 # . . discard args -169 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP -170 # read-byte(_test-buffered-file) -171 # . . push args -172 68/push _test-buffered-file/imm32 -173 # . . call -174 e8/call read-byte/disp32 -175 # . . discard args -176 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -177 # read-byte(_test-buffered-file) -178 # . . push args -179 68/push _test-buffered-file/imm32 -180 # . . call -181 e8/call read-byte/disp32 -182 # . . discard args -183 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -184 # check-ints-equal(EAX, 'b', msg) -185 # . . push args -186 68/push "F - test-read-byte-multiple"/imm32 -187 68/push 0x62/imm32 -188 50/push-EAX -189 # . . call -190 e8/call check-ints-equal/disp32 -191 # . . discard args -192 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -193 # . end -194 c3/return -195 -196 test-read-byte-end-of-file: -197 # - call read-byte on an empty 'file', check that it returns 0xffffffff -198 # setup -199 # . clear-stream(_test-stream) -200 # . . push args -201 68/push _test-stream/imm32 -202 # . . call -203 e8/call clear-stream/disp32 -204 # . . discard args -205 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -206 # . clear-stream(_test-buffered-file+4) -207 # . . push args -208 b8/copy-to-EAX _test-buffered-file/imm32 -209 05/add-to-EAX 4/imm32 -210 50/push-EAX -211 # . . call -212 e8/call clear-stream/disp32 -213 # . . discard args -214 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -215 # read-byte(_test-buffered-file) -216 # . . push args -217 68/push _test-buffered-file/imm32 -218 # . . call -219 e8/call read-byte/disp32 -220 # . . discard args -221 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP -222 # check-ints-equal(EAX, 0xffffffff, msg) -223 # . . push args -224 68/push "F - test-read-byte-end-of-file"/imm32 -225 68/push 0xffffffff/imm32 -226 50/push-EAX -227 # . . call -228 e8/call check-ints-equal/disp32 -229 # . . discard args -230 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP -231 # . end -232 c3/return -233 -234 == data -235 -236 # a test buffered file for _test-stream -237 _test-buffered-file: -238 # file descriptor or (address stream) -239 _test-stream/imm32 -240 # current write index -241 00 00 00 00 -242 # current read index -243 00 00 00 00 -244 # length (6) -245 06 00 00 00 -246 # data -247 00 00 00 00 00 00 # 6 bytes -248 -249 # . . vim:nowrap:textwidth=0 + 37 #? e8/call test-read-byte-refills-buffer/disp32 + 38 # syscall(exit, Num-test-failures) + 39 8b/copy 0/mod/indirect 5/rm32/.disp32 . . 3/r32/EBX Num-test-failures/disp32 # copy *Num-test-failures to EBX + 40 b8/copy-to-EAX 1/imm32 + 41 cd/syscall 0x80/imm8 + 42 + 43 # return next byte value in EAX, with top 3 bytes cleared. + 44 # On EOF, return 0xffffffff. + 45 read-byte: # f : (address buffered-file) -> byte-or-eof/EAX + 46 # . prolog + 47 55/push-EBP + 48 89/copy 3/mod/direct 5/rm32/EBP . . . 4/r32/ESP . . # copy ESP to EBP + 49 # . save registers + 50 51/push-ECX + 51 56/push-ESI + 52 # ESI = f + 53 8b/copy 1/mod/*+disp8 4/rm32/sib 5/base/EBP 4/index/none . 6/r32/ESI 8/disp8 . # copy *(EBP+8) to ESI + 54 # ECX = f->read + 55 8b/copy 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 8/disp8 . # copy *(ESI+8) to ECX + 56 # if (f->read >= f->write) populate stream from file + 57 3b/compare 1/mod/*+disp8 6/rm32/ESI . . . 1/r32/ECX 4/disp8 . # compare ECX with *(ESI+4) + 58 7c/jump-if-lesser $read-byte:from-stream/disp8 + 59 # . clear-stream(stream = f+4) + 60 # . . push args + 61 8d/copy-address 1/mod/*+disp8 6/rm32/ESI . . . 0/r32/EAX 4/disp8 . # copy ESI+4 to EAX + 62 50/push-EAX + 63 # . . call + 64 e8/call clear-stream/disp32 + 65 # . . discard args + 66 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP + 67 # . f->read must now be 0; update ECX + 68 31/xor 3/mod/direct 1/rm32/ECX . . . 1/r32/ECX . . # clear ECX + 69 # . EAX = read(f->fd, stream = f+4) + 70 # . . push args + 71 50/push-EAX + 72 ff 6/subop/push 0/mod/indirect 6/rm32/ESI . . . . . . # push *ESI + 73 # . . call + 74 e8/call read/disp32 + 75 # . . discard args + 76 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP + 77 # if EAX = 0 return 0xffffffff + 78 81 7/subop/compare 3/mod/direct 0/rm32/EAX . . . . . 0/imm32 # compare EAX + 79 75/jump-if-not-equal $read-byte:from-stream/disp8 + 80 b8/copy-to-EAX 0xffffffff/imm32 + 81 eb/jump $read-byte:end/disp8 + 82 $read-byte:from-stream: + 83 # read byte from stream + 84 # AL = f->data[f->read] + 85 31/xor 3/mod/direct 0/rm32/EAX . . . 0/r32/EAX . . # clear EAX + 86 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/ESI 1/index/ECX . 0/r32/AL 0x10/disp8 . # copy byte at *(ESI+ECX+16) to AL + 87 # ++f->read + 88 ff 0/subop/increment 1/mod/*+disp8 6/rm32/ESI . . . . 8/disp8 . # increment *(ESI+8) + 89 $read-byte:end: + 90 # . restore registers + 91 5e/pop-to-ESI + 92 59/pop-to-ECX + 93 # . epilog + 94 89/copy 3/mod/direct 4/rm32/ESP . . . 5/r32/EBP . . # copy EBP to ESP + 95 5d/pop-to-EBP + 96 c3/return + 97 + 98 # - tests + 99 +100 test-read-byte-single: +101 # - check that read-byte returns first byte of 'file' +102 # setup +103 # . clear-stream(_test-stream) +104 # . . push args +105 68/push _test-stream/imm32 +106 # . . call +107 e8/call clear-stream/disp32 +108 # . . discard args +109 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +110 # . clear-stream(_test-buffered-file+4) +111 # . . push args +112 b8/copy-to-EAX _test-buffered-file/imm32 +113 05/add-to-EAX 4/imm32 +114 50/push-EAX +115 # . . call +116 e8/call clear-stream/disp32 +117 # . . discard args +118 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +119 # . write(_test-stream, "Ab") +120 # . . push args +121 68/push "Ab"/imm32 +122 68/push _test-stream/imm32 +123 # . . call +124 e8/call write/disp32 +125 # . . discard args +126 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +127 # read-byte(_test-buffered-file) +128 # . . push args +129 68/push _test-buffered-file/imm32 +130 # . . call +131 e8/call read-byte/disp32 +132 # . . discard args +133 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +134 # check-ints-equal(EAX, 'A', msg) +135 # . . push args +136 68/push "F - test-read-byte-single"/imm32 +137 68/push 0x41/imm32 +138 50/push-EAX +139 # . . call +140 e8/call check-ints-equal/disp32 +141 # . . discard args +142 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +143 # . end +144 c3/return +145 +146 test-read-byte-multiple: +147 # - call read-byte twice, check that second call returns second byte +148 # setup +149 # . clear-stream(_test-stream) +150 # . . push args +151 68/push _test-stream/imm32 +152 # . . call +153 e8/call clear-stream/disp32 +154 # . . discard args +155 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +156 # . clear-stream(_test-buffered-file+4) +157 # . . push args +158 b8/copy-to-EAX _test-buffered-file/imm32 +159 05/add-to-EAX 4/imm32 +160 50/push-EAX +161 # . . call +162 e8/call clear-stream/disp32 +163 # . . discard args +164 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +165 # . write(_test-stream, "Ab") +166 # . . push args +167 68/push "Ab"/imm32 +168 68/push _test-stream/imm32 +169 # . . call +170 e8/call write/disp32 +171 # . . discard args +172 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +173 # read-byte(_test-buffered-file) +174 # . . push args +175 68/push _test-buffered-file/imm32 +176 # . . call +177 e8/call read-byte/disp32 +178 # . . discard args +179 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +180 # read-byte(_test-buffered-file) +181 # . . push args +182 68/push _test-buffered-file/imm32 +183 # . . call +184 e8/call read-byte/disp32 +185 # . . discard args +186 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +187 # check-ints-equal(EAX, 'b', msg) +188 # . . push args +189 68/push "F - test-read-byte-multiple"/imm32 +190 68/push 0x62/imm32 +191 50/push-EAX +192 # . . call +193 e8/call check-ints-equal/disp32 +194 # . . discard args +195 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +196 # . end +197 c3/return +198 +199 test-read-byte-end-of-file: +200 # - call read-byte on an empty 'file', check that it returns 0xffffffff +201 # setup +202 # . clear-stream(_test-stream) +203 # . . push args +204 68/push _test-stream/imm32 +205 # . . call +206 e8/call clear-stream/disp32 +207 # . . discard args +208 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +209 # . clear-stream(_test-buffered-file+4) +210 # . . push args +211 b8/copy-to-EAX _test-buffered-file/imm32 +212 05/add-to-EAX 4/imm32 +213 50/push-EAX +214 # . . call +215 e8/call clear-stream/disp32 +216 # . . discard args +217 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +218 # read-byte(_test-buffered-file) +219 # . . push args +220 68/push _test-buffered-file/imm32 +221 # . . call +222 e8/call read-byte/disp32 +223 # . . discard args +224 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +225 # check-ints-equal(EAX, 0xffffffff, msg) +226 # . . push args +227 68/push "F - test-read-byte-end-of-file"/imm32 +228 68/push 0xffffffff/imm32 +229 50/push-EAX +230 # . . call +231 e8/call check-ints-equal/disp32 +232 # . . discard args +233 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +234 # . end +235 c3/return +236 +237 test-read-byte-refills-buffer: +238 # - consume buffered-file's buffer, check that next read-byte still works +239 # setup +240 # . clear-stream(_test-stream) +241 # . . push args +242 68/push _test-stream/imm32 +243 # . . call +244 e8/call clear-stream/disp32 +245 # . . discard args +246 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +247 # . clear-stream(_test-buffered-file+4) +248 # . . push args +249 b8/copy-to-EAX _test-buffered-file/imm32 +250 05/add-to-EAX 4/imm32 +251 50/push-EAX +252 # . . call +253 e8/call clear-stream/disp32 +254 # . . discard args +255 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +256 # . write(_test-stream, "Abcdefgh") +257 # . . push args +258 68/push "Abcdefgh"/imm32 +259 68/push _test-stream/imm32 +260 # . . call +261 e8/call write/disp32 +262 # . . discard args +263 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 8/imm32 # add to ESP +264 # pretend buffer is full +265 # . _test-buffered-file->read = 6 # >= _test-buffered-file->length +266 b8/copy-to-EAX _test-buffered-file/imm32 +267 c7/copy 1/mod/*+disp8 0/rm32/EAX . . . . 8/disp8 6/imm32 # copy to *(EAX+8) +268 # read-byte(_test-buffered-file) +269 # . . push args +270 68/push _test-buffered-file/imm32 +271 # . . call +272 e8/call read-byte/disp32 +273 # . . discard args +274 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 4/imm32 # add to ESP +275 # check-ints-equal(EAX, 'A', msg) +276 # . . push args +277 68/push "F - test-read-byte-refills-buffer"/imm32 +278 68/push 0x41/imm32 +279 50/push-EAX +280 # . . call +281 e8/call check-ints-equal/disp32 +282 # . . discard args +283 81 0/subop/add 3/mod/direct 4/rm32/ESP . . . . . 0xc/imm32 # add to ESP +284 # . end +285 c3/return +286 +287 == data +288 +289 # a test buffered file for _test-stream +290 _test-buffered-file: +291 # file descriptor or (address stream) +292 _test-stream/imm32 +293 # current write index +294 00 00 00 00 +295 # current read index +296 00 00 00 00 +297 # length (6) +298 06 00 00 00 +299 # data +300 00 00 00 00 00 00 # 6 bytes +301 +302 # . . vim:nowrap:textwidth=0 -- cgit 1.4.1-2-gfad0