数値署名

私はいつもプログラミングの魔法に魅了されてきました。一見無意味なコードが何か面白いことをする小さなトリックです。 最も有名なものは「署名」で、短いテキスト(通常は著者の名前)を印刷します。 前回私難解なプログラミング言語に基づいてこのようなトリックをいくつか示しましたが、新年の挨拶を準備するときにいくつかの読者にとっても役立ちました:-)本当の魔法は、毎日使用する完全に通常の言語でそのようなギズモを作成することですC ++またはJava。 この記事では、入力として数値定数のみを使用して短いテキストを表示するいくつかの方法を示します。



免責事項:上記のトリックのほとんどはメモリを使用した低レベルのアクションに基づいているため、結果はコンピューターのアーキテクチャと使用するコンパイラーによって異なる場合があります(私はgccを使用しています)。




C ++は、メモリとポインタを使用した周辺操作を冷静に指しているため、数字で文字列を指定するタイプを難読化することは、ほとんど一般的なことです:-)最も簡単な例:



#include <stdio.h> int main() { int A = 2037539149; printf((char *)&A); }
      
      







どのように機能しますか? printf関数の最初の唯一の必須引数はchar * formatであり、出力形式を設定します。 通常、定数文字列が渡され、変数部分は次の引数から取得されます。 引数としてchar *変数を使用しても機能しますが、コンパイラは「文字列リテラルではなく、形式引数なしの形式」という警告が表示されます。



(char *)&Aは、変数Aのアドレスを(この変数に実際に格納されているものに関係なく)文字の配列へのポインターとして扱います。 問題は小さいです。たとえば、Mary-> 0x4D 0x61 0x72 0x79-> 0x7972614D(文字は最下位から最上位へと逆の順序で印刷されます)-> 2037539149のように、目的の単語を構成するAバイトを入れます。



この方法の制限は、最大4文字の長さの単語を印刷することであり、intには収まりません。 intをunsigned long longに置き換えると、8文字が取得できます。



 #include <stdio.h> int main() { unsigned long long A = 8751164009814452552ULL; printf((char *)&A); }
      
      







タスクを複雑にし、整数から浮動小数点数に移行します。 内部表現を理解している人が少ないので、これにより難読化の度合いが高まります:-)



最も簡単な例:



 #include <stdio.h> int main() { double A = 2.222663600523023e-313; printf((char*)&A); }
      
      







どのように機能しますか? はい、同じように、特定の行を出力するための定数のみを取得するのが少し難しくなります。 名前の後に改行を入れて「Mary」を出力するには、メモリにバイトセット0x4D 0x61 0x72 0x79 0x0Aが必要です。 これらのバイトによって正確に記述された二重定数を検索するには、次のハックを使用できます。

1.目的のバイトを16進数として文字列に書き込みます(最初の方法と同様):A7972614D。

2.この行から、数値をunsigned long longとして読み取りますが、double型の変数に書き込みます。

3.たとえば、STLを使用して、結果の変数を可能な限り正確に印刷します。



 #include <stdio.h> #include <iostream> #include <iomanip> #include <limits> using namespace std; int main() { double a; sscanf("A7972614D", "%llx", (unsigned long long *)&a); cout << setprecision (numeric_limits<double>::digits10 + 1) << a << endl; }
      
      







必要に応じて、コードを複雑にすることができます。たとえば、数値定数を直接ではなく、いくつかの計算の結果として設定できます。 魔法の定数pi、e、黄金比などからテキストを取得するのは素晴らしいことです。 この記事は、次の形式の素晴らしい再帰的な署名に触発されました(定数は変更されました):



 #include <stdio.h> double x = 0.003609087829883, y; int main() { return(*(char*)&x?x*=y=x,main():printf((char*)&y)); }
      
      







デバッグ出力を再フォーマットして追加することにより、このコードが数値xを再帰的に2乗し、最後のゼロ以外の累乗(再び文字列のように)を出力することを確認できます。 4文字のテキストは10-300のオーダーの定数であるように見えるため、この定数の2乗は実際にはゼロになります。 コード内のソース定数は、テキスト定数の2のべき乗の根として計算されます。



多くの言語では、プログラマにメモリやデータ型の自由を認めていませんが、10進数以外の数値システムで数値を表現することにより、より古典的な方法でそれを行うことができます。 私の名前がAdaの場合、16進数に制限することは可能ですが、Maryは35以上、36以上が必要です。



 public class Magic { public static void main(String[] args) { System.out.println(Integer.toString(1040398,36)); } }
      
      







よろしく

370288658856287000618250P






All Articles