TurboLaunch 5.1.3セキュリティ研究

TurboLaunch 5.1.3を簡単に保護するか、3つの方法で破壊します(パッチ、スニファー、keygen)。



対象 :TurboLaunch 5.1.3
ツール :OllyDbg 1.10、Dup2(パッチ作成用)、OllyDbg用CodeRipperプラグイン、Delphi 7(keygen作成用)

退屈な夜だったので、「掘り下げて」みたいプログラムを探していました。 最初に、1バイトを編集してAWBackuper 4.0からトライアルを削除しましたが、それは非常に面白くないように思われ、それから長い間(約4年)コンピューターにあったプログラムを思い出しました-これはSavard SoftwareのTurboLaunchでした。 Keygenが存在します(おそらく10程度)が、それらのいずれにも小さなニュアンスは見られません(全体的には重要な役割を果たしませんが)、それについては少し後になります。

そして、始めましょう...

パッチ

初心者にとっては一番簡単だからです。
犠牲者をOllyDbgにロードします(その後、olya、ollyのみ)。 開始してnag-windowが表示されたら、[登録コードを入力]をクリックします
画像

名前(DimitarSerg)と「正直に購入した」コード1234567890を入力します
非常に奇妙ですが、次のメッセージが表示されます。
画像

テキスト文字列でメッセージテキストを探しましょう。 RMB->検索->すべての参照テキスト文字列。

私たちは見つけます:
画像

もう少し高く、00529CD3からのジャンプ 、つまりそこから来ました。
素晴らしい、そこにあるものを見てみましょう:

「クラシック」:
CALL TurboLau.0053AEB0
TEST AL,AL
JE @TurboLau_00529D99


したがって、チェックがあり、テストの結果に応じてジャンプします。
以下の行があります。

00529D1A |. BA F49D5200 MOV EDX,TurboLau.00529DF4 ; ASCII "REGISTERED TO: "
そしてそのような:
00529D3B |. 68 0C9E5200 PUSH TurboLau.00529E0C ; ASCII "Thank you for registering! Be sure to check out our web site for updated versions of TurboLaunch and other programs written by "

それでは、00529CCCをご覧ください|。 E8 DF110100 CALL TurboLau.0053AEB0
別の呼び出しがあり、登録手順に類似した何かの中にあります。 さて、それなしでできるのに、なぜ検証手順が必要なのでしょうか?!

そのため、540628での登録手順の最初に、「クラシック」パッチを作成します
xor eax,eax // EAX
inc eax // EAX = EAX +1
Retn // return

変更を保存します。 RMB->実行可能ファイルにコピー->すべての変更->ファイルを保存します

TurboLaunch1.exeなどの新しい名前で保存します
喜んでいますが、見返りにこれを取得します:
画像

ああああ。 整合性チェック。 まあ、神は彼女と一緒にいる:
デバッガーでプログラムをリロードし、ブレークポイントを設定してMessageBoxA関数を呼び出します
bp MessageBoxA

「メインスレッドの呼び出しスタック」ウィンドウで、どこから来たのかを確認します。
画像

RMB-> Show Callを実行し、アドレスで検索します
00450CA4 |. E8 8F75FBFF CALL <JMP.&user32.MessageBoxA> ; \MessageBoxA

上にスクロールして確認してください:
00450C7B |> \84DB TEST BL,BL
00450C7D |. 74 60 JE SHORT TurboLau.00450CDF

もう一度確認してください。
条件付き遷移を無条件に変更し(JE-> JMP)、変更を保存して開始します。 やあ、プログラムが始まる。

購入を求めるウィンドウが表示されなくなったため、[About]ウィンドウに「Registered to」と表示されます。
一般的に、誰かのために登録された、それは良いことです。

Dup2またはuPPPでパッチを作成しても問題はありません。

シリアル番号を検索します。

上記のように、正しい/間違ったシリアル番号に関するメッセージは、結果に応じて形成されます

00529CD1 |. 84C0 TEST AL,AL

そして、上記の行は次のとおりです。
00529CCC |. E8 DF110100 CALL TurboLau.0053AEB0
生成手順全体がここで行われるのは論理的です...

私たちは見ます:
0053AEB0 /$ 8B90 68010000 MOV EDX,DWORD PTR DS:[EAX+168]
0053AEB6 |. 8B80 64010000 MOV EAX,DWORD PTR DS:[EAX+164]
0053AEBC |. E8 67570000 CALL TurboLau.00540628
0053AEC1 \. C3 RETN


