Follow Slashdot stories on Twitter

 



Forgot your password?
typodupeerror
×
User Journal

Journal Journal: 80x86 command-line utility... similar to MORE/PAUSE

This utility echoes all its piped input, then it displays "Press any key to continue. . ." and waits for a keypress.

Why did I write it? Well, I wanted it. Plus, it was a good chance to figure out some stuff that had been bugging me about piped input in DOS. First of all, I detect whether the input was redirected (and jump directly to the exit if it wasn't). Next, I discovered that I needed to enter an idle loop to wait for the input to be ready. Finally, I was unable to find any method of properly detecting an EOF on the input stream, but on a hunch I assumed that the input stream would be full and as soon as the read failed I was done. I don't know if it's "right", but it appears to work. (Note: empty input streams will cause it to hang, e.g. del *.* /q | wait. I don't know how to fix this.)

Copy, paste into Notepad, save as "wait_asm.bat", and execute. It will create an executable, wait.com, which can be used like this:

dir | wait

...which will display the directory listing followed by "Press any key to continue. . .", and will exit after a key is pressed.

If you want to be able to use the wait utility like any other DOS command (from any directory), move it into the C:\Windows\system32\ folder (where the rest of the DOS command-line utilities are located).

@echo off
goto batch

a
MOV AX,4400
XOR BX,BX ;device 0 = input
INT 21 ;get device info
AND DX,1 ;check for standard input
JNZ 011f ;_exit
MOV AH,06
MOV DL,FF
;_begin
INT 21 ;get next character from buffer
JZ 0111 ;_begin
;_getch
MOV DL,AL
INT 21 ;print the character
MOV DL,FF
INT 21 ;get next character from buffer
JNZ 0115 ;_getch
;_exit
MOV AH,09
MOV DX,0134 ;_msg
INT 21
;_wait
MOV AH,01
INT 16 ;see if a key was pressed
JZ 0126 ;_wait
XOR AH,AH
INT 16 ;remove the keystroke from the buffer
MOV AH,4C
INT 21 ;DOS %errorlevel% = ASCII code of key
;_msg
DB "Press any key to continue. . .$"
;ASCIIZ
db "wait.com",0
;compile
MOV AX,CS
MOV DS,AX
MOV AH,3C
XOR CX,CX
MOV DX,0153 ;ASCIIZ
INT 21
MOV BX,AX
MOV CX,0153 ;ASCIIZ
MOV DX,0100 ;where the program starts
SUB CX,DX
MOV AH,40
INT 21
MOV AH,3E
INT 21
MOV AX,4c01
INT 21

r ip
15c
g
q

:batch
if exist %0 goto extension
debug<%0.bat>nul
goto done

:extension
debug<%0>nul

:done
echo Done.|wait.com

User Journal

Journal Journal: Real Men...

...don't need C to write a Valentine's day card (nor a redundant microcontroller when they already have all the computing power they need in their desktop PC).

(Copy, paste into Notepad, save as untitled.bat, double-click to launch.)

Note to Vista users: Vista dropped support for full-screen DOS graphics modes, but the .com executable will still run in DOSBox. (If you copy debug.exe into your DOSBox C folder, the batch file will run in DOSBox – otherwise you'll have to run the batch in Vista and run the .com with DOSBox.)

@echo off
goto batch
 
a
;Generates random numbers using an Additive Lagged Fibonacci Generator, j=7, k=10.
;The system timer (clock ticks since midnight) is used to seed a LCG to generate initial values
;Random values are masked using top[col] <= row < bottom[col]
        call 01d0 ;_seed
        mov ax,0012
        int 10 ;Set video mode 12 (640x480x16 graphics)
        mov bx,0284 ;_pal
        mov dx,03c8
        xor al,al
        out dx,al
        mov dx,03c9
        xor cl,cl
;_setpal
        mov al,cl
        xlat
        out dx,al
        inc cl
        cmp cl,12
        jne 012c ;_tst1
        mov dx,03c8
        mov al,14
        out dx,al
        mov dx,03c9
        jmp 0116 ;_setpal
;_tst1
        cmp cl,15
        jne 013c ;_tst2
        mov dx,03c8
        mov al,07
        out dx,al
        mov dx,03c9
        jmp 0116 ;_setpal
;_tst2
        cmp cl,18
        jne 014c ;_tst3
        mov dx,03c8
        mov al,38
        out dx,al
        mov dx,03c9
        jmp 0116 ;_setpal
;_tst3
        cmp cl,30
        jne 0116 ;_setpal
        mov di,02b6 ;_top
        mov si,07b6 ;_bottom
;_loop
        call 01a0 ;_rand
        mov bx,0005
        xor dx,dx
        div bx
        shl ax,1
        mov bx,0029
        xor dx,dx
        div bx
        mov cx,ax ;CX holds the column number
        call 01a0 ;_rand
        mov bx,000c
        xor dx,dx
        div bx
        mov bx,0005
        mul bx
        mov bx,0039
        xor dx,dx
        div bx
        xchg ax,dx ;DX holds the row number
        mov ah,0c
        and al,0f
        call 020a ;_plot
        call 0243 ;_glow
;Check for keypress (non-blocking call) to exit
        mov ah,06
        mov dl,ff
        int 21
        jz 0157 ;_loop
        mov ax,0002
        int 10 ;Set video mode 2 (25x80x16 text)
        mov ax,4c01
        int 21 ;return to DOS
;Return the next random number in AX.
;_rand
        xor bh,bh
        mov bl,[01f5+14] ;_lastValues
        mov ax,[bx+01f5] ;_lastValues
        add bx,06
        cmp bx,14
        jl 01b5 ;_next1rand
        sub bx,14
;_next1rand
        add ax,[bx+01f5] ;_lastValues
;Store the new random number (AX) in the last values history
        mov bl,[01f5+14] ;_lastValues
        mov [bx+01f5],ax ;_lastValues
;Increment our pointer to the oldest last value
        inc bx
        inc bx
        cmp bx,14
        jl 01cb ;_next2rand
        sub bx,14
;_next2rand
        mov [01f5+14],bl ;_lastValues
        ret
;Seed the random number generator using the system timer
;_seed
        xor ah,ah
        int 1a ;Get ticks since midnight in CX:DX
        mov [01f5],dx ;_lastValues
        mov ax,dx
        xor bx,bx
;_LCG
        mov dx,4e35
        mul dx
        inc ax
        inc bx
        inc bx
        mov [bx+01f5],ax ;_lastValues
        cmp bx,12
        jl 01dc ;_LCG
        or ax,0001 ;LFG needs at least 1 odd initial value
        mov [bx+01f5],ax ;_lastValues
        ret
;_lastValues
dw 0,0,0,0,0,0,0,0,0,0
db 0
;Plot the pixel if it's within the masked area
;_plot
        mov bp,ax
        mov bx,cx
        shl bx,1
        mov ax,[di+bx]
        cmp ax,dx
        ja 0223 ;_noplot
        mov ax,[si+bx]
        cmp ax,dx
        jbe 0223 ;_noplot
        mov ax,bp
        xor bh,bh
        int 10 ;plot the pixel
        ret
;_noplot
;adjust out-of-range values so we'll end up plotting them somewhere
;this makes a cool ring effect by adjusting the colour :)
        mov ax,bp
        mov bx,13f
        sub bx,cx
        sar bx,1
        sar bx,1
        sar bx,1
        add cx,bx ;move toward the centre (horizontally)
        mov bx,ef
        sub bx,dx
        sar bx,1
        sar bx,1
        sar bx,1
        add dx,bx ;move toward the centre (vertically)
        or al,8 ;tweak the colour (brighter / whiter)
        jmp 020a ;_plot
;_glow
        call 01a0 ;_rand
        cmp ax,6000
        jge 024c ;_glow0
        ret
