Discussion:
CM3 revisited
(too old to reply)
Kerr-Mudd, John
2023-02-26 12:17:25 UTC
Permalink
On Mon, 13 Feb 2023 22:31:01 +0000
Many years (decades actually) ago a one time regular here, Laura
Fairhead, posted a com to ascii program, called CM3. I've gone back to
looking at the decoder and have failed to find any way of shortening
it. But I've revamped the "create" program to just output ASCII code
(dropping the batch surrounds of 'Echo/' and '>>fn.com') from 759
bytes to 394 and made another that outputs the encoded program to STDOUT
(rather than immediately executing), that one's a bit shorter at 376.
max com file input size is c.50k. (one read, one write)
Here they are: (encoded by the 2nd program), so save to file & run to
recreate - feel free to step through them and run a virus scanner 1st!
I can post debug dumps if preferred.
1) Program to convert a DOS COM file to ASCII executable;
to recreate the binary copy and paste to 'prog1.com' or somesuch then run
prog1 >makeexec.com
usage is makeexec dosprog.com > asciexec.com
'asciexec' can then be run as if it were 'dosprog'
6h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,
.+HWM4LVC4qsv9[T}uqrxB`h3HS(iNkBgUa,2bfa'Yfx0bVQ$W-N*$')=0i
W`ST7T;)K(?j'?/:u1:e`4r(rTZII0$$o6DI$(bI$$))7$$[v:I)zKNqgwJ
YwfpIVK4]Any3ZAomX0Aq?/y2{,T`=V\.g9cxp`3=Xk[=V\m{HVd-H5U-Go
3_dXa:D+d/)9ZVACKYJI3Y~URN+nz?1esSmLi.V=1J`;GHv(uZHtzaJHoAE
.DJ~}zDd{O*ApK{CE,$sb$$5e?:l]\J=~ddAj}WTL$$$$I#
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
to recreate the binary copy and paste to 'prog2.com' or somesuch then run
prog2 >makeASCI.com
usage is makeASCI dosprog.com > asciprog.txt
6h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,
.+4WM4LVC4qsv9[T}ul-6JMbG_ZniNkBgUa,2bfa'Yfx0bVQzrj?($$f)_i
EsLo$5KrLdORw$sklui$U[E+_ht`PdRBBfcgBgXFKY1uR6aty5oWwh(29nF
J9uI6m+tx2wVVJ=V\Kp?9N)}2yu.a=V]pBC-?XEG${TN46_yUJT$vg8cv,.
when 'asciprog.txt' is copy and pasted to 'asciprog' and then run it will
recreate 'dosprog' to STDOUT i.e.
asciprog>dosprog.com
Seems I failed to xpost this back in mid-Feb.



I have since created a hex executer in a similar vein; it had a bug that's
taken me an embarrassing amount of time to track down. My program
worked fine under GRDB, (after stepping to ensure the fixedup code had
erm been fixedup), but went wrong with larger hex programs if executed
directly.
It turns out I was assuming that CX contains the length of the
executable (text) at start. This seems to not be the case, certainly on my
CMD box under XP - here it (CX) seems to be set to 0x00FF, so short
programs would decode OK, but larger ones truncated.

Does anyone here know if this is a known bug or is it something
peculiar to my setup? Is there any simple way to get the current
program's length (I'd prefer not to have to find my fn, then open and
search to end! ).

Any test report gratefully received in one of these forums; probably
c.o.m.p is best for relevance.
--
Bah, and indeed Humbug.
Terje Mathisen
2023-02-26 19:33:41 UTC
Permalink
Post by Kerr-Mudd, John
On Mon, 13 Feb 2023 22:31:01 +0000
Many years (decades actually) ago a one time regular here, Laura
Fairhead, posted a com to ascii program, called CM3. I've gone back to
looking at the decoder and have failed to find any way of shortening
it. But I've revamped the "create" program to just output ASCII code
(dropping the batch surrounds of 'Echo/' and '>>fn.com') from 759
bytes to 394 and made another that outputs the encoded program to STDOUT
(rather than immediately executing), that one's a bit shorter at 376.
max com file input size is c.50k. (one read, one write)
I love this stuff!

Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.

You end up with 70+ valid byte values, the worst problem is how do you
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)