0053AEB0にブレークポイントを設定し、名前/登録番号を入力すると、ここで停止し、入力されたデータが読み取られていることを確認します。つまり、最も興味深いのはCALL TurboLau.00540628です。

F7に沿ってトレースし、読み取り、いくつかの変換、他の操作などを確認します。 など、その結果、この手順に注意と忍耐の数分を与えた場合、命令の実行中に

00540758 |. 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C]

表示されます:
スタックSS:[0012F1AC] = 00C66E8C、(ASCII「D1F74F-5L3GRT-3WDULJ」)
うーん、正しいシリアル番号ですか?! DimitarSergという名前とシリアル番号D1F74F-5L3GRT-3WDULJを試します。このプログラムは買収を祝福します。

シリアル番号は平文で表示されるため、スニファーシリーズはバタンと書かれています。00540758の直後にあるアドレスのEAXレジスター、つまり0054075Bを調べるだけです。

スニファーシリーズの記述方法については説明しませんが、AT4REチームにはSerial Sniffer Creatorのようなツールがあり、使用できます。次のようになります。
画像

しかし、Unicodeでシリアル番号を盗聴せず、インターフェイスに頻繁に不具合があるため、お勧めしません。
スニファーを作成するためのいくつかの例(テンプレート)が公開されているため、アセンブラーまたはDelphiは手作業で「完成」します。

Keygen

もちろん、最も興味深いのはもちろん、keygenを書くことです。
上で説明したように、生成手順全体は00540628から始まります
登録データ、トレースを入力します。 この場所に注意してください:
画像

この呼び出しをご覧ください。 名前、計算に対して実行されるいくつかの操作が表示されます。 計算の最初の部分が行われ、その結果は少し後で使用されることを事前に言います。 私はアセンブラの「素晴らしい仕様」ではないので、CodeRipperプラグインを使用します。

2つのkeygenメソッドを示します。Delphiのインラインアセンブラコードと、pascalの完全に翻訳されたコードです。

Copy Source | Copy HTML
  1. プロシージャ GenClick( ダミー :ポインタ;送信者:PControl);
  2. var NameBuffer、SerNum:ストリング;
  3. len、sn_tmp: integer ;
  4. 始める
  5. Nm.Text <> ''の 場合、開始
  6. NameBuffer:= Nm.Text;
  7. len:=長さ(Nm.Text);
  8. ASM
  9. プッシュ
  10. mov ECX、NameBuffer
  11. mov EBX、len
  12. @ TurboLau_0053F42E:
  13. XOR EAX、EAX
  14. MOV AL、BYTE PTR DS:[ECX]
  15. SHL EAX、8
  16. XOR EDX、EAX
  17. MOV EAX、8
  18. @ TurboLau_0053F43C:
  19. テストDH、080h
  20. JE @ TurboLau_0053F44B
  21. EDX、EDXを追加
  22. XOR EDX、01021h
  23. JMP @ TurboLau_0053F44D
  24. @ TurboLau_0053F44B:
  25. EDX、EDXを追加
  26. @ TurboLau_0053F44D:
  27. 12月
  28. JNZ @ TurboLau_0053F43C
  29. INC ECX
  30. 12月 ebx
  31. JNZ @ TurboLau_0053F42E
  32. MOV EAX、EDX
  33. EAX、0FFFFh
  34. mov sn_tmp、EAX
  35. ポパド
  36. 終了
  37. Edit.text:= Int2Hex((sn_tmp)、4);
  38. 終わり
  39. 他に
  40. Edit.Text:= '名前を入力してください' ;
  41. 終了 ;


手順を個別に持ってきたのはなぜですか? 私にとっては簡単だった、私はすぐにリッピングされたコードの正しい動作を見ることができます。 たとえば、名前がDimitarSergの場合sn_tmp = E330

さて、もう一度、技術的な問題:アドレス5406BCから540752までのCodeRipperプラグインを使用します(これは大きな生成サイクルであることがわかります)。 私が注意したいのは、いくつかの呼び出しです。 CodeRipperは「; <= Jump / Call Address Not Resolved」と書き込みます。それらのほとんどは不要で、削除できますが、ここでは
005406EE |。 E8 F52DECFF || CALL TurboLau.004034E8
以下の理由により、この呼び出しは削除できません。

Copy Source | Copy HTML
  1. @ TurboLau_004034E8:
  2. プッシュEBX
  3. XOR EBX、EBX
  4. IMUL EDX、DWORD PTR DS:[EBX + 0542008h]、08088405h
  5. INC EDX
  6. MOV DWORD PTR DS:[EBX + 0542008h]、EDX
  7. MUL EDX
  8. MOV EAX、EDX
  9. POP EBX
  10. Retn


これは(当時は知りませんでしたが)これは標準のランダムであり、DWORD PTR DS:[EBX + 0542008h](sn_tmpもあります)-これはRandomSeedです。

そして、リッピングされたコードでは、別のプロシージャとして呼び出すのではなく、単に呼び出しの場所にコピーするだけです。フラグメントを次に示します。
Copy Source | Copy HTML
  1. @ TurboLau_005406E9:
  2. MOV EAX、021h
  3. //-> CALL @ TurboLau_004034E8; <=ジャンプ/解決されないアドレスを呼び出す
  4. //コンテンツを呼び出します
  5. プッシュEBX
  6. XOR EBX、EBX
  7. IMUL EDX、sn_tmp、08088405h
  8. INC EDX
  9. Mov sn_tmp、edx
  10. MUL EDX
  11. MOV EAX、EDX
  12. POP EBX
  13. MOV EBX、EAX
  14. INC EBX
  15. MOV AL、BYTE PTR SS:[EBP-0Dh]
  16. XOR AL、0FFh
  17. EAX、0FFh
  18. EBX、EAXを追加
  19. Dec Esi
  20. JNZ @ TurboLau_005406E9


私もラインに注意を払いたい
00540715 |。 BA 1C085400 | MOV EDX、TurboLau.0054081C; ASCII「GF2DSA38HJKL7M4NZXCV5BY9UPT6R1EWQ40I1CP7Z7GOEPQLZ」

登録コードは直接依存しているため、「キー」と呼ぶことができます。 アドレス0054081Cの文字列へのポインタがedxレジスタに書き込まれます。
Asmov挿入と純粋なPascalを備えたDelphi keygenの完全なソースコードが添付されており、そこには複雑なものは何もありません。

さて、そして私が物語を始めたのは、これらすべての世代の後、私たちは止まらず、踏みつけていくつかの名前/ニックネームなどを見る

当然、これは原始的なブラックリストです。
Copy Source | Copy HTML
  1. @ TurboLau_005407C4:
  2. MOV EAX、DWORD PTR SS:[EBP-4]; ブラックリスト検証サイクル
  3. MOV EDX、DWORD PTR DS:[ESI]
  4. CALL @ TurboLau_00405030
  5. JNZ @ TurboLau_005407D4
  6. XOR EBX、EBX
  7. JMP @ TurboLau_005407DA
  8. @ TurboLau_005407D4:
  9. ESIを追加 、4
  10. 12月エディ
  11. JNZ @ TurboLau_005407C4


Nitrogen / TSRh TeaM、REVENGE Crew、FiGHTiNG FOR FUN、TEAM VIRILITYなどの興味深いニックネーム... ヒントが得られると思います。
合計44名。 問題なく手動でコピーアンドペーストし、型の文字列配列にハンマーで打ち込む
BlackList:文字列=(...)の配列[0..43]。生成時に、目的の名前がブラックリストにあるかどうかを確認します。 (ファイルBlackList.txtも添付します)。

「完全な幸福」のために、asmを挿入したコードをpascalに変換します。

