• Re: CM3 revisited

    From Kerr-Mudd, John@21:1/5 to John" on Sun Feb 26 12:17:25 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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)

    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


    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to John on Sun Feb 26 20:33:41 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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. :-)

    Terje


    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


    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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to Terje Mathisen on Sun Feb 26 21:03:01 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    On Sun, 26 Feb 2023 20:33:41 +0100
    Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:

    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!

    Hope you found it works OK your end.

    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!


    []

    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)
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to John on Mon Feb 27 10:47:49 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    Kerr-Mudd, John wrote:
    On Sun, 26 Feb 2023 20:33:41 +0100
    Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:

    I love this stuff!

    Hope you found it works OK your end.

    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. :-)


    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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to John" on Fri Mar 3 19:56:45 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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)
    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Johann 'Myrkraverk' Oskarsson@21:1/5 to John on Sat Mar 4 05:36:03 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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.


    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)
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to John on Fri Mar 3 22:38:25 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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

    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.


    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)
    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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to Terje Mathisen on Sat Mar 4 10:46:30 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    On Fri, 3 Mar 2023 22:38:25 +0100
    Terje Mathisen <terje.mathisen@nospicedham.tmsw.no> wrote:

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to All on Sat Mar 4 10:44:44 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    On Sat, 4 Mar 2023 05:36:03 +0800
    Johann 'Myrkraverk' Oskarsson <johann@nospicedham.myrkraverk.invalid>
    wrote:

    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
    []

    Update: Now in pure ASCII!
    I meant 'Alphanum'.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to John" on Sat Mar 4 17:06:49 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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 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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to John on Sun Mar 5 14:45:40 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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 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"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to Terje Mathisen on Sun Mar 5 16:29:19 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    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 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.

    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.


    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.

    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
    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
    ;; set dx=0
    push dx
    pop cx
    ;; set cx=0

    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
    ??CX=0100
    push cx ; BX

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

    push dx
    ;; cx pshurely?

    pop ax
    I 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:
    inc si
    xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
    ; I can only use dh
    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!

    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!

    --
    Bah, and indeed Humbug.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Terje Mathisen@21:1/5 to John on Mon Mar 6 11:35:01 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    Nice if you to actually read the code, I did notice that the comments
    had several errors, probably leftovers from previous attempts. :-)

    Terje

    Kerr-Mudd, John wrote:
    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 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.

    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.


    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.

    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
    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
    ;; set dx=0
    push dx
    pop cx
    ;; set cx=0

    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
    ??CX=0100
    push cx ; BX

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

    push dx
    ;; cx pshurely?

    pop ax
    I 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:
    inc si
    xor ch,[si] ; CH is zero -> MOV CH,[SI+48]
    ; I can only use dh
    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!

    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!



    --
    - <Terje.Mathisen at tmsw.no>
    "almost all programming can be viewed as an exercise in caching"

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kerr-Mudd, John@21:1/5 to John" on Sat Mar 11 20:44:58 2023
    XPost: alt.lang.asm, comp.os.msdos.programmer

    On Sun, 5 Mar 2023 16:29:19 +0000
    "Kerr-Mudd, John" <admin@nospicedham.127.0.0.1> wrote:

    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 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.

    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.

    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.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)