;_glow0
        mov ax,[02b4] ;_count
        mov cx,ax
        inc ax
        mov [02b4],ax ;_count
        shr ah,1
        shr ch,1
        cmp ah,ch
        jnz 025e ;_glow1
        ret
;_glow1
        cmp ah,40
        jbe 026d ;_glow2
        mov bh,ah
        mov ah,80
        sub ah,bh
        jns 026d ;_glow2
        neg ah
;_glow2
        cmp ah,40
        jne 0273 ;_glow3
        ret
;_glow3
        mov dx,03c8
        xor al,al
        out dx,al
        mov dx,03c9
        mov al,ah
        out dx,al
        xor al,al
        out dx,al
        out dx,al
        ret
;_pal
db 0,0,0,7,0,0,f,0,0,17,0,0,1f,0,0,27,0,0,2f,0,0,37,0,0,3f,0,0
db 3f,9,9,3f,12,12,3f,1b,1b,3f,24,24,3f,2d,2d,3f,36,36,3f,3f,3f
;_count
dw 0
;_top
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,90,88,82,7e
dw 7b,76,74,72,6f,6c,6a,68,65,63,62,60,5e,5c,5b,59
dw 57,56,55,54,53,51,50,4e,4d,4c,4b,4a,49,48,47,45
dw 44,43,42,41,40,3f,3e,3e,3d,3c,3b,3a,3a,39,38,37
dw 36,35,35,34,33,33,33,32,31,31,30,2f,2f,2e,2e,2d
dw 2d,2c,2b,2b,2b,2b,2a,29,29,28,28,27,27,27,26,26
dw 25,25,25,24,24,24,23,23,23,22,22,22,22,21,21,21
dw 21,20,20,20,20,1f,1f,1f,1f,1f,1e,1e,1e,1e,1d,1d
dw 1d,1d,1d,1d,1d,1d,1d,1c,1c,1c,1c,1c,1c,1c,1c,1c
dw 1c,1c,1c,1c,1c,1c,1c,1c,1b,1b,1b,1b,1b,1b,1b,1b
dw 1b,1b,1b,1b,1b,1c,1c,1c,1c,1c,1c,1c,1c,1c,1c,1c
dw 1c,1c,1c,1c,1d,1d,1d,1d,1d,1d,1d,1d,1e,1e,1e,1e
dw 1e,1e,1e,1f,1f,1f,20,20,20,20,20,20,21,21,21,22
dw 22,22,22,23,23,23,23,24,24,24,25,25,25,26,26,26
dw 26,27,27,27,28,28,29,29,29,2a,2a,2a,2b,2b,2c,2c
dw 2d,2d,2e,2e,2f,2f,30,30,31,32,32,33,33,33,34,35
dw 35,36,37,37,38,39,39,3a,3b,3c,3c,3d,3e,3f,40,41
dw 41,40,3f,3e,3d,3c,3c,3b,3a,39,39,38,37,37,36,35
dw 35,34,33,33,33,32,32,31,30,30,2f,2f,2e,2e,2d,2d
dw 2c,2c,2b,2b,2a,2a,2a,29,29,29,28,28,27,27,27,26
dw 26,26,26,25,25,25,24,24,24,23,23,23,23,22,22,22
dw 22,21,21,21,20,20,20,20,20,20,1f,1f,1f,1e,1e,1e
dw 1e,1e,1e,1e,1d,1d,1d,1d,1d,1d,1d,1d,1c,1c,1c,1c
dw 1c,1c,1c,1c,1c,1c,1c,1c,1c,1c,1c,1b,1b,1b,1b,1b
dw 1b,1b,1b,1b,1b,1b,1b,1b,1c,1c,1c,1c,1c,1c,1c,1c
dw 1c,1c,1c,1c,1c,1c,1c,1c,1c,1d,1d,1d,1d,1d,1d,1d
dw 1d,1d,1e,1e,1e,1e,1f,1f,1f,1f,1f,20,20,20,20,21
dw 21,21,21,22,22,22,22,23,23,23,24,24,24,25,25,25
dw 26,26,27,27,27,28,28,29,29,2a,2b,2b,2b,2b,2c,2d
dw 2d,2e,2e,2f,2f,30,31,31,32,33,33,33,34,35,35,36
dw 37,38,39,3a,3a,3b,3c,3d,3e,3e,3f,40,41,42,43,44
dw 45,47,48,49,4a,4b,4c,4d,4e,50,51,53,54,55,56,57
dw 59,5b,5c,5e,60,62,63,65,68,6a,6c,6f,72,74,76,7b
dw 7e,82,88,90,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;_bottom
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,b0,b7,bc,c1
dw c7,ca,cd,cf,d4,d7,d9,dd,df,e2,e4,e6,e9,eb,ed,ee
dw f0,f3,f5,f7,f8,fb,fd,fe,ff,101,103,105,106,108,109,10a
dw 10c,10e,10f,111,113,114,115,117,118,119,11b,11c,11d,11e,120,121
dw 123,124,125,126,127,128,129,12a,12c,12d,12e,12f,130,131,132,133
dw 135,136,137,138,139,13a,13b,13c,13d,13e,13f,140,141,142,143,144
dw 145,146,147,148,149,14a,14b,14c,14c,14d,14e,14f,150,151,152,153
dw 154,154,155,156,157,158,159,159,15a,15b,15c,15d,15d,15e,15e,15f
dw 160,161,162,162,163,164,165,166,166,167,168,169,169,16a,16b,16b
dw 16c,16d,16e,16f,16f,170,171,171,172,173,173,174,174,175,176,176
dw 177,178,178,179,17a,17a,17b,17c,17c,17d,17e,17e,17f,180,180,180
dw 181,182,182,183,183,184,185,185,186,187,187,188,188,189,18a,18a
dw 18a,18b,18c,18d,18d,18d,18e,18e,18f,190,191,191,191,192,193,193
dw 194,194,195,195,196,196,197,198,198,198,199,19a,19a,19b,19c,19c
dw 19c,19d,19e,19e,19f,19f,1a0,1a0,1a1,1a1,1a2,1a2,1a3,1a4,1a4,1a5
dw 1a5,1a6,1a6,1a7,1a8,1a8,1a9,1aa,1aa,1ab,1ab,1ac,1ac,1ad,1ae,1af
dw 1af,1b0,1b1,1b1,1b2,1b3,1b4,1b5,1b6,1b8,1b9,1ba,1bb,1bc,1bc,1bc
dw 1bc,1bc,1bc,1bb,1ba,1b9,1b8,1b6,1b5,1b4,1b3,1b2,1b1,1b1,1b0,1af
dw 1af,1ae,1ad,1ac,1ac,1ab,1ab,1aa,1aa,1a9,1a8,1a8,1a7,1a6,1a6,1a5
dw 1a5,1a4,1a4,1a3,1a2,1a2,1a1,1a1,1a0,1a0,19f,19f,19e,19e,19d,19c
dw 19c,19c,19b,19a,19a,199,198,198,198,197,196,196,195,195,194,194
dw 193,193,192,191,191,191,190,18f,18e,18e,18d,18d,18d,18c,18b,18a
dw 18a,18a,189,188,188,187,187,186,185,185,184,183,183,182,182,181
dw 180,180,180,17f,17e,17e,17d,17c,17c,17b,17a,17a,179,178,178,177
dw 176,176,175,174,174,173,173,172,171,171,170,16f,16f,16e,16d,16c
dw 16b,16b,16a,169,169,168,167,166,166,165,164,163,162,162,161,160
dw 15f,15e,15e,15d,15d,15c,15b,15a,159,159,158,157,156,155,154,154
dw 153,152,151,150,14f,14e,14d,14c,14c,14b,14a,149,148,147,146,145
dw 144,143,142,141,140,13f,13e,13d,13c,13b,13a,139,138,137,136,135
dw 133,132,131,130,12f,12e,12d,12c,12a,129,128,127,126,125,124,123
dw 121,120,11e,11d,11c,11b,119,118,117,115,114,113,111,10f,10e,10c
dw 10a,109,108,106,105,103,101,ff,fe,fd,fb,f8,f7,f5,f3,f0
dw ee,ed,eb,e9,e6,e4,e2,df,dd,d9,d7,d4,cf,cd,ca,c7
dw c1,bc,b7,b0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;_ASCIIZ
                db "untitled.com",0
