Windows の世界でこの種の難読化スキームに精通している人はいますか?
正しく理解すれば、ROT13のような単純な回転暗号です。
なぜ誰もがこれを使用するのでしょうか?
まあ、一般的に、これは非常に一般的です。難読化する必要があるデータがあるとします。ただし、復号化アルゴリズムとキーは、視聴者が持っているソフトウェアに組み込まれている必要があります。AES のような手の込んだものを使用しても意味がありません。なぜなら、AES をクラックする代わりに、誰かがアルゴリズムを掘り下げて、コードからキーを取り出すことができるからです。隠された鍵を見つけるよりもクラックするのがわずかに難しい暗号化スキームは、完全な暗号化スキームと同じくらい優れています。(多くの場合、停止することについて本当に心配することさえありませんただし、攻撃者が契約上または法律上の理由で悪意を持って行動したに違いないという事実の後に証明することについて.) したがって、単純なローテーション暗号または単純な xor 暗号のいずれかを使用します。高速で、間違いにくく、簡単です。最悪の場合は、手動で復号化して破損したデータを回復することもできます。
詳細については:
ASCII 以外の文字を処理したい場合は、ほぼ Unicode を使用する必要があります。固定の 8 ビット文字セットまたはローカル システムの OEM 文字セットを使用すると、他のマシンからのパスワードを処理できなくなります。
Python スクリプトでは、ほぼ確実に Unicode 文字を処理します。Python では、 でバイト単位str
、または で Unicode 文字を処理するためunicode
です。WCHAR *
ただし、Windows ネイティブ API は UTF-16-LE コード ポイント(別名 16 ビット ワードの文字列) を扱うため、Windows C または .NET アプリは UTF-16 を使用する可能性がはるかに高くなります。
では、なぜ 4142 なのか? まあ、キーが何であるかは問題ではありません。一部のプログラマーが42を提案したと思います。彼のマネージャーは、「それはあまり安全ではないようだ」と言った。彼はため息をつき、こう言った。「なぜ、どの鍵よりも安全な鍵がないのかは、すでに説明した...わかっているだろうが、忘れてほしい。4142 はどうだろうか?」マネージャーは、「ああ、それは本当に安全な番号のようですね!」と言いました。それが4142の理由です。
ライブラリ関数でない場合は、魔法の 142 番号に頼らずにこれらの値の難読化を解除するためのより良い方法を考えてください。
魔法の 4142 に頼る必要がありますが、これをもっと簡単にすることができます。
def decrypt(block):
return struct.pack('>H', (4142 - int(block, 10)) % 65536)
したがって、5 文字の各ブロックは、C unsigned-short ラップアラウンド規則を使用して、4142 から減算された UTF-16 コード単位の 10 進数表現です。
これをネイティブの Windows C で実装するのは簡単ですが、Python では少し難しくなります。私が思い付くことができる最高の変換関数は次のとおりです。
def decrypt_block(block):
return struct.pack('>H', (4142 - int(block, 10)) % 65536)
def decrypt(pwd):
blocks = [pwd[i:i+5] for i in range(0, len(pwd), 5)]
return ''.join(map(decrypt_block, blocks)).decode('utf-16-be')
これは C や C# ではもっと些細なことで、おそらく彼らが実装したものなので、私が何をしているのか説明させてください。
文字列を 5 文字のブロックのシーケンスに変換する方法は既に知っています。
私int(block, 10)
はあなたのと同じことをしていますint(block.lstrip('0'))
.'0'
接頭辞がPythonにそれを10進数ではなく8進数として扱わせないようにしますが、より明示的にします. Jython 2.2 ではこれが実際に必要だとは思いません (最新の Python/Jython では絶対に必要ではありません) が、念のため残しました。
次に、C では、unsigned short x = 4142U - y;
自動的に適切にアンダーフローする を実行するだけです。Python にはunsigned short
値がなく、 signed だけint
なので、アンダーフローを手動で行う必要があります。(Python は床除算と剰余を使用するため、符号は常に除数と同じです。これは C では当てはまりません。少なくとも C99 とほとんどのプラットフォームの C89 では当てはまりません。)
次に、C では、unsigned short を 16 ビットの「ワイド文字」にキャストします。Python にはそれを行う方法がないため、 を使用する必要がありますstruct.pack
。(これをビッグ エンディアンに変換していることに注意してください。これは、デバッグが容易になるためです。C では、ネイティブ エンディアンに変換します。これは Windows であるため、リトル エンディアンになります。)
これで、2 文字の UTF-16-BE コード ポイントのシーケンスが得られました。join
それらを 1 つの大きな文字列にまとめdecode
てから、UTF-16-BE にします。
私がこれを正しく理解していることを本当にテストしたい場合は、非 ASCII だけでなく、非西洋文字を見つける必要があります。特に、次のものが必要です。
- > U+4142 で < U+10000 のキャラクター。U+7000 (瀀) のようなほとんどの CJK 表意文字は、この条件に適合します。
'41006'
4142-0x7000 が unsigned short としてロールオーバーされるため、これは のように表示されます。
- >= U+10000 のキャラクター。これには、一般的ではない CJK 文字、特殊な数学文字、古代のスクリプトの文字などが含まれます。4142-0xd800=14382、および 4142-0xdf00=12590 なので、
'1438212590'
.
1 つ目は見つけるのが難しく、私が扱ったほとんどの中国語および日本語ネイティブのプログラマーでさえ ASCII パスワードを使用しています。2 つ目は、なおさらです。歴史言語学の教授以外は、パスワードに古風なスクリプトを使用することを考えることさえあるでしょう。マーフィーの法則により、正しいコードを記述した場合は決して使用されませんが、そうでない場合は、コードを出荷するとすぐに表示されることが保証されています。