ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[1.c]ÄÄ

//  Advanced ZCME
//  Permutating Engine Research

//  Copyright (C) 1997, 1998 Z0MBiE/29A
//
//  *** NOT FOR [RE]PUBLISHING/DISASM IN VX-ZINES, EXCEPT 29A ***

//  Internal version: 0.04
//  Last modified: 18-07-98

#include "params.h"

char ZERO_FILL_ARRAY[max_size-0x1300] = {0};

#include "system.h"
#include "crt.h"
#include "fileio.h"
#include "random.h"

#include "disasm.h"
#include "engine.h"

void main(void)
  {
    pchar p;

    #ifdef SKIP_PRINTF
    asm
__1:	lea	di, printf
	mov	al, 0xC3
	stosb
	lea	di, __1
	mov	cx, __2 - __1
	mov	al, 0x90
	rep	stosb
    end;
    #endif

    clrscr(3);
    asm
__2:end;

    printf("Startup code executed\n");

    run_engine();

    printf("Terminating\n");

    exit(0);
  }


ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[1.c]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[params.h]ÄÄ

/* DEBUG parameters */

#define SKIP_PRINTF
#define SKIP_DEBUGFILES

/* ENGINE parameters */

#define SKIP_JMPS
//#define SKIP_JMPS_BUT_ADD_NOPS

#define RANDOM_JCC
//#define INVERSE_JCC

#define SKIP_NOP
//#define SKIP_INT3

#define SKIP_RANDOM

#define ADD_RANDOM	 30
#define CHANGE_CMD

//#define FILL_UNUSED_CC
#define FILL_UNUSED_RANDOM

#define USE_RANDOM_IP	 20

#define min_left	 20
#define min_right	 40
#define min_right_left	 20

#define KILL_J2J
#define MAKE_SHORT_JMPS