;_compile
                MOV AX,CS
                MOV DS,AX
                MOV AH,3c
                XOR CX,CX
                MOV DX,0cb6 ;_ASCIIZ
                INT 21
                MOV BX,AX
                MOV CX,0cb6 ;_ASCIIZ
                MOV DX,0100 ;where the program starts
                SUB CX,DX
                MOV AH,40
                INT 21
                MOV AH,3e
                INT 21
                MOV AX,4c01
                INT 21
 
r ip
cc3
g
q
 
:batch
if exist untitled.com goto run
 
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
untitled.com

User Journal

Journal Journal: Base64 decoder (80x86)

Decodes standard MIME-encoded base64 data. (Non-printable characters won't be visible, but they are echoed. E.g. the bell character, 07, should cause the terminal to beep.)

Every 4 characters typed will be decoded to the corresponding 3 characters. (Nothing will be echoed until 4 input characters have been typed.) Any input characters outside the base64 character table will be ignored and will not count toward the 4-character sequence.

The = character is a special character in base64 encoding: it is only used to pad the end of base64-encoded data when encoding the last 1 or 2 bytes (instead of the 3 bytes needed to have a full 24-bit chunk). Although the base64 encoding standard does not allow = symbols in the middle of base64-encoded output, the code does not attempt to verify this. The = symbol is treated as if it was an A (index 0) and it adjusts the number of output characters that are printed: If the 4-character sequence contains one = symbol, only the high 16 bits will be printed (2 characters). If it contains two = symbols, only the high 8 bits will be printed (1 character). Although sequences containing more than two = characters are not permitted according to the base64-encoding standard, the code will still treat them like A's (index 0) and print only the high 8 bits.

See also: Base64 encoder (80x86)

Paste in Notepad, save as base64de_asm.bat, run.

@echo off
goto batch
 
a
;Base64 decoder
;Accepts input from STDIN and prints to STDOUT
;Input bytes are buffered and decoded at intervals of 4 bytes
;Esc or Ctrl-Z exit, any buffered input will be discarded
;_input
        mov si,01cc ;_outbuffer
        mov bx,0003 ;loop counter
        mov dx,0002 ;counts output chars
;_inloop
        mov di,018c ;_charset
        mov ah,08
        int 21 ;get a key
        cmp al,1b ;check for esc
        jnz 013a ;_continue
;_quit
        mov ah,03
        xor bh,bh
        int 10 ;get cursor position
        mov ah,08
        int 10 ;preserve character under cursor
        mov ah,02
        mov bl,al
        mov cx,dx
        mov dl,1a
        int 21 ;send ^z
        mov dx,cx
        int 10 ;restore cursor position
        mov ah,0a
        mov al,bl
        mov cx,1
        int 10 ;restore character under cursor
        mov ax,4c01
        int 21 ;quit to dos
;_continue
        cmp al,1a ;check for ^z
        jz 0114 ;_quit
        cmp al,3d ;check for = (padding)
        jnz 0147 ;_process
        dec dx ;subtract an output character
        xor al,al
        jmp 0150 ;_skip
;_process
        mov cx,0040 ;64 = number of valid chars
        repnz
        scasb ;find al
        jnz 0109 ;_inloop
        mov al,cl
;_skip
        shl al,1
        shl al,1
        mov ah,[si]
        mov cl,06
        rol ax,cl
        mov [si],ah
        shl al,1
        shl al,1
        mov ah,[si+1]
        rol ax,cl
        mov [si+1],ah
        shl al,1
        shl al,1
        mov ah,[si+2]
        shl ax,cl
        mov [si+2],ah
        dec bx
        jns 0109 ;_inloop
;_output
        mov bx,0002
        sub bx,dx
        add si,bx
        mov bx,dx
        mov ah,02
;_printloop
        mov dl,[bx+si] ;get the next character to be printed
        int 21
        dec bx
        jns 0182 ;_printloop
        jmp 0100 ;_input
;_charset
        db "/+9876543210zyxwvutsrqponmlkjihgfedcbaZYXWVUTSRQPONMLKJIHGFEDCBA"
;_outbuffer
        db 0,0,0
;ASCIIZ
db "base64de.com",0
;compile
MOV AX,CS
MOV DS,AX
MOV AH,3C
XOR CX,CX
MOV DX,01cf ;ASCIIZ
INT 21
MOV BX,AX
MOV CX,01cf ;ASCIIZ
MOV DX,0100 ;where the program starts
SUB CX,DX
MOV AH,40
INT 21
MOV AH,3E
INT 21
MOV AX,4C00
INT 21
 
r ip
1dc
g
q
 
:exists
echo You don't need to run this. Run BASE64DE.COM instead.
goto run
 
:batch
if exist base64de.com goto exists
 
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
pause
cls
base64de.com

User Journal

Journal Journal: Base64 encoder (80x86)

So, this is your standard MIME base64 encoding process. It takes 3 bytes of data, packs them into a 24-bit value, splits it into 6-bit chunks, and uses them as indexes into a 64-character table. Once you type three letters, it gives you the four-character representation (nothing is echoed until the full 3 characters are typed).

The lines are wrapped at 76 characters per the MIME spec, and if the input terminates with one or two extra bytes (i.e. not an even multiple of 3 bytes) the 24-bit field is zero-padded at the end. In this case the last 1 or 2 characters of the four-character representation are replaced with = (instead of A) to avoid having extra NULL bytes at the end of the data after decoding.

For example, the string "Hello World" (without quotes), which has three sets of three characters with two characters left over, is encoded as: SGVsbG8gV29ybGQ=

See also: Base64 decoder (80x86)

Same drill: paste in Notepad, save as base64en_asm.bat, run.

@echo off
goto batch
 
a
;Base64 encoder
;Accepts input from STDIN and prints to STDOUT
;Input bytes are buffered and encoded at intervals of 3 bytes
;Esc or Ctrl-Z exit, 0-2 buffered bytes may be encoded at this point
        mov di,0227 ;_inbuffer
        mov si,01e7 ;_charset
;_input
        mov bx,0002 ;loop counter
        xor dx,dx
        mov ah,08
;_inloop
        int 21 ;get a key
        cmp al,1b ;check for esc
        jnz 0129 ;_continue
;_finish
        cmp bx,02
        jnz 0120 ;_pad
        mov ah,02
        mov cx,0001
        jmp 01aa ;_crlf
;_pad
;pad buffer with nulls so we can encode it
        mov byte ptr [bx+di],0
        inc dx ;cx counts how many bytes we null-padded
        dec bx
        jns 0120 ;_pad
        jmp 0132 ;_output
;_continue
        cmp al,1a ;check for ^z
        jz 0113 ;_finish
        mov [bx+di],al ;store byte in buffer
        dec bx
        jns 010d ;_inloop
;_output
;encode bytes stored in 3-byte input buffer
        xor bh,bh
        xor al,al
        mov ah,[di+2] ;get the first byte from the input buffer
        mov cl,06
        rol ax,cl
        mov bl,al
        mov cl,[bx+si]
        mov [di+6],cl ;put the first character in the output buffer
        mov cl,06
        shr ax,cl
        mov al,[di+1] ;get the 2nd input byte
        mov cl,04
        shl ax,cl
        mov bl,ah
        mov cl,[bx+si]
        mov [di+5],cl ;put the 2nd character in the output buffer
        cmp dx,0002 ;see if we need to pad output
        jnz 0162 ;_output2
        dec dx
        mov byte ptr [di+4],3d ;pad with =
        jmp 0175 ;_output3
;_output2
        xor ah,ah
        mov cl,04
        shl ax,cl
        mov al,[di] ;get the 3rd input byte
        shl ax,1
        shl ax,1
        mov bl,ah
        mov cl,[bx+si]
        mov [di+4],cl ;put the 3rd character in the output buffer
;_output3
        cmp dx,0001 ;see if we need to pad output
        jnz 0180 ;_output4
        mov byte ptr [di+3],3d ;pad with =
        jmp 018b ;_print
;_output4
        shr al,1
        shr al,1
        mov bl,al
        mov cl,[bx+si]
        mov [di+3],cl ;put the 4th character in the output buffer
;_print
        mov cx,dx ;save dx because we need it
        mov bl,03
        add di,03 ;point to the output buffer now
        mov ah,02
;_printloop
        mov dl,[bx+di] ;get the next character to be printed
        int 21
        dec bx
        jns 0194 ;_printloop
        cmp cx,0001
        jz 01aa ;_crlf
        add byte ptr [di+4],04 ;increment the column counter
        cmp byte ptr [di+4],4c ;check column width
        jnz 01b6 ;_nocrlf
;_crlf
        mov byte ptr [di+4],00 ;reset the column counter
        mov dl,0d
        int 21
        mov dl,0a
        int 21
;_nocrlf
        sub di,03 ;point to the input buffer again
        cmp cx,0001
        jz 01c1 ;_quit
        jmp 0106 ;_input
;_quit
        mov ah,03
        xor bh,bh
        int 10 ;get cursor position
        mov ah,08
        int 10 ;preserve character under cursor
        mov ah,02
        mov bl,al
        mov cx,dx
        mov dl,1a
        int 21 ;send ^z
        mov dx,cx
        int 10 ;restore cursor position
        mov ah,0a
        mov al,bl
        mov cx,1
        int 10 ;restore character under cursor
        mov ax,4c01
        int 21 ;quit to dos
;_charset
        db "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
;_inbuffer
        db 0,0,0
;_outbuffer
        db 0,0,0,0
;_count
        db 0
;ASCIIZ
db "base64en.com",0
;compile
MOV AX,CS
MOV DS,AX
MOV AH,3C
XOR CX,CX
MOV DX,022f ;ASCIIZ
INT 21
MOV BX,AX
MOV CX,022f ;ASCIIZ
MOV DX,0100 ;where the program starts
SUB CX,DX
MOV AH,40
INT 21
MOV AH,3E
INT 21
MOV AX,4C00
INT 21
 
r ip
23c
g
q
 
:exists
echo You don't need to run this. Run BASE64EN.COM instead.
goto run
 
:batch
if exist base64en.com goto exists
 
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
pause
cls
base64en.com

User Journal

Journal Journal: Lagged Fibonacci Generator (80x86)

This program implements a lagged Fibonacci generator with constants j=7, k=10. A linear congruential generator is used to seed the list of initial values; the system timer is used to seed the LCG.

Initially I included a routine to print each random number so I could redirect the output into a .csv file and plot the points in Excel, but I've taken that code out. Now, the program instead switches to display mode 12 (640x480x16 graphics mode) and plots "snow" on the screen in random locations and colours. Pressing any key ends the program.

Like the other ones, paste this in Notepad and save it as a .bat file. Run it and it does the rest.

@echo off
goto batch
 
a
;Generates random numbers using an Additive Lagged Fibonacci Generator, j=7, k=10.
;The system timer (clock ticks since midnight) is used to seed a LCG to generate initial values
call 017d ;_seed
mov ax,0012
int 10 ;Set video mode 12 (640x480x16 graphics)
;_loop
call 014d ;_rand
mov bx,0005
xor dx,dx
div bx
shl ax,1
mov bx,0029
xor dx,dx
div bx
mov cx,ax ;CX holds the column number
call 014d ;_rand
mov bx,000c
xor dx,dx
div bx
mov bx,0005
mul bx
mov bx,0039
xor dx,dx
div bx
xchg ax,dx ;DX holds the row number
mov ah,0c
and al,0f
int 10 ;plot the pixel
;Check for keypress to exit
mov ah,06
mov dl,ff
int 21
jz 0108 ;_loop
mov ax,0002
int 10 ;Set video mode 2 (25x80x16 text)
mov ax,4c01
int 21 ;return to DOS
;Return the next random number in AX.
;_rand
xor bh,bh
mov bl,[01a2+14] ;_lastValues
mov ax,[bx+01a2] ;_lastValues
add bx,06
cmp bx,14
jl 0162 ;_next1rand
sub bx,14
;_next1rand
add ax,[bx+01a2] ;_lastValues
;Store the new random number (AX) in the last values history
mov bl,[01a2+14] ;_lastValues
mov [bx+01a2],ax ;_lastValues
;Increment our pointer to the oldest last value
inc bx
inc bx
cmp bx,14
jl 0178 ;_next2rand
sub bx,14
;_next2rand
mov [01a2+14],bl ;_lastValues
ret
;Seed the random number generator using the system timer
;_seed
xor ah,ah
int 1a ;Get ticks since midnight in CX:DX
mov [01a2],dx ;_lastValues
mov ax,dx
xor bx,bx
;_LCG
mov dx,4e35
mul dx
inc ax
inc bx
inc bx
mov [bx+01a2],ax ;_lastValues
cmp bx,12
jl 0189 ;_LCG
or ax,0001 ;LFG needs at least 1 odd initial value
mov [bx+01a2],ax ;_lastValues
ret
;_lastValues
dw 0,0,0,0,0,0,0,0,0,0
db 0
;_ASCIIZ
        db "lfg_snow.com",0
;_compile
        MOV AX,CS
        MOV DS,AX
        MOV AH,3C
        XOR CX,CX
        MOV DX,01b7 ;_ASCIIZ
        INT 21
        MOV BX,AX
        MOV CX,01b7 ;_ASCIIZ
        MOV DX,0100 ; where the program starts
        SUB CX,DX
        MOV AH,40
        INT 21
        MOV AH,3E
        INT 21
        MOV AX,4C00
        INT 21
 
r ip
1c4
g
q
 
:batch
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
pause
cls
lfg_snow.com

User Journal

Journal Journal: MD5 in 80x86 (MASM)

You'll have to assemble this one with MASM. I don't feel like adapting it for debug...

How to assemble: Copy and paste into notepad, save as md5.asm, and assemble with MASM to create md5.exe.

; +-- MD5 -- d9dfaaaf50701ed5851a58123cbaf925284218aee788f4cc3c11e1d7d2f96721 -->
; | --> started 22.aug.08 -- completed 24.aug.08 <--
; | The MD5 function implemented in 80x86 assembly language
; | Calculates the hash of an input string MSG of length LEN.
; | The MD5 procedure stores the hash as a 16-byte binary value beginning at H0.
; | The PRINT procedure displays the 16-bit binary hash as 32-digit hexadecimal.
; +----------------------------------------------------------------------------->
 
; This is the maximum string length.
; It has to be 0-255 because INT 10h can't input longer strings than 255 bytes.
; If you're using the MD5 proc to hash longer data, you'll have to input it somehow
; and store the data length in LEN, which is a word (allowing an input data size
; up to 64k, if you change the .MODEL directive).
MAX_LEN EQU 255
 
; -- Macro definitions -----------------------------
FnF MACRO i
            MOV AX, VC ; f = d xor (b and (c xor d))
            MOV BX, VC+2
            XOR AX, VD
            XOR BX, VD+2
            AND AX, VB
            AND BX, VB+2
            XOR AX, VD
            XOR BX, VD+2
            MOV VF, AX
            MOV VF+2, BX
 
            MOV BYTE PTR VG, i ; g = i
            ENDM
 
FnG MACRO i
            MOV AX, VB ; f = c xor (d and (b xor c))
            MOV BX, VB+2
            XOR AX, VC
            XOR BX, VC+2
            AND AX, VD
            AND BX, VD+2
            XOR AX, VC
            XOR BX, VC+2
            MOV VF, AX
            MOV VF+2, BX
 
            MOV CL, i ; g = (5*i + 1) mod 16
            SHL CL, 1
            SHL CL, 1
            ADD CL, i
            INC CL
            AND CL, 0Fh
            MOV VG, CL
            ENDM
 
FnH MACRO i
            MOV AX, VB ; f = b xor c xor d
            MOV BX, VB+2
            XOR AX, VC
            XOR BX, VC+2
            XOR AX, VD
            XOR BX, VD+2
            MOV VF, AX
            MOV VF+2, BX
 
            MOV CL, i ; g = (3*i + 5) mod 16
            SHL CL, 1
            ADD CL, i
            ADD CL, 5
            AND CL, 0Fh
            MOV VG, CL
            ENDM
 
FnI MACRO i
            MOV AX, VD ; f = c xor (b or (not d))
            MOV BX, VD+2
            NOT AX
            NOT BX
            OR AX, VB
            OR BX, VB+2
            XOR AX, VC
            XOR BX, VC+2
            MOV VF, AX
            MOV VF+2, BX
 
            MOV CX, i ; g = (7*i) mod 16
            SHL CX, 1 ; 16-bit. 63*8 doesn't fit in 8 bits.
            SHL CX, 1
            SHL CX, 1
            SUB CX, i
            AND CL, 0Fh
            MOV VG, CL
            ENDM
 
UpdVars MACRO Rn, Kn_L, Kn_H
            LOCAL LOOP
 
            MOV AX, VD ; temp = d
            MOV TEMP, AX
            MOV AX, VD+2
            MOV TEMP+2, AX
 
            MOV AX, VC ; d = c
            MOV VD, AX
            MOV AX, VC+2
            MOV VD+2, AX
 
            MOV AX, VB ; c = b
            MOV VC, AX
            MOV AX, VB+2
            MOV VC+2, AX
 
            MOV AX, VA ; BX:AX = (a + f + Kn + w[g])
            MOV BX, VA+2
            MOV CX, VF
            ADD AX, CX
            MOV CX, VF+2
            ADC BX, CX ; Add with carry
            ADD AX, Kn_L
            ADC BX, Kn_H
            MOV SI, DI ; SI points to the beginning of this chunk
            XOR CH, CH ; Clear CH
            MOV CL, VG
            SHL CX, 1
            SHL CX, 1 ; Multiply VG*4 to find the offset of w[g]
            ADD SI, CX ; SI points to w[g]
            MOV CX, [SI]
            ADD AX, CX
            MOV CX, [SI]+2
            ADC BX, CX
            ; Now rotate BX:AX to the left Rn times
            MOV CL, Rn
LOOP: SHL AX, 1 ; Bit shifted out of low word goes into carry
            RCL BX, 1 ; Shift left & shift carry into LSB of high word
            ADC AL, 0 ; Bring carry bit back into LSB of low byte
            DEC CL
            JNZ LOOP ; Loop Rn times
 
            ADD VB, AX ; VB = VB + BX:AX
            ADC VB+2, BX
 
            MOV AX, TEMP ; a = temp
            MOV VA, AX
            MOV AX, TEMP+2
            MOV VA+2, AX
            ENDM
 
; Compares two 16-byte values. I'm not using this but it might be useful in the future.
; DS:SI = address of first value, ES:DI = address of 2nd value.
; Return: ZR if equal, NZ if unequal
Comp MACRO
            MOV CX, 16
            REPE CMPSB
            ENDM
; -- End macro definitions -------------------------
 
.MODEL SMALL
.STACK 64
 
.DATA
; MAX_L, ACTUAL, and MSG must be adjacent in this order. Don't mess with them.
MAX_L DB MAX_LEN ; Don't change this, change the MAX_LEN EQU instead.
ACTUAL DB ? ; This is where DOS will put the actual string length
MSG DB MAX_LEN DUP (?) ; Holds the string that we'll be hashing
            DB 8 DUP (?), 64 DUP (?) ; Space to pad the message. Don't change this either.
LEN DW ? ; ACTUAL gets copied here. MD5 uses this, not ACTUAL.
PROMPT DB "Enter string: $"
 
; These 4 dwords will hold the MD5 hash as it's being calculated and the final result
H0 DW ?,?
H1 DW ?,?
H2 DW ?,?
H3 DW ?,?
; These will hold intermediate values
VA DW ?,?
VB DW ?,?
VC DW ?,?
VD DW ?,?
VF DW ?,?
VG DB ?
TEMP DW ?,?
 
; Un-comment the appropriate line to give upper/lowercase hex when printing an MD5 hash.
HEX DB "0123456789abcdef"
;HEX DB "0123456789ABCDEF"
 
; Initial values for H0-H3 and VA-VD.
; Loaded in 16-bit words because we can't address a dword.
H0_H EQU 6745h
H0_L EQU 2301h
H1_H EQU 0EFCDh
H1_L EQU 0AB89h
H2_H EQU 98BAh
H2_L EQU 0DCFEh
H3_H EQU 1032h
H3_L EQU 5476h
 
; Array of K dword values: k[i] = floor(abs(sin(i + 1)) * (2^32))
K0_H EQU 0D76Ah
K0_L EQU 0A478h
K1_H EQU 0E8C7h
K1_L EQU 0B756h
K2_H EQU 2420h
K2_L EQU 70DBh
K3_H EQU 0C1BDh
K3_L EQU 0CEEEh
K4_H EQU 0F57Ch
K4_L EQU 0FAFh
K5_H EQU 4787h
K5_L EQU 0C62Ah
K6_H EQU 0A830h
K6_L EQU 4613h
K7_H EQU 0FD46h
K7_L EQU 9501h
K8_H EQU 6980h
K8_L EQU 98D8h
K9_H EQU 8B44h
K9_L EQU 0F7AFh
K10_H EQU 0FFFFh
K10_L EQU 5BB1h
K11_H EQU 895Ch
K11_L EQU 0D7BEh
K12_H EQU 6B90h
K12_L EQU 1122h
K13_H EQU 0FD98h
K13_L EQU 7193h
K14_H EQU 0A679h
K14_L EQU 438Eh
K15_H EQU 49B4h
K15_L EQU 0821h
K16_H EQU 0F61Eh
K16_L EQU 2562h
K17_H EQU 0C040h
K17_L EQU 0B340h
K18_H EQU 265Eh
K18_L EQU 5A51h
K19_H EQU 0E9B6h
K19_L EQU 0C7AAh
K20_H EQU 0D62Fh
K20_L EQU 105Dh
K21_H EQU 0244h
K21_L EQU 1453h
K22_H EQU 0D8A1h
K22_L EQU 0E681h
K23_H EQU 0E7D3h
K23_L EQU 0FBC8h
K24_H EQU 21E1h
K24_L EQU 0CDE6h
K25_H EQU 0C337h
K25_L EQU 07D6h
K26_H EQU 0F4D5h
K26_L EQU 0D87h
K27_H EQU 455Ah
K27_L EQU 14EDh
K28_H EQU 0A9E3h
K28_L EQU 0E905h
K29_H EQU 0FCEFh
K29_L EQU 0A3F8h
K30_H EQU 676Fh
K30_L EQU 02D9h
K31_H EQU 8D2Ah
K31_L EQU 4C8Ah
K32_H EQU 0FFFAh
K32_L EQU 3942h
K33_H EQU 8771h
K33_L EQU 0F681h
K34_H EQU 6D9Dh
K34_L EQU 6122h
K35_H EQU 0FDE5h
K35_L EQU 380Ch
K36_H EQU 0A4BEh
K36_L EQU 0EA44h
K37_H EQU 4BDEh
K37_L EQU 0CFA9h
K38_H EQU 0F6BBh
K38_L EQU 4B60h
K39_H EQU 0BEBFh
K39_L EQU 0BC70h
K40_H EQU 289Bh
K40_L EQU 7EC6h
K41_H EQU 0EAA1h
K41_L EQU 27FAh
K42_H EQU 0D4EFh
K42_L EQU 3085h
K43_H EQU 0488h
K43_L EQU 1D05h
K44_H EQU 0D9D4h
K44_L EQU 0D039h
K45_H EQU 0E6DBh
K45_L EQU 99E5h
K46_H EQU 1FA2h
K46_L EQU 7CF8h
K47_H EQU 0C4ACh
K47_L EQU 5665h
K48_H EQU 0F429h
K48_L EQU 2244h
K49_H EQU 432Ah
K49_L EQU 0FF97h
K50_H EQU 0AB94h
K50_L EQU 23A7h
K51_H EQU 0FC93h
K51_L EQU 0A039h
K52_H EQU 655Bh
K52_L EQU 59C3h
K53_H EQU 8F0Ch
K53_L EQU 0CC92h
K54_H EQU 0FFEFh
K54_L EQU 0F47Dh
K55_H EQU 8584h
K55_L EQU 5DD1h
K56_H EQU 6FA8h
K56_L EQU 7E4Fh
K57_H EQU 0FE2Ch
K57_L EQU 0E6E0h
K58_H EQU 0A301h
K58_L EQU 4314h
K59_H EQU 4E08h
K59_L EQU 11A1h
K60_H EQU 0F753h
K60_L EQU 7E82h
K61_H EQU 0BD3Ah
K61_L EQU 0F235h
K62_H EQU 2AD7h
K62_L EQU 0D2BBh
K63_H EQU 0EB86h
K63_L EQU 0D391h
 
; Per-round shift amounts.
; Every 4 values repeat to fill gaps, i.e. 4-15 are 7,12,17,22,7,12,17,22,7,12,17,22.
R0 EQU 7
R1 EQU 12
R2 EQU 17
R3 EQU 22
R16 EQU 5
R17 EQU 9
R18 EQU 14
R19 EQU 20
R32 EQU 4
R33 EQU 11
R34 EQU 16
R35 EQU 23
R48 EQU 6
R49 EQU 10
R50 EQU 15
R51 EQU 21
 
.CODE
MAIN PROC FAR
            ; Set up the segment registers
            MOV AX, @DATA
            MOV DS, AX
            MOV ES, AX
 
            ; Code
            MOV AH, 09h
            MOV DX, OFFSET PROMPT
            INT 21h ; Display a prompt
 
            MOV AH, 0Ah
            MOV DX, OFFSET MAX_L
            INT 21h ; Get user-entered string to hash
 
            MOV AH, 03h
            MOV BH, 0
            INT 10h ; Get the cursor position
            MOV AH, 02h
            MOV DL, 79
            INT 10h ; Move the cursor to column 80
            MOV AH, 02h
            MOV DL, " "
            INT 21h ; Print a space to move to the next row
 
            XOR AH, AH
            MOV AL, ACTUAL
            MOV LEN, AX ; Store length in LEN as 16-bit
 
            MOV AX, OFFSET MSG
            MOV BX, LEN
            PUSH AX ; Push the arguments onto the stack
            PUSH BX
            CALL MD5 ; Calculate the MD5 of the string
            ADD SP, 4 ; Clear the arguments from the stack
 
            MOV AX, OFFSET H0 ; Get a pointer to the MD5 hash
            PUSH AX
            CALL PRINT ; Print the result
            ADD SP, 2
 
            ; Return to DOS
DONE: MOV AH, 4Ch
            INT 21h
MAIN ENDP
 
; -- Procedures ---------------------------------------------------------------
 
; Calculates the MD5 hash of a string.
; Pass a 16-bit pointer to the string and the string length as a 16-bit number.
; Arguments must be passed by pushing them onto the stack in that order.
MD5 PROC
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH DX
            PUSH BP
            MOV BP, SP
 
            ; Arguments:
            ; [BP]+12: string length (16-bit)
            ; [BP]+14: pointer to string (16-bit)
 
            ; Initialize variables:
            ; copy H0_H:H0_L to H0
            MOV DI, OFFSET H0
            MOV AX, H0_L
            MOV BX, H0_H
            MOV [DI], AX
            MOV [DI]+2, BX
            ; copy H1_H:H1_L to H1
            MOV DI, OFFSET H1
            MOV AX, H1_L
            MOV BX, H1_H
            MOV [DI], AX
            MOV [DI]+2, BX
            ; copy H2_H:H2_L to H2
            MOV DI, OFFSET H2
            MOV AX, H2_L
            MOV BX, H2_H
            MOV [DI], AX
            MOV [DI]+2, BX
            ; copy H3_H:H3_L to H3
            MOV DI, OFFSET H3
            MOV AX, H3_L
            MOV BX, H3_H
            MOV [DI], AX
            MOV [DI]+2, BX
 
            ; Pre-processing:
            MOV DI, [BP]+14 ; DI points to the string to hash
            MOV BX, [BP]+12 ; BX holds the length of the string
            AND BX, 0FFC0h ; BX = INT(BX/64)*64
            ADD DI, BX ; DI points to the last 64-byte chunk
            MOV BX, [BP]+12
            AND BX, 003Fh ; BX = length MOD 64, last chunk length
            MOV BYTE PTR [BX+DI], 80h ; Pad with binary 10000000
 
PP0: INC BX ; Increment chunk length
            AND BX, 003Fh ; MOD 64 again
            JNZ PP1
            ADD DI, 0040h ; Add 64 to the chunk pointer
PP1: CMP BX, 0038h ; Stop if we've reached the 57th byte
            JZ PP2
            MOV BYTE PTR [BX+DI], 00h ; Pad with more 0's
            JMP PP0 ; Loop until chunk is 56 bytes long
 
PP2: MOV AX, [BP]+12 ; AX holds the un-padded string length
            MOV CX, 8 ; bits per byte
            MUL CX ; DX:AX = original string length in bits
            MOV [BX+DI], AX ; Append length (64-bit little endian)
            MOV [BX+DI]+2, DX
            MOV WORD PTR [BX+DI]+4, 0000h
            MOV WORD PTR [BX+DI]+6, 0000h
            ADD BX, 8 ; Increase the string length
            ADD BX, DI
            MOV DI, [BP]+14 ; Point to the beginning of the string
            SUB BX, DI
            MOV DX, BX ; DX = total string length (in bytes)
 
CHUNK: ; Initialize hash value for this chunk:
            MOV AX, H0 ; Set VA = H0
            MOV VA, AX
            MOV AX, H0+2
            MOV VA+2, AX
 
            MOV AX, H1 ; Set VB = H1
            MOV VB, AX
            MOV AX, H1+2
            MOV VB+2, AX
 
            MOV AX, H2 ; Set VC = H2
            MOV VC, AX
            MOV AX, H2+2
            MOV VC+2, AX
 
            MOV AX, H3 ; Set VD = H3
            MOV VD, AX
            MOV AX, H3+2
            MOV VD+2, AX
 
; ~~ Loops 0-15/63 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            FnF 0 ; f = d xor (b and (c xor d)), g = i
            UpdVars R0, K0_L, K0_H
 
            FnF 1
            UpdVars R1, K1_L, K1_H
 
            FnF 2
            UpdVars R2, K2_L, K2_H
 
            FnF 3
            UpdVars R3, K3_L, K3_H
 
            FnF 4
            UpdVars R0, K4_L, K4_H
 
            FnF 5
            UpdVars R1, K5_L, K5_H
 
            FnF 6
            UpdVars R2, K6_L, K6_H
 
            FnF 7
            UpdVars R3, K7_L, K7_H
 
            FnF 8
            UpdVars R0, K8_L, K8_H
 
            FnF 9
            UpdVars R1, K9_L, K9_H
 
            FnF 10
            UpdVars R2, K10_L, K10_H
 
            FnF 11
            UpdVars R3, K11_L, K11_H
 
            FnF 12
            UpdVars R0, K12_L, K12_H
 
            FnF 13
            UpdVars R1, K13_L, K13_H
 
            FnF 14
            UpdVars R2, K14_L, K14_H
 
            FnF 15
            UpdVars R3, K15_L, K15_H
 
; ~~ Loops 16-31/63 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            FnG 16
            UpdVars R16, K16_L, K16_H
 
            FnG 17
            UpdVars R17, K17_L, K17_H
 
            FnG 18
            UpdVars R18, K18_L, K18_H
 
            FnG 19
            UpdVars R19, K19_L, K19_H
 
            FnG 20
            UpdVars R16, K20_L, K20_H
 
            FnG 21
            UpdVars R17, K21_L, K21_H
 
            FnG 22
            UpdVars R18, K22_L, K22_H
 
            FnG 23
            UpdVars R19, K23_L, K23_H
 
            FnG 24
            UpdVars R16, K24_L, K24_H
 
            FnG 25
            UpdVars R17, K25_L, K25_H
 
            FnG 26
            UpdVars R18, K26_L, K26_H
 
            FnG 27
            UpdVars R19, K27_L, K27_H
 
            FnG 28
            UpdVars R16, K28_L, K28_H
 
            FnG 29
            UpdVars R17, K29_L, K29_H
 
            FnG 30
            UpdVars R18, K30_L, K30_H
 
            FnG 31
            UpdVars R19, K31_L, K31_H
 
; ~~ Loops 32-47/63 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            FnH 32
            UpdVars R32, K32_L, K32_H
 
            FnH 33
            UpdVars R33, K33_L, K33_H
 
            FnH 34
            UpdVars R34, K34_L, K34_H
 
            FnH 35
            UpdVars R35, K35_L, K35_H
 
            FnH 36
            UpdVars R32, K36_L, K36_H
 
            FnH 37
            UpdVars R33, K37_L, K37_H
 
            FnH 38
            UpdVars R34, K38_L, K38_H
 
            FnH 39
            UpdVars R35, K39_L, K39_H
 
            FnH 40
            UpdVars R32, K40_L, K40_H
 
            FnH 41
            UpdVars R33, K41_L, K41_H
 
            FnH 42
            UpdVars R34, K42_L, K42_H
 
            FnH 43
            UpdVars R35, K43_L, K43_H
 
            FnH 44
            UpdVars R32, K44_L, K44_H
 
            FnH 45
            UpdVars R33, K45_L, K45_H
 
            FnH 46
            UpdVars R34, K46_L, K46_H
 
            FnH 47
            UpdVars R35, K47_L, K47_H
 
; ~~ Loops 48-63/63 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            FnI 48
            UpdVars R48, K48_L, K48_H
 
            FnI 49
            UpdVars R49, K49_L, K49_H
 
            FnI 50
            UpdVars R50, K50_L, K50_H
 
            FnI 51
            UpdVars R51, K51_L, K51_H
 
            FnI 52
            UpdVars R48, K52_L, K52_H
 
            FnI 53
            UpdVars R49, K53_L, K53_H
 
            FnI 54
            UpdVars R50, K54_L, K54_H
 
            FnI 55
            UpdVars R51, K55_L, K55_H
 
            FnI 56
            UpdVars R48, K56_L, K56_H
 
            FnI 57
            UpdVars R49, K57_L, K57_H
 
            FnI 58
            UpdVars R50, K58_L, K58_H
 
            FnI 59
            UpdVars R51, K59_L, K59_H
 
            FnI 60
            UpdVars R48, K60_L, K60_H
 
            FnI 61
            UpdVars R49, K61_L, K61_H
 
            FnI 62
            UpdVars R50, K62_L, K62_H
 
            FnI 63
            UpdVars R51, K63_L, K63_H
 
            ; Add the hash values for this 64-byte chunk
            MOV AX, VA ; h0 = h0 + a
            ADD H0, AX
            MOV AX, VA+2
            ADC H0+2, AX
            MOV AX, VB ; h1 = h1 + b
            ADD H1, AX
            MOV AX, VB+2
            ADC H1+2, AX
            MOV AX, VC ; h2 = h2 + c
            ADD H2, AX
            MOV AX, VC+2
            ADC H2+2, AX
            MOV AX, VD ; h3 = h3 + d
            ADD H3, AX
            MOV AX, VD+2
            ADC H3+2, AX
 
            ADD DI, 64 ; Increase the chunk pointer
            SUB DX, 64 ; Decrease the string length
            JNZ CHUNK ; Hash the next chunk if not done
 
            POP BP
            POP DX
            POP CX
            POP BX
            POP AX
            RET
MD5 ENDP
 
PRINT PROC
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH DX
            PUSH BP
            MOV BP, SP
 
            ; Arguments:
            ; [BP]+12: pointer to the 16-byte binary hash
 
            MOV AH, 2 ; Set AH for INT 21h (output character)
            XOR BH, BH ; This should always = 0
 
            MOV SI, OFFSET HEX
            MOV DI, [BP]+12 ; DI points to the first byte
            MOV CL, 16 ; Set up the loop counter
 
PRN_BYTE: MOV BL, [DI] ; Get the next byte
            SHR BL, 1 ; Get high nibble by shifting right 4x
            SHR BL, 1
            SHR BL, 1
            SHR BL, 1
            MOV DL, [SI+BX] ; Get the ASCII hex digit
            INT 21h ; Print it
 
            MOV BL, [DI] ; Get the current byte again
            AND BL, 0Fh ; Get the low nibble
            MOV DL, [SI+BX] ; Get the hex digit
            INT 21h ; And print it
 
            INC DI ; Point to the next byte
            DEC CL
            JNZ PRN_BYTE ; Loop back until we're done
 
            POP BP
            POP DX
            POP CX
            POP BX
            POP AX
            RET
PRINT ENDP
            END MAIN

User Journal

Journal Journal: HTML/80x86 polyglot

Don't even ask...

javascript:void(prompt("Source code",unescape("<!-- %u0152\xC8%u017D\xD8\xBAP!\x81\xF2%20%20\xB4)%u20AC\xF4 \xCD!\xB4L0\xC0\xCD! --><html><head></head><body><script type=\x22text/javascript\x22>document.write(String(\x22Hello world!$\x22).split(\x22$\x22)[0])\x3B</script></body></html>")));

Copy and paste into the address bar (IE or FF tested). Copy the prompted value and paste it into Notepad; that's the source code*. Save as polyglot.[com|htm] (ANSI encoding) and run. Note: the 80x86 implementation doesn't wait around, so run it from the command prompt or the window will disappear before you see the output.

*Because /. doesn't like the strange characters, I can't post the source code directly. However, once you've saved it as .htm in Notepad as described above – Unicode weirdness notwithstanding – opening it with a browser, viewing the source, copying and pasting into Notepad, and saving as .com should yield an identical copy of the program.

Note: The String() value is the actual data that the 80x86 code displays. As a result, you can easily change it to whatever pleases you. (Leave the $ at the end; it's the delimiter for the interrupt that prints the string. Consequentially, you can't print a string containing a $ character.) However, the beginning of the string is hard-coded, so you won't be able to change the HTML before it (for example to add a <title> value)... actually, try it and see what happens (don't make the HTML shorter though...).

