Napisz samoreplikujący się program.

11

Napisz prosty program, który sam się kopiuje po uruchomieniu.

Twój program powinien być jakimś plikiem wykonywalnym w systemie Windows, Linux itp., Powinien wygenerować nowy plik wykonywalny, który jest identyczny z oryginalnym plikiem wykonywalnym, z losową nazwą i zakończony.

Twój program nie powinien obejmować żadnego odczytu lub kopiowania plików. Dozwolone jest tylko zapisywanie plików w celu wygenerowania nowego pliku wykonywalnego.

(PS. Byłem bardzo zawstydzony, gdy w Wikipedii Self-replicating programprzekierowałem do Computer virusartykułu ...: / ...)

Wygrywa najmniejszy plik wykonywalny. Twoja odpowiedź może być kodem programistycznym z odpowiednim systemem operacyjnym i kompilatorem, kodem zestawu lub zrzutem HEX pliku wykonywalnego.

JiminP
źródło
6
Wydaje się, że różni się to tylko trywialnie od istniejących wyzwań [quine]. A może źle zrozumiałem?
dmckee --- były moderator kotek
1
@dmckee Widziałem asembler Quine i samoreplikujący się program Hello World akceptujący kopiowanie, ale nie mogłem znaleźć programu, który sam się pisze , a nie jego kodu .
JiminP
1
... ale chcę zobaczyć, jak to naprawdę działa! .. nie wiem, jak można rozszerzyć ten pomysł za pomocą kodów binarnych .. mimo że czytam artykuł Quine na Wikipedii. PS. kompilatory do replikacji i języki skryptowe nie są dozwolone ...: /
JiminP
4
Każdy problem można uczynić nieco trudniejszym i brzydszym, dodając do niego więcej ograniczeń. Uważam ten problem za trywialne rozszerzenie problemu quine.
Alexandru
1
Jeśli wygra najmniejszy rozmiar pliku wykonywalnego, czy nie powinniśmy również uwzględniać kodu interpretera jako części rozmiaru pliku wykonywalnego, aby był sprawiedliwy dla użytkowników skompilowanych języków?
Thomas Dignan,

Odpowiedzi:

4

Bash, 236

Dłużej niż to absolutnie konieczne, ale nienawidzę długich linii. Końcowy znak nowej linii nie jest opcjonalny.

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 $$
JB
źródło
Właściwie to nie jest to, czego chciałem, ponieważ napisałem „złe” pytanie, a twoja odpowiedź to świetny quine ...
JiminP
@JiminP: Jak to nie jest to, czego chciałeś? Ponownie przeczytałem opis problemu dwa razy i nie rozumiem.
JB
Cóż ... to, czego chciałem, to wykonywalny kod binarny. Jak przyznałem powyżej, ponieważ moje pytanie nie było całkiem „właściwe” ... przepraszam za to.
JiminP
3
@JiminP Cóż, tak, słowo „binarne” w ogóle nie pojawia się w pytaniu. Właśnie znalazłem to w komentarzach, ale dla takiego ograniczenia po prostu tego nie wycina. Możesz otworzyć nowe pytanie ze wszystkimi skonsolidowanymi danymi wejściowymi z komentarzy. Sugeruję, abyś użył piaskownicy, aby upewnić się, że stali bywalcy pomogą ci rozwiązać drobne szczegóły. Ale uwaga, odpowiedzi binarne bywają nudne.
JB
10

Zestaw dla systemu Linux x86, 106 bajtów

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     $ - $$

To jest dla asemblera nasm. Zbuduj plik binarny za pomocą wiersza polecenia:nasm -f bin -o a.out selfrep.asm && chmod +x a.out

Oto ten sam plik co zrzut heksowy: 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

Zgodnie z żądaniem program kopiuje się do osobnego pliku. (Program mógłby być znacznie krótszy, gdyby pozwolono mu po prostu pisać na standardowe wyjście i pozwolić użytkownikowi na przekierowanie do pliku).

Unikałem używania jakichkolwiek sztuczek na granicy, aby zmniejszyć rozmiar. Powinien to być w pełni zgodny 32-bitowy plik binarny ELF.

Edytowano, aby dodać : W powyższej wersji utworzony plik jest zwykłym plikiem, ale przychodzi mi do głowy, że za kilka bajtów (i mały zakręt reguł) możesz stworzyć coś bardziej interesującego. Ta wersja jest tylko dwa bajty dłuższa i ma 108 bajtów:

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     $ - $$

Nazwij tę wersję asrdla „samoreplikatora”:nasm -f bin -o asr asr.asm && chmod +x asr

Wersja zrzutu szesnastkowego dla osób z upośledzeniem nasm: 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

Po uruchomieniu tworzy prawie identyczny plik o nazwie bsr, ale taki, który sam jest wykonywalny. Uruchomienie go spowoduje utworzenie kolejnego pliku binarnego o nazwie csr. I tak dalej.

(Zauważ, że irytujące rzeczy zaczynają się później zsr. Zastanawiałem się nad stworzeniem wersji, która kaskadowo zmieniałaby nazwy na atritd., Ale myślę, że większość ludzi wcześniej się nudzi, więc prawdopodobnie nie jest to warte wszystkich dodatkowych bajtów. )

chlebak
źródło
+1 za odpowiedź montażu! Czy widziałeś wyzwanie związane z montażem ?
MD XF,
2

Oto proof-of-concept (niemodyfikowany), który pokazuje, w jaki sposób można korzystać z usług kompilacji w .NET do kompilacji kodu źródłowego w locie w celu wygenerowania identycznego wyniku. Pierwsza kopia nie jest identyczna z oryginałem, ale kolejne kopie z kolejnych uruchomień są dokładnie identyczne z losowymi nazwami plików:

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);
        }
    }
}

Dane wyjściowe demonstracji w wierszu polecenia:

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>
mellamokb
źródło
2

Partia

Wersja 1 (30 bajtów)

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

Wygrałem! :)

st0le
źródło
odwołanie% 0 powoduje odczyt z pliku, co narusza reguły. Poza tym moja wersja binarna jest jeszcze krótsza. :-)
Peter Ferrie
1

Plik COM systemu DOS - 50 bajtów

Tworzy plik, w X.COMktórym Xjest zastępowany cyfrą one aktualnego czasu. Pliki COM są po prostu ładowane do pamięci z przesunięciem 100hsegmentu danych (CS i DS są ustawione tak samo), dzięki czemu możemy po prostu zapisać tę pamięć do pliku.

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.

źródło 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 $-$$
Geoff Reedy
źródło
1

Plik DOS .COM, 29 bajtów

„@” Jest losowo zastępowane nieparzystą literą w pierwszej połowie + część alfabetu (A, C, E, G itp.). Pliki wyjściowe mają 255 lub 256 bajtów. Początkowe rejestry w rzeczywistym DOS (w przeciwieństwie do debuggera) to 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
Peter Ferrie
źródło
0

Plik COM DOS - 36 bajtów

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 

Nazwa pliku wyjściowego jest określona w wierszu polecenia, obcięta do formatu 8.3, spacje OK (spacje w nazwach plików DOS są dozwolone). Testowane przy użyciu wiersza polecenia WinXP.

Skizz
źródło