Self-modifying code is not limited to
assembly.
A couple of high-level languages offer the (usually evil) choice to change your code in run time.
The best example is most likely COBOL. The ALTER statement works in the following way :
.
. (some thousands of lines snipped)
.
PERFORM READ-DATA
UNTIL MY-SUM IS GREATER THAN 700.
.
. (some more lines snipped)
.
READ-DATA SECTION.
HERE-IT-GOES.
GO TO INITIAL-ITERATION.
INITIAL-ITERATION.
MOVE 0 TO MY-SUM.
ALTER HERE-IT-GOES
TO PROCEED TO MORE-ITERATIONS.
GO TO READ-FROM-FILE.
MORE-ITERATIONS.
ADD INPUT-SUM TO MY-SUM ROUNDED.
READ-FROM-FILE.
READ INFILE.
READ-DATA-EXIT.
EXIT.
What it does is simple: Read records from an input file until the sum of values in a certain field of the input field is greater than 700.
The ALTER statement changes the statement
GO TO INITIAL-ITERATION.
into
GO TO MORE-ITERATIONS.
during run-time.
Most people who wrote COBOL compilers apart from IBM decided not to implement ALTER.
Some lesser-known languages like NODAL and POCAL also offered self-modifying code features, easier to implement because both were interpreted languages.
A sample in POCAL :
10.10 SET I=0
10.20 SET POCLIN(10.10)="SET I=" I+1
10.30 DO 20!30
10.40 TYPE "Program used " I " times" !
10.50 END
20.10 SAVE "(SOMEDISK:SOMEUSER)STUPID:POCL"
30.10 TYPE "Saving failed - tough luck !"
This program not only modifies itself, it also saves itself back to disk.
The conclusion might be that languages which allow for self-modifying code are also self-obfuscating.