User Journal

Journal Journal: Binary-to-ASCII (80x86)

Binary-to-ASCII in 80x86 assembly (oblig: ASCII-to-binary)

@echo off
goto batch
 
a
        mov ax,cs
        mov ds,ax
        xor bh,bh ;page number (always 0)
;_begin
        xor cx,cx ;initialize bit count (ch) and ascii char (cl)
        mov ah,08
        int 10 ;get the character under the cursor
        mov bl,al ;save it so we can restore it later
;_getch
        mov ah,08
        int 21 ;get a key
        cmp al,1b ;check for esc
        jz 014d ;goto _quit
        cmp al,1a ;check for ^z
        jz 014d ;goto _quit
        cmp al,30 ;check for "0"
        jz 0124 ;goto _procch
        cmp al,31 ;check for "1"
        jz 0124 ;goto _procch
        jmp 010e ;goto _getch
;_procch
        mov ah,0a
        mov dx,cx ;preserve bit count & ascii char
        mov cx,1
        int 10 ;send typed digit to console
        mov cx,dx ;restore bit count & ascii char
        shl cl,1 ;shift to make room for new bit
        and al,1 ;convert ascii "0" and "1" to binary 0/1
        or cl,al ;put the new bit in the lsb of cl
        inc ch ;increment bit counter
        cmp ch,8
        jnz 010e ;goto _getch
;_out
        mov dl,cl ;move ascii char to dl for output on int 21
        mov ah,0a
        mov al,bl ;move original char to al for output
        mov cx,1
        int 10 ;restore the character that we overwrote
        mov ah,02
        int 21 ;print ascii char
        jmp 0106 ;goto _begin
;_quit
        mov ah,03
        xor bh,bh
        int 10 ;get cursor position
        mov ah,08
        int 10 ;preserve character under cursor
        mov ah,02
        mov bl,al
        mov cx,dx
        mov dl,1a
        int 21 ;send ^z
        mov dx,cx
        int 10 ;restore cursor position
        mov ah,0a
        mov al,bl
        mov cx,1
        int 10 ;restore character under cursor
        mov ah,4c
        int 21 ;return to dos
;_ASCIIZ
        db "bin2asc.com",0
;_compile
        MOV AX,CS
        MOV DS,AX
        MOV AH,3C
        XOR CX,CX
        MOV DX,0172 ;_ASCIIZ
        INT 21
        MOV BX,AX
        MOV CX,0172 ;_ASCIIZ
        MOV DX,0100
        SUB CX,DX
        MOV AH,40
        INT 21
        MOV AH,3E
        INT 21
        MOV AX,4C01
        INT 21
 
r ip
17e
g
q
 