#define max_size 0x3000+0x0100
#define max_cmd  3000
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[params.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[system.h]ÄÄ

#define make_ptr( seg,ofs ) ( (void _seg * )( seg ) +( void near * )( ofs ))
#define ptr_seg( fp )	    ( (unsigned )( void _seg * )( void far * )( fp ))
#define ptr_ofs( fp )	    ( (unsigned )( fp ))

typedef unsigned char	  byte;
typedef unsigned int	  word;
typedef unsigned long	  dword;

#define short		signed char
#define pchar		const far char *

#define MAX(a,b)	a > b ? a : b
#define MIN(a,b)	a < b ? a : b

#define asm		asm {
#define end		}

void exit(byte exitcode);
void fillchar(pchar buf, word bufsize, char filler);
void move(pchar src, pchar dest, word size);
word len(pchar str);

void beep(void)
  {
    asm
	mov	al, 7
	int	29h
    end;
  }

void exit(byte exitcode)
  {
    asm
	mov	al, exitcode
	add	al, '0'
	int	29h
	mov	ah, 4Ch
	mov	al, exitcode
	int	21h
    end;
  }

void fillchar(pchar buf, word bufsize, char filler)
  {
    asm
	mov	cx, bufsize
	or	cx, cx
	jz	__1
	les	di, buf
	mov	al, filler
	cld
	rep	stosb
__1:
    end;
  }

void move(pchar src, pchar dest, word size)
  {
    asm
	mov	cx, size
	or	cx, cx
	jz	__1
	push	ds
	lds	si, src
	les	di, dest
	cld
	rep	movsb
	pop	ds
__1:
    end;
  }

word len(pchar str)
  {
    asm
	les	di, str
	mov	cx, 0ffffh
	xor	al, al
	repnz	scasb
	neg	cx
	dec	cx
	dec	cx
	xchg	cx, ax
    end;
  }

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[system.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[crt.h]ÄÄ

void clrscr(byte mode);

void pascal printf_char(char c);
void pascal printf_dword(dword d);
void printf_word(word w);
void printf_byte(byte b);
void pascal printf_long(long l);
void printf_int(int i);
void printf_short(short s);
void pascal printf_hexchar(byte b);
void pascal printf_hexbyte(byte b);
void pascal printf_hexword(word w);
void pascal printf_hexdword(dword d);
void pascal printf_crlf(void);

void printf(pchar format, ...);



void clrscr(byte mode)
  {
    asm
	xor	ax, ax
	mov	al, mode
	int	10h
    end;
  }

void pascal printf_char(char c)
  {
    asm
	mov	ah, 2
	mov	dl, c
	int	21h
    end;
  }

void pascal printf_crlf(void)
  {
    printf_char(13);
    printf_char(10);
  }

void pascal printf_dword(dword d)
  {
    asm
	mov	eax, d
	call	__1
	jmp	__3
__1:	xor	edx, edx
	mov	ebx, 10
	div	ebx
	push	dx
	or	eax, eax
	jz	__2
	call	__1
__2:	pop	ax
	add	al, '0'
	push	ax
	call	printf_char
	ret
__3:
    end;
  }

void printf_word(word w)
  {
    printf_dword(w);
  }

void printf_byte(byte b)
  {
    printf_dword(b);
  }

void pascal printf_long(long l)
  {
    if (l < 0)
      {
	printf_char('-');
	l = -l;
      }
    printf_dword(l);
  }

void printf_int(int i)
  {
    printf_long(i);
  }

void printf_short(short s)
  {
    printf_long(s);
  }

void pascal printf_hexchar(byte b)
  {
    if (b <= 9)
      printf_char('0'+b);
    else
      printf_char('A'+b-10);
  }

void pascal printf_hexbyte(byte b)
  {
     printf_hexchar(b >> 4);
     printf_hexchar(b & 15);
  }

void pascal printf_hexword(word w)
  {
     printf_hexbyte(w >> 8);
     printf_hexbyte(w & 255);
  }

void pascal printf_hexdword(dword d)
  {
     printf_hexword(d >> 16);
     printf_hexword(d & 65535);
  }

void printf(pchar format, ...)
  {
    int stack_ptr = 0;
    asm
	push	ds
	lds	si, format
	cld

__nextchar:
	lodsb

	or	al, al
	jz	__exit

	cmp	al, '%'
	je	__percent

	cmp	al, 10
	je	__crlf

__putchar:
	push	ax
	call	printf_char

	jmp	__nextchar

__crlf: call	printf_crlf

	jmp	__nextchar

__percent:
	lodsb

	or	al, al
	jz	__exit

	cmp	al, 'c'
	je	__c
	cmp	al, 'i'
	je	__i
	cmp	al, 'l'
	je	__l
	cmp	al, 'b'
	je	__b
	cmp	al, 'w'
	je	__w
	cmp	al, 'd'
	je	__d
	cmp	al, 'B'
	je	__B_
	cmp	al, 'W'
	je	__W_
	cmp	al, 'D'
	je	__D_

	jmp	__putchar

__pop_ax:
	mov	di, stack_ptr
	add	word ptr stack_ptr, 2
	mov	ax, [bp+8+di]
	ret

__pop_eax:
	mov	di, stack_ptr
	add	word ptr stack_ptr, 4
	mov	eax, [bp+8+di]
	ret

__c:	call	__pop_ax
	push	ax
	call	printf_char

	jmp	__nextchar

__s:	call	__pop_ax
	push	ax
	call	printf_short

	jmp	__nextchar

__i:	call	__pop_ax
	push	ax
	call	printf_int

	jmp	__nextchar

__l:	call	__pop_eax
	push	eax
	call	printf_long

	jmp	__nextchar

__b:	call	__pop_ax
	push	ax
	call	printf_byte

	jmp	__nextchar

__w:	call	__pop_ax
	push	ax
	call	printf_word

	jmp	__nextchar

__d:	call	__pop_eax
	push	eax
	call	printf_dword

	jmp	__nextchar

__B_:	call	__pop_ax
	push	ax
	call	printf_hexbyte

	jmp	__nextchar

__W_:	call	__pop_ax
	push	ax
	call	printf_hexword

	jmp	__nextchar

__D_:	call	__pop_eax
	push	eax
	call	printf_hexdword

	jmp	__nextchar


__exit:
	pop	ds
    end;
  }
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[crt.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[fileio.h]ÄÄ

#define handle		word

handle openfile(pchar fname);
handle createfile(pchar fname);
void closefile(handle h);
word readfile(handle h, pchar buf, word bufsize);
word writefile(handle h, pchar buf, word bufsize);
dword filepos(handle h);
dword seekfile(handle h, dword newpos);
dword seekeof(handle h);
dword filesize(handle h);

handle openfile(pchar fname)
  {
    asm
	push	ds
	mov	ax, 3d02h
	lds	dx, fname
	int	21h
	pop	ds
    end;
  }

handle createfile(pchar fname)
  {
    asm
	push	ds
	mov	ah, 3Ch
	xor	cx, cx
	lds	dx, fname
	int	21h
	pop	ds
    end;
  }

void closefile(handle h)
  {
    asm
	mov	ah, 3Eh
	mov	bx, h
	int	21h
    end;
  }

word readfile(handle h, pchar buf, word bufsize)
  {
    asm
	push	ds
	mov	ah, 3Fh
	mov	bx, h
	mov	cx, bufsize
	lds	dx, buf
	int	21h
	pop	ds
    end;
  }

word writefile(handle h, pchar buf, word bufsize)
  {
    asm
	push	ds
	mov	ah, 40h
	mov	bx, h
	mov	cx, bufsize
	lds	dx, buf
	int	21h
	pop	ds
    end;
  }

dword filepos(handle h)
  {
    asm
	mov	ax, 4201h
	mov	bx, h
	int	21h
    end;
  }

dword seekfile(handle h, dword newpos)
  {
    asm
	mov	ax, 4200h
	mov	bx, h
	mov	cx, word ptr newpos + 2
	mov	dx, word ptr newpos + 0
	int	21h
    end;
  }

dword seekeof(handle h)
  {
    asm
	mov	ax, 4202h
	mov	bx, h
	xor	cx, cx
	cwd
	int	21h
    end;
  }

dword filesize(handle h)
  {
    dword savepos, retvalue;
    savepos = filepos(h);
    retvalue = seekeof(h);
    seekfile(h, savepos);
    return(retvalue);
  }

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[fileio.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[random.h]ÄÄ

int rndword;

word random_word(void);
word rnd_word(word range);
word rnd_word_minmax(word min, word max);

word random_word(void)
  {
    asm
	mov	bx, rndword
	in	al, 40h
	xor	bl, al
	in	al, 40h
	add	bh, al
	in	al, 41h
	sub	bl, al
	in	al, 41h
	xor	bh, al
	in	al, 42h
	add	bl, al
	in	al, 42h
	sub	bh, al
	mov	ax, bx
	rol	ax, 1
	xor	dx, dx
	mov	cx, 10007
	mul	cx
	inc	ax
	rol	ax, 1
	mov	rndword, ax
    end;
  }

word rnd_word(word range)
  {
    if (range == 0)
      return(0);
    else
      return(random_word() % range);
  }

word rnd_word_minmax(word min, word max)
  {
    return(rnd_word(max-min+1) + min);
  }
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[random.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[disasm.h]ÄÄ

#define cf_is66 	0x0001
#define cf_is67 	0x0002
#define cf_isSEG	0x0004
#define cf_isREP	0x0008
#define cf_isLOCK	0x0010
#define cf_is0F 	0x0020
#define cf_isMODRM	0x0040
#define cf_isSIB	0x0080
#define cf_isMEM	0x0100
#define cf_isDATA	0x0200
#define cf_isDATAREL	0x0400

#define ct_UNKNOWN	0
#define ct_JMP		1
#define ct_JCC		2
#define ct_CALL 	3
#define ct_RET		4

typedef union datauion
  {
    word       w[3];
    byte       b[6];
  } dataunion;

typedef struct tcmdrec
  {
    word       flags;		// cf_xxxx
    word       type;		// ct_xxxx
    word       size;		// total cmd. size
    word       base;		// instruction offset (16-bit)
    byte       px_SEG;		// prefix: segment prefix
    byte       px_REP;		// prefix: repz/repnz
    byte       opcode;
    byte       modrm;
    byte       mod;
    byte       reg;
    byte       rm;
    byte       sib;
    word       memsize;
    byte       mem[4];
    word       datasize;

    dataunion	data;

    word       jmpptr;		// jmp/call ABSOLUTE pointer (+base), 16-bit
  } tcmdrec;

void dump(pchar cmd, word size)
  {
    printf("%W ",(word) cmd);
    for (; size>0; size--, cmd++)
      printf(" %B", (byte) (*cmd));
    printf("\n");
  }

#define getbyte(x)    { x = (byte)  (*cmd_ptr++);   };
#define getword(x)    { x = (word)  (*cmd_ptr+=1);  };
#define getdword(x)   { x = (dword) (*cmd_ptr+=2);  };

#define getnextbyte(x) { x = ((byte) (*cmd_ptr)); }

tcmdrec r;
pchar cmd_ptr;
word disasm_base;

void modrm_proc(void)
  {

    getbyte(r.modrm);

    r.mod = r.modrm >> 6;
    r.reg = (r.modrm >> 3) & 7;
    r.rm  = r.modrm  & 7;

    if ((r.flags & cf_is67) == 0)
    {
       // 16-bit MODR/M

      if (((r.mod == 0) && (r.rm == 6)) || (r.mod == 2)) r.memsize = 2;
      if (r.mod == 1) r.memsize = 1;

    }
    else
    {
       // 32-bit MODR/M

      if (((r.mod == 0) && (r.rm == 5)) || (r.mod == 2)) r.memsize = 4;
      if (r.mod == 1) r.memsize = 1;

      if (r.rm == 4)
	{
	  r.flags |= cf_isSIB;
	  getbyte(r.sib);
	};

    };

  }

void disasm(pchar cmd, tcmdrec far *rec)
  {
    byte b,nextbyte;
    int i;

    fillchar(&r, sizeof(tcmdrec), 0x00);

    r.base = (word) cmd;
    r.jmpptr = -1;

    cmd += disasm_base;
    cmd_ptr = cmd;

    // begin disasm

prefix:
    getbyte(b);

    if ((b==0x2E) ||
	(b==0x26) ||
	(b==0x3E) ||
	(b==0x36) ||
	(b==0x64) ||
	(b==0x65))
      {
	r.flags |= cf_isSEG;
	r.px_SEG = b;
	goto prefix;
      }

    if ((b==0xF2) ||
	(b==0xF3))
      {
	r.flags |= cf_isREP;
	r.px_REP = b;
	goto prefix;
      }

    switch(b)
      {
	case 0x66: r.flags |= cf_is66;
		   goto prefix;
	case 0x67: r.flags |= cf_is67;
		   goto prefix;
	case 0xF0: r.flags |= cf_isLOCK;
		   goto prefix;
      };

    // prefix analyzed

    r.opcode = b;

    if (b == 0x0F) goto prefix_0F;

    getnextbyte(nextbyte);

    if (b == 0xE9)
      {
	r.type	   = ct_JMP;
	goto	   data_offs_rel;
      }

    if (b == 0xE8)
      {
	r.type	   = ct_CALL;
	goto	   data_offs_rel;
      }

    if ((b & 0xF0) == 0x70)
      {
	r.type	   = ct_JCC;
	goto	   data_byte_rel;
      }

    if (b == 0xEB)
      {
	r.type	   = ct_JMP;
	goto	   data_byte_rel;
      }

    if ((b == 0xC3) || (b == 0xCF))
      {
	r.type	   = ct_RET;
	goto	   okey;
      }

    if (b == 0xC2)
      {
	r.type	   = ct_RET;
	goto	   data_word;
      }

    if (b == 0xC8)
      goto	 data_3xbyte;

    if (
       (b == 0xC9) ||
       (b == 0xFC) ||
       (b == 0xAA) ||
       (b == 0xA4) ||
       (b == 0xAE) ||
       (b == 0x98) ||
       (b == 0x99) ||
       (b == 0xAC) ||
       (b == 0xCC)		// int 3
       )
      goto	 okey;

    if ((b & 0xFC) == 0x88)
      goto modrm;

    if ((b & 0xFE) == 0xC6)
      goto modrm_data_w_66;

    if ((b & 0xF0) == 0xB0)
      goto data_w3_66;


    if ((b & 0xFC) == 0xA0)
      goto data_offs;

    if (
       (b == 0xCD) ||
       (b == 0xE4)
       )
      goto data_byte;

    if ((b & 0xF0) == 0x50)
      goto okey;

    if ((b == 0xFF) &&
       (
       (((nextbyte >> 3) & 7) == 0) || (((nextbyte >> 3) & 7) == 6)
       ))
       goto modrm;

    if ((b & 0xFE) == 0xC4)		   //  gluk !
      goto modrm;

    if ((b & 0xE6) == 0x06)
      goto okey;

    if ((b & 0xC4) == 0x00)
      goto modrm;

    if ((b & 0xFC) == 0x80)
      goto modrm_data_sw_66;

    if ((b & 0xC6) == 0x04)
      goto data_w_66;

    if ( ((b & 0xFE) == 0xF6) && (((nextbyte >> 3) & 6) == 2) )
      goto modrm;

    if ((b & 0xF0) == 0x40)
      goto okey;

    if ( ((b & 0xFE) == 0xFE) && (((nextbyte >> 3) & 6) == 0) )
      goto modrm;

    if ((b & 0xF8) == 0x90)
      goto okey;

    if (b == 0x6A)
      goto data_byte;
    if (b == 0x68)
      goto data_66;

    if ( ((b & 0xFE) == 0xF6) && (((nextbyte >> 3) & 6) == 6) )
      goto modrm;

    if ((b & 0xFC) == 0xD0)
      goto modrm;

    if ((b & 0xFE) == 0xC0)
      goto modrm_data_byte;

    if ((b & 0xFE) == 0x84)
      goto modrm;

    if ( ((b & 0xF6) == 0xF6) && (((nextbyte >> 3) & 7) == 0) )
      goto modrm_data_w_66;

    if ((b & 0xFE) == 0xA8)
      goto data_w_66;

    if ((b & 0xFD) == 0x8C)
      goto modrm;

    if (b == 0x8D)
      goto modrm;

    if (  ((b & 0xFE) == 0xF6) && (((nextbyte >> 3) & 7) == 4)	)
      goto modrm;

    if ((b & 0xFE) == 0x86)
      goto modrm;

error:
    dump(cmd, 10);
    printf("<- unknown command\n");
    exit(1);


prefix_0F:

    r.flags |= cf_is0F;
    getbyte(b);
    r.opcode = b;
    getnextbyte(nextbyte);

    if ((b & 0xF0) == 0x80)
      {
	r.type	   = ct_JCC;
	goto	   data_offs_rel;
      }

    if ((b & 0xF6) == 0xB6)
      goto modrm;




   goto error;



modrm_data_byte:
   modrm_proc();
   goto data_byte;

modrm_data_w_66:
   modrm_proc();
   goto data_w_66;

modrm_data_sw_66:
   modrm_proc();
   goto data_sw_66;

modrm:
   modrm_proc();
   goto okey;

data_w3_66:
   if ((r.opcode & 0x08) != 0)
     goto data_66;
   else
     goto data_byte;

data_sw_66:
   if ((r.opcode & 0x02) != 0)
     goto data_byte;
   goto data_w_66;

data_w_66:
   if ((r.opcode & 0x01) != 0)
     goto data_66;
   else
     goto data_byte;

data_byte:
    r.datasize = 1;
    goto data;

data_66:
    if ((r.flags & cf_is66) == 0)
      goto data_word;
    else
      goto data_dword;

data_dword:
    r.datasize = 4;
    goto data;

data_word:
    r.datasize = 2;
    goto data;

data_3xbyte:
    r.datasize = 3;
    goto data;

data_offs:
    if ((r.flags & cf_is67) == 0)
      r.datasize = 2;
    else
      r.datasize = 4;
    goto data;

data_offs_rel:
    if ((r.flags & cf_is66) == 0)
      r.datasize = 2;
    else
      r.datasize = 4;
    goto data_rel;

data_byte_rel:
    r.datasize = 1;
    goto data_rel;

data_rel:
    r.flags |= cf_isDATAREL;
    goto data;

data:
    r.flags |= cf_isDATA;
    goto okey;

okey:
    if (r.datasize != 0)
      for (i=0; i<r.datasize; i++)
	getbyte(r.data.b[i]);

    if (r.memsize != 0)
      for (i=0; i<r.memsize; i++)
	getbyte(r.mem[i]);

    // end disasm

    r.size = cmd_ptr - cmd;

    if ((r.flags & cf_isDATAREL) != 0)
      {
	r.jmpptr = r.base + r.size;
	if (r.datasize == 1)
	  r.jmpptr += (short) r.data.b[0];
	else
	  if (r.datasize == 2)
	    r.jmpptr += (int) r.data.w[0];
	  else
	    {
	      printf("Disasm error calculating r.jmpptr: r.datasize=%w", r.datasize);
	      exit(0);
	    }
      }

    // dump(cmd, r.size);

    move(&r, rec, sizeof(tcmdrec));
  }

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[disasm.h]ÄÄ
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[engine.h]ÄÄ

#define OUTPUT_FILLER	0xCC

#define UNUSED		'-'
#define MARKED		'x'
#define FORNEXTPASS	'N'

byte output[max_size];
byte buf_mark[max_size];
word link_2[max_cmd];
word link_1[max_cmd];
word link_max;
word out_ip;

void mark_cmd(word ofs, word size, byte marker)
  {
    if (buf_mark[ofs] == MARKED)
      {
	printf("Alredy MARKED\n");
	return;
      }
    for (; size > 0; size--)
      buf_mark[ofs++] = marker;
  }

void store_byte(byte b)
  {
    output[out_ip++] = b;
  }

void store_word(word w)
  {
    store_byte(w & 255);
    store_byte(w >> 8);
  }


void store_link(word old_ip,
		word new_ip)
  {
    if (link_max >= max_cmd)
      {
	printf("Too many links(commands)\n");
	exit(1);
      }
    link_1[link_max] = old_ip;
    link_2[link_max] = new_ip;
    link_max++;

    printf("link #%w: %W <--> %W\n", link_max,old_ip,new_ip);
  }

void store_jmp(word to_ip)
  {
    printf("*** STORE_JMP: offs=%W\n", to_ip);

    store_link(0xFFFE, out_ip);

    store_byte(0xE9);
    store_word(to_ip);
  }

void store_jmp_output(word to_ip)
  {
    word w;
    printf("*** STORE_JMP_OUTPUT: offs=%W\n", to_ip);

    store_link(0xFFFF, out_ip);

    //store_byte(0x90);

    store_byte(0xE9);
    store_word(to_ip - (out_ip+2));

  }

word free_space(word start)
  {
    int i;

    for (i=0; (start+i)<max_size, output[start+i] == OUTPUT_FILLER ; i++) ;

    return(i);
  }

void make_new_ip(void)
  {
     word i;
     word c;

     printf("Executing NEW_IP, searching for IP...\n");

     for (c=0; c<1000; c++)
       {

	 i = rnd_word_minmax(0x100+min_left, max_size-min_right);
	 if ( free_space(i) > (min_left+min_right) )
	   goto found;

       };

     printf("***WARNING***: No free space in output buffer\n");
     return;

found:

     i += min_left;

     printf("New IP found at %W\n", i);

     store_jmp_output(i);
     out_ip = i;

  }

void random_new_ip(void)
  {
    #ifdef USE_RANDOM_IP

    printf("Executing RANDOM_NEW_IP\n");

    if (rnd_word(USE_RANDOM_IP) == 0)
      {
	make_new_ip();
      };

    #endif
  }

byte store_inversed_jmp;

void store_cmd(word ip, word size)
  {
    pchar p;
    tcmdrec r;
    word i;

    if (free_space(out_ip) < min_right_left)
      make_new_ip();
    else
      random_new_ip();

    printf("*** STORE_CMD: offs=%W size=%W\n", ip, size);

    store_link(ip, out_ip);

    disasm(make_ptr(_CS,ip), &r);

    if ((r.type == ct_JMP) || (r.type == ct_JCC) || (r.type == ct_CALL))
      {

	if (  (store_inversed_jmp == 1) && (r.type == ct_JCC)  )
	  {
	    r.jmpptr = ip-disasm_base + r.size;
	    r.opcode ^= 1;
	  }

	if ((r.opcode & 0xF0) == 0x80)
	  {
	    store_byte(0x0F);
	    store_byte(r.opcode);
	    store_word(r.jmpptr);
	    return;
	  }

	if ((r.opcode & 0xF0) == 0x70)
	  {
	    store_byte(0x0F);
	    store_byte(r.opcode - 0x70 + 0x80);
	    store_word(r.jmpptr);
	    return;
	  }

	if (r.opcode == 0xEB)
	  {
	    store_byte(0xE9);
	    store_word(r.jmpptr);
	    return;
	  }

	if ( (r.opcode == 0xE8) || (r.opcode == 0xE9) )
	  {
	    store_byte(r.opcode);
	    store_word(r.jmpptr);
	    return;
	  }

	printf("ERROR 1, X=%B\n", r.opcode);
	exit(2);
      }

    #ifdef SKIP_NOP
    if (r.opcode == 0x90)
      return;
    #endif

    #ifdef SKIP_INT3
    if (r.opcode == 0xCC)
      return;
    #endif

    #ifdef SKIP_RANDOM

    if (r.size == 2)
    if (
	(
	  ((r.opcode & 0xFE) == 0x86) ||
	  ((r.opcode & 0xFE) == 0x88)
	)
	&&
	(r.mod == 3)
       )
	 return;

    #endif

    #ifdef CHANGE_CMD
    i = r.opcode & 0xFE;
    if (r.size == 2)
    if (r.mod == 3)
    if ( (i == 0x08) ||
	 (i == 0x0A) ||
	 (i == 0x20) ||
	 (i == 0x22) ||
	 (i == 0x84) )
      {
	i = rnd_word(5);
	if (i == 0) i = 0x08;
	if (i == 1) i = 0x0A;
	if (i == 2) i = 0x20;
	if (i == 3) i = 0x22;
	if (i == 4) i = 0x84;
	store_byte(((r.opcode & 0x01) + i));
	store_byte(r.modrm);

	return;
      };
    #endif

    for (; size>0; size--)
      {
	p = make_ptr(_CS,ip++);
	store_byte( (byte) *p );
      }

    #ifdef ADD_RANDOM
    if (rnd_word(ADD_RANDOM) == 0)
      {
	word f;
	store_byte(0x86 + rnd_word(4));
	f = (random_word() & 7);
	store_byte(0xC0 + (f << 3) + f);

      };
    #endif

  }

byte pass_action;

void process_1(word ip)
  {
    tcmdrec rec;

nextcmd:
     if ((ip <	0x0100) ||
	 (ip >= max_size))
       {
	 printf("IP range check error, exiting\n");
	 return;
       }

     disasm(make_ptr(_CS,ip), &rec);

     printf("Marking: ");
     dump(make_ptr(_CS,ip+disasm_base), rec.size);

     if (pass_action == 2)
       {
	 printf("PASS 2: Saving offset %W to LINK_2[%w]\n", ip, link_max);

	 if (link_max > max_cmd*2)     // *2 becoz using 2 arrays: ..._2 & 1
	   {
	     printf("Too many links!!!");
	     exit(3);
	   };

	 link_2[link_max] = ip;
	 link_max++;
       }

     if (buf_mark[ip] == MARKED)
       {
	 printf("Alredy marked, exiting\n");
	 if (pass_action == 1)
	   store_jmp(ip+disasm_base);
	 return;
       };
     mark_cmd(rec.base, rec.size, MARKED);

     if (rec.type == ct_UNKNOWN)
       {
	 if (pass_action == 1)
	   store_cmd(ip+disasm_base, rec.size);
	 ip += rec.size;
       };

     if (rec.type == ct_RET)
       {
	 if (pass_action == 1)
	   store_cmd(ip+disasm_base, rec.size);
	 printf("[RET]  Exiting\n");
	 return;
       };

     if (rec.type == ct_JMP)
       {

	 if (pass_action == 1)
	   {
	     #ifndef SKIP_JMPS
	       store_cmd(ip+disasm_base, rec.size);
	     #else
	       store_link(ip+disasm_base, out_ip);
	       #ifdef SKIP_JMPS_BUT_ADD_NOPS
	       store_byte(0x90);
	       #endif
	     #endif
	   }

	 printf("[JMP]  Changing IP to %W\n", rec.jmpptr);
	 ip = rec.jmpptr;
       };

     if (rec.type == ct_CALL)
       {
	 if (pass_action == 1)
	   store_cmd(ip+disasm_base, rec.size);
	 ip+=rec.size;
	 printf("[CALL] Marking for next pass: %W\n", rec.jmpptr);
	 mark_cmd(rec.jmpptr, 1, FORNEXTPASS);
       };

     if (rec.type == ct_JCC)
       {

	 #ifdef RANDOM_JCC
	 word rnd = rnd_word(2);
	 #else
	   #ifdef INVERSE_JCC
	   word rnd = 1;
	   #else
	   word rnd = 0;
	   #endif
	 #endif

	 if (rnd == 0)
	   {

	     store_inversed_jmp = 0;

	     if (pass_action == 1)
	       store_cmd(ip+disasm_base, rec.size);

	     ip+=rec.size;

	     printf("[Jcc]  Marking for next pass: %W\n", rec.jmpptr);
	     mark_cmd(rec.jmpptr, 1, FORNEXTPASS);

	   };

	 if (rnd == 1)
	   {

	     store_inversed_jmp = 1;

	     if (pass_action == 1)
	       store_cmd(ip+disasm_base, rec.size);

	     ip+=rec.size;

	     printf("[Jcc] ***INVERSED***  Marking for next pass: %W\n", ip);
	     mark_cmd(ip, 1, FORNEXTPASS);

	     printf("Changing IP to %W\n", rec.jmpptr);
	     ip = rec.jmpptr;

	   };

       };

     goto nextcmd;
  }

void mark_unused(void)
  {
    int i;

    fillchar(buf_mark, max_size, UNUSED);
    link_max = 0;

    printf("Marking entry point(s)\n");

    process_1(0x0100);

cycle:
    printf("Searching for FORNEXTPASS mark(s)\n");

    for (i = 0; i < max_size; i++)
      if (buf_mark[i] == FORNEXTPASS)
	{
	  printf("Found at %W\n", i);
	  process_1(i);
	  goto cycle;
	}

    printf("No FORNEXTPASS-mark(s) found\n");
  }

void run_engine(void)
  {
    handle h;
    word i;
    word j;
    word k;
    word w;
    word q;
    word e;
    pchar p;
    tcmdrec r1;
    tcmdrec r2;
    tcmdrec r3;

    printf("Engine!\n  {\n");

    fillchar(output, max_size, OUTPUT_FILLER);
    out_ip = 0x100;

    disasm_base = 0;
    pass_action = 1;
    printf("Marking UNUSED commands (1)\n");
    mark_unused();

    #ifndef SKIP_DEBUGFILES

    printf("Writing file(s)\n");

    h = createfile("buf_mark.1");
    writefile(h, buf_mark, max_size);
    closefile(h);
    h = createfile("link_1.1");
    writefile(h, link_1, link_max * 2);
    closefile(h);
    h = createfile("link_2.1");
    writefile(h, link_2, link_max * 2);
    closefile(h);

    h = createfile("output.1");
    writefile(h, &output[0x100], max_size-0x100);
    closefile(h);

    #endif

    printf("Updating JMPs...\n");

    fillchar(buf_mark, max_size, UNUSED);

    for (i=0; i<link_max; i++)
      if (link_1[i] != 0xFFFF)
      {
	for (j=0; j<link_max; j++)
	  if (i != j)
	    if (link_2[i] == link_2[j])
	      if (link_1[j] == 0xFFFF)
		goto skip_cycle;

	printf("DEBUG: &out[...]=%W, ...=%W i=%w link_1[i]=%W \n", (word) &output[link_2[i]], link_2[i], i, link_1[i]);

	p = &output[link_2[i]];
	disasm(p, &r);

	if (
	   (r.type == ct_JMP) ||
	   (r.type == ct_JCC) ||
	   (r.type == ct_CALL)
	   )
	 {
	    printf("Command to update found at %W\n", link_2[i]);

	    if (buf_mark[link_2[i]] == MARKED)
	      printf("Alredy updated");
	    else
	    {
		buf_mark[link_2[i]] = MARKED;

		if ( (r.opcode == 0xE9) || (r.opcode == 0xE8) )
		  k=1;
		else
		  k=2;

		printf("k=%w\n",k);

		w = r.data.w[0];

		printf("Points to %W\n",w);

		q = 0;
		for (j=0; j<link_max; j++)
		  if (link_1[j] == w)
		    {
		      printf("Link to (replacing with) %W, j=%w, patch at %W+, link_1[j]=%W\n", link_2[j], j, link_2[i], link_1[j]);

		      e = (int) link_2[j] - (link_2[i] + r.size);

		      output[link_2[i]+k  ] = e & 255;
		      output[link_2[i]+k+1] = ((word) e) >> 8;

		      q++;
		    }

		if (q != 1)
		  {
		    printf("ERROR 2, q=%w\n",q);
		    exit(4);
		  }

	    };

	 };
skip_cycle:
      };

    disasm_base = ((word) &output[0x0100]) - 0x100;
    pass_action = 2;
    printf("Marking UNUSED commands (2)\n");
    mark_unused();

    #ifndef SKIP_DEBUGFILES

    printf("Writing file(s)\n");

    h = createfile("buf_mark.2");
    writefile(h, buf_mark, max_size);
    closefile(h);
    h = createfile("link_1.2");
    writefile(h, link_1, link_max * 2);
    closefile(h);
    h = createfile("link_2.2");
    writefile(h, link_2, link_max * 2);
    closefile(h);

    #endif

    #ifdef KILL_J2J

    printf("Searching for Jxx-JMP, CALL-JMP, CALL-RET situations\n");

    for (i=0; i<link_max; i++)
      {
	disasm(make_ptr(_CS,link_2[i]), &r1);

	if ( (r1.type == ct_CALL) && (r1.opcode == 0xE8) )
	  {
	    disasm(make_ptr(_CS, r1.jmpptr), &r2);

	    if (r2.opcode == 0xC3)
	      {
		printf("CALL-RET found at %W, points to %W\n", r1.base, r1.jmpptr);

		j=r1.base;
		output[j  ] = 0x87; // xchg ax, ax
		output[j+1] = 0xC0;
		output[j+2] = 0x90; // nop
	      };
	  };

	if (
	   (r1.type == ct_JCC ) ||
	   (r1.type == ct_CALL) ||
	   (r1.type == ct_JMP)
	   )
	  {
	    printf("Jxx-JMP or CALL-JMP found at %W, points to %W\n", r1.base, r1.jmpptr);

	    disasm(make_ptr(_CS, r1.jmpptr), &r2);
	    if (r2.type != ct_JMP)
	      printf("Suxx...\n");
	    else
	      {

cycle:		printf("Points to %W\n", r2.jmpptr);

		disasm(make_ptr(_CS, r2.jmpptr), &r3);
		if (r3.type == ct_JMP)
		  {
		    move(&r3, &r2, sizeof(tcmdrec));
		    goto cycle;
		  };

		printf("Updating: cmd at %W, jmpptr=%W -> %W \n", r1.base, r1.jmpptr, r2.jmpptr );

		j=r1.base;
		if ((r1.flags & cf_is0F) != 0) j++;  // 0F
		j++;  // opcode

		w = r2.jmpptr - (j+2);
		output[j  ] = w & 255;
		output[j+1] = w >> 8;

	      };

	  };

      };

    printf("Marking UNUSED commands (3)\n");
    mark_unused();

    #endif

    #ifdef MAKE_SHORT_JMPS

    printf("Searching for Jxx/JMPs\n");

    for (i=0; i<link_max; i++)
      {
	disasm(make_ptr(_CS,link_2[i]), &r1);


	if (r1.type == ct_JCC)
	  {
	    w = r1.jmpptr - (r1.base+2);
	    if ( ((short) (w & 255)) == w)
	      {
		 printf("Changing JCC at %W, r1.data.w[0]=%W\n", r1.base, r1.data.w[0]);

		 output[r1.base+0] = r1.opcode - 0x10;
		 output[r1.base+1] = w & 255;
		 output[r1.base+2] = 0x87;    // xchg ax, ax
		 output[r1.base+3] = 0xC0;    //
	      };
	  };


	if (r1.type == ct_JMP)
	  {
	    w = r1.jmpptr - (r1.base+2);
	    if ( ((short) (w & 255)) == w)
	      {
		 printf("Changing JMP at %W, r1.data.w[0]=%W\n", r1.base, r1.data.w[0]);

		 output[r1.base+0] = 0xEB;
		 output[r1.base+1] = w & 255;
		 buf_mark[r1.base+2] = UNUSED;
	      };
	  };

      };

    #endif

    #ifdef FILL_UNUSED_CC
    printf("Filling UNUSED space with 0xCC\n");
    for (i=0; i<max_size; i++)
      if (buf_mark[i] == UNUSED)
	output[i] = 0xCC;
    #endif

    #ifdef FILL_UNUSED_RANDOM
    printf("Filling UNUSED space with RANDOM bytes\n");
    for (i=0; i<max_size; i++)
      if (buf_mark[i] == UNUSED)
	output[i] = random_word();
    #endif

    printf("Writing 1.COM\n");

    h = openfile("1.com");
    writefile(h, &output[0x100], max_size-0x100);
    closefile(h);

    printf("  }\nEngine terminated.\n");
  }

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ[engine.h]ÄÄ