Terje
Post by Kerr-Mudd, John
Here they are: (encoded by the 2nd program), so save to file & run to
recreate - feel free to step through them and run a virus scanner 1st!
I can post debug dumps if preferred.
1) Program to convert a DOS COM file to ASCII executable;
to recreate the binary copy and paste to 'prog1.com' or somesuch then run
prog1 >makeexec.com
usage is makeexec dosprog.com > asciexec.com
'asciexec' can then be run as if it were 'dosprog'
6h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,
.+HWM4LVC4qsv9[T}uqrxB`h3HS(iNkBgUa,2bfa'Yfx0bVQ$W-N*$')=0i
W`ST7T;)K(?j'?/:u1:e`4r(rTZII0$$o6DI$(bI$$))7$$[v:I)zKNqgwJ
YwfpIVK4]Any3ZAomX0Aq?/y2{,T`=V\.g9cxp`3=Xk[=V\m{HVd-H5U-Go
3_dXa:D+d/)9ZVACKYJI3Y~URN+nz?1esSmLi.V=1J`;GHv(uZHtzaJHoAE
.DJ~}zDd{O*ApK{CE,$sb$$5e?:l]\J=~ddAj}WTL$$$$I#
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
to recreate the binary copy and paste to 'prog2.com' or somesuch then run
prog2 >makeASCI.com
usage is makeASCI dosprog.com > asciprog.txt
6h}aXP5y`P]4nP_XW(F4(F6(F=(FF)FH(FL(Fe(FR0FTs*}`A?+,
.+4WM4LVC4qsv9[T}ul-6JMbG_ZniNkBgUa,2bfa'Yfx0bVQzrj?($$f)_i
EsLo$5KrLdORw$sklui$U[E+_ht`PdRBBfcgBgXFKY1uR6aty5oWwh(29nF
J9uI6m+tx2wVVJ=V\Kp?9N)}2yu.a=V]pBC-?XEG${TN46_yUJT$vg8cv,.
when 'asciprog.txt' is copy and pasted to 'asciprog' and then run it will
recreate 'dosprog' to STDOUT i.e.
asciprog>dosprog.com
Seems I failed to xpost this back in mid-Feb.
I have since created a hex executer in a similar vein; it had a bug that's
taken me an embarrassing amount of time to track down. My program
worked fine under GRDB, (after stepping to ensure the fixedup code had
erm been fixedup), but went wrong with larger hex programs if executed
directly.
It turns out I was assuming that CX contains the length of the
executable (text) at start. This seems to not be the case, certainly on my
CMD box under XP - here it (CX) seems to be set to 0x00FF, so short
programs would decode OK, but larger ones truncated.
Does anyone here know if this is a known bug or is it something
peculiar to my setup? Is there any simple way to get the current
program's length (I'd prefer not to have to find my fn, then open and
search to end! ).
Any test report gratefully received in one of these forums; probably
c.o.m.p is best for relevance.
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
Kerr-Mudd, John
2023-02-26 21:03:01 UTC
Permalink
On Sun, 26 Feb 2023 20:33:41 +0100
Post by Terje Mathisen
Post by Kerr-Mudd, John
On Mon, 13 Feb 2023 22:31:01 +0000
Many years (decades actually) ago a one time regular here, Laura
Fairhead, posted a com to ascii program, called CM3. I've gone back to
looking at the decoder and have failed to find any way of shortening
it. But I've revamped the "create" program to just output ASCII code
(dropping the batch surrounds of 'Echo/' and '>>fn.com') from 759
bytes to 394 and made another that outputs the encoded program to STDOUT
(rather than immediately executing), that one's a bit shorter at 376.
max com file input size is c.50k. (one read, one write)
I love this stuff!
Hope you found it works OK your end.
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
You end up with 70+ valid byte values, the worst problem is how do you
Laura used 5:4 encoding which requires 85 ASCII codes.
Post by Terje Mathisen
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)
Well quite; I think that's the only way. So I'd say it can't be done. I
refuse your challenge!
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
1) Program to convert a DOS COM file to ASCII executable;
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
[]
3)
Post by Terje Mathisen
Post by Kerr-Mudd, John
I have since created a hex executer in a similar vein
(Doesn't work under XP, but works with std dos .COM startup values)
--
Bah, and indeed Humbug.
Terje Mathisen
2023-02-27 09:47:49 UTC
Permalink
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 20:33:41 +0100
Post by Terje Mathisen
I love this stuff!
Hope you found it works OK your end.
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
You end up with 70+ valid byte values, the worst problem is how do you
Laura used 5:4 encoding which requires 85 ASCII codes.
Here's my own version of this:

next_block:
xor ax,ax
xor bp,bp
mov bl,5 ; 5 input chars/4-byte output block!
next_char:
inc si
xchg ax,bp ; Mul old value by 85
mul di
xchg ax,bp
mul di
mov cx,256-21h
add cl,[si]
add ax,cx ; and add in the current char (-21h)
adc bp,dx
dec bl
jnz next_char

push bp ; Save this block (reverse order!)
push ax
sub bh,5 ; More blocks?
ja next_block



I have used lots of different encodings for these, prior to that MIME
version. As an example, base 91 gives you 6.5+ bits so 16:13 expansion.

The key here was to find an encoding order which made the decoder as
simple as possible, basically just adding bits at the bottom and
extracting bytes as soon as I had enough bits/entropy.
...
Something like

acc = acc*91 + curr;
half_bits += 13;
if half_bits >= 16 {
*dst++ = acc & 255;
acc >>= 8;
half_bits &= 15;
}
I think I started the half_bits register at -16 so that I could branch
when the adding of 13 would overflow, but I'd have to look at my old
code to verify. :-)
Post by Kerr-Mudd, John
Post by Terje Mathisen
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)
Well quite; I think that's the only way. So I'd say it can't be done. I
refuse your challenge!
Many years later I saw a totally different way to do it, using a
custom-made compiler to generate code that filled an entire 64KB
segment, relying on address wraparound to get back to the top,
effectively having to interleave the various loops without accidentally
landing on a previously used code address. :-)