:exists
echo You don't need to run this. Run BIN2ASC.COM instead.
goto run
 
:batch
if exist bin2asc.com goto exists
 
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
pause
cls
bin2asc.com

Assembly: Copy and paste into Notepad. Save as "bin2asc-asm.bat" (include the quotes to force the extension). Run the batch file in Windows by double-clicking or by executing it from the command prompt. On its first run, the batch file will run debug.exe and assemble the bin2asc.com executable in the current directory. After assembling the executable the batch will launch it. (Subsequently you can launch the executable without need for the batch file.)

Use: Type or paste (using the sys menu on the command prompt window) binary into the DOS window. All characters other than '1', '0', Esc, and ^Z will be ignored (this allows the program to be forgiving of spaces or newline characters in the binary). Every 8 binary digits will be converted to the corresponding ASCII character. Use the sys menu to copy the output (if needed). Esc or ^Z exit.

User Journal

Journal Journal: ASCII-to-binary (80x86)

ASCII-to-binary in 80x86 assembly (oblig: Binary-to-ASCII)

@echo off
goto batch
 
a
        mov ax,cs
        mov ds,ax
        xor ch,ch ;initialize column counter
;_newchar
        mov ah,08
        int 21 ;get a key
        cmp al,1b ;check for esc
        jz 0159 ;goto _quit
        cmp al,1a ;check for ^z
        jz 0159 ;goto _quit
        mov ah,0a
        xor bh,bh
        mov dh,ch ;preserve column counter
        mov cx,1
        int 10 ;send to console in case output is redirected
        mov ch,dh ;restore column counter
        mov cl,8
        mov ah,02
