Scrivi un programma autoreplicante.


11

Scrivi un semplice programma che si copia da solo quando eseguito.

Il tuo programma dovrebbe essere una sorta di file eseguibile su Windows, Linux, ecc., Dovrebbe generare un nuovo file eseguibile, che è identico al tuo file eseguibile originale, con nome casuale ed esci.

Il tuo programma non dovrebbe comportare alcun tipo di lettura o copia di file. È consentita solo la scrittura di file per la generazione di nuovi file eseguibili.

(PS. Ero abbastanza imbarazzato quando su Wikipedia, Self-replicating programreindirizza Computer virusall'articolo ...: / ...)

Vince la dimensione del file eseguibile più piccola. La tua risposta potrebbe essere un codice di programmazione con sistema operativo e compilatore, codice assembly o dump esadecimali corretti di un file eseguibile.


6
Questo sembra variare solo banalmente dalle sfide esistenti [quine]. O ho frainteso?
dmckee --- ex gattino moderatore,

1
@dmckee Ho visto Assembly Language Quine e il programma Hello World autoreplicarsi che accettava la copia, ma non riuscivo a trovare la scrittura del programma stessa , non il suo codice .
JiminP,

1
... ma voglio vedere come funziona davvero! .. Non so come l'idea possa essere estesa con codici binari .. anche se ho letto l'articolo Quine su Wikipedia. PS. non sono consentiti compilatori per la replica e nessun linguaggio di script ...: /
JiminP

4
Qualsiasi problema può essere reso leggermente più difficile e brutto aggiungendo ulteriori vincoli ad esso. Trovo che questo problema sia una banale estensione del problema delle quine.
Alexandru,

1
Se vince la dimensione dell'eseguibile più piccola, non dovremmo considerare anche il codice dell'interprete come parte della dimensione dell'eseguibile perché ciò sia corretto per gli utenti delle lingue compilate?
Thomas Dignan,

Risposte:


4

Bash, 236

Più lungo del necessario, ma odio le lunghe file. La nuova riga finale non è facoltativa.

b=\\ q=\' r=\> d=\$
s='exec >$$; echo b=$b$b q=$b$q r=$b$r d=$b$d; echo s=$q$s$q'
t='echo t=$q$t$q; echo $s; echo $t; chmod 777 $$'
exec >$$; echo b=$b$b q=$b$q r=$b$r d=$b$d; echo s=$q$s$q
echo t=$q$t$q; echo $s; echo $t; chmod 777 $$

In realtà, non è quello che volevo, tuttavia, dato che ho scritto una domanda "sbagliata" e la tua risposta è un gran quine ...
JiminP

@JiminP: come non è quello che volevi? Ho appena letto nuovamente la descrizione del problema due volte e non riesco a capire.
JB,

Bene ... quello che volevo era un codice binario eseguibile. Come ho ammesso sopra, poiché la mia domanda non era del tutto "giusta" ... scusatemi per quello.
JiminP,

3
@JiminP Beh, sì, la parola "binario" non appare affatto nella domanda. L'ho appena trovato nei commenti, ma per una tale restrizione, non lo taglia. È possibile aprire una nuova domanda con tutti gli input consolidati dai commenti. Ti suggerisco di usare la sandbox per assicurarti che i clienti abituali ti aiutino a stirare i piccoli dettagli. Ma attenzione, le risposte binarie tendono ad essere davvero noiose.
JB,

10

Assembly per x86 Linux, 106 byte

BITS 32
                org     0x2E620000
                db      0x7F, "ELF", 1, 1, 1, 0 ; e_ident
                dd      0, 0
                dw      2                       ; e_type
                dw      3                       ; e_machine
                dd      1                       ; e_version
                dd      _start                  ; e_entry
                dd      phdr - $$               ; e_phoff
                dd      0                       ; e_shoff
                dd      0                       ; e_flags
                dw      0x34                    ; e_ehsize
                dw      0x20                    ; e_phentsize
phdr:           dd      1                       ; e_phnum       ; p_type
                                                ; e_shentsize
                dd      0                       ; e_shnum       ; p_offset
                                                ; e_shstrndx
                dd      $$                                      ; p_vaddr
fname           equ     $ - 2
                db      'out', 0                                ; p_paddr
                dd      filesize                                ; p_filesz
                dd      filesize                                ; p_memsz
                dd      5                                       ; p_flags
                dd      0x1000                                  ; p_align
_start:         mov     al, 5                   ; 5 = open syscall
                mov     ebx, fname
                mov     cl, 65                  ; 65 = O_WRONLY | O_CREAT
                mov     dx, 666q
                int     0x80
                lea     edx, [byte ecx + filesize - 65]
                xchg    eax, ebx
                xchg    eax, ecx
                mov     cl, 0
                mov     al, 4                   ; 4 = write syscall
                int     0x80
                mov     al, 1                   ; 1 = exit syscall
                int     0x80
filesize        equ     $ - $$

Questo è per l'assemblatore nasm. Costruisci il binario con la riga di comando:nasm -f bin -o a.out selfrep.asm && chmod +x a.out

Ecco lo stesso file di un dump esadecimale: 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 02 00 03 00 01 00 00 00 4C 00 62 2E 2C 00 00 00 00 00 00 00 00 00 00 00 34 00 20 00 01 00 00 00 00 00 00 00 00 00 62 2E 6F 75 74 00 6A 00 00 00 6A 00 00 00 05 00 00 00 00 10 00 00 B0 05 BB 36 00 62 2E B1 41 66 BA B6 01 CD 80 8D 51 29 93 91 B1 00 B0 04 CD 80 B0 01 CD 80

Come richiesto, il programma si copia in un file separato. (Il programma avrebbe potuto essere significativamente più breve se fosse stato autorizzato a scrivere su stdout e consentire all'utente di reindirizzare a un file.)

Ho evitato di usare qualsiasi trucco borderline per ridurne le dimensioni. Questo dovrebbe essere un binario ELF a 32 bit completamente conforme.

Modificato per aggiungere : nella versione precedente il file creato è solo un file semplice, ma mi viene in mente che per un paio di byte (e una piccola curva delle regole), puoi creare qualcosa di un po 'più interessante. Questa versione ha solo due byte in più, a 108 byte:

BITS 32
                org     0x00010000
                db      0x7F, "ELF", 1, 1, 1, 0 ; e_ident
                dd      0, 0
                dw      2                       ; e_type
                dw      3                       ; e_machine
                dd      1                       ; e_version
                dd      _start                  ; e_entry
                dd      phdr - $$               ; e_phoff
                dd      0                       ; e_shoff
                dd      0                       ; e_flags
                dw      0x34                    ; e_ehsize
                dw      0x20                    ; e_phentsize
phdr:           dd      1                       ; e_phnum       ; p_type
                                                ; e_shentsize
                dd      0                       ; e_shnum       ; p_offset
                                                ; e_shstrndx
                dd      $$                                      ; p_vaddr
fname:          db      'asr', 0                                ; p_paddr
                dd      filesize                                ; p_filesz
                dd      filesize                                ; p_memsz
                dd      7                                       ; p_flags
                dd      0x1000                                  ; p_align
_start:         mov     al, 5                   ; 5 = open syscall
                mov     ebx, fname
                inc     byte [ebx]
                mov     cl, 65                  ; 65 = O_WRONLY | O_CREAT
                mov     dx, 777q
                int     0x80
                lea     edx, [byte ecx + filesize - 65]
                xchg    eax, ebx
                xchg    eax, ecx
                mov     cl, 0
                mov     al, 4                   ; 4 = write syscall
                int     0x80
                mov     al, 1                   ; 1 = exit syscall
                int     0x80
filesize        equ     $ - $$

Denominare questa versione asr, per "un autoreplicatore":nasm -f bin -o asr asr.asm && chmod +x asr

Versione di dump esadecimale per i non vedenti: 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 02 00 03 00 01 00 00 00 4C 00 01 00 2C 00 00 00 00 00 00 00 00 00 00 00 34 00 20 00 01 00 00 00 00 00 00 00 00 00 01 00 61 73 72 00 6C 00 00 00 6C 00 00 00 07 00 00 00 00 10 00 00 B0 05 BB 38 00 01 00 FE 03 B1 41 66 BA FF 01 CD 80 8D 51 2B 93 91 B1 00 B0 04 CD 80 B0 01 CD 80

Quando lo esegui, crea un file quasi identico chiamato bsr, ma uno che è esso stesso eseguibile. Eseguendolo creerà un altro file binario chiamato csr. E così via.

(Si noti che le cose fastidiose iniziano a succedere dopo zsr. Ho preso in considerazione l' atridea di creare una versione in cui il nome cambierebbe e così via, ma penso che la maggior parte delle persone si annoierà molto prima, quindi probabilmente non vale tutti i byte extra. )


+1 per la risposta dell'assemblea! Hai visto la sfida dell'assemblea quine ?
MD XF,

2

Ecco un proof-of-concept (ungolfed) che mostra come i servizi di compilazione in .NET potrebbero essere utilizzati per compilare il codice sorgente al volo per generare un output identico. La prima copia non è identica all'originale, ma le copie successive delle esecuzioni successive sono esattamente identiche ai nomi di file casuali:

using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;

namespace _2947
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello world!");

            var s = @"
using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace _2947
{{
    class Program
    {{
        static void Main(string[] args)
        {{
            Console.WriteLine({1}Hello world!{1});

            var s = @{1}{0}{1};
            s = string.Format(s, s, '{1}');

            string exeName = Environment.CurrentDirectory + @{1}\{1} + new Random().Next(1000, 9999) + {1}.exe{1};

            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = true;
            cp.OutputAssembly = exeName;
            cp.GenerateInMemory = false;
            cp.TreatWarningsAsErrors = false;
            cp.ReferencedAssemblies.Add({1}System.dll{1});

            var c = CSharpCodeProvider.CreateProvider({1}cs{1});
            var cr = c.CompileAssemblyFromSource(cp, s);
        }}
    }}
}}
";
            s = string.Format(s, s, '"');

            string exeName = Environment.CurrentDirectory + @"\" + new Random().Next(1000, 9999) + ".exe";

            CompilerParameters cp = new CompilerParameters();
            cp.GenerateExecutable = true;
            cp.OutputAssembly = exeName;
            cp.GenerateInMemory = false;
            cp.TreatWarningsAsErrors = false;
            cp.ReferencedAssemblies.Add("System.dll");

            var c = CSharpCodeProvider.CreateProvider("cs");
            var cr = c.CompileAssemblyFromSource(cp, s);
        }
    }
}

Output dimostrativo dalla riga di comando:

C:\projects\codegolf\2947\2947\bin\Debug>2947
Hello world!

C:\projects\codegolf\2947\2947\bin\Debug>dir
 Volume in drive C has no label.
 Volume Serial Number is 361D-4479

 Directory of C:\projects\codegolf\2947\2947\bin\Debug

09/27/2011  02:17 PM    <DIR>          .
09/27/2011  02:17 PM    <DIR>          ..
09/27/2011  02:17 PM             7,680 2947.exe
09/27/2011  02:17 PM            13,824 2947.pdb
09/27/2011  01:33 PM            11,600 2947.vshost.exe
09/27/2011  02:17 PM             6,656 8425.exe
               4 File(s)         39,760 bytes
               2 Dir(s)   6,486,368,256 bytes free

C:\projects\codegolf\2947\2947\bin\Debug>8425
Hello world!

C:\projects\codegolf\2947\2947\bin\Debug>dir
 Volume in drive C has no label.
 Volume Serial Number is 361D-4479

 Directory of C:\projects\codegolf\2947\2947\bin\Debug

09/27/2011  02:17 PM    <DIR>          .
09/27/2011  02:17 PM    <DIR>          ..
09/27/2011  02:17 PM             7,680 2947.exe
09/27/2011  02:17 PM            13,824 2947.pdb
09/27/2011  01:33 PM            11,600 2947.vshost.exe
09/27/2011  02:17 PM             6,656 7538.exe
09/27/2011  02:17 PM             6,656 8425.exe
               5 File(s)         46,416 bytes
               2 Dir(s)   6,486,360,064 bytes free

C:\projects\codegolf\2947\2947\bin\Debug>7538
Hello world!

C:\projects\codegolf\2947\2947\bin\Debug>dir
 Volume in drive C has no label.
 Volume Serial Number is 361D-4479

 Directory of C:\projects\codegolf\2947\2947\bin\Debug

09/27/2011  02:17 PM    <DIR>          .
09/27/2011  02:17 PM    <DIR>          ..
09/27/2011  02:17 PM             7,680 2947.exe
09/27/2011  02:17 PM            13,824 2947.pdb
09/27/2011  01:33 PM            11,600 2947.vshost.exe
09/27/2011  02:17 PM             6,656 4127.exe
09/27/2011  02:17 PM             6,656 7538.exe
09/27/2011  02:17 PM             6,656 8425.exe
               6 File(s)         53,072 bytes
               2 Dir(s)   6,486,351,872 bytes free

C:\projects\codegolf\2947\2947\bin\Debug>

2

Lotto

Versione 1 (30 byte)

type%0>%random%.bat&type%0>con

Io vinco! :)


il riferimento% 0 provoca una lettura dal file, che viola le regole. Inoltre, la mia versione binaria è ancora più breve. :-)
peter ferrie il

1

File COM DOS - 50 byte

Crea un file X.COMdove Xviene sostituito con le cifre dell'ora corrente. I file COM vengono semplicemente caricati in memoria all'offset 100hdel segmento di dati (CS e DS sono impostati per essere gli stessi) in modo da poter semplicemente scrivere questa memoria su un file.

0000000: b402 cd1a 80e6 0f80 ce30 8836 2c01 31c9  .........0.6,.1.
0000010: ba2c 01b4 3ccd 21c6 062c 0178 89c3 b440  .,..<.!..,.x...@
0000020: ba00 01b9 3200 cd21 b44c cd21 782e 636f  ....2..!.L.!x.co
0000030: 6d00                                     m.

fonte di nasm

org 100h ; this is a COM file
mov ah,02h ; fn=get time
int 1ah ; rtc interrupt
; convert to ascii - dh gets ones digit of seconds
and dh,0fh
or dh,30h
mov [fname],dh ; move time into filename
xor cx,cx ; clear attributes
mov dx,fname ; load filename
mov ah,3ch ; fn=create file
int 21h ; dos interrupt
mov byte [fname],'x' ; reset filename
mov bx,ax ; set filehandle
mov ah,40h ; fn=write to file
mov dx,100h ; offset is the loaded binary
mov cx,len ; length of write
int 21h ; dos iterrupt
mov ah,4ch ; fn=exit
int 21h ; dos interrupt
fname: db 'x.com',0
len equ $-$$

1

File DOS .COM, 29 byte

La "@" viene sostituita casualmente da una lettera dispari nella prima metà + parte dell'alfabeto (A, C, E, G, ecc.). I file di output sono 255 o 256 byte. I registri iniziali in DOS reale (al contrario di un debugger) sono AX = 0000, CX = 00FF, SI = 0100.

40       INC  AX         ;"@"
2E       CS:             ;"."
43       INC  BX         ;"C"
4F       DEC  DI         ;"O"
4D       DEC  BP         ;"M"
00 20    ADD  [BX+SI],AH ;"\0" and dummy parm
E4 40    IN   AL,40
24 0F    AND  AL,0F
0C 41    OR   AL,41
88 04    MOV  [SI],AL
B4 3C    MOV  AH,3C
41       INC  CX
89 F2    MOV  DX,SI
CD 21    INT  21
93       XCHG BX,AX
B4 40    MOV  AH,40
49       DEC  CX
CD 21    INT  21
C3       RET

0

File COM DOS - 36 byte

56 BE 80 00 AD FE C8 A2 10 01 7E 17 89 F2 88 74
02 B4 3C 33 C9 CD 21 72 0A 8B D8 B4 40 5A B9 24
00 CD 21 C3 

Il nome del file di output è specificato nella riga di comando, troncato nel formato 8.3, spazi OK (gli spazi nei nomi di file DOS sono legali). Testato utilizzando il prompt dei comandi di WinXP.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.