Copy Source | Copy HTML
  1. // ...
  2. var
  3. ブラックリスト:文字列の配列[ 0 .. 43 ] =( 'zircon / pc97'、 'freeware'、 'registered user'、 <br/> 'NuZ''c97'、 'Registered'、 'kOUGER![CB4] '、' Cosmo Cramer 1997 '、' Cosmo Cramer MJ13 '、 <br/> ' MJ13 Forever '、' cH / Phrozen Crew '、' Everybody '、' iCEMAN [uCF] '、' pank '、' Henry Pan '、 <br/> 'iTR [CORE]'、 'mpbaer'、 'C​​ORE / JES'、 'C​​hen Borchang'、 'n03l'、 'ODIN 97'、 'lgb / cORE''97'、 <br/> 'MCC '、' blastsoft '、' CORE / DrRhui '、' Vizion / CORE '、' TEAM ViRiLiTY '、' Nambulu '、' NuZPc97 '、 <br/> ' Weazel '、' Phrozen Crew '、' TEAM VIRILITY '、' x3u '、' Reg Name '、' FiGHTiNG FOR FUN '、' RaSCaL [TMG] '、 <br/> ' Nitros ^ 21 '、' TEAM TSRH '、' ttdown.com '、' Nitrogen / TSRh TeaM '、'無料プログラム '、' REVENGE Crew '、 <br/> ' Vladimir Kasho '、' Alexej Melnikov '、' Seth W. Hinshaw ' ;
  4. // ...
  5. プロシージャ生成;
  6. ヴァール
  7. NameBuffer、SerNum: ストリング ;
  8. EDX、EAX、len、 iab 、tmp1: 整数 ;
  9. テキスト名: PChar ;
  10. 始める
  11. len:= GetWindowTextLengthA( TxtNameHwnd );
  12. len> 1の場合
  13. 始める
  14. {名前入力からテキストを取得}
  15. GetMem( テキスト名、len + 1 );
  16. GetWindowTextA( TxtNameHwnd、PAnsiChar(テキスト名 )、len + 1 );
  17. {シリアルを生成}
  18. KeyStr:= 'GF2DSA38HJKL7M4NZXCV5BY9UPT6R1EWQ40I1CP' ;
  19. NameBuffer:= String( Textname );
  20. SerNum:= '' ;
  21. ランダム化
  22. EDX:= 0 ;
  23. for i := 1からlen do
  24. 始める
  25. EDX:= EDX xor( ord(NameBuffer [i] )shl 8 );
  26. EAX:= 8 ;
  27. 一方、EAX <> 0
  28. 始める;
  29. if( EDX shr 8 and $ 0FF )> = $ 80
  30. それから
  31. EDX:= EDX shl 1 xor $ 1021
  32. 他に
  33. EDX:= EDX shl 1 ;
  34. dec( EAX );
  35. 終わり;
  36. 終わり;
  37. RandSeed:= EDXおよび$ 0FFFF;
  38. i := 1 ;
  39. i <> $ 13 do
  40. 始める
  41. a := 0 ;
  42. b := $ 13 - i ;
  43. b > 0の場合
  44. 始める
  45. 一方、 b > 0
  46. 始める
  47. a :=ランダム( 33 );
  48. inc( a );
  49. i > lenの場合
  50. tmp1:= ord( NameBuffer [i mod len]
  51. 他に
  52. tmp1:= ord( NameBuffer [i] );
  53. tmp1:= tmp1 xor $ 0FFおよび$ 0FF;
  54. a := a + tmp1;
  55. dec( b );
  56. 終わり;
  57. 終わり;
  58. 一方 > 21ドル
  59. 始める
  60. a := a-$ 21 ;
  61. 終わり;
  62. SerNum:= SerNum + KeyStr [ a ];
  63. inc( i );
  64. 終わり;
  65. 挿入( '-'、SerNum、7 );
  66. 挿入( 「-」、SerNum、14 );
  67. iの場合 := 0から43
  68. 始める
  69. NameBuffer = Black List [ i ]の場合
  70. 始める
  71. SerNum:= 'BLACKLISTED NAME' ;
  72. 休憩
  73. 他の終わり;
  74. 終わり;
  75. {結果を表示}
  76. SetWindowTextA( TxtSerialHwnd、PChar(SerNum ));
  77. FreeMem( テキスト名、len + 1 );
  78. 終わり
  79. その他
  80. { 表示エラー}
  81. SetWindowText( TxtSerialHwnd、 '不十分な文字..' );
  82. 終わり;

その結果、私はそのようなkeygenを得ました:
画像

サイズ36.5 Kb(アンパック)。このような小さなkeygenサイズは、DelphiのライブラリであるKOL(Key Objects Library)を使用して実現されます。WinApiを使用してロゴを貼り付け、xm / v2mトラックを追加することもできますkeygen and did)、しかし、私のアドバイスは-Delphiでkeygenを記述する場合はVCLを使用しないでください... 400kb以上-これはkeygenのサイズではありません!
純粋なアセンブラーが好きな人-Masm(Fasm、Tasm)を手に。

これが私の話の終わりであり、誰かがこの記事から何かを得ることを願っています。

Source: https://habr.com/ru/post/J132843/


All Articles