;_nextbit
        mov dl,30 ;set output char to "0"
        shl al,1
        jnb 012b ;goto _iszero
        inc dl ;change output char to "1"
;_iszero
        mov bl,al ;preserve input char
        int 21 ;print "0" or "1"
        mov al,bl ;restore input char
        dec cl ;decrement the bit counter
        jnz 0123 ;goto _nextbit
        add ch,8 ;increase the column counter
        add ch,[0180] ;add _padlen
        and ch,7f ;don't allow ch to go above 127
        cmp ch,47 ;see if we're overflowing the line
        jnb 014d ;goto _crlf
        mov ah,09
        mov dx,017e ;address of _padding
        int 21 ;print padding string
        jmp 0106 ;goto _newchar
;_crlf
        xor ch,ch ;reset the column counter
        mov dl,0d
        int 21 ;print cr
        mov dl,0a
        int 21 ;print lf
        jmp 0106 ;goto _newchar
;_quit
        mov ah,03
        xor bh,bh
        int 10 ;get cursor position
        mov ah,08
        int 10 ;preserve character under cursor
        mov ah,02
        mov bl,al
        mov cx,dx
        mov dl,1a
        int 21 ;send ^z
        mov dx,cx
        int 10 ;restore cursor position
        mov ah,0a
        mov al,bl
        mov cx,1
        int 10 ;restore character under cursor
        mov ah,4c
        int 21 ;return to dos
;_padding
        db " ","$"
;_padlen
        db 1
;_ASCIIZ
        db "asc2bin.com",0
;_compile
        MOV AX,CS
        MOV DS,AX
        MOV AH,3C
        XOR CX,CX
        MOV DX,0181 ;_ASCIIZ
        INT 21
        MOV BX,AX
        MOV CX,0181 ;_ASCIIZ
        MOV DX,0100
        SUB CX,DX
        MOV AH,40
        INT 21
        MOV AH,3E
        INT 21
        MOV AX,4C01
        INT 21
 
r ip
18d
g
q
 
:exists
echo You don't need to run this. Run ASC2BIN.COM instead.
goto run
 
:batch
if exist asc2bin.com goto exists
 
if exist %0 goto extension
debug < %0.bat
goto run
 
:extension
debug < %0
 
:run
pause
cls
asc2bin.com

Assembly: Copy and paste into Notepad. Save as "asc2bin-asm.bat" (include the quotes to force the extension). Run the batch file in Windows by double-clicking or by executing it from the command prompt. On its first run, the batch file will run debug.exe and assemble the asc2bin.com executable in the current directory. After assembling the executable the batch will launch it. (Subsequently you can launch the executable without need for the batch file.)

Use: Type or paste (using the sys menu on the command prompt window) into the DOS window. Use the sys menu to copy the output. Esc or ^Z exit.

User Journal

Journal Journal: Handy bookmarklet...

javascript:var d=document.getElementsByTagName('div');for(var i=0;i<d.length;i++)if(d[i].className=='oneline'){document.getElementById(d[i].id.split('_').join('_link_')).onclick();i=d.length;}void(0);

I call it "Scroll to first abbreviated post". That said, you should probably be able to figure out what it does.

Slashdot Top Deals

A morsel of genuine history is a thing so rare as to be always valuable. -- Thomas Jefferson

Working...