Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ecm new exeflat format #78

Merged
merged 12 commits into from
May 30, 2022
Merged

Conversation

ecm-pushbx
Copy link
Contributor

Copying the commit message of the first commit in this PR:

This format has several advantages:

  • The CONFIG block need not be moved.

  • The entire compressed image (depacker and payload) need not be moved another time before the UPX depacker's own operation.

  • The CONFIG block always lives at 00602h, and the kernel need not be aware whether it was compressed for detecting which CONFIG block to use.

  • Support for compressed images beyond 64 KiB for free. (The assembly define TEST_FILL_INIT_TEXT can be passed in NASMENV to test this support with 32 KiB of LFSR output.)

  • A subsequent commit will shorten the stub to 64 bytes, compared to the prior 32 + 45 = 77 bytes, with no loss of features. (The packed payload is a bit shorter too.) (PR: This commit is included in the PR.)

  • The new stub also sets ds and es to the segment value that would point to the DOS/EXE process's PSP. This is apparently not used by the UPX depacker but could be in a future or past version, or if another packer is used.

Additional PR comments: There are more commits that add DOS/SYS format compression, as well as the ability to force DOS/SYS or DOS/EXE format compression by omitting the other format's entry file switch to exeflat. The new entry header stub can be assembled into anything between 32 and 192 bytes, exeflat need not be modified to allow longer entry files (up to 192 bytes).

This format has several advantages:

* The CONFIG block need not be moved.

* The entire compressed image (depacker and payload) need
not be moved another time before the UPX depacker's own
operation.

* The CONFIG block always lives at 00602h, and the kernel
need not be aware whether it was compressed for detecting
which CONFIG block to use.

* Support for compressed images beyond 64 KiB for free.
(The assembly define TEST_FILL_INIT_TEXT can be passed in
NASMENV to test this support with 32 KiB of LFSR output.)

* A subsequent commit will shorten the stub to 64 bytes,
compared to the prior 32 + 45 = 77 bytes, with no loss
of features. (The packed payload is a bit shorter too.)

* The new stub also sets ds and es to the segment value
that would point to the DOS/EXE process's PSP. This is
apparently not used by the UPX depacker but could be in
a future or past version, or if another packer is used.
The code still allows for up to 192 bytes, should that
be useful. Simply by re-assembling upxentry.asm then
re-running exeflat, the changes will be picked up.
@ecm-pushbx
Copy link
Contributor Author

