Bagaimana cara kerja program C ini?
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
Ini mengkompilasi sebagaimana adanya (diuji pada gcc 4.6.3
). Ini mencetak waktu ketika dikompilasi. Di sistem saya:
!! !!!!!! !! !!!!!! !! !!!!!!
!! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !!
!! !!!!!! !! !! !! !! !! !!!!!!
!! !! !! !! !! !! !!
!! !! !! !! !! !! !!
!! !!!!!! !! !! !! !!!!!!
Sumber: sykes2 - Jam dalam satu baris , petunjuk penulis sykes2
Beberapa petunjuk: Tidak ada kompilasi peringatan per default. Dikompilasi dengan -Wall
, peringatan berikut dikirimkan:
sykes2.c:1:1: warning: return type defaults to ‘int’ [-Wreturn-type]
sykes2.c: In function ‘main’:
sykes2.c:1:14: warning: value computed is not used [-Wunused-value]
sykes2.c:1:1: warning: implicit declaration of function ‘putchar’ [-Wimplicit-function-declaration]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]
c
obfuscation
deobfuscation
dangkal
sumber
sumber
printf("%d", _);
ke awalmain
cetakan: pastebin.com/HHhXAYdJint
./a.out $(seq 0 447)
Jawaban:
Mari kita hapuskannya.
Indentasi:
Memperkenalkan variabel untuk mengurai kekacauan ini:
Perhatikan bahwa
-~i == i+1
karena dua-pelengkap. Karena itu, kita punyaSekarang, perhatikan bahwa
a[b]
itu sama denganb[a]
, dan terapkan-~ == 1+
perubahan itu lagi:Mengubah rekursi menjadi loop dan menyelinap dengan sedikit penyederhanaan:
Ini menghasilkan satu karakter per iterasi. Setiap karakter ke-64, itu menghasilkan baris baru. Kalau tidak, ia menggunakan sepasang tabel data untuk mencari tahu apa yang akan dihasilkan, dan menempatkan karakter 32 (spasi) atau karakter 33 (a
!
). Tabel pertama (">'txiZ^(~z?"
) adalah satu set 10 bitmap yang menggambarkan penampilan setiap karakter, dan tabel kedua (";;;====~$::199"
) memilih bit yang sesuai untuk ditampilkan dari bitmap.Tabel kedua
Mari kita mulai dengan memeriksa tabel kedua
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
,.i/64
adalah nomor baris (6 hingga 0) dani*2&8
8 iffi
adalah 4, 5, 6 atau 7 mod 8.if((i & 2) == 0) shift /= 8; shift = shift % 8
memilih digit oktal tinggi (untuki%8
= 0,1,4,5) atau digit oktal rendah (untuki%8
= 2,3,6,7) dari nilai tabel. Tabel shift akhirnya tampak seperti ini:atau dalam bentuk tabel
Perhatikan bahwa penulis menggunakan terminator nol untuk dua entri tabel pertama (licik!).
Ini dirancang setelah tampilan tujuh segmen, dengan
7
s sebagai blank. Jadi, entri dalam tabel pertama harus menentukan segmen yang menyala.Tabel pertama
__TIME__
adalah makro khusus yang didefinisikan oleh preprocessor. Itu mengembang ke konstanta string yang berisi waktu di mana preprocessor dijalankan, dalam bentuk"HH:MM:SS"
. Perhatikan bahwa itu berisi persis 8 karakter. Perhatikan bahwa 0-9 memiliki nilai ASCII 48 hingga 57 dan:
memiliki nilai ASCII 58. Outputnya adalah 64 karakter per baris, sehingga menyisakan 8 karakter per karakter__TIME__
.7 - i/8%8
dengan demikian indeks__TIME__
yang saat ini sedang output (7-
diperlukan karena kita beralihi
ke bawah). Jadi,t
adalah karakter__TIME__
sebagai keluaran.a
akhirnya sama dengan yang berikut dalam biner, tergantung pada inputt
:Setiap angka adalah bitmap yang menggambarkan segmen yang menyala di layar tujuh segmen kami. Karena semua karakter 7-bit ASCII, bit tinggi selalu dihapus. Dengan demikian,
7
dalam tabel segmen selalu dicetak sebagai kosong. Tabel kedua terlihat seperti ini dengan7
s sebagai blank:Jadi, misalnya,
4
adalah01101010
(bit 1, 3, 5, dan 6 set), yang dicetak sebagaiUntuk memperlihatkan bahwa kami benar-benar memahami kode, mari sesuaikan outputnya sedikit dengan tabel ini:
Ini dikodekan sebagai
"?;;?==? '::799\x07"
. Untuk tujuan artistik, kami akan menambahkan 64 ke beberapa karakter (karena hanya 6 bit rendah yang digunakan, ini tidak akan mempengaruhi output); ini memberi"?{{?}}?gg::799G"
(perhatikan bahwa karakter ke-8 tidak digunakan, sehingga kita dapat benar-benar membuatnya menjadi apa pun yang kita inginkan). Menempatkan tabel baru kami di kode asli:kita mendapatkan
seperti yang kami harapkan. Ini tidak sekokoh aslinya, yang menjelaskan mengapa penulis memilih untuk menggunakan tabel yang dia lakukan.
sumber
*
(dereferensi) dan+
: PMari format ini agar lebih mudah dibaca:
Jadi, menjalankannya tanpa argumen, _ (argc secara konvensional) adalah
1
.main()
akan secara rekursif memanggil dirinya sendiri, melewati hasil-(~_)
(bitwise negatif BUKAN_
), jadi benar-benar akan 448 rekursi (Hanya kondisi di mana_^448 == 0
).Mengambil itu, itu akan mencetak 7 garis lebar 64 karakter (kondisi terner luar, dan
448/64 == 7
). Jadi mari kita tulis ulang sedikit lebih bersih:Sekarang,
32
adalah desimal untuk ruang ASCII. Itu bisa mencetak spasi atau '!' (33 adalah '!', Maka '&1
' pada akhirnya). Mari kita fokus pada gumpalan di tengah:Seperti yang dikatakan poster lain,
__TIME__
adalah waktu kompilasi untuk program, dan merupakan string, jadi ada beberapa aritmatika string yang terjadi, serta mengambil keuntungan dari array subscript menjadi dua arah: a [b] sama dengan b [a] untuk array karakter.Ini akan memilih salah satu dari 8 karakter pertama di
__TIME__
. Ini kemudian diindeks menjadi[">'txiZ^(~z?"-48]
(0-9 karakter adalah 48-57 desimal). Karakter dalam string ini harus dipilih karena nilai ASCII mereka. Manipulasi kode ASCII karakter yang sama ini berlanjut melalui ekspresi, untuk menghasilkan pencetakan '' atau '!' tergantung pada lokasi dalam mesin terbang karakter.sumber
Menambahkan ke solusi lain,
-~x
sama denganx+1
karena~x
sama dengan(0xffffffff-x)
. Ini sama dengan(-1-x)
komplemen 2s, begitu-~x
juga-(-1-x) = x+1
.sumber
Saya mengurangi modulo arithmetics sebanyak yang saya bisa dan menghilangkan rekursi
Memperluasnya sedikit lagi:
sumber