• C

Self modifying C code.

The technique used to be big to prevent assembly programs being hacked.
Can/Has this been done for C?
Just a link or two :)
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Lab_RatAuthor Commented:
Give it a bit longer, and if noone else surfs by, post an answer.
I have only ever done this in assembler. The ICL 1301 machine had no modifier so that indexing an array consisted of fishing out the accessor instruction, adding the array offset to the address part, sticking it back into the code and falling into it to get the damm thing executed. And that of couse in 64 words of page memory because we then have to fetch the next code page from drum otherwise we wrap round and start fromn the beginning again. All good clean fun and very warm in winter with this 80K Watt machine.
   An interesting anecdote which I might be permitted to add here is that the Programming Manual for the built-in Line Printer explicitly warns you about print sequences which could make the printer burst into flames. As the paper feed drum went round you had to raise and lower a pawl on a ratchet. The timing was critical to get a certain amount of paper through. One line feed or a vertical tab or whatever.  If you raised and lowered the pawl too fast the electromagnet would get hot which in turn could alight the paper and eventually the printer would catch fire.
   We ought to start a thread in the lounge for this machine. It was a marvel of complexity and intricacy only for those who were, for example, undaunted at the task of doing the Times Crossword during the tea break (as a relaxing diversion).
Your Guide to Achieving IT Business Success

The IT Service Excellence Tool Kit has best practices to keep your clients happy and business booming. Inside, you’ll find everything you need to increase client satisfaction and retention, become more competitive, and increase your overall success.

In Win32 this has become harder. You are not allowed to write to your own code segment always..
You use to have programs like lzexe who compressed executables as executables, so they use what you said.
The problem with this code is the jump tables and scheduling.
I once read how to write to a code segment in the book Undocumented Windows.  There's an undocumented system call PrestoChangeSelector that converts a read-only code segment to a writeable data segment and back again by toggling a bit in the selector.

I'm afriad I don't have the book with me at work right now, it's at home, so I can't provide the details until tomorrow.
This is something I got out of a book on C Techniques.  If I remember, I'll try to check the full name of it when I get home.  2 files -> modify.h and modify.c
Hope this helps.

/*MODIFY.H - Header file for MODIFY.C.*/

struct exeheader
  unsigned id;            /* EXE file id. */
  unsigned bytemod;      /* Load module image size mod 512. */
  unsigned pages;            /* File size (including header) div 512. */
  unsigned reloc_items;      /* Number of relocation table items. */
  unsigned size;            /* Header size in 16-byte paragraphs. */
  unsigned minparagraphs;  /* Min number of paragraphs above program. */
  unsigned maxparagraphs;  /* Max number of paragraphs above program. */
  unsigned stackseg;      /* Displacement of stack segment. */
  unsigned spreg;            /* Initial SP register value. */
  int checksum;            /* Negative checksum (not used). */
  unsigned ipreg;            /* Initial IP register value. */
  unsigned codeseg;      /* Displacement of code segment. */
  unsigned first_reloc;      /* First relocation item. */
  unsigned ovln;            /* Overlay number. */

#define EXEH_SIZE  sizeof(struct exeheader)

/* EXE file signature. */
#define EXE_ID  0x5A4D

#if !defined(TRUE)
#define FALSE  0
#define TRUE   (!FALSE)

/* Function prototypes. */
int exemodify(const char *progname, int keepdt, ...);

/*****  END .H FILE *****/

MODIFY.C - Modify global variables in EXE or COM file.
For Turbo C versions 2.0 and above.  This code is public domain.

#include <dir.h>
#include <dos.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>

#include <modify.h>

int exemodify(char *progname, int keepdt, [void *data1,
     unsigned n1, [void *data2, unsigned n2, [ ... ]]]

int exemodify(const char *progname, int keepdt, ...)
char _progname[MAXPATH];      /* Program name. */
char ext[MAXEXT];                  /* Program extension. */
struct exeheader exe;            /* EXE file header. */
char *pathptr;                  /* Pointer to program path. */
int progfile;                  /* Program file handle. */
int iscomfile;                  /* TRUE if program is a COM file. */
long filelen;                  /* Program file length. */
struct ftime dtstamp;            /* Program date/time stamp. */
va_list datalist;            /* List of data items to be written to file. */
char *data;                  /* Pointer to current data item. */
unsigned n;                  /* Size of current data item. */
long seeklen;                  /* Seek length into program file. */
int retcode;                  /* Function return code. */

if (_osmajor < 3)
  /* Search DOS PATH for program. */
  if ((pathptr = searchpath(progname)) != NULL)
    strcpy(_progname, pathptr);
    _progname[0] = 0;
  /* Program name is 0th parameter in DOS versions 3.0 and up. */
  strcpy(_progname, _argv[0]);

/* Assume error. */
retcode = -1;

if (_progname[0])
  if ((progfile = open(_progname, O_RDWR | O_BINARY)) != -1)
    iscomfile = fnsplit(_progname, NULL, NULL, NULL, ext) & EXTENSION && !strnicmp(ext, ".COM", 4);

    if (!iscomfile && (read(progfile, &exe, EXEH_SIZE) != EXEH_SIZE || exe.id != EXE_ID))
      /* File is not a COM file and does not have a valid EXE file header. */
      errno = EINVFMT;
      /* Cannot write beyond end of file. */
      filelen = filelength(progfile);

      if (keepdt)
      /* Save date/time stamp. */
      getftime(progfile, &dtstamp);

      retcode = 0;
      va_start(datalist, keepdt);

      while ((data = va_arg(datalist, char *)) != NULL)
      if (iscomfile)
        /* Seek length is data offset - PSP size. */
        seeklen = FP_OFF(data) - 256;
        /* Seek length is (data segment - (PSP + PSP size) + EXE size) * 16 + data offset. */
        seeklen = ((unsigned long)(FP_SEG(data) - (_psp + 16) + exe.size) << 4) + (unsigned long)FP_OFF(data);

      n = va_arg(datalist, unsigned);

      if (seeklen + n <= filelen && lseek(progfile, seeklen, SEEK_SET) != -1L && write(progfile, data, n) == n)
        /* Seek and write was successful. */


      if (keepdt)
      /* Restore date/time stamp. */
      setftime(progfile, &dtstamp);

  /* File not found. */
  errno = ENOENT;

return (retcode);


>>In Win32 this has become harder. You are not allowed to
>>write to your own code segment always..

This will do it ;-)

VirtualProtect( ..., PAGE_EXECUTE_READWRITE, ...);

Doing something is harder than doing nothing...
You have to agree with me. It's a lot harder to make
LZEXE for NT than it is to make LZEXE for Dos.
You CAN still write assembly code for Win32, you can also include assembly code with most C compilers.  It is relatively easy, as you know to write assembly code that self-modifies.  The problem with C is that you rarely know at source-coding time what the generated code would be, so you would be asiming at a moving target.  Also, it would change if you re-compiled with different options or a different compiler.

I have seen and used code that does this for Win32, it uses assembly language insertes into the C source.  Horrible, but it does work.

With many REAL operating systems there would be a further problem that the code would be executed from a segment that is marked read-only and so self modification would be a further problem.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
What, no more anecdotes? I was looking forward to old hands dithering on about what it was like in the old days when you HAD to do this sort of thing.
Self-modifying code is a pain in the arse.  I had to do it on the Commodore 64 a few times...there are only three 8-bit registers for you to use, so sometime the only way to get things done fast was to modify operands rather than use the turtle-on-ritalin indexed indirect mode.
Lab_RatAuthor Commented:
BigRat, I'm too younf to be using anecdotes, give me a few more years and I'll be waffling on about the Sinclair ZX Spectrum 128k+2a (Revision 2), now THERE was a computer that you could spill coke on and it.........
Self modifying code is easy.  Just use LISP! :)
(dodges C-coder launched rotten fruits)
Lab_RatAuthor Commented:
Thanks everyone,
but it's time to lock up and go home.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.