From 1f02844bd2901c9023e6cd1aeb3d0ea5fe6f88cb Mon Sep 17 00:00:00 2001 From: Dimitris Panokostas Date: Wed, 8 Nov 2023 16:46:22 +0100 Subject: [PATCH] enhancement: Improved DMS support Check DMS input buffer under/overflow. Improved encrypted DMS support, some DMS files decode correctly (valid CRC) with more than 1 key but only 1 key returns correct data. --- src/archivers/dms/pfile.cpp | 64 +++++++++++++++++++++------------- src/archivers/dms/u_deep.cpp | 38 ++++++-------------- src/archivers/dms/u_deep.h | 2 +- src/archivers/dms/u_heavy.cpp | 44 +++++++++-------------- src/archivers/dms/u_heavy.h | 2 +- src/archivers/dms/u_medium.cpp | 15 +++----- src/archivers/dms/u_medium.h | 2 +- src/archivers/dms/u_quick.cpp | 12 +++---- src/archivers/dms/u_quick.h | 2 +- src/archivers/dms/u_rle.cpp | 9 +++-- src/archivers/dms/u_rle.h | 2 +- 11 files changed, 87 insertions(+), 105 deletions(-) diff --git a/src/archivers/dms/pfile.cpp b/src/archivers/dms/pfile.cpp index b28f7b3b9..f3e8706ba 100644 --- a/src/archivers/dms/pfile.cpp +++ b/src/archivers/dms/pfile.cpp @@ -399,7 +399,7 @@ static USHORT Process_Track(struct zfile *fi, struct zfile *fo, UCHAR *b1, UCHAR -static USHORT Unpack_Track_2(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, UCHAR cmode, UCHAR flags){ +static USHORT Unpack_Track_2(UCHAR *b1, UCHAR *b2, USHORT pklen1, USHORT pklen2, USHORT unpklen, UCHAR cmode, UCHAR flags){ switch (cmode){ case 0: /* No Compression */ @@ -407,24 +407,24 @@ static USHORT Unpack_Track_2(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen break; case 1: /* Simple Compression */ - if (Unpack_RLE(b1,b2,unpklen)) return ERR_BADDECR; + if (Unpack_RLE(b1,b2, pklen1,unpklen)) return ERR_BADDECR; break; case 2: /* Quick Compression */ - if (Unpack_QUICK(b1,b2,pklen2)) return ERR_BADDECR; - if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR; + if (Unpack_QUICK(b1,b2,pklen1,pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2,b1,pklen2,unpklen)) return ERR_BADDECR; memcpy(b2,b1,(size_t)unpklen); break; case 3: /* Medium Compression */ - if (Unpack_MEDIUM(b1,b2,pklen2)) return ERR_BADDECR; - if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR; + if (Unpack_MEDIUM(b1,b2,pklen1,pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2,b1,pklen2,unpklen)) return ERR_BADDECR; memcpy(b2,b1,(size_t)unpklen); break; case 4: /* Deep Compression */ - if (Unpack_DEEP(b1,b2,pklen2)) return ERR_BADDECR; - if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR; + if (Unpack_DEEP(b1,b2,pklen1,pklen2)) return ERR_BADDECR; + if (Unpack_RLE(b2,b1,pklen2,unpklen)) return ERR_BADDECR; memcpy(b2,b1,(size_t)unpklen); break; case 5: @@ -432,15 +432,15 @@ static USHORT Unpack_Track_2(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen /* Heavy Compression */ if (cmode==5) { /* Heavy 1 */ - if (Unpack_HEAVY(b1,b2,flags & 7,pklen2)) return ERR_BADDECR; + if (Unpack_HEAVY(b1,b2,flags & 7,pklen1,pklen2)) return ERR_BADDECR; } else { /* Heavy 2 */ - if (Unpack_HEAVY(b1,b2,flags | 8,pklen2)) return ERR_BADDECR; + if (Unpack_HEAVY(b1,b2,flags | 8,pklen1,pklen2)) return ERR_BADDECR; } if (flags & 4) { memset(b1,0,unpklen); /* Unpack with RLE only if this flag is set */ - if (Unpack_RLE(b2,b1,unpklen)) return ERR_BADDECR; + if (Unpack_RLE(b2,b1,pklen2,unpklen)) return ERR_BADDECR; memcpy(b2,b1,(size_t)unpklen); } break; @@ -471,13 +471,14 @@ static USHORT Unpack_Track(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, static USHORT pass; int maybeencrypted; int pwrounds; - UCHAR *tmp; - USHORT prevpass = 0; + int firstpass = -1; + UCHAR *tmp, *tmp_dms_text; + USHORT prevpass = pass; if (passfound) { if (number != 80) dms_decrypt(b1, pklen1, b1); - r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); + r = Unpack_Track_2(b1, b2, pklen1, pklen2, unpklen, cmode, flags); if (r == NO_PROBLEM) { if (usum1 == dms_Calc_CheckSum(b2,(ULONG)unpklen)) return NO_PROBLEM; @@ -490,19 +491,27 @@ static USHORT Unpack_Track(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, passretries--; pwrounds = 0; maybeencrypted = 0; - tmp = (unsigned char*)malloc (pklen1); + tmp = xmalloc(UCHAR, pklen1); + tmp_dms_text = xmalloc(UCHAR, 0x3fc8); memcpy (tmp, b1, pklen1); memset(b2, 0, unpklen); + memcpy(tmp_dms_text, dms_text, 0x3fc8); for (;;) { - r = Unpack_Track_2(b1, b2, pklen2, unpklen, cmode, flags); + r = Unpack_Track_2(b1, b2, pklen1, pklen2, unpklen, cmode, flags); if (r == NO_PROBLEM) { if (usum1 == dms_Calc_CheckSum(b2,(ULONG)unpklen)) { passfound = maybeencrypted; if (passfound) write_log (_T("DMS: decryption key = 0x%04X\n"), prevpass); - err = NO_PROBLEM; - pass = prevpass; - break; + // if bootblock does not have "DOS", check other keys too + if (number > 0 || firstpass == pass || (b2[0] == 'D' && b2[1] == 'O' && b2[2] == 'S')) { + err = NO_PROBLEM; + pass = prevpass; + break; + } + if (firstpass < 0) { + firstpass = pass; + } } } if (number == 80 || !enc) { @@ -515,13 +524,20 @@ static USHORT Unpack_Track(UCHAR *b1, UCHAR *b2, USHORT pklen2, USHORT unpklen, pass++; dms_decrypt(b1, pklen1, tmp); pwrounds++; - if (pwrounds == 65536) { - err = ERR_CSUM; - passfound = 0; - break; + if (pwrounds >= 65536) { + if (firstpass < 0) { + err = ERR_CSUM; + passfound = 0; + break; + } + pass = firstpass; + PWDCRC = pass; + dms_decrypt(b1, pklen1, tmp); } + memcpy(dms_text, tmp_dms_text, 0x3fc8); } - free (tmp); + xfree(tmp_dms_text); + xfree(tmp); return err; } diff --git a/src/archivers/dms/u_deep.cpp b/src/archivers/dms/u_deep.cpp index 95245f89b..307961271 100644 --- a/src/archivers/dms/u_deep.cpp +++ b/src/archivers/dms/u_deep.cpp @@ -16,18 +16,14 @@ #include "u_deep.h" #include "getbits.h" - -INLINE USHORT DecodeChar(void); -INLINE USHORT DecodePosition(void); -INLINE void update(USHORT c); +static USHORT DecodeChar(void); +static USHORT DecodePosition(void); +static void update(USHORT c); static void reconst(void); - USHORT dms_deep_text_loc; int dms_init_deep_tabs=1; - - #define DBITMASK 0x3fff /* uses 16Kb dictionary */ #define F 60 /* lookahead buffer size */ @@ -37,7 +33,6 @@ int dms_init_deep_tabs=1; #define R (T - 1) /* position of root */ #define MAX_FREQ 0x8000 /* updates tree when the */ - static USHORT freq[T + 1]; /* frequency table */ static USHORT prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ @@ -46,8 +41,6 @@ static USHORT prnt[T + N_CHAR]; /* pointers to parent nodes, except for the */ static USHORT son[T]; /* pointers to child nodes (son[], son[] + 1) */ - - static void Init_DEEP_Tabs(void){ USHORT i, j; @@ -69,9 +62,7 @@ static void Init_DEEP_Tabs(void){ dms_init_deep_tabs = 0; } - - -USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT origsize){ +USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT pklen1, USHORT origsize){ USHORT i, j, c; UCHAR *outend; @@ -93,12 +84,13 @@ USHORT Unpack_DEEP(UCHAR *in, UCHAR *out, USHORT origsize){ dms_deep_text_loc = (USHORT)((dms_deep_text_loc+60) & DBITMASK); - return 0; -} - + in += pklen1; + if (dms_indata == in + 2 || dms_indata == in + 1 || dms_indata == in + 0) return 0; + return 1; +} -INLINE USHORT DecodeChar(void){ +static USHORT DecodeChar(void){ USHORT c; c = son[R]; @@ -115,9 +107,7 @@ INLINE USHORT DecodeChar(void){ return c; } - - -INLINE USHORT DecodePosition(void){ +static USHORT DecodePosition(void){ USHORT i, j, c; i = GETBITS(8); DROPBITS(8); @@ -128,8 +118,6 @@ INLINE USHORT DecodePosition(void){ return (USHORT) (c | i) ; } - - /* reconstruction of tree */ static void reconst(void){ @@ -167,11 +155,9 @@ static void reconst(void){ } } - - /* increment frequency of given code by one, and update tree */ -INLINE void update(USHORT c){ +static void update(USHORT c){ USHORT i, j, k, l; if (freq[R] == MAX_FREQ) { @@ -203,5 +189,3 @@ INLINE void update(USHORT c){ } } while ((c = prnt[c]) != 0); /* repeat up to root */ } - - diff --git a/src/archivers/dms/u_deep.h b/src/archivers/dms/u_deep.h index ae542ee9a..211640541 100644 --- a/src/archivers/dms/u_deep.h +++ b/src/archivers/dms/u_deep.h @@ -1,6 +1,6 @@ -USHORT Unpack_DEEP(UCHAR *, UCHAR *, USHORT); +USHORT Unpack_DEEP(UCHAR *, UCHAR *, USHORT, USHORT); extern int dms_init_deep_tabs; extern USHORT dms_deep_text_loc; diff --git a/src/archivers/dms/u_heavy.cpp b/src/archivers/dms/u_heavy.cpp index 59812ec39..9ebae455a 100644 --- a/src/archivers/dms/u_heavy.cpp +++ b/src/archivers/dms/u_heavy.cpp @@ -1,21 +1,19 @@ /* - * xDMS v1.3 - Portable DMS archive unpacker - Public Domain - * Written by Andre Rodrigues de la Rocha - * - * Lempel-Ziv-Huffman decompression functions used in Heavy 1 & 2 - * compression modes. Based on LZH decompression functions from - * UNIX LHA made by Masaru Oki - * - */ - +* xDMS v1.3 - Portable DMS archive unpacker - Public Domain +* Written by Andre Rodrigues de la Rocha +* +* Lempel-Ziv-Huffman decompression functions used in Heavy 1 & 2 +* compression modes. Based on LZH decompression functions from +* UNIX LHA made by Masaru Oki +* +*/ #include "cdata.h" #include "u_heavy.h" #include "getbits.h" #include "maketbl.h" - #define NC 510 #define NPT 20 #define N1 510 @@ -27,15 +25,12 @@ static USHORT c_table[4096], pt_table[256]; USHORT dms_lastlen, dms_np; USHORT dms_heavy_text_loc; - static USHORT read_tree_c(void); static USHORT read_tree_p(void); -INLINE USHORT decode_c(void); -INLINE USHORT decode_p(void); - +static USHORT decode_c(void); +static USHORT decode_p(void); - -USHORT Unpack_HEAVY(UCHAR *in, UCHAR *out, UCHAR flags, USHORT origsize){ +USHORT Unpack_HEAVY(UCHAR *in, UCHAR *out, UCHAR flags, USHORT pklen1, USHORT origsize){ USHORT j, i, c, bitmask; UCHAR *outend; @@ -69,12 +64,13 @@ USHORT Unpack_HEAVY(UCHAR *in, UCHAR *out, UCHAR flags, USHORT origsize){ } } - return 0; -} - + in += pklen1; + if (dms_indata == in + 2 || dms_indata == in + 1 || dms_indata == in + 0) return 0; + return 1; +} -INLINE USHORT decode_c(void){ +static USHORT decode_c(void){ USHORT i, j, m; j = c_table[GETBITS(12)]; @@ -94,9 +90,7 @@ INLINE USHORT decode_c(void){ return j; } - - -INLINE USHORT decode_p(void){ +static USHORT decode_p(void){ USHORT i, j, m; j = pt_table[GETBITS(8)]; @@ -126,8 +120,6 @@ INLINE USHORT decode_p(void){ } - - static USHORT read_tree_c(void){ USHORT i,n; @@ -149,8 +141,6 @@ static USHORT read_tree_c(void){ return 0; } - - static USHORT read_tree_p(void){ USHORT i,n; diff --git a/src/archivers/dms/u_heavy.h b/src/archivers/dms/u_heavy.h index 80f1be839..243ee1cbf 100644 --- a/src/archivers/dms/u_heavy.h +++ b/src/archivers/dms/u_heavy.h @@ -1,6 +1,6 @@ -USHORT Unpack_HEAVY(UCHAR *, UCHAR *, UCHAR, USHORT); +USHORT Unpack_HEAVY(UCHAR *, UCHAR *, UCHAR, USHORT, USHORT); extern USHORT dms_heavy_text_loc; diff --git a/src/archivers/dms/u_medium.cpp b/src/archivers/dms/u_medium.cpp index e0a771c17..8cefd20a5 100644 --- a/src/archivers/dms/u_medium.cpp +++ b/src/archivers/dms/u_medium.cpp @@ -7,7 +7,6 @@ * */ - #include #include "cdata.h" @@ -15,19 +14,14 @@ #include "getbits.h" #include "tables.h" - #define MBITMASK 0x3fff - USHORT dms_medium_text_loc; - - -USHORT Unpack_MEDIUM(UCHAR *in, UCHAR *out, USHORT origsize){ +USHORT Unpack_MEDIUM(UCHAR *in, UCHAR *out, USHORT pklen1, USHORT origsize){ USHORT i, j, c; UCHAR u, *outend; - initbitbuf(in); outend = out+origsize; @@ -52,7 +46,8 @@ USHORT Unpack_MEDIUM(UCHAR *in, UCHAR *out, USHORT origsize){ } dms_medium_text_loc = (USHORT)((dms_medium_text_loc+66) & MBITMASK); - return 0; -} - + in += pklen1; + if (dms_indata == in + 2 || dms_indata == in + 1 || dms_indata == in + 0) return 0; + return 1; +} diff --git a/src/archivers/dms/u_medium.h b/src/archivers/dms/u_medium.h index 18c0ce859..9e8aac1e3 100644 --- a/src/archivers/dms/u_medium.h +++ b/src/archivers/dms/u_medium.h @@ -1,5 +1,5 @@ -USHORT Unpack_MEDIUM(UCHAR *, UCHAR *, USHORT); +USHORT Unpack_MEDIUM(UCHAR *, UCHAR *, USHORT, USHORT); extern USHORT dms_medium_text_loc; diff --git a/src/archivers/dms/u_quick.cpp b/src/archivers/dms/u_quick.cpp index 1cc08ccca..e8e782bc9 100644 --- a/src/archivers/dms/u_quick.cpp +++ b/src/archivers/dms/u_quick.cpp @@ -6,21 +6,17 @@ * */ - #include #include "cdata.h" #include "u_quick.h" #include "getbits.h" - #define QBITMASK 0xff - USHORT dms_quick_text_loc; - -USHORT Unpack_QUICK(UCHAR *in, UCHAR *out, USHORT origsize){ +USHORT Unpack_QUICK(UCHAR *in, UCHAR *out, USHORT pklen1, USHORT origsize){ USHORT i, j; UCHAR *outend; @@ -42,6 +38,8 @@ USHORT Unpack_QUICK(UCHAR *in, UCHAR *out, USHORT origsize){ } dms_quick_text_loc = (USHORT)((dms_quick_text_loc+5) & QBITMASK); - return 0; -} + in += pklen1; + if (dms_indata == in + 2 || dms_indata == in + 1 || dms_indata == in + 0) return 0; + return 1; +} diff --git a/src/archivers/dms/u_quick.h b/src/archivers/dms/u_quick.h index 2cfdf4afc..7397e0d61 100644 --- a/src/archivers/dms/u_quick.h +++ b/src/archivers/dms/u_quick.h @@ -1,5 +1,5 @@ -USHORT Unpack_QUICK(UCHAR *, UCHAR *, USHORT); +USHORT Unpack_QUICK(UCHAR *, UCHAR *, USHORT, USHORT); extern USHORT dms_quick_text_loc; diff --git a/src/archivers/dms/u_rle.cpp b/src/archivers/dms/u_rle.cpp index ff46c561e..ac53f5559 100644 --- a/src/archivers/dms/u_rle.cpp +++ b/src/archivers/dms/u_rle.cpp @@ -12,11 +12,10 @@ #include "cdata.h" #include "u_rle.h" - - -USHORT Unpack_RLE(UCHAR *in, UCHAR *out, USHORT origsize){ +USHORT Unpack_RLE(UCHAR *in, UCHAR *out, USHORT pklen1, USHORT origsize){ USHORT n; UCHAR a,b, *outend; + UCHAR *inp = in + pklen1; outend = out+origsize; while (out inp) return 1; if (b == 0xff) { n = *in++; n = (USHORT)((n<<8) + *in++); @@ -36,7 +36,6 @@ USHORT Unpack_RLE(UCHAR *in, UCHAR *out, USHORT origsize){ out += n; } } + return 0; } - - diff --git a/src/archivers/dms/u_rle.h b/src/archivers/dms/u_rle.h index 0cf24938a..2aa830545 100644 --- a/src/archivers/dms/u_rle.h +++ b/src/archivers/dms/u_rle.h @@ -1,3 +1,3 @@ -USHORT Unpack_RLE(UCHAR *, UCHAR *, USHORT); +USHORT Unpack_RLE(UCHAR *, UCHAR *, USHORT, USHORT);