Terje
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
Kerr-Mudd, John
2023-03-03 19:56:45 UTC
Permalink
On Sun, 26 Feb 2023 21:03:01 +0000
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 20:33:41 +0100
.
Post by Kerr-Mudd, John
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)
Well quite; I think that's the only way. So I'd say it can't be done. I
refuse your challenge!
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
1) Program to convert a DOS COM file to ASCII executable;
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
[]
3)
Post by Terje Mathisen
Post by Kerr-Mudd, John
I have since created a hex executer in a similar vein
(Doesn't work under XP, but works with std dos .COM startup values)
Update: Now in pure ASCII!

PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0

B409BA0801CD21C348656C6C6F20776F726C642124Z


(Last line is the payload, you can probably read it yourself - it's "Hello
World""
--
Bah, and indeed Humbug.
Johann 'Myrkraverk' Oskarsson
2023-03-03 21:36:03 UTC
Permalink
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 21:03:01 +0000
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 20:33:41 +0100
.
Post by Kerr-Mudd, John
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)
Well quite; I think that's the only way. So I'd say it can't be done. I
refuse your challenge!
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
1) Program to convert a DOS COM file to ASCII executable;
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
[]
3)
Post by Terje Mathisen
Post by Kerr-Mudd, John
I have since created a hex executer in a similar vein
(Doesn't work under XP, but works with std dos .COM startup values)
Update: Now in pure ASCII!
PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
(Last line is the payload, you can probably read it yourself - it's "Hello
World""
Maybe I'm missing some context, but how exactly am I supposed to test
this? I went as far as pasting this into a .com file, and analyze in
IDA Free, but I see no INT 0x21 calls, neither with nor without line breaks.

I even tried to run it in DOSBox-X, but that just hung, so I guess
something is broken or missing? Or I did something wrong.
--
Johann | email: invalid -> com | www.myrkraverk.com/blog/
I'm not from the Internet, I just work there. | twitter: @myrkraverk
Kerr-Mudd, John
2023-03-04 10:44:44 UTC
Permalink
On Sat, 4 Mar 2023 05:36:03 +0800
Post by Johann 'Myrkraverk' Oskarsson
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 21:03:01 +0000
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 20:33:41 +0100
.
Post by Kerr-Mudd, John
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
[]
Post by Johann 'Myrkraverk' Oskarsson
Post by Kerr-Mudd, John
Post by Kerr-Mudd, John
Post by Terje Mathisen
Post by Kerr-Mudd, John
I have since created a hex executer in a similar vein
[]
Post by Johann 'Myrkraverk' Oskarsson
Post by Kerr-Mudd, John
Update: Now in pure ASCII!
I meant 'Alphanum'.
Post by Johann 'Myrkraverk' Oskarsson
Post by Kerr-Mudd, John
PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0
B409 BA0801 CD21 C3 48656C6C6F20776F726C642124 Z
mov ah,9;mov dx,108;int 21;ret; db 'Hello World!'$ EndofHexMarker
(Last line is the payload, you can probably read it yourself - it's "Hello
World""
Maybe I'm missing some context, but how exactly am I supposed to test
this? I went as far as pasting this into a .com file, and analyze in
IDA Free, but I see no INT 0x21 calls, neither with nor without line breaks.
I even tried to run it in DOSBox-X, but that just hung, so I guess
something is broken or missing? Or I did something wrong.
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.

I suspect this is the issue.

spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).

I admit I did post as soon as I had it working once, so not a lot of
testing done!

Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
--
Bah, and indeed Humbug.
Kerr-Mudd, John
2023-03-04 17:06:49 UTC
Permalink
On Sat, 4 Mar 2023 10:44:44 +0000
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 05:36:03 +0800
[alphanum hex decode & run program]
Post by Kerr-Mudd, John
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.
I suspect this is the issue.
spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).
Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
Bigger, but needs another line; now registers on entering the
decoded hex payload prog set as DOS would (si set to 0x100, cx to lth of
payload prog; dx/bp/di restored - I only have room to save 3 original
register values).

I dont have the space to 'set si' as I'd like at start.

WURVX4uVSPSSVPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VptC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5A5D89F981E99B015157B85EF3ABB8A45EABB8595FABB0E9AAB8FE002BC7
AB58BF000157FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
--
Bah, and indeed Humbug.
Terje Mathisen
2023-03-05 13:45:40 UTC
Permalink
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 10:44:44 +0000
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 05:36:03 +0800
[alphanum hex decode & run program]
Post by Kerr-Mudd, John
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.
I suspect this is the issue.
spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).
Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
Bigger, but needs another line; now registers on entering the
decoded hex payload prog set as DOS would (si set to 0x100, cx to lth of
payload prog; dx/bp/di restored - I only have room to save 3 original
register values).
I dont have the space to 'set si' as I'd like at start.
WURVX4uVSPSSVPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VptC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5A5D89F981E99B015157B85EF3ABB8A45EABB8595FABB0E9AAB8FE002BC7
AB58BF000157FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
I'll try this!

Compare with my code which manages to do everything with a single
modified instruction (the backwards branch), everything else is as written.

Line endings starts as CRLF, but any zero, one or two-byte control char
combination is OK.

The primary bootstrap fixes that first branch instruction and jumps
(forward) into thesecodary bootstrap which picks up pairs of bytes from
the input stream and combines them, not as HEX since that requires shift
operations, but with (0 xor byte1) xor byte2 - byte2 - byte2 which was
the first combination I found that was capable of generating all
possible byte values using local mime ascii opcodes.

The secondary bootstrap contains the shortes possible MIME decoder I
could come up with, it is used with a plain standard Base64 payload for
4:3 packing of the actual payload binary.

.model tiny
.code
.286
org 100h
boot1:
; jmp encode_mime
pop dx
push dx
pop cx

org 103h

push cx
dec cx
push cx ; CX = FFFF
inc sp
pop ax ; CX = 00FF

push cx ; POPA into AX (0FF)
push cx ; CX
push dx ; DX

inc cx ; AX = 0100
push cx ; BX

push dx ; SP (ignored)
push dx ; BP = 0000

push dx
pop ax
sub al,32h ; AX = 1CE
sub al,4Eh ; AX = 180
push ax ; SI = 180
push ax ; DI = 180

popa ; Init all regs!

push dx
pop ax
sub ax,5952h

xor [bx+7Ah],ax ; Turn INC BP/INC BP into JMP TOP
org $-1 ; Fixup offset byte value!
db (offset patch_here - 256)

jnz second_line ; Jump to fixup bx!

back_again:
dec sp ; Restore SP (I don't like an odd stack!)

push dx
pop ax
sub al,68h
sub al,67h ; AX = 0030h
push ax ; CX = 0030h (On stack top)

; Patch illegal (non-mime) opcodes
push dx
pop ax
sub al,'0'
sub al,'0'
xor [bx + 1],al
org $-1
db (offset patch1 - 1 - 256)

jnz boot2

org 140h

end_of_line:
; db 13,10 ; End of first line of code!
inc bx
inc bx

second_line:

inc bp
inc bp
patch_here:
; jmp back_again
inc bp ; Patch location might move up!
inc bp

top:
inc si
xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
push cx
pop ax
cmp ax,'+' * 256 + '0'
jb next ; White-space?

cmp ax,'=' * 256 + '0'
je boot3 ; Finished?

xor [di],ch ; [DI] is zero -> MOV [DI],DH
dec dx ; First/second byte in pair?
jnz next ; First, so get another char!

; Generate 8-bit value and increment destination pointer

sub [di],ch ; Subtract twice
sub [di],ch ; *dest++ = (first xor second) - 2*second
inc di

rept 20
inc bp
endm

boot2: ; Might be moved up as well!
inc dx
inc dx ; MOV BX,2

next:
pop cx
push cx ; CX = 0030h
and [di],ch ; MOV byte ptr [DI],0 -> Zero target byte
jz top + 128
patch1 label near

filetail db '0'
filename db "filename.ext=(c)_TMathisen'95"

db '&&&&&&' ; Ascii Filler, skipped by decoder

org 180h
boot3 label near

StartOfBoot2 label byte
nop
nop ; Two filler bytes in case of missing CRLFs

lea dx,[copyrt$]
mov ah,9
int 21h ; Print a copyright msg

cld
mov cx,002h ; No bits saved, shift two bits
xor dx,dx ; Empty buffer
push di ; Save starting decode offset

; SI -> start of MIME-encoded binary file

top_of_loop:
push cx
push di
skip_white:
lodsb
mov cx,65 ; Mime table length
lea di,[MIME_Table]
repne scasb
jne skip_white
jcxz save_file

mov ax,di
pop di
pop cx
sub ax, offset MIME_Table + 1

and cx,707h ; Mask bits & shift counts
mov dh,dl
xor dl,dl
shl ax,cl
or dx,ax
add cx,602h ; Add 6 to bits count and 2 to shift

cmp ch,8
jb top_of_loop

mov [di],dh ; Save a full byte!
jmp top_of_loop

save_file:
pop ax ; Restore stack!
pop ax

lea dx,[filename] ; Offset to "filename.ext"
mov si,dx
name_end:
lodsb
cmp al,'<'
jne name_end
dec si
mov byte ptr [si],0

mov ah,3Ch ; Create/truncate file!
xor cx,cx
int 21h
jc error

xchg ax,bx ; BX = file handle

pop dx ; retrieve starting position

mov cx,di ; - Final position
sub cx,dx ; = Total length

add cx,'0'
sub cl,[filetail]
sbb ch,0 ; Adjust file length!

mov ah,40h ; Write to file
int 21h
jc error
mov byte ptr [si],'$'
lea dx,[filename] ; Offset to "filename.ext"
mov ah,9
int 21h
jc error

mov ah,3Eh
int 21h
jc error

lea dx,ok_msg$
mov al,0
jmp cont
error:
lea dx,file_err$
mov al,1
cont:
push ax
mov ah,9
int 21h
pop ax
mov ah,4Ch
int 21h

MIME_Table label byte
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='

copyrt$ db 'MAKEMIME (c) Terje Mathisen 1995. Binary to TEXT.COM converter'
db 13,10,'$'
file_err$ db 'File IO error!',13,10,'$'
ok_msg$ db ' created!'
crlf$ db 13,10,'$'

EndOfBoot2 label byte

start$ db '"$'
end$ db '"\',13,10,'$'

lead$ db '"!!$'
tail$ db '"\',13,10,'"$'
slutt$ db '=";',13,10,'$'

MimePair label byte
db "H8I8G7F7E7D7A9B7A7A8A5A6A3A4A1A2A/A0B0B+A+E0F0F+E+D+J0K0L0M0N0O0"
db "Q/P/S+R+Q+P+W+V+U+T+auavZzatXzXyXxYxWwVwRzSzPzPyPxPwPvPuJzKzHzHy"
db "HxIxGwFwBzCzAyAzAwAxAuAvAsAtAqArAoApAmAnAkAlAiAjAgAhAeAfAcAdAaAb"
db "CaBaDbDaBZCZAYAZAWAXAUAVASATAQARAOAPAMANAKALAIAJAGAHAEAFACADAAAB"
db "CABADBDAGAFAHBHAKAJALBLAOANAPBPASARATBTAWAVAXBXAaGZAaEaFaCaDaAaB"
db "cAbAdBdAgAfAhBhAkAjAlBlAoAnApBpAsArAtBtAwAvAxBxA0XzA0V0U0T0S0R0Q"
db "0P0/2P2+1+0+6P6+5+4++K/L+M+Jy9x9x8y8w7v7u7t7q9p9p8p7p6p5p4p3i9h9"
db "h8i8g7f7e7d7a9b7a7a8a5a6a3a4Y9X9X8Y8W7V7U7T7Q9P9P8P7P6P5P4P3I9H9"

patch_bytes:
pop dx
push dx
pop cx

encode_mime:
mov si,100h
mov ax,word ptr [patch_bytes]
mov ds:[si],ax
mov al,byte ptr [patch_bytes+2]
mov ds:[si+2],al

cld

mov di,2
toplines:
lea dx,[start$]
mov ah,9
int 21h
mov cx,64
topchars:
mov dl,[si]
inc si
call print_c
dec cx
jnz topchars

lea dx,[end$]
mov ah,9
int 21h

dec di
jnz toplines

mov di, offset EndOfBoot2 - offset StartOfBoot2

lea dx,[lead$]
mov ah,9
int 21h
mov cx,1F04h ; 31 pairs on first line, shift count = 4
doline:
dochar:
xor bx,bx
mov bl,[si]
add bx,bx
inc si
mov dl,MimePair[bx]
call print_c
mov dl,MimePair[bx+1]
call print_c

dec di
jz done

dec ch
jnz dochar

lea dx,[tail$]
mov ah,9
int 21h

mov ch,32 ; length of next line

jmp doline

done:
lea dx,[slutt$]
mov ah,9
int 21h

mov ax,4C00h
int 21h

print_c proc
cmp dl,'\'
je @@escape
cmp dl,'"'
jne @@normal
@@escape:
push dx
mov dl,'\'
mov ah,2
int 21h
pop dx
@@normal:
mov ah,2
int 21h
ret
print_c endp

end boot1
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
Kerr-Mudd, John
2023-03-05 16:29:19 UTC
Permalink
On Sun, 5 Mar 2023 14:45:40 +0100
Post by Terje Mathisen
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 10:44:44 +0000
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 05:36:03 +0800
[alphanum hex decode & run program]
Post by Kerr-Mudd, John
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.
I suspect this is the issue.
spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).
Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
Bigger, but needs another line; now registers on entering the
decoded hex payload prog set as DOS would (si set to 0x100, cx to lth of
payload prog; dx/bp/di restored - I only have room to save 3 original
register values).
I dont have the space to 'set si' as I'd like at start.
NB this means the following requires/assumes si=0x100 at start.
Post by Terje Mathisen
Post by Kerr-Mudd, John
WURVX4uVSPSSVPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VptC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5A5D89F981E99B015157B85EF3ABB8A45EABB8595FABB0E9AAB8FE002BC7
AB58BF000157FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
I'll try this!
under a debugger, note that you'll need to set si to 0x100 if not the
default, and you'll need to step through the decode loop a few times to
ensure the first bytes of hex are decoded, not fall through to execute the
cr[lf] that's there beforehand! the central
65cr5MJ5205235MJ520523
is just filler, dont worry about tracking the value of ax, it's not used.
Post by Terje Mathisen
Compare with my code which manages to do everything with a single
modified instruction (the backwards branch), everything else is as written.
Well done, all those fixups I do (maxed out at 9) are hard to keep from
straying out of alphanum locations, hence the early 6666666 pad.
Post by Terje Mathisen
Line endings starts as CRLF, but any zero, one or two-byte control char
combination is OK.
The primary bootstrap fixes that first branch instruction and jumps
(forward) into thesecodary bootstrap which picks up pairs of bytes from
the input stream and combines them, not as HEX since that requires shift
operations, but with (0 xor byte1) xor byte2 - byte2 - byte2 which was
the first combination I found that was capable of generating all
possible byte values using local mime ascii opcodes.
I did my own version of that back 5 years ago; inspired by your revelation
then; but I possibly didn't publish it, abandoning after seeing my effort
was lots bigger than Laura's CM3.