Tested building and running the kernel with XUPX= (empty string), XUPX='upx --8086 --best' (DOS/EXE compression), XUPX=true (no compression but pretend we're compressed), as well as with the CI build KGC8632 and KWC8632.

Also tested DOS/SYS and forced DOS/EXE compression with my test payload wrapped in kernshim.asm. Note that the kernel command line is not properly passed because testpl expects it in a LOADCMDLINE structure on the stack, differing from the lsvCommandLine buffer used by the FreeDOS load protocol extension, plus testpl does not use the stack address stored by the DOS/EXE entry header stub into the help data. This is an example of the set of commands used to build and pack a test executable:

nasm -D_PADDING=4096 -D_LARGE=0 -I ../lmacros/ ../ldosboot/testpl.asm -o testpl.bin -l testpl.lst
nasm ../ldosboot/kernshim.asm -I ../lmacros/ -D_FILE="'testpl.bin'" -o test2.exe -l test2.lst
utils/exeflat.exe test2.exe test2.sys 0x60 -Dutils/upxdevic.bin -Eutils/upxentry.bin -U upx --8086 --best

@ecm-pushbx
Copy link
Contributor Author

  • Support for compressed images beyond 64 KiB for free. (The assembly define TEST_FILL_INIT_TEXT can be passed in NASMENV to test this support with 32 KiB of LFSR output.)

Here is an lDebug script I made for checking the LFSR data: https://pushbx.org/ecm/test/20220525.sld (Needs yesterday's or newer lDebug with the LFSR variables.)

r v0 := cs
r vc := 8000 / 4
r rclimit := vc * 100
rc.replace r v1 := 0; r v2 := 1; r lfsr := v2; @:loop
rc.append @if (dword [v0:v1] != v2) then goto :end; @r v2 := lfsr; @r v1 +:= 4
rc.append @r vc -:= 1; @if (vc) then goto :loop; \; All match; @goto :eof
rc.append @:end; \; Mismatch found

Using it requires a little setup.

Build the kernel with the define enabled: rm kernel/kernel.exe kernel/kernel.obj; NASMENV=-DTEST_FILL_INIT_TEXT make all COMPILER=gcc XUPX='upx --8086 --best' && dosemu -K bin -E "sys config kernel.sys skipconfigseconds=-1 checkdebugger=1" -dumb -quiet

Get the lDebug release, build a boot image with it and the kernel:

nasm ../../ldebug/misc/quit.asm -o quit.com
echo -ne ':bootstartup\nr dco or= 4000\nboot protocol freedos\nr\n' > ldebug.sld
echo -ne 'shell=quit.com\r\n' > fdconfig.sys
wget -c https://pushbx.org/ecm/test/20220525.sld
wget -c https://pushbx.org/ecm/download/ldebug.zip
unzip -j -o ldebug.zip bin/ldebug.com
nasm -I ../../lmacros/ ../../ldosboot/boot.asm -D_LOAD_NAME="'LDEBUG'" -D_COMPAT_LDOS=1 -o boot.bin
nasm -I ../../lmacros/ ../../bootimg/bootimg.asm -D_PAYLOADFILE="'ldebug.com','ldebug.sld','../../eftest/bin/kernel.sys','fdconfig.sys','quit.com','20220525.sld'" -D_BOOTFILE="'boot.bin'" -o diskette.img
qemu-system-i386 -fda diskette.img -boot order=a -curses -chardev serial,id=serial2,path=/tmp/vptty-dos -serial null -serial chardev:serial2

The entire log of this debugging session is contained in https://pushbx.org/ecm/test/20220526/trace.log

Here is just the interesting part:

AX=1864 BX=025C CX=0000 DX=1739 SP=1006 BP=0064 SI=5B94 DI=3308
DS=0060 ES=0054 SS=1CF2 CS=0060 IP=00D0 NV UP EI PL NZ NA PO NC
0060:00D0 EA0080250E        jmp     0E25:8000
-
AX=1864 BX=025C CX=0000 DX=1739 SP=1006 BP=0064 SI=5B94 DI=3308
DS=0060 ES=0054 SS=1CF2 CS=0E25 IP=8000 NV UP EI PL NZ NA PO NC
0E25:8000 FC                cld
-y 20220525.sld
-r v0 := cs
-r vc := 8000 / 4
-r rclimit := vc * 100
-rc.replace r v1 := 0; r v2 := 1; r lfsr := v2; @:loop
-rc.append @if (dword [v0:v1] != v2) then goto :end; @r v2 := lfsr; @r v1 +:= 4
-rc.append @r vc -:= 1; @if (vc) then goto :loop; \; All match; @goto :eof
-rc.append @:end; \; Mismatch found
-rc
&r v1 := 0
&r v2 := 1
&r lfsr := v2
&; All match
-

@ecm-pushbx
Copy link
Contributor Author

Finally here is an alternative solution that I explored this week: https://pushbx.org/ecm/test/20220526/fdkernel-big-stub.txt

It would require some way to split the compressed image into two parts, which could have been done by exeflat or using commands like dd if=kernel.bin of=lead.bin bs=1 count=48 and dd if=kernel.bin of=trail.bin bs=1 skip=48. And it would still use the UPX help data at 005E0h with the load unit, CONFIG block, and original stack pointer.

@PerditionC
Copy link
Contributor

This is looking nice. I haven't had a chance to try yet, just reading through it.

@ecm-pushbx
Copy link
Contributor Author

Fixed a comment error in the DOS/SYS device header writer, and there is an error in the PR's message:

The new entry header stub can be assembled into anything between 32 and 192 bytes, exeflat need not be modified to allow longer entry files (up to 192 bytes).

Only the DOS/EXE entry is allowed up to 192 bytes. The DOS/SYS entry is allowed up to 176 bytes, as the device header takes up 16 bytes in the layout of the decompressed kernel, and the entry stub plus the header may take up up to 192 bytes.

@ecm-pushbx
Copy link
Contributor Author

Added another commit as I noticed the CI build log listed the UPX output first, before the part of the exeflat output that happened before calling UPX. This is a screenshot showing the problem:

Screenshot_20220527-213504

Source: https://github.com/FDOS/kernel/runs/6630701821?check_suite_focus=true

Appears to be fixed in https://github.com/FDOS/kernel/runs/6630955128?check_suite_focus=true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants