健康! このプログラムのことを聞いたことがないのに驚かないでしょう。 私のように、
Python Debuggerが役立つ日まで。 はい、私は知っています、
pdbがありますが、その機能とその表示方法はまったく好きではありませんでした。 短い検索の後、この素晴らしい製品に出会いました。
Pythonアプリケーションのデバッグに役立つすべてのものがあります(すぐに言います。私はこの言語を勉強したことがないので、不正確な点が出てきても、誓わないでください)。
注意:記事の手順を繰り返して、あなた自身の危険とリスクで行動します!
だから、私たちは始めています...
私は言わなければならない患者は珍しいです。 まず、バイトコードではありますが、ソース(!!!)が付属しています。 第二に、それが時々起こるように...一般的に、あなたは見るでしょう。
まず、プログラムをダウンロードします(
Wing IDE Professional v 5.1.4 )。 インストールし、フォルダーを検査します。 メインの実行可能ファイルは
./bin/wing.exeにあります。 それを実行します。
Pythonの欠如に呪われているので、インストールしてください。 バージョン
2が必要です(現在はバージョン
2.7.9です )。 プログラムを再度実行します。 今回は、パッチのインストールと再起動を提案しています。 やってみましょう。
これで、ライセンスを要求するウィンドウがポップアップします(プロバージョンがあるため)。 いくつかのナンセンスを紹介しましょう:
次の答えが得られます。
面白いのは、プログラム自体がキーの長さ(ハイフンを含まない20)と、それが始まるべき文字を教えてくれることです。 原則として、これから保護の調査を開始することはすでに可能です-この行はプログラムファイルにあります。
もっと面白い。 検索結果はファイル
./bin/2.7/src.zipで見つかりました!
はい、はい。 すべてが本当にそうです:プログラムにはソースが付属しています。 それらを掘り下げる必要があります。
ステージ2:ソースコードを調べる
Total Commanderで
Total Archive検索をオンにして、その行をもう一度見つけます。 行はファイルにあります:
./bin /
2.7 /
src.zip /
process /
wingctl.pyo 。
PYOファイルは、「
最適化された 」
Pythonバイトコードを持つバイナリです。
Pythonには幸いなことに、いくつかのバイトコードデコンパイラがあります。 検索の邪魔にならないように、便利なリンクを提供します。
- Easy Python Decompiler ( EPD ) -2つの逆コンパイラーが接続されているシェル( Uncompyle2およびDecompyle ++ );
- Fork Uncompyle2-他の人が解凍できないものを時々解凍します。
そのため、src.zipアーカイブ全体を
srcフォルダーに解凍し(近くに既に
srcフォルダーがあり、そこに他のものをすべて解凍します)、
EPDを設定します。
プロセスの終了を待っており、何が起こったかを調べに行きます。 そして、出力は
_disで終わるファイルを逆コンパイルしました。 名前を
.pyに変更します。 すべて問題ありませんが、末尾が
_dis_failedのファイルもあることが
わかります。これは、逆コンパイラがこれらのファイルをマスターしなかったことを意味します。 幸いなことに、ファイルは1つしかありません:
edit / editor.pyo_dis_failedそれにDecompyle ++を設定してみましょう...同じトラブル。 予備の逆コンパイラへのリンクを与えたのも不思議ではありません。 他の人が失敗したことをしたのは彼でした。 次に、srcフォルダーからすべての
pyo /
pycファイルを削除し、
.py * _disを
.pyに名前変更します。
次に、
opensource.zipアーカイブに対して上記のすべてを繰り返し、同じ名前の隣接フォルダーに解凍します。
external.zipアーカイブに触れないことにしました。これを調べると、Python用に個別にインストールできるライブラリがあることがわかるからです。 やってみましょう:
pip install docutils
- py2pdf- 外部フォルダーに入れます。
- Imaging-1.1.7-実行してインストールします。 外部フォルダーから削除できます。
- pygtk-以前のファイルと同じ。
残りのライブラリ(
pyscintilla2および
pysqlite )は、以前のように単に
external.zipアーカイブから抽出され、逆コンパイルされます。
ステージ3および4:ソースコード自体。 デバッグ
Pythonスクリプトを検索した後、プログラムフォルダーのルートにあるwing.py
ファイルに出会いました。 そして、最初のコメントは私たちに伝えます:
簡単に言うと、スクリプトに
--use-srcパラメーターを指定すると、起動時に
srcのソースファイル(スクリプトではなく)
Wing IDEのルートディレクトリの
opensourceフォルダーが使用されます。
ルートフォルダーを見ると、別の
srcフォルダーとその中の
.pyファイルが見つかりました。 それらを
srcフォルダーに上書きしてスローします(ここでは、すべて同じオリジナルで、逆コンパイルされたファイルではありません)。
ここで、3つすべてのフォルダー(少し上に表示)をプログラムのルートディレクトリにコピーします。 ローンを作ってみましょう...
Wing IDEを実行し、その中の
binディレクトリから
wing.pyファイルを開きます。 次に、パラメータフィールドの
[デバッグ ]
-> [デバッグ環境 ]メニューで、
-- use-srcを指定します。 デバッガーを開始します(
F5キー)。 フォルダーのコピーに関するすべての詐欺が成功した場合、実行中の
Wing IDEの 2番目のコピーを取得します。 いいね!
次に、親の
Wing IDEでファイルを開き、
先に不良
ライセンスID (
wingctl.py )に関する行を見つけ、このメッセージの前にブレークを入れます。
デバッグされた
Wing IDEで、 [ヘルプ]-> [ライセンスを入力 ]メニューに移動し、ルールに従ってキーを入力します(
20文字、セットの最初の
['T'、 'N'、 'E'、 'C'を覚えてください)
、「1」、「3」、「6」] ):
[
続行]を押すと、お
ばあちゃんの力が得られます。 最初の興味深い関数:
abstract.ValidateAndNormalizeLicenseID(id) 。
F7で説明しましょう。 もう1つあります:
__ValidateAndNormalize(id) 。 それに行きましょう。
最初の検証チェック:
for c in code: if c in ('-', ' ', '\t'): pass elif c not in textutils.BASE30: code2 += c badchars.add(c) else: code2 += c
ライセンスID文字が
textutils.BASE30セットに属している必要があることが
わかります。
BASE30 = '123456789ABCDEFGHJKLMNPQRTVWXY'
__ValidateAndNormalize(id) noの他のチェックと同様 入力した識別子を修正し、再度繰り返します。 すでに最初の文字のチェックに合格しています:
if len(id2) > 0 and id2[0] not in kLicenseUseCodes: errs.append(_('Invalid first character: Should be one of %s') % str(kLicenseUseCodes))
次に、2番目の文字を示します。
if len(id2) > 1 and id2[1] != kLicenseProdCode:
kLicenseProdCodes = {config.kProd101: '1', config.kProdPersonal: 'L', config.kProdProfessional: 'N', config.kProdEnterprise: 'E'} kLicenseProdCode = kLicenseProdCodes[config.kProductCode]
なぜなら
Professionalバージョンがあり、2番目の文字は
Nでなければなりません-正しい、そして戻ります。
abstract.ValidateAndNormalizeLicenseID(id)はエラーなしで歩いた。 素晴らしい。 おっと:
if len(errs) == 0 and id[0] == 'T': errs.append(_('You cannot enter a trial license id here'))
Fixim(私は
Eを選択しました)、そして続行します。 コードの下に目を向けると、以前のチェック以外に何も見つかりませんでしたので、
F5でのデバッグを大胆に手放しました。 新しいウィンドウ:
ランダムなテキストを入力すると、エラーメッセージ(再び
20文字で、アクティベーションコードは
AXXで始まるはずです)が表示され、ファイル内で検索され、ブレークに配置されます。
最初のチェック関数:
abstract.ValidateAndNormalizeActivation(act) 。 再び
BASE30アフィリエーションをチェックします。 既に渡したプレフィックスを確認します。
if id2[:3] != kActivationPrefix: errs.append(_("Invalid prefix: Should be '%s'") % kActivationPrefix)
次の興味深い場所:
err, info = self.fLicMgr._ValidateLicenseDict(lic2, None) if err == abstract.kLicenseOK:
self.fLicMgr._ValidateLicenseDictに移動し
ます 。 ここで、ライセンスからのハッシュが形成されます:
lichash = CreateActivationRequest(lic) act30 = lic['activation'] if lichash[2] not in 'X34': hasher = sha.new() hasher.update(lichash) hasher.update(lic['license']) digest = hasher.hexdigest().upper() lichash = lichash[:3] + textutils.SHAToBase30(digest) errs, lichash = ValidateAndNormalizeRequest(lichash)
このブロックを実行した後に
lichashの内容を見ると、そのテキストはアクティベーションコード入力ボックスに表示される
リクエストコードに似ていますが、いくつかの数字は異なります。 さて、アクティベーションに影響を与えないランダムな部分がいくつかあると思います(偶然、さらに確認されます!)。
次に、最初の3文字がアクティベーションコードから切り取られ、ハイフンが削除され、
BASE16に変換され、必要に応じてゼロが追加されます。
act = act30.replace('-', '')[3:] hexact = textutils.BaseConvert(act, textutils.BASE30, textutils.BASE16) while len(hexact) < 20: hexact = '0' + hexact
そして、それは最も興味深いものです:
valid = control.validate(lichash, lic['os'], lic['version'][:lic['version'].find('.')], hexact)
一部の
コントロールは
validate関数を呼び出し、
lichash (
要求コード )、キーが作成されるオペレーティングシステムの名前、プログラムのバージョン、および変換されたアクティベーションコードを渡します。 なぜこの場所に注意を払ったのですか? 実際、この
コントロールは
pyd-ファイル(
監視するオブジェクトの名前を追加し、
__ file__フィールドを
確認することで確認でき
ます )であり、1つのエクスポートされた関数(
validateではない)彼女がする方法を知っている。 さて、
Hex Raysデコンパイラからそれを見てみましょう...
ステップ5:これはPythonではありません
IDA Proで
コントロール (
ctlutil.pyd )をプルし、エクスポートされた
initctlutil関数を
確認します。
int initctlutil() { return Py_InitModule4(aCtlutil, &off_10003094, 0, 0, 1013); }
off_10003094は、エクスポートされたメソッドの名前とアドレスが示される構造です。 ここに
検証があります:
.data:100030A4 dd offset aValidate ; "validate" .data:100030A8 dd offset sub_10001410
sub_10001410プロシージャを含むすべてのコードの中で、これは最も興味深いように見えます。
if ( sub_10001020(v6, &v9) || strcmp(&v9, v7) ) { result = PyInt_FromLong(0); }
sub_10001020にも
行きましょう 。 視覚的に変数に名前を付けるのではなく、名前を付けて適切に名前を付けるのは興味深いでしょう。 やってみましょう。
IDA Proデバッガーをセットアップします。
スクリーンショットからはすべてが明らかだと思います。最終的に
pyd-ファイルをロードするアプリケーションを指定しました。
ここで、ブレーカーを
sub_10001020の先頭に
配置し、変数と入力パラメーターの調査を開始します。 短いデバッグプロセスの後、次の関数リストにアクセスします。
Convert_reqest_key関数コード int __usercall convert_reqest_key@<eax>(char *version@<eax>, const char *platform@<ecx>, const char *activation_key, char *out_key) { unsigned int len_1;
そして、この関数を呼び出す場所は次の形式を取ります。
if ( convert_reqest_key(version, platform, request_key, out_key) || strcmp(out_key, act_key_hash) ) { result = PyInt_FromLong(0); }
これらすべてから、
convert_reqest_key関数を使用して
リクエストコードが変換され、変換されたアクティベーションコードと比較されると結論付けることができます。 その変換を覚えていますか?
次に、必要に応じて、最初の3文字がアクティベーションコードから切り取られ、ハイフンが削除され、 BASE16に変換され、ゼロが埋め込まれます
したがって、正しいアクティベーションコードを取得するために、次の操作を実行できます。
- 変換関数convert_reqest_keyを実行します。
- strcmpの実行場所で、 out_keyの内容を探します。
- out_keyの先頭にある余分なゼロを削除します。
- out_keyをBASE30に変換し直します。
- 削除された文字を行の先頭に追加します( AXX )。
- オプションで、5文字ごとにハイフンを付けます。
私は愚かに哲学するつもりはありませんが、
Pythonプログラムコードに
印刷を絞り込みます。
print("AXX" + textutils.BaseConvert("FCBCFEFD2FF684FA6A4F", textutils.BASE16, textutils.BASE30))
出力にキーがあります:
ウィングライド-2015/05/24 04:03:47- AXX3Q6BQHKQ773D24P58
アクティベーションキーの入力フィールドに入力すると、大事なものを受け取りました。
結果
ご覧のように、ハッキングのプロセスはそれほど面倒ではありません! それのコンパイルされたバージョンであなた自身のソースコードを探る...これは、もちろん面白いです。
著者がソースをプログラムに添付した理由はわかりません(ほとんどの場合、バイトコードの形で)。 しかし、これには価値がないことを理解していると思います!
どうもありがとう。