My double byte table had all alphanum combinations except for 4,
which was annoying. Luckily my code didn't use them.


This time around I decided to disallow all non-alphanum, so can't use
'sub' as you do here.

I'd like a short way to get 0x100 in si, but it takes 7 bytes
- this is too much as space is very limited on line 1.


Thanks for posting your source, I think
Post by Terje Mathisen
The secondary bootstrap contains the shortes possible MIME decoder I
could come up with, it is used with a plain standard Base64 payload for
4:3 packing of the actual payload binary.
.model tiny
.code
.286
org 100h
; jmp encode_mime
pop dx
;; set dx=0
Post by Terje Mathisen
push dx
pop cx
;; set cx=0
Post by Terje Mathisen
org 103h
;?
Post by Terje Mathisen
push cx
dec cx
push cx ; CX = FFFF
inc sp
pop ax ; CX = 00FF
push cx ; POPA into AX (0FF)
push cx ; CX
push dx ; DX
inc cx ; AX = 0100
??CX=0100
Post by Terje Mathisen
push cx ; BX
push dx ; SP (ignored)
push dx ; BP = 0000
push dx
;; cx pshurely?
Post by Terje Mathisen
pop ax
I dont see this - dx was 0?
Post by Terje Mathisen
sub al,32h ; AX = 1CE
sub al,4Eh ; AX = 180
push ax ; SI = 180
push ax ; DI = 180
popa ; Init all regs!
push dx
pop ax
sub ax,5952h
xor [bx+7Ah],ax ; Turn INC BP/INC BP into JMP TOP
org $-1 ; Fixup offset byte value!
db (offset patch_here - 256)
jnz second_line ; Jump to fixup bx!
dec sp ; Restore SP (I don't like an odd stack!)
push dx
pop ax
sub al,68h
sub al,67h ; AX = 0030h
push ax ; CX = 0030h (On stack top)
; Patch illegal (non-mime) opcodes
push dx
pop ax
sub al,'0'
sub al,'0'
xor [bx + 1],al
org $-1
db (offset patch1 - 1 - 256)
jnz boot2
org 140h
; db 13,10 ; End of first line of code!
inc bx
inc bx
inc bp
inc bp
; jmp back_again
inc bp ; Patch location might move up!
inc bp
I like that you've considered changes to eol ; I've not done that this
time.
Post by Terje Mathisen
inc si
xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
; I can only use dh
Post by Terje Mathisen
push cx
pop ax
cmp ax,'+' * 256 + '0'
jb next ; White-space?
cmp ax,'=' * 256 + '0'
je boot3 ; Finished?
xor [di],ch ; [DI] is zero -> MOV [DI],DH
dec dx ; First/second byte in pair?
jnz next ; First, so get another char!
; Generate 8-bit value and increment destination pointer
sub [di],ch ; Subtract twice
sub [di],ch ; *dest++ = (first xor second) - 2*second
inc di
rept 20
inc bp
endm
boot2: ; Might be moved up as well!
inc dx
inc dx ; MOV BX,2
doh so much simpler than my byte toggle!
Post by Terje Mathisen
pop cx
push cx ; CX = 0030h
and [di],ch ; MOV byte ptr [DI],0 -> Zero target byte
jz top + 128
patch1 label near
filetail db '0'
filename db "filename.ext=(c)_TMathisen'95"
db '&&&&&&' ; Ascii Filler, skipped by decoder
org 180h
boot3 label near
StartOfBoot2 label byte
nop
nop ; Two filler bytes in case of missing CRLFs
lea dx,[copyrt$]
mov ah,9
int 21h ; Print a copyright msg
cld
mov cx,002h ; No bits saved, shift two bits
xor dx,dx ; Empty buffer
push di ; Save starting decode offset
; SI -> start of MIME-encoded binary file
push cx
push di
lodsb
mov cx,65 ; Mime table length
lea di,[MIME_Table]
repne scasb
jne skip_white
jcxz save_file
mov ax,di
pop di
pop cx
sub ax, offset MIME_Table + 1
and cx,707h ; Mask bits & shift counts
mov dh,dl
xor dl,dl
shl ax,cl
or dx,ax
add cx,602h ; Add 6 to bits count and 2 to shift
cmp ch,8
jb top_of_loop
mov [di],dh ; Save a full byte!
jmp top_of_loop
pop ax ; Restore stack!
pop ax
lea dx,[filename] ; Offset to "filename.ext"
mov si,dx
lodsb
cmp al,'<'
jne name_end
dec si
mov byte ptr [si],0
mov ah,3Ch ; Create/truncate file!
xor cx,cx
int 21h
jc error
xchg ax,bx ; BX = file handle
pop dx ; retrieve starting position
mov cx,di ; - Final position
sub cx,dx ; = Total length
add cx,'0'
sub cl,[filetail]
sbb ch,0 ; Adjust file length!
mov ah,40h ; Write to file
int 21h
jc error
mov byte ptr [si],'$'
lea dx,[filename] ; Offset to "filename.ext"
mov ah,9
int 21h
jc error
mov ah,3Eh
int 21h
jc error
lea dx,ok_msg$
mov al,0
jmp cont
lea dx,file_err$
mov al,1
push ax
mov ah,9
int 21h
pop ax
mov ah,4Ch
int 21h
MIME_Table label byte
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
copyrt$ db 'MAKEMIME (c) Terje Mathisen 1995. Binary to TEXT.COM converter'
db 13,10,'$'
file_err$ db 'File IO error!',13,10,'$'
ok_msg$ db ' created!'
crlf$ db 13,10,'$'
EndOfBoot2 label byte
start$ db '"$'
end$ db '"\',13,10,'$'
lead$ db '"!!$'
tail$ db '"\',13,10,'"$'
slutt$ db '=";',13,10,'$'
MimePair label byte
db "H8I8G7F7E7D7A9B7A7A8A5A6A3A4A1A2A/A0B0B+A+E0F0F+E+D+J0K0L0M0N0O0"
db "Q/P/S+R+Q+P+W+V+U+T+auavZzatXzXyXxYxWwVwRzSzPzPyPxPwPvPuJzKzHzHy"
db "HxIxGwFwBzCzAyAzAwAxAuAvAsAtAqArAoApAmAnAkAlAiAjAgAhAeAfAcAdAaAb"
db "CaBaDbDaBZCZAYAZAWAXAUAVASATAQARAOAPAMANAKALAIAJAGAHAEAFACADAAAB"
db "CABADBDAGAFAHBHAKAJALBLAOANAPBPASARATBTAWAVAXBXAaGZAaEaFaCaDaAaB"
db "cAbAdBdAgAfAhBhAkAjAlBlAoAnApBpAsArAtBtAwAvAxBxA0XzA0V0U0T0S0R0Q"
db "0P0/2P2+1+0+6P6+5+4++K/L+M+Jy9x9x8y8w7v7u7t7q9p9p8p7p6p5p4p3i9h9"
db "h8i8g7f7e7d7a9b7a7a8a5a6a3a4Y9X9X8Y8W7V7U7T7Q9P9P8P7P6P5P4P3I9H9"
pop dx
push dx
pop cx
mov si,100h
mov ax,word ptr [patch_bytes]
mov ds:[si],ax
mov al,byte ptr [patch_bytes+2]
mov ds:[si+2],al
cld
mov di,2
lea dx,[start$]
mov ah,9
int 21h
mov cx,64
mov dl,[si]
inc si
call print_c
dec cx
jnz topchars
lea dx,[end$]
mov ah,9
int 21h
dec di
jnz toplines
mov di, offset EndOfBoot2 - offset StartOfBoot2
lea dx,[lead$]
mov ah,9
int 21h
mov cx,1F04h ; 31 pairs on first line, shift count = 4
xor bx,bx
mov bl,[si]
add bx,bx
inc si
mov dl,MimePair[bx]
call print_c
mov dl,MimePair[bx+1]
call print_c
dec di
jz done
dec ch
jnz dochar
lea dx,[tail$]
mov ah,9
int 21h
mov ch,32 ; length of next line
jmp doline
lea dx,[slutt$]
mov ah,9
int 21h
mov ax,4C00h
int 21h
print_c proc
cmp dl,'\'
cmp dl,'"'
push dx
mov dl,'\'
mov ah,2
int 21h
pop dx
mov ah,2
int 21h
ret
print_c endp
end boot1
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
If you've got the room for LUT, sure!
--
Bah, and indeed Humbug.
Terje Mathisen
2023-03-06 10:35:01 UTC
Permalink
Nice if you to actually read the code, I did notice that the comments
had several errors, probably leftovers from previous attempts. :-)

Terje
Post by Kerr-Mudd, John
On Sun, 5 Mar 2023 14:45:40 +0100
Post by Terje Mathisen
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 10:44:44 +0000
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 05:36:03 +0800
[alphanum hex decode & run program]
Post by Kerr-Mudd, John
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.
I suspect this is the issue.
spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).
Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
Bigger, but needs another line; now registers on entering the
decoded hex payload prog set as DOS would (si set to 0x100, cx to lth of
payload prog; dx/bp/di restored - I only have room to save 3 original
register values).
I dont have the space to 'set si' as I'd like at start.
NB this means the following requires/assumes si=0x100 at start.
Post by Terje Mathisen
Post by Kerr-Mudd, John
WURVX4uVSPSSVPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VptC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5A5D89F981E99B015157B85EF3ABB8A45EABB8595FABB0E9AAB8FE002BC7
AB58BF000157FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
I'll try this!
under a debugger, note that you'll need to set si to 0x100 if not the
default, and you'll need to step through the decode loop a few times to
ensure the first bytes of hex are decoded, not fall through to execute the
cr[lf] that's there beforehand! the central
65cr5MJ5205235MJ520523
is just filler, dont worry about tracking the value of ax, it's not used.
Post by Terje Mathisen
Compare with my code which manages to do everything with a single
modified instruction (the backwards branch), everything else is as written.
Well done, all those fixups I do (maxed out at 9) are hard to keep from
straying out of alphanum locations, hence the early 6666666 pad.
Post by Terje Mathisen
Line endings starts as CRLF, but any zero, one or two-byte control char
combination is OK.
The primary bootstrap fixes that first branch instruction and jumps
(forward) into thesecodary bootstrap which picks up pairs of bytes from
the input stream and combines them, not as HEX since that requires shift
operations, but with (0 xor byte1) xor byte2 - byte2 - byte2 which was
the first combination I found that was capable of generating all
possible byte values using local mime ascii opcodes.
I did my own version of that back 5 years ago; inspired by your revelation
then; but I possibly didn't publish it, abandoning after seeing my effort
was lots bigger than Laura's CM3.
My double byte table had all alphanum combinations except for 4,
which was annoying. Luckily my code didn't use them.
This time around I decided to disallow all non-alphanum, so can't use
'sub' as you do here.
I'd like a short way to get 0x100 in si, but it takes 7 bytes
- this is too much as space is very limited on line 1.
Thanks for posting your source, I think
Post by Terje Mathisen
The secondary bootstrap contains the shortes possible MIME decoder I
could come up with, it is used with a plain standard Base64 payload for
4:3 packing of the actual payload binary.
.model tiny
.code
.286
org 100h
; jmp encode_mime
pop dx
;; set dx=0
Post by Terje Mathisen
push dx
pop cx
;; set cx=0
Post by Terje Mathisen
org 103h
;?
Post by Terje Mathisen
push cx
dec cx
push cx ; CX = FFFF
inc sp
pop ax ; CX = 00FF
push cx ; POPA into AX (0FF)
push cx ; CX
push dx ; DX
inc cx ; AX = 0100
??CX=0100
Post by Terje Mathisen
push cx ; BX
push dx ; SP (ignored)
push dx ; BP = 0000
push dx
;; cx pshurely?
Post by Terje Mathisen
pop ax
I dont see this - dx was 0?
Post by Terje Mathisen
sub al,32h ; AX = 1CE
sub al,4Eh ; AX = 180
push ax ; SI = 180
push ax ; DI = 180
popa ; Init all regs!
push dx
pop ax
sub ax,5952h
xor [bx+7Ah],ax ; Turn INC BP/INC BP into JMP TOP
org $-1 ; Fixup offset byte value!
db (offset patch_here - 256)
jnz second_line ; Jump to fixup bx!
dec sp ; Restore SP (I don't like an odd stack!)
push dx
pop ax
sub al,68h
sub al,67h ; AX = 0030h
push ax ; CX = 0030h (On stack top)
; Patch illegal (non-mime) opcodes
push dx
pop ax
sub al,'0'
sub al,'0'
xor [bx + 1],al
org $-1
db (offset patch1 - 1 - 256)
jnz boot2
org 140h
; db 13,10 ; End of first line of code!
inc bx
inc bx
inc bp
inc bp
; jmp back_again
inc bp ; Patch location might move up!
inc bp
I like that you've considered changes to eol ; I've not done that this
time.
Post by Terje Mathisen
inc si
xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
; I can only use dh
Post by Terje Mathisen
push cx
pop ax
cmp ax,'+' * 256 + '0'
jb next ; White-space?
cmp ax,'=' * 256 + '0'
je boot3 ; Finished?
xor [di],ch ; [DI] is zero -> MOV [DI],DH
dec dx ; First/second byte in pair?
jnz next ; First, so get another char!
; Generate 8-bit value and increment destination pointer
sub [di],ch ; Subtract twice
sub [di],ch ; *dest++ = (first xor second) - 2*second
inc di
rept 20
inc bp
endm
boot2: ; Might be moved up as well!
inc dx
inc dx ; MOV BX,2
doh so much simpler than my byte toggle!
Post by Terje Mathisen
pop cx
push cx ; CX = 0030h
and [di],ch ; MOV byte ptr [DI],0 -> Zero target byte
jz top + 128
patch1 label near
filetail db '0'
filename db "filename.ext=(c)_TMathisen'95"
db '&&&&&&' ; Ascii Filler, skipped by decoder
org 180h
boot3 label near
StartOfBoot2 label byte
nop
nop ; Two filler bytes in case of missing CRLFs
lea dx,[copyrt$]
mov ah,9
int 21h ; Print a copyright msg
cld
mov cx,002h ; No bits saved, shift two bits
xor dx,dx ; Empty buffer
push di ; Save starting decode offset
; SI -> start of MIME-encoded binary file
push cx
push di
lodsb
mov cx,65 ; Mime table length
lea di,[MIME_Table]
repne scasb
jne skip_white
jcxz save_file
mov ax,di
pop di
pop cx
sub ax, offset MIME_Table + 1
and cx,707h ; Mask bits & shift counts
mov dh,dl
xor dl,dl
shl ax,cl
or dx,ax
add cx,602h ; Add 6 to bits count and 2 to shift
cmp ch,8
jb top_of_loop
mov [di],dh ; Save a full byte!
jmp top_of_loop
pop ax ; Restore stack!
pop ax
lea dx,[filename] ; Offset to "filename.ext"
mov si,dx
lodsb
cmp al,'<'
jne name_end
dec si
mov byte ptr [si],0
mov ah,3Ch ; Create/truncate file!
xor cx,cx
int 21h
jc error
xchg ax,bx ; BX = file handle
pop dx ; retrieve starting position
mov cx,di ; - Final position
sub cx,dx ; = Total length
add cx,'0'
sub cl,[filetail]
sbb ch,0 ; Adjust file length!
mov ah,40h ; Write to file
int 21h
jc error
mov byte ptr [si],'$'
lea dx,[filename] ; Offset to "filename.ext"
mov ah,9
int 21h
jc error
mov ah,3Eh
int 21h
jc error
lea dx,ok_msg$
mov al,0
jmp cont
lea dx,file_err$
mov al,1
push ax
mov ah,9
int 21h
pop ax
mov ah,4Ch
int 21h
MIME_Table label byte
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
copyrt$ db 'MAKEMIME (c) Terje Mathisen 1995. Binary to TEXT.COM converter'
db 13,10,'$'
file_err$ db 'File IO error!',13,10,'$'
ok_msg$ db ' created!'
crlf$ db 13,10,'$'
EndOfBoot2 label byte
start$ db '"$'
end$ db '"\',13,10,'$'
lead$ db '"!!$'
tail$ db '"\',13,10,'"$'
slutt$ db '=";',13,10,'$'
MimePair label byte
db "H8I8G7F7E7D7A9B7A7A8A5A6A3A4A1A2A/A0B0B+A+E0F0F+E+D+J0K0L0M0N0O0"
db "Q/P/S+R+Q+P+W+V+U+T+auavZzatXzXyXxYxWwVwRzSzPzPyPxPwPvPuJzKzHzHy"
db "HxIxGwFwBzCzAyAzAwAxAuAvAsAtAqArAoApAmAnAkAlAiAjAgAhAeAfAcAdAaAb"
db "CaBaDbDaBZCZAYAZAWAXAUAVASATAQARAOAPAMANAKALAIAJAGAHAEAFACADAAAB"
db "CABADBDAGAFAHBHAKAJALBLAOANAPBPASARATBTAWAVAXBXAaGZAaEaFaCaDaAaB"
db "cAbAdBdAgAfAhBhAkAjAlBlAoAnApBpAsArAtBtAwAvAxBxA0XzA0V0U0T0S0R0Q"
db "0P0/2P2+1+0+6P6+5+4++K/L+M+Jy9x9x8y8w7v7u7t7q9p9p8p7p6p5p4p3i9h9"
db "h8i8g7f7e7d7a9b7a7a8a5a6a3a4Y9X9X8Y8W7V7U7T7Q9P9P8P7P6P5P4P3I9H9"
pop dx
push dx
pop cx
mov si,100h
mov ax,word ptr [patch_bytes]
mov ds:[si],ax
mov al,byte ptr [patch_bytes+2]
mov ds:[si+2],al
cld
mov di,2
lea dx,[start$]
mov ah,9
int 21h
mov cx,64
mov dl,[si]
inc si
call print_c
dec cx
jnz topchars
lea dx,[end$]
mov ah,9
int 21h
dec di
jnz toplines
mov di, offset EndOfBoot2 - offset StartOfBoot2
lea dx,[lead$]
mov ah,9
int 21h
mov cx,1F04h ; 31 pairs on first line, shift count = 4
xor bx,bx
mov bl,[si]
add bx,bx
inc si
mov dl,MimePair[bx]
call print_c
mov dl,MimePair[bx+1]
call print_c
dec di
jz done
dec ch
jnz dochar
lea dx,[tail$]
mov ah,9
int 21h
mov ch,32 ; length of next line
jmp doline
lea dx,[slutt$]
mov ah,9
int 21h
mov ax,4C00h
int 21h
print_c proc
cmp dl,'\'
cmp dl,'"'
push dx
mov dl,'\'
mov ah,2
int 21h
pop dx
mov ah,2
int 21h
ret
print_c endp
end boot1
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
If you've got the room for LUT, sure!
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
Kerr-Mudd, John
2023-03-11 20:44:58 UTC
Permalink
On Sun, 5 Mar 2023 16:29:19 +0000
Post by Kerr-Mudd, John
On Sun, 5 Mar 2023 14:45:40 +0100
Post by Terje Mathisen
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 10:44:44 +0000
Post by Kerr-Mudd, John
On Sat, 4 Mar 2023 05:36:03 +0800
[alphanum hex decode & run program]
Post by Kerr-Mudd, John
Thanks for testing, I'm running it in a CMD box under Windows XP; the
program does a lot of self-modification and relies on SI being 0x0100 at
startup.
I suspect this is the issue.
spacing /cr/lf shouldn't matter once in the hexcode region. (i.e 1st 2
lines must be asis).
Sadly I'm unable to retain startup register values as 'pusha' (0x60) is not
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
Bigger, but needs another line; now registers on entering the
decoded hex payload prog set as DOS would (si set to 0x100, cx to lth of
payload prog; dx/bp/di restored - I only have room to save 3 original
register values).
I dont have the space to 'set si' as I'd like at start.
NB this means the following requires/assumes si=0x100 at start.
Post by Terje Mathisen
Post by Kerr-Mudd, John
WURVX4uVSPSSVPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VptC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5A5D89F981E99B015157B85EF3ABB8A45EABB8595FABB0E9AAB8FE002BC7
AB58BF000157FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
I'll try this!
under a debugger, note that you'll need to set si to 0x100 if not the
default, and you'll need to step through the decode loop a few times to
ensure the first bytes of hex are decoded, not fall through to execute the
cr[lf] that's there beforehand! the central
65cr5MJ5205235MJ520523
is just filler, dont worry about tracking the value of ax, it's not used.
[]
Post by Kerr-Mudd, John
I'd like a short way to get 0x100 in si, but it takes 7 bytes
- this is too much as space is very limited on line 1.
OK; I've managed to get rid of 2 FUs, allowing me to set si to 0x100 at
start -

hMJX5MKWPURPSSSSP4vPPaH5gF0f60fA0F80Fu1FM1Fm1Fq5
66q7bOL72N9666uX0F4SX3F41F4MV0F4SZ2505SZ2v405GPSX3F41F4X0F54z0rczZuX5A
5D89F981E99A0157B85EF3ABB8A459ABB85E5FABB0E9AAB8FE002BC7AB585F5751FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
--
Bah, and indeed Humbug.
Terje Mathisen
2023-03-03 21:38:25 UTC
Permalink
I removed the extra blank line and tried to disassemble/run/single-step
this using symdeb under dosbox: When it came to a couple of funky
opcodes, ending with a single 63h byte, it just hung. :-(

Up to that point I had seen a lot of self-modifications to parts of the
PSP, but no obvious attempt to generate a backwards jump inside the main
body?

Terje
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 21:03:01 +0000
Post by Kerr-Mudd, John
On Sun, 26 Feb 2023 20:33:41 +0100
.
Post by Kerr-Mudd, John
Post by Terje Mathisen
Now go back and redo this using only those ascii chars that are
guaranteed (by the MIME standard) to never needing to be quoted, i.e.
they will pass transparently over every single known email gateway etc.
address ememory when all opcodes that target (POP) BX/SI/DI/BP happens
to use banned byte values. The only way I found to make it work was to
require at least an 80186 which is the first cpu to support POPA. :-)
Well quite; I think that's the only way. So I'd say it can't be done. I
refuse your challenge!
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
1) Program to convert a DOS COM file to ASCII executable;
[]
Post by Terje Mathisen
Post by Kerr-Mudd, John
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
[]
3)
Post by Terje Mathisen
Post by Kerr-Mudd, John
I have since created a hex executer in a similar vein
(Doesn't work under XP, but works with std dos .COM startup values)
Update: Now in pure ASCII!
PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5
q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5
5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
(Last line is the payload, you can probably read it yourself - it's "Hello
World""
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
Kerr-Mudd, John
2023-03-04 10:46:30 UTC
Permalink
On Fri, 3 Mar 2023 22:38:25 +0100
Post by Terje Mathisen
I removed the extra blank line and tried to disassemble/run/single-step
this using symdeb under dosbox: When it came to a couple of funky
opcodes, ending with a single 63h byte, it just hung. :-(
Up to that point I had seen a lot of self-modifications to parts of the
PSP, but no obvious attempt to generate a backwards jump inside the main
body?
requires SI=0x100 to fixup in place.
--
Bah, and indeed Humbug.
Loading...