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.
As they are just variations on a theme, the same restriction applies:
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?+, fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZsX2YVQH .+HWM4LVC4qsv9[T}uqrxB`h3HS(iNkBgUa,2bfa'Yfx0bVQ$W-N*$')=0i EsLo$7E1_dORw$Mt`cNhc93c_get+f\YtWI,@;yVnT[jd=`*nGHUS)t/39( W`ST7T;)K(?j'?/:u1:e`4r(rTZII0$$o6DI$(bI$$))7$$[v:I)zKNqgwJ ID@a~-P;?}fF[dC3:CQwk9bqei2[pHR2[pHR@zd6:96}tJ)9`RMDsTh=N;P 4g_c'icT(vo7blJ:}btejaUFXW8@`Voq$W5O$$)HhXt5HK_AQ}-bHn{290K (H,HYn9aHn~4@Mgsk(0Ca;@=6,QOBN\6oIsHQRMCN37GUe[2MCN96KPrz4H 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?+, fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZsX1yDQH .+4WM4LVC4qsv9[T}ul-6JMbG_ZniNkBgUa,2bfa'Yfx0bVQzrj?($$f)_i EsLo$5KrLdORw$sklui$U[E+_ht`PdRBBfcgBgXFKY1uR6aty5oWwh(29nF fIa:r(QJ6h`g-L6$/2`J'pD\:lW:E;Ba5_x'oYoe9D\Q@9@2GS9@2G39@2F k9@2Fi9@2FR__9'lei+i\*JkJ'ne+yD'Y6WH1P'm-$a7nHl90uQ*ROVHj{? _`{)z*t0rLendO756$rgsRBM[r@8h?iVJpcR-GxxRsM.}w+Irs[zH[Kx5*8 Xk@BNwxr0FLJzHZk,uKn@gFI:-n}0L.FLKm$bz)9\X_GDBnPNz?L(6oUxkD J9uI6m+tx2wVVJ=V\Kp?9N)}2yu.a=V]pBC-?XEG${TN46_yUJT$vg8cv,. ;\80s3W1ihCJmI_Hw.RtMd/o1HtC:TCcgXfPB8GDOZmqA:\@R4E*\[Je8?I b/}H?V0rL@bc4_`\$)[[d#
when 'asciprog.txt' is copy and pasted to 'asciprog' and then run it will recreate 'dosprog' to STDOUT i.e.
asciprog>dosprog.com
On Mon, 13 Feb 2023 22:31:01 +0000
"Kerr-Mudd, John" <admin@127.0.0.1> wrote:
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.
As they are just variations on a theme, the same restriction applies:
max com file input size is c.50k. (one read, one write)
Seems I failed to xpost this back in mid-Feb.
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?+,
fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZsX2YVQH
.+HWM4LVC4qsv9[T}uqrxB`h3HS(iNkBgUa,2bfa'Yfx0bVQ$W-N*$')=0i
EsLo$7E1_dORw$Mt`cNhc93c_get+f\YtWI,@;yVnT[jd=`*nGHUS)t/39(
W`ST7T;)K(?j'?/:u1:e`4r(rTZII0$$o6DI$(bI$$))7$$[v:I)zKNqgwJ
ID@a~-P;?}fF[dC3:CQwk9bqei2[pHR2[pHR@zd6:96}tJ)9`RMDsTh=N;P
4g_c'icT(vo7blJ:}btejaUFXW8@`Voq$W5O$$)HhXt5HK_AQ}-bHn{290K
(H,HYn9aHn~4@Mgsk(0Ca;@=6,QOBN\6oIsHQRMCN37GUe[2MCN96KPrz4H
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?+,
fkOU):G*@Crv,*t$HU[rlf~#IubfRfXf(V#fj}fX4{PY$@fPfZsZsX1yDQH
.+4WM4LVC4qsv9[T}ul-6JMbG_ZniNkBgUa,2bfa'Yfx0bVQzrj?($$f)_i
EsLo$5KrLdORw$sklui$U[E+_ht`PdRBBfcgBgXFKY1uR6aty5oWwh(29nF
fIa:r(QJ6h`g-L6$/2`J'pD\:lW:E;Ba5_x'oYoe9D\Q@9@2GS9@2G39@2F
k9@2Fi9@2FR__9'lei+i\*JkJ'ne+yD'Y6WH1P'm-$a7nHl90uQ*ROVHj{?
_`{)z*t0rLendO756$rgsRBM[r@8h?iVJpcR-GxxRsM.}w+Irs[zH[Kx5*8
Xk@BNwxr0FLJzHZk,uKn@gFI:-n}0L.FLKm$bz)9\X_GDBnPNz?L(6oUxkD
J9uI6m+tx2wVVJ=V\Kp?9N)}2yu.a=V]pBC-?XEG${TN46_yUJT$vg8cv,.
;\80s3W1ihCJmI_Hw.RtMd/o1HtC:TCcgXfPB8GDOZmqA:\@R4E*\[Je8?I
b/}H?V0rL@bc4_`\$)[[d#
when 'asciprog.txt' is copy and pasted to 'asciprog' and then run it will
recreate 'dosprog' to STDOUT i.e.
asciprog>dosprog.com
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.
Kerr-Mudd, John wrote:
On Mon, 13 Feb 2023 22:31:01 +0000
"Kerr-Mudd, John" <admin@127.0.0.1> wrote:
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.
As they are just variations on a theme, the same restriction applies:
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. :-)
[]
1) Program to convert a DOS COM file to ASCII executable;
[]
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
(Doesn't work under XP, but works with std dos .COM startup values)I have since created a hex executer in a similar vein
On Sun, 26 Feb 2023 20:33:41 +0100
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
Hope you found it works OK your end.
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
Laura used 5:4 encoding which requires 85 ASCII codes.
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!
On Sun, 26 Feb 2023 20:33:41 +0100
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
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!
[]
[]
1) Program to convert a DOS COM file to ASCII executable;
[]
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
3)
(Doesn't work under XP, but works with std dos .COM startup values)I have since created a hex executer in a similar vein
On Sun, 26 Feb 2023 21:03:01 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sun, 26 Feb 2023 20:33:41 +0100.
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
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!
[]
[]
1) Program to convert a DOS COM file to ASCII executable;
[]
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
3)
(Doesn't work under XP, but works with std dos .COM startup values)I have since created a hex executer in a similar vein
Update: Now in pure ASCII!
PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5 q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5 5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
(Last line is the payload, you can probably read it yourself - it's "Hello World""
On Sun, 26 Feb 2023 21:03:01 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sun, 26 Feb 2023 20:33:41 +0100.
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
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!
[]
[]
1) Program to convert a DOS COM file to ASCII executable;
[]
2) Program to create an ASCII text program which can then be
run to recreate a DOS binary program.
3)
(Doesn't work under XP, but works with std dos .COM startup values)I have since created a hex executer in a similar vein
Update: Now in pure ASCII!
PVSh7ZSSVVX4uPPaH5BF0f90fD0fH0fO0FF0Fq1FR4d0FQ0FT1Fm5 q4z0r06666666bOi7cop2VGtC28hVsPY65cr5MJ5205235MJ520523uzZuz5 5789F981E99301B85EF3ABB8A458ABB0E9AAB8FE002BC7AB58BF0001FFD0
B409BA0801CD21C348656C6C6F20776F726C642124Z
(Last line is the payload, you can probably read it yourself - it's "Hello World""
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?
On 3/4/2023 3:56 AM, Kerr-Mudd, John wrote:[]
On Sun, 26 Feb 2023 21:03:01 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sun, 26 Feb 2023 20:33:41 +0100.
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
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.
[]I have since created a hex executer in a similar vein
I meant 'Alphanum'.Update: Now in pure ASCII!
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.
On Sat, 4 Mar 2023 05:36:03 +0800
Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
wrote:
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.
On Sat, 4 Mar 2023 10:44:44 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sat, 4 Mar 2023 05:36:03 +0800
Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
wrote:
[alphanum hex decode & run program]
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 fixupsBigger, but needs another line; now registers on entering the
into invalid alphanums. - might be doable with some more thought.
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
Kerr-Mudd, John wrote:
On Sat, 4 Mar 2023 10:44:44 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sat, 4 Mar 2023 05:36:03 +0800
Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
wrote:
[alphanum hex decode & run program]
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 notBigger, but needs another line; now registers on entering the
an Alphanum, and to push individually makes the distances to the fixups
into invalid alphanums. - might be doable with some more thought.
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;; set dx=0
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;; set cx=0
pop cx
org 103h
push cx??CX=0100
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;; cx pshurely?
push dx ; SP (ignored)
push dx ; BP = 0000
push dx
pop axI dont see this - dx was 0?
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:; I can only use dh
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"
On Sun, 5 Mar 2023 14:45:40 +0100
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
Kerr-Mudd, John wrote:NB this means the following requires/assumes si=0x100 at start.
On Sat, 4 Mar 2023 10:44:44 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sat, 4 Mar 2023 05:36:03 +0800
Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
wrote:
[alphanum hex decode & run program]
Bigger, but needs another line; now registers on entering the
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.
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!
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.
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.
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.
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
The secondary bootstrap contains the shortes possible MIME decoder I;; set dx=0
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;; set cx=0
pop cx
org 103h
;?
??CX=0100
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;; cx pshurely?
push dx ; SP (ignored)
push dx ; BP = 0000
push dx
pop axI dont see this - dx was 0?
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
I like that you've considered changes to eol ; I've not done that this
time.
top:; I can only use dh
inc si
xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
push cxdoh so much simpler than my byte toggle!
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"
If you've got the room for LUT, sure!
On Sun, 5 Mar 2023 14:45:40 +0100
Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:
Kerr-Mudd, John wrote:
On Sat, 4 Mar 2023 10:44:44 +0000
"Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:
On Sat, 4 Mar 2023 05:36:03 +0800
Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
wrote:
[alphanum hex decode & run program]
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 notBigger, but needs another line; now registers on entering the
an Alphanum, and to push individually makes the distances to the fixups >> into invalid alphanums. - might be doable with some more thought.
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.
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.
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.
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 493 |
Nodes: | 16 (2 / 14) |
Uptime: | 13:57:15 |
Calls: | 9,711 |
Calls today: | 1 |
Files: | 13,740 |
Messages: | 6,181,696 |