Makine kodunda yalnızca yazdırılabilir görünür ASCII karakterleri kullanarak x86 / x86-64'te farklı dallar


14

Görev basit: Makine kodunda yalnızca yazdırılabilir görünür ASCII karakterleri 0x21 ... 0x7e (boşluk ve del'e izin verilmez) kullanarak x86 (32 bit) ve x86-64 (64 bit) içinde farklı dallara ayrılan bir program yazın .

  • Koşullu toplamaya izin verilmez.
  • API çağrılarının kullanılmasına izin verilmiyor.
  • Çekirdek modu (ring 0) kodunun kullanılmasına izin verilmiyor.
  • Kod, Linux'ta veya başka bir korumalı mod işletim sisteminde IA-32 ve x86-64'te istisnalara neden olmadan çalışmalıdır.
  • İşleyişi komut satırı parametrelerine bağlı olmamalıdır.
  • Tüm talimatlar sadece 0x21 ... 0x7e (33 ... 126 ondalık) aralığındaki ASCII karakterleri kullanılarak makine kodunda kodlanmalıdır. Örneğin; kendi kendini değiştiren kod kullanmadığınız sürece cpuidsınırların 0f a2dışındadır.
  • Aynı ikili kod x86 ve x86-64'te çalıştırılmalıdır, ancak dosya başlıkları (ELF / ELF64 / vb.) Farklı olabileceğinden, yeniden birleştirmeniz ve bağlamanız gerekebilir. Ancak, ikili kod değişmemelidir.
  • Çözümler i386 ... Core i7 arasındaki tüm işlemcilerde çalışmalıdır, ancak daha sınırlı çözümlerle de ilgileniyorum.
  • Kod 32 bit x86'da dallanmalıdır, ancak x86-64'te değil veya tam tersi olmalıdır, ancak koşullu atlamaların kullanılması bir zorunluluk değildir (dolaylı atlama veya çağrı da kabul edilir). Şube hedef adresi, bazı kodlar için kısa bir atlayışın ( jmp rel8) sığdığı en az 2 bayt boşluk olacak şekilde olmalıdır.

Kazanan cevap, makine kodunda en az bayt kullanan cevaptır. Dosya başlığındaki baytlar (örneğin ELF / ELF64) sayılmaz ve daldan sonraki herhangi bir kod baytı (test amacıyla vb.) Sayılmaz.

Lütfen cevabınızı ASCII, onaltılık bayt ve yorumlanmış kod olarak sunun.

Benim çözümüm, 39 bayt:

ASCII: fhotfhatfhitfhutfhotfhatfhitfhut_H3<$t!

onaltılık: 66 68 6F 74 66 68 61 74 66 68 69 74 66 68 75 74 66 68 6F 74 66 68 61 74 66 68 69 74 66 68 75 74 5F 48 33 3C 24 74 21.

Kod:

; can be compiled eg. with yasm.
; yasm & ld:
; yasm -f elf64 -m amd64 -g dwarf2 x86_x86_64_branch.asm -o x86_x86_64_branch.o; ld x86_x86_64_branch.o -o x86_x86_64_branch
; yasm & gcc:
; yasm -f elf64 -m amd64 -g dwarf2 x86_x86_64_branch.asm -o x86_x86_64_branch.o; gcc -o x86_x86_64_branch x86_x86_64_branch.o

section .text
global main
extern printf

main:
    push    word 0x746f     ; 66 68 6f 74 (x86, x86-64)
    push    word 0x7461     ; 66 68 61 74 (x86, x86-64)
    push    word 0x7469     ; 66 68 69 74 (x86, x86-64)
    push    word 0x7475     ; 66 68 75 74 (x86, x86-64)

    push    word 0x746f     ; 66 68 6f 74 (x86, x86-64)
    push    word 0x7461     ; 66 68 61 74 (x86, x86-64)
    push    word 0x7469     ; 66 68 69 74 (x86, x86-64)
    push    word 0x7475     ; 66 68 75 74 (x86, x86-64)

    db      0x5f            ; x86:    pop edi
                            ; x86-64: pop rdi

    db      0x48, 0x33, 0x3c, 0x24
                            ; x86:
                            ; 48          dec eax
                            ; 33 3c 24    xor edi,[esp]

                            ; x86-64:
                            ; 48 33 3c 24 xor rdi,[rsp]

    jz      @bits_64        ; 0x74 0x21
                            ; branch only if running in 64-bit mode.

; the code golf part ends here, 39 bytes so far.

; the rest is for testing only, and does not affect the answer.

    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop

    jmp     @bits_32

@bits_64:
    db      0x55                    ; push rbp

    db      0x48, 0x89, 0xe5        ; mov rbp,rsp
    db      0x48, 0x8d, 0x3c, 0x25  ; lea rdi,
    dd      printf_msg              ; [printf_msg]
    xor     eax,eax
    mov     esi,64

    call    printf
    db      0x5d                    ; pop rbp

    NR_exit equ 60

    xor     edi,edi
    mov     eax,NR_exit     ; number of syscall (60)
    syscall

@bits_32:
    lea     edi,[printf_msg]
    mov     esi,32
    call    printf

    mov     eax,NR_exit
    int     0x80

section .data

printf_msg: db "running in %d-bit system", 0x0a, 0

1
Gerçekten kulübe sıcak şapka çarptı :)
aditsu çıkın çünkü SE kötü 17

Güzel. Tuhaf, ama güzel. Kazanan koşulu "en kısa" olarak ayarladığınızdan, etiketi [code-golf] olarak değiştireceğim ve yeni bir açıklayıcı etiket ekleyeceğim. Onlardan hoşlanmıyorsanız, bana bildirin.
dmckee --- eski moderatör yavru kedi

Yanıtlar:


16

7 bayt

0000000: 6641 2521 2173 21                        fA%!!s!

32 bit olarak

00000000  6641              inc cx
00000002  2521217321        and eax,0x21732121

64 bit olarak

00000000  6641252121        and ax,0x2121
00000005  7321              jnc 0x28

and64 bit sürüm her zaman atlar böylece taşıma bayrağını temizler. 64-bit için 6641işlenen boyutu geçersiz kılmanın ardından rex.bgelen işleniş boyutu and16 bit olur. 32-bit'de 6641tam bir talimattır, bu nedenle andöneki yoktur ve 32-bit işlenen boyutuna sahiptir. Bu and, yalnızca 64 bit modunda yürütülen iki baytlık talimat vererek tüketilen hemen bayt sayısını değiştirir .


1
Tebrikler 1k'a ulaştı.
DavidC

bu davranış CPU'ya özgüdür. Bazı 64 bit sistemler 64 bit modunda 66 öneki yok sayar.
peter ferrie

@peterferrie Bunun için bir referansınız var mı? Benim okumam, REX.W ayarlandığında 66 saatlik bir önek yok sayılır, ancak bunun yalnızca REX.B'si vardır
Geoff Reedy

pardon, yanılıyorum. Bu şekilde etkilenen yalnızca kontrol aktarımıdır (örneğin 66 e8, Intel'de 16 bit IP'ye geçmez).
peter ferrie

7

11 bayt

ascii: j6Xj3AX,3t!
hex: 6a 36 58 6a 33 41 58 2c 33 74 21

32-bit, 0x41 sadece gerçeği kullanır, inc %ecx64-bit raxise aşağıdaki poptalimatın hedef kaydını değiştiren önektir .

        .globl _check64
_check64:
        .byte   0x6a, 0x36      # push $0x36
        .byte   0x58            # pop %rax
        .byte   0x6a, 0x33      # push $0x33

        # this is either "inc %ecx; pop %eax" in 32-bit, or "pop %r8" in 64-bit.
        # so in 32-bit it sets eax to 0x33, in 64-bit it leaves rax unchanged at 0x36.
        .byte   0x41            # 32: "inc %ecx", 64: "rax prefix"
        .byte   0x58            # 32: "pop %eax", 64: "pop %r8"

        .byte   0x2c, 0x33      # sub $0x33,%al
        .byte   0x74, 0x21      # je (branches if 32 bit)

        mov     $1,%eax
        ret

        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        mov     $0,%eax
        ret

Bunu OSX'te yazdı, montajcınız farklı olabilir.

Şununla ara:

#include <stdio.h>
extern int check64(void);
int main(int argc, char *argv[]) {
  if (check64()) {
    printf("64-bit\n");
  } else {
    printf("32-bit\n");
  }
  return 0;
}

2

7 bayt

66 önekine dayanmamak.

$$@$Au!

32 bit:

00000000 24 24 and al,24h
00000002 40    inc eax
00000003 24 41 and al,41h
00000005 75 21 jne 00000028h

AL, INC'den sonra 0 biti ayarlayacak, ikincisi VE onu koruyacak, dal alınacaktır.

64 bit:

00000000 24 24    and al,24h
00000002 40 24 41 and al,41h
00000005 75 21    jne 00000028h

İlk VE sonrasında AL 0 biti açık olacak, dal alınmayacak.


0

Sadece C9h yazdırılabilir olsaydı ...

32 bit:

00000000 33 C9 xor  ecx, ecx
00000002 63 C9 arpl ecx, ecx
00000004 74 21 je   00000027h

ARPL, Z bayrağını temizleyerek dalın alınmasına neden olacak.

64 bit:

00000000 33 C9 xor    ecx, ecx
00000002 63 C9 movsxd ecx, ecx
00000004 74 21 je     00000027h

XOR Z bayrağını ayarlayacak, MOVSXD bunu değiştirmeyecek, dal alınmayacak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.