難読化されたTeXの解読(tkbctf3 Misc 100 Real World TeX)
tkbctf3で出題された問題。
問題
^^5c^^66^^75^^74^^75^^72^^65^^6c^^65^^74^^7e ^^5c^^63^^61^^74^^63^^6f^^64^^65^^60K7 KK5cKK65KK6eKK64KK6cKK69KK6eKK65KK63KK68KK61KK72- KK5cKK73KK74KK72KK69KK6eKK67KK60 KK7eKK60I13KK7eKK60G10KK5cKK6cKK65KK74 IKK7eI86G10I83G7I72G1I90V0I78V2I80G6I82G5 I13G9I76G13ZKK6cKK65KK74GLZKK6cKK65KK74I65G13LZSS46ZKK66SS6fKK6eKK74VLZSS54ZSS6dSS61SS67KK73KK74SS65KK70V ZSS46ZSS62KK69SS67KK3dSS63KK6dKK7210VKK73SS63SS61KK6cKK65SS64VZSS6dKK61KK67KK73KK74SS65KK704V ZKK46ZKK73SS63KK3dSS63KK6dKK63KK73SS6310VKK73KK63SS61SS6cSS65KK64VZKK6dKK61SS67SS73KK74KK65KK704V ZSS46ZKK62SS66SS3dSS63SS6dSS62SS7810ZKK72KK65KK6cKK61SS78V ZKK64SS65SS66ZKK68SS6fP1P2HP2P1NVLKK41ZSS68SS6fV KK60KK60HZKK62SS69KK67VSS4dNSS6fSS73SS74VKK70KK72KK6fKK67KK72SS61SS6dKK6dKK69KK6eSS67V SS6cSS61KK6eKK67KK75KK61KK67SS65SS73VKK61SS72KK65VSS70KK61KK72SS74SS6cSS79VSS61VKK77KK61SS79VSS6fSS66V SS65SS78SS70KK72SS65SS73KK73SS69SS6eKK67VSS74SS68KK69KK6eKK67SS73VKK69KK6eVV SS74SS65SS72SS6dKK73VSS6fSS66VVSS6fSS74KK68SS65KK72VKK74SS68KK69SS6eSS67SS73V KK61KK6eKK64VSS70SS61SS72KK74SS6cSS79VVSS61VSS62SS61SS73KK69SS63VSS73KK65SS74V SS6fSS66VKK67SS69SS76SS65SS6eVKK74SS68SS69KK6eKK67SS73SS2eKK27KK27VZKK76SS73KK6bSS69SS70V10KK70KK74V HZSS73KK63ZSS63KK61SS74KK63SS6fKK64KK65KK60SS4912VKK41SS73KK49SS41KK69SS6dKK6dNVKK69SS73VV KK74KK68KK65VHZKK62KK66VSS6bSS65SS79SS77KK6fKK72KK64NVSS6fKK66VSS74KK68KK69KK73VSS71KK75KK65KK73SS74KK69KK6fKK6eKK21V ZKK6eSS65SS77SS77SS72KK69SS74SS65ZSS61ZKK72SS65KK6cSS61SS78V ZSS6fKK70KK65KK6eSS6fSS75KK74ZSS61KK3dZSS6aKK6fSS62KK6eSS61SS6dKK65SS2eKK69KK64KK78ZSS72KK65SS6cSS61KK78V ZKK77KK72KK69KK74KK65ZKK61HKK41SS61SS4cKK6eKK411SS64SS6eVSS69KK73VSS61KK6eSS6fKK74SS68KK65SS72VKK6bKK65SS79SS77KK6fKK72KK64KK21NV ZKK63KK6cSS6fKK73KK65SS6fSS75SS74ZSS61ZSS72SS65SS6cKK61KK78VZKK62SS79KK65
実はこれは正しいTeXファイルで、先頭に
\documentclass{article} \begin{document}
を、末尾に
\end{document}
を追加するとコンパイルできて、1個目のフラグが表示される。(ファイル名).idxに2個目のフラグが出力される。
どのようにコンパイルされているのか辿ってみたら面白かった。
1行目
TeXでは^^nnは文字コード0xnnの文字になる。これで1行目が解読できる。
\futurelet~ \catcode`K7
\futureletが良く分からないけど、まず\catcode`K7が実行され、以降に~ A Bが出てくると\catcode A Bが実行されるらしい。\catcodeは\catcode `K 7でKのカテゴリーコードを7にする。`Kの代わりに、\catcode 75 7と、文字コードを10進数で書くこともできる。カテゴリーコードはここに載っている。\catcode`K7によって、以降Kは^と同じ働きをするようになる。よって、KKnnは文字コード0xnnの文字になる。
\futurelet~ \catcode`K7 \endlinechar- \string` ~`I13~`G10\let I~I86G10I83G7I72G1I90V0I78V2I80G6I82G5 I13G9I76G13ZletGLZletI65G13LZSS46ZfSS6fntVLZSS54ZSS6dSS61SS67stSS65pV ZSS46ZSS62iSS67=SS63mr10VsSS63SS61leSS64VZSS6dagstSS65p4V ZFZsSS63=SS63mcsSS6310VscSS61SS6cSS65dVZmaSS67SS73tep4V ZSS46ZbSS66SS3dSS63SS6dSS62SS7810ZrelaSS78V ZdSS65SS66ZhSS6fP1P2HP2P1NVLAZSS68SS6fV ``HZbSS69gVSS4dNSS6fSS73SS74VprogrSS61SS6dminSS67V SS6cSS61nguagSS65SS73VaSS72eVSS70arSS74SS6cSS79VSS61VwaSS79VSS6fSS66V SS65SS78SS70rSS65SS73sSS69SS6egVSS74SS68ingSS73VinVV SS74SS65SS72SS6dsVSS6fSS66VVSS6fSS74hSS65rVtSS68iSS6eSS67SS73V andVSS70SS61SS72tSS6cSS79VVSS61VSS62SS61SS73iSS63VSS73eSS74V SS6fSS66VgSS69SS76SS65SS6eVtSS68SS69ngSS73SS2e''VZvSS73kSS69SS70V10ptV HZSS73cZSS63aSS74cSS6fde`SS4912VASS73ISS41iSS6dmNViSS73VV theVHZbfVSS6bSS65SS79SS77ordNVSS6ffVSS74hisVSS71uesSS74ion!V ZnSS65SS77SS77SS72iSS74SS65ZSS61ZrSS65lSS61SS78V ZSS6fpenSS6fSS75tZSS61=ZSS6aoSS62nSS61SS6deSS2eidxZSS72eSS6cSS61xV ZwriteZaHASS61SS4cnA1SS64SS6eVSS69sVSS61nSS6ftSS68eSS72VkeSS79SS77ord!NV ZclSS6fseSS6fSS75SS74ZSS61ZSS72SS65SS6caxVZbSS79e
3行目(と4行目の一部)
~`I13~`G10
~が\catcodeになっているので、これは、
\catcode `I 13 \catcode `G 10
と等価。Iのカテゴリコードを~と同じに、Gのカテゴリコードを空白と同じにしている。Iのカテゴリコードを英文字から変えたことで、\Iではなく、Iだけでコマンドとして使えるようになる。
\let I~
Iに~を代入。今、~は\catcodeなので、I A Bと書くと、\catcode A Bになる。
I86G10I83G7I72G1I90V0I78V2I80G6I82G5 I13G9I76G13
Iが\catcodeでGが空白文字なので、
\catcode 86 10 % V → [ ] \catcode 83 7 % S → ^ \catcode 72 1 % H → { \catcode 90 0 % Z → \ \catcode 78 2 % N → } \catcode 80 6 % P → # \catcode 82 5 % R → \n \catcode 13 9 % \r → \0 \catcode 76 13 % L → ~
になる。
Sが^なので、以降、SSnnは0xnnになる。
\futurelet~ \catcode`K7 \endlinechar- \string` ~`I13~`G10\let I~I86G10I83G7I72G1I90V0I78V2I80G6I82G5 I13G9I76G13ZletGLZletI65G13LZFZfontVLZTZmagstepV ZFZbig=cmr10VscaledVZmagstep4V ZFZsc=cmcsc10VscaledVZmagstep4V ZFZbf=cmbx10ZrelaxV ZdefZhoP1P2HP2P1NVLAZhoV ``HZbigVMNostVprogrammingV languagesVareVpartlyVaVwayVofV expressingVthingsVinVV termsVofVVotherVthingsV andVpartlyVVaVbasicVsetV ofVgivenVthings.''VZvskipV10ptV HZscZcatcode`I12VAsIAimmNVisVV theVHZbfVkeywordNVofVthisVquestion!V ZnewwriteZaZrelaxV ZopenoutZa=Zjobname.idxZrelaxV ZwriteZaHAaLnA1dnVisVanotherVkeyword!NV ZcloseoutZaZrelaxVZbye
4行目
ZletGLZlet
↓
\let L \let
Lが\letになる。
I65G13
↓
\catcode 65 13 % A → ~
あとで、\let A hogeをするため。
LZFZfontVLZTZmagstepV
↓
\let \F \font \let \T \magstep
5-7行目
ZFZbig=cmr10VscaledVZmagstep4V ZFZsc=cmcsc10VscaledVZmagstep4V ZFZbf=cmbx10ZrelaxV
↓
\F\big=cmr10 scaled \magstep4 \F\sc=cmcsc10 scaled \magstep4 \F\bf=cmbx10 \relax
8行目
ZdefZhoP1P2HP2P1NVLAZhoV
↓
\def \ho #1#2 {#2#1} \let A \ho
直後の文字を入れ替えるコマンドAを定義している。
9行目以降
``HZbigVMNostVprogrammingV languagesVareVpartlyVaVwayVofV expressingVthingsVinVV termsVofVVotherVthingsV andVpartlyVVaVbasicVsetV ofVgivenVthings.''VZvskipV10ptV HZscZcatcode`I12VAsIAimmNVisVV theVHZbfVkeywordNVofVthisVquestion!V ZnewwriteZaZrelaxV ZopenoutZa=Zjobname.idxZrelaxV ZwriteZaHAaLnA1dnVisVanotherVkeyword!NV ZcloseoutZaZrelaxVZbye
↓
``{\big M}ost programming languages are partly a way of expressing things in terms of other things and partly a basic set of given things.'' \vskip 10pt {\sc\catcode`I12 AsIAimm} is the {\bf keyword} of this question! \newwrite\a\relax \openout\a=\jobname.idx\relax \write\a{AaLnA1dn is another keyword!} \closeout\a\relax \bye
\catcode`I12でIが英文字に戻り、コマンドAをによって直後の文字が入れ替わるので、
{\sc Ismim} {Land1n is another keyword!}