ブラックボックス方匏を䜿甚した商甚保護をバむパスし、リネヌゞュ2のパケットハックを蚘述したす

プロロヌグ


Tフォヌラムの友人の1人が、尊敬されるxkorの著者ずしお、䞍正行為の䞖界党䜓に知られおいるl2phxプログラムを曞き換えるこずを提案したずき、それはすべお1幎前に始たりたした。
L2phx自䜓l2パケットハック、パケット、スラムは、系統2クラむアント他のmmorpgのバヌゞョンがありたすの着信および発信パケットすべおがLSPで実装されおいるのスニファヌであり、個々のパケットを送信/眮換する機胜を備えおいたす。 Xkorは次のように詊みたした暗号化バむパスメ゜ッドの実装、矎しいGUIなど。 しかし、frisheksの悪意のある管理者はそのようなアプリケヌションを奜たなかった。それは次の1日のむベントの開始時に圌らの収入を著しく殺した。 はい、はい、名前以倖の人がどのサヌバヌにもアクセスしお、このツヌルで完党な乱亀を手配するこずができたした。 同時に、あらゆる皮類の商甚保護があり、パケットの䜿甚を正垞にブロックできたせんでしたが、それらの䞭で最も巧劙なトラフィックはさらに暗号化されおいたす。 このような保護の1぀は、S。保護に察応しおいたす。今日、S保護はすべおのトップリネヌゞ2サヌバヌにありたす。ずころで、xkorはそのような結果を提䟛し、パケット埩号化モゞュヌルnewxor.dllを独自に䜜成する機胜を実装したした。 はい、それを曞いただけでは合理的ではありたせんでした新しいサヌバヌ==新しいnewxor。 初心者はクラむアントのメモリHxD、チヌト゚ンゞンなどを倉曎しおパケットを送信できなかったため、l2での䞍正行為は次第に死に始めたした。

それから、私はこのベンチャヌをあたり真剣に受け止めたせんでした私はクラむアント->サヌバヌパケットキャプチャモゞュヌルを曞き、それを攟棄したした。 なんで なぜなら。 しかし、ほんの3日前、私はこのプロゞェクトの䜜業を再開し、この蚘事を公開するこずにしたした。 なんで 珟圚、l2詐欺垫コミュニティは死んでいたす。 すべおのバグず掗濯機は、SkypeずフォヌラムTで互いに通信する10人の手にありたす。そしお、私も去るこずにしたした。 そしお、あなたが去るなら、それは矎しいだけです2幎前、私はワヌキングバッグを倢芋たしたが、今日はそれを必芁ずしたせん。

免責事項


9月はその幎霢を考慮しお非垞にすぐに燃え䞊がりたす。぀たり、9月1日にモスクワの孊校の1぀で昚幎に䌚いたす。 孊校の文孊のリストは開かれず、詊隓の準備をする本はクロヌれットの䞭に散らばっおいたす。 時間がありたせん。 コヌドの䞀郚は急いで投げられたす。これは、非垞に楜しいニュヌスが䜜業の完了埌に初めお明らかになったためですが、それに぀いおは埌で詳しく説明したす。 たた、蚘事は文孊蚀語で曞かれおいたせん。 しかし、それはそうです。

パケット代行受信サヌバヌ->クラむアント


クラむアントがサヌバヌから受信するすべおのパケットは、゚クスポヌトされたUNetworkHandler::AddNetworkQueue内で呌び出すこずで最終的にキャッチできたす。

画像

これはラッパヌであり、その内郚には元の関数ぞのゞャンプがありたす。

画像

ここで、Sのトリッキヌな防埡が、サヌバヌ䞊でさらに暗号化されたパケットを解読するこずは明らかです。 同じコヌドがメモリ内でどのように芋えるかを芋るず、次のこずがわかりたす。

画像

控えめに蚀っお、これは特定のハンドラヌの近くで最も䞀般的なjmpです。 ハンドラヌ自䜓は興味深いものではなく、それ自䜓で機胜するようにしたす。 このフックの埌にフックを眮き、パケットを埩号化された圢匏で取埗したす。 その埌、最初の問題が発生したした。 科孊的な突きの方法により、 VirtualProtectやVirtualAllocなどの機胜が゚ラヌで動䜜し、それらがないず、レむが保護されたメモリに入るこずができないこずが明らかになりたした。 なぜこれが起こっおいるのですか 私は決しお芋぀けたせんでした、時間がありたせんでした。 しかし、S保護はNtProtectVirtualMemoryをむンタヌセプトし、そこで䜕かを行うず蚀えたす。 それから私は防埡を欺くためにcな蚈画を立お始めたしたが、私の怠inessが優勢であり、私はこれを愚かにしたした

 HANDLE hMain = OpenProcess(PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId()); VirtualProtectEx(hMain, ... ); 

もちろん、プロセス内にいるこずを考えるず、矎しくありたせん蚀及するのを忘れおいたしたが、dllを蚘述しおいたす。 しかし、それは動䜜したす。 フックに戻るず、2番目の問題が発生したす。保護は、この関数の最初の10〜20バむトをチェックしたす。 すぐに刀明し、呪われた堎所に窓が出おくるかもしれたせん。 どうする そうです、フックを぀けおください。 オフセット0x14を遞択したした䞊の図を参照。 jmp nearは5バむトかかりたす。それらを曞き換えたす

 add esi, 0x3c push 0x1 

に

 jmp ... 

これを忘れないでください。おそらくハンドラの最埌にそれらを埩元する必芁がありたす。 ずころで。 フックは、むンポヌトしたEnterCriticalSection内たたは他の堎所に配眮できたす。 さらに進みたす。 2010幎にAddNetworkQueue関数に枡されるパッケヌゞの構造は、尊敬されるGoldFinchによっお公開されたした。

 struct NetworkPacket { unsigned char id, _padding1, exid, _padding2; unsigned short size, _padding3; unsigned char* data; } 

idずdataフィヌルドに興味がありたす。 ecx内容ず同様に。 なぜecxか 簡単です __thiscallを扱っおおり、 UNetworkHandlerクラスの関数を呌び出すには、オブゞェクトぞのポむンタヌが必芁です。 ecxで送信されたす。 なんで電話する必芁があるの さらに、あなたはすべおを理解したすが、今のずころ完成したコヌドを提䟛したす

 BYTE *AddNetworkQueue = (BYTE *)GetProcAddress(hEngine, "?AddNetworkQueue@UNetworkHandler@@UAEHPAUNetworkPacket@@@Z"); AddNetworkQueue += *(DWORD *)(AddNetworkQueue + 1) + 5; retAddr_AddNetworkQueue = (DWORD)AddNetworkQueue + 0x19; trmpAddr = (DWORD)wrapper_AddNetworkQueue - ((DWORD)AddNetworkQueue + 0x14 + 5); VirtualProtectEx(hMain, AddNetworkQueue + 0x14, 1, PAGE_EXECUTE_READWRITE, &tmpProtect); *(AddNetworkQueue + 0x14) = 0xE9; *(DWORD *)(AddNetworkQueue + +0x14 + 1) = trmpAddr; VirtualProtectEx(hMain, AddNetworkQueue + 0x14, 1, PAGE_EXECUTE, &tmpProtect); while (!unh) Sleep(100); 

準備ができおいない人は、この瞬間に死にたいず思うでしょう。 実際、すべおがシンプルです。 AddNetworkQueue += *(DWORD *)(AddNetworkQueue + 1) + 5; jmpを䜿甚したラッパヌから実際のAddNetworkQueue関数に移動するだけです。 unhずは これは、ハンドラヌで倉数に抌し蟌んだものず同じecx倀です。

 void __declspec(naked) wrapper_AddNetworkQueue() { __asm { pushad pushfd sub [unh], 0 jnz L1 mov [unh], ecx L1: lea eax, [esp + 44] //32 (pushad) + 4 (pushfd) + 4 (push 4) + 4 (ret addr) push eax call [handler_AddNetworkQueue] popfd popad add esi, 0x3c //see disasm push 0x1 jmp [retAddr_AddNetworkQueue] } } void __stdcall handler_AddNetworkQueue(DWORD *stack) { NetworkPacket_t *pck = (NetworkPacket_t *)*stack; if (ShowServerPck) { printf("s -> c | %02hhX ", pck->id); for (int i = 0; i < pck->size; i++) printf("%02hhX ", pck->data[i]); printf("\n"); } } 

ここで、naked wrapper_AddNetworkQueue関数はすべおのレゞスタの倀をunh倀unh取埗しお、ハンドラヌを呌び出したす。 その䞭で、スタックを恐れるこずなくパッケヌゞを䟿利に凊理し、制埡をラッパヌに戻したす。 圌は、詰たった指瀺を埩元し、元のコヌドを壊した堎所にゞャンプしたす。 Noos、1぀少ない問題。

クラむアント→サヌバヌパケットキャプチャ


正盎なずころ、これらは最もおいしいパッケヌゞです。 すべおのデュヌプの70がベヌスになっおいるのはそれらです。 䞀般にSendPacketず呌ばれる非゚クスポヌト関数は、これらのパケットの送信を担圓したす。

 UNetworkHandler::SendPacket(char* msk, ...) 

この関数には、最初の匕数マスクに基づいおスタックから取埗する可倉数のパラメヌタヌがありたす。 このCDEの䜏所や茞出された女性の䜏所を取埗する方法は それは簡単です、それがどのように呌ばれるかを芋おください。 この蚘事はapi lineage 2のチュヌトリアルではないず䞻匵しおいるため、具䜓的な呌び出し䟋を瀺したす。

画像

これで、レゞスタ倀が必芁な理由が明確になりたす。

ecx 

 SendPacket = (BYTE *)*(DWORD *)(**(DWORD **)(unh + 0x48) + 0x68); SendPacket += *(DWORD *)(SendPacket + 1) + 5; 

SendPacketはラッパヌでもあり、その䞭にはmain関数の通垞のjmpがありたす。 その始たりは次のようになりたす。

画像

そしお、次のように、 AddNetworkQueueずの類掚によるメモリ内で

画像

繰り返したすが、特定のハンドラヌぞの平凡なゞャンプですが、この堎合は無芖できたせん-パケットの暗号化を実行したす。 どうする ゞャンプで䞊曞きしようずするず、ディフェンスSが誓いたす。 そしお、あなたがこのゞャンプに沿っお行けば

画像

圌女、もう䞀回ゞャンプ。 私はそれを台無しにしたすそれらのうちさらに5぀がありたすjmpの代替/近くの呌び出し。 難読化を扱っおいたす、クヌルです。 制埡フロヌを埩元するのが面倒だずしたらどうでしょうか

前額法


これらの5぀のjmpの1぀を自分の近くに曞き盎しおみたせんか 最初はそれだけでしたが、それは臎呜的な間違いでした。 刀明したように、Sプロテクションはこれらの堎所のコヌドの敎合性をチェックし、元のコヌドず䞀臎しない堎合は誓いたす。 しかし すぐではありたせん、カヌル 15分埌にのみ。 もちろん、開発段階では、そのような時間のパフォヌマンスをテストする䜙裕はありたせんでした。 プロゞェクト党䜓の䜜業の終わりに、私はうれしい驚きを芚えたした。 しかし、私はしおれたせんが、... 2番目の臎呜的なミスを犯したした。 別名難読化コヌドの䞊にむンラむンパッチ手法を詊しおみたずころ、自己クリアフック残念ながら、gitに関する質問に察するそのオプションの゜ヌスコヌドはありたせん。 仕組みガベヌゞ呜什を探し、ハンドラヌの近くでjmpで䞊曞きしたす。 その䞭で、すぐに元のバむトを埩元しjmpが眮かれたメモリに曞き蟌み、ハンドラヌ内の詰たったバむトを実行するだけではありたせん、トリックを行い、制埡を元の関数に戻したす。 しかし、このオプションは䞀床だけ機胜したすか ぀たり、フックを再床蚭定するたでです。 保護Sは関数の最初のバむトのみをチェックし、最埌にフックを眮いおも単語を蚀っおいないこずを思い出しおください。 SendPacketの最埌に2番目のフックを配眮したす。これは、難読化されたコヌドのガベヌゞ呜什のアドレスの゚ントリの近くでjmpを生成する最も䞀般的なフックです。 私の蚀葉では、これを理解するこずは非垞に簡単ではありたせんが、スキヌムは次のずおりです。

  1. 保護ハンドラヌSのガベヌゞ呜什の代わりにフックを蚭定したす。最埌に、これらのガベヌゞ呜什をメモリに埩元しおゞャンプしたす。 このようにしお、フックを消去したす。
  2. 保護ハンドラヌSは、制埡を凊理しお元のSendPacket関数にSendPacketたす。
  3. 最埌に2番目のフックを配眮し、最初のフックを再むンストヌルしたす。

なぜこの小さなスキヌムを臎呜的なミスず呌ぶのですか 実際、このアプロヌチは、保護が珟圚のスレッドからのコヌドの敎合性をチェックする堎合にのみ機胜するずいうこずです。 2番目のスレッドの重さがあり、最初のスレッドのバむト数をチェックしおいる堎合、このトリックは機胜したせん。 そしおそれは起こった、私はちょうど時間をかけた。 どうする メモリ内のバむトを倉曎するこずはできたせん 生き方は 窓を出る

バック方匏


実際、この状況では、フックをむンストヌルするためのオプションがいく぀かありたす。 そのうちの1぀を遞択したした。メモリペヌゞの暩限を倉曎するこずによるフックです。 はい、これは最良の遞択肢ではありたせんが、締め切りは燃えおいたしたこの蚘事が曞かれた盎前に最埌に行われたこずを思い出したす。 ここでは、Broken Swordの「保護されたモヌドのIntelプロセッサ」のすばらしいシリヌズの蚘事を参照する䟡倀がありたす。 読んで、怠けないでください。 たた、Matt Pietrekによる䞀連の蚘事ぞの参照ずしお、「a」Win32 SEHの内郚からの匕甚もありたす。 グヌグルはずおも簡単です。 さお、私はあなたがすべおの塩が䜕であるかを理解するこずを望みたす。 SendPacketプロシヌゞャSendPacketれおいるペヌゞの属性を倉曎したす実際、S保護ハンドラヌが配眮されおいるメモリペヌゞの属性を倉曎するこずにしたした。詳现は埌ほど説明したす。 耇雑に聞こえたすが、実際には、次のコヌドを実行する必芁がありたす。

 VirtualProtectEx(hMain, SendPacket, 1, PAGE_EXECUTE | PAGE_GUARD, &tmpProtect); 

クラむアントがSendPacket関数を呌び出した埌、䟋倖がスロヌされたす。これは凊理する必芁がありたす。 私は本圓にtibに぀いお曞きたくないので、私たちはすべおを非垞に単玔に行い、審矎的にはしたせん 。

 AddVectoredExceptionHandler(1, wrapper_SendPacket); 

では、 SendPacketを呌び出すず、 wrapper_SendPacketたす。

 long __stdcall wrapper_SendPacket(PEXCEPTION_POINTERS exInfo) { if (exInfo->ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) { VirtualProtectEx(hMain, SendPacket, 1, PAGE_EXECUTE, &tmpProtect); if (exInfo->ContextRecord->Eip == (DWORD)SendPacket) { handler_SendPacket((DWORD *)exInfo->ContextRecord->Esp + 3); //4 (ret addr) + 4 (ret addr) + 4 (1 arg) } return EXCEPTION_CONTINUE_EXECUTION; } return EXCEPTION_CONTINUE_SEARCH; } 

お気づきかもしれたせんが、 wrapper_SendPacket関数はVirtualProtectEx呌び出したす。これにより、ペヌゞ属性が正芏化され、制埡が返されたす。 しかし、ペヌゞ属性を正芏化するには==フックを削陀したす。 「額の方法」で説明した䞊蚘の2番目の方法を䜿甚し、 SendPacket関数の終わりをむンタヌセプトしお再床蚭定したす関数には2぀のレットがあるため、2぀のフックを蚭定したす。

 trmpAddr = (DWORD)wrapper_SendPacketEnd - ((DWORD)SendPacket + 0xb5 + 5); //first ret inside SendPacket VirtualProtectEx(hMain, SendPacket + 0xb5, 1, PAGE_EXECUTE_READWRITE, &tmpProtect); *(SendPacket + 0xb5) = 0xE9; *(DWORD *)(SendPacket + 0xb5 + 1) = trmpAddr; trmpAddr = (DWORD)wrapper_SendPacketEnd - ((DWORD)SendPacket + 0xc5 + 5); //second ret inside SendPacket *(SendPacket + 0xc5) = 0xE9; *(DWORD *)(SendPacket + 0xc5 + 1) = trmpAddr; VirtualProtectEx(hMain, SendPacket + 0xc5, 1, PAGE_EXECUTE, &tmpProtect); 

wrapper_SendPacketEnd自䜓

 void __declspec(naked) wrapper_SendPacketEnd() { __asm { pushad pushfd call [handler_SendPacketEnd] popfd popad add esp, 0x2000 //see disasm ret } } void __stdcall handler_SendPacketEnd() { if (ShowClientPck) VirtualProtectEx(hMain, SendPacket, 1, PAGE_EXECUTE | PAGE_GUARD, &tmpProtect); } 

PAGE_GUARD属性を蚭定しおPAGE_GUARDだけで、 PAGE_GUARDの最埌ではなく、それを呌び出す関数に戻るだけで、耇雑なこずはありたせん。

wrapper_SendPacketに戻りたしょう。 忘れないでください チェックに泚意しおください

 if (exInfo->ContextRecord->Eip == (DWORD)SendPacket)) { ... } 

それ以倖の堎合はありたすか 幞いなこずに、私たちの堎合、残念ながらそうです。 VirtualProtectExを実行するず、少なくずもメモリのペヌゞ党䜓の属性が倉曎されたす。 これらの最小4キロバむトのコヌドは䜿甚できたせん。 たた、他の手順が存圚する堎合がありたす。 これらの䟋倖は、SendPacketが呌び出されたずきに必ずしもスロヌされるずは限りたせん。 これはこのメ゜ッドの䞻な欠点です最埌にフックが埩元されないプロシヌゞャを呌び出すず、ハンドラヌはフックを削陀したすが、解決されたす。 それを修正するためのいく぀かのオプションがありたす。 最高品質ではなく、最速を䜿甚したす。 匕数PAGE_GUARDしおVirtualProtectExを愚かに生成したす。 この目的のためにスポむラヌそれだけではありたせん、゚クスポヌトされた関数FPlayerSceneNode::Render(FRenderInterface *)が遞択されたした。これはルヌプ内のメむンスレッドによっお呌び出されたす

画像

防埡Sは、最初にそれを傍受しおも誓いたせん。 VirtualProtectExをむンタヌセプトしお生成したす。 これは、フックがトリガヌされるこずを100保蚌したすか もちろん違いたす。 95のみ。 それで十分でした。 私は束葉杖を煩わせず、転がしたせんでした。 フックはengine.dllのアドレススペヌスではなく、保護ハンドラヌSのアドレスにむンストヌルされるず䞊蚘で曞きたした。なぜですか 回答のほんの䞀郚です

 if (exInfo->ContextRecord->Eip == (DWORD)SendPacket)) { ... } 

はるかに経隓的に怜蚌枈み。 SendPacketの最埌にむンストヌルしたフックに、パケットの送信埌に100衚瀺される特定のむンゞケヌタヌラむンの出力を远加するず、次の図が衚瀺されたす。

画像

連続する#pck行は、フックが機胜しなかったこずを瀺しおいたす同じ5。 䞊蚘のおを芁玄したす。

  1. メモリペヌゞの属性を倉曎し、䟋倖ハンドラを蚭定したす
  2. その䞭で、元の属性を埩元し、 SendPacketのアドレスで䟋倖が発生した堎合、独自のハンドラヌを呌び出すこずができたす
  3. 最終的に、制埡は元のSendPacket関数に戻り、その最埌に2番目のフックがありたす
  4. 次に、メモリペヌゞの属性を再蚭定し、 SendPacketを呌び出したコヌドに制埡を移したす。
  5. この時点で、 Renderプロシヌゞャでは、同じメモリスポヌンぞの同じ属性のむンストヌルがスポヌンされたす。

サヌバヌぞのパケットの送信


最もおいしいが、パケットキャプチャを䞭心ずしたタンバリンずのダンスの埌、クラむアント->サヌバヌは非垞にシンプルです。 䞊蚘でSendPacketアドレスを取埗する方法を孊びたした。そこで、この関数に匕数を枡す䟋をスパむしたした。 どうする 電話しおみおください そしおかなりたくさん。 engine.dllのアドレス空間からではなく匕数をスリップしようずしおいたす-額に入れたす。 engine.dllのアドレス空間からではなく、リタヌンアドレスをスリップしようずしおいたす。耳で取埗したす。 メむンストリヌムからではなく、dll`kiから盎線に関数を呌び出そうずしおいたす-肝臓を通過したす。 最終的に、レシピは次のずおりです。

  1. 保護されたSは、゚クスポヌトされたengine.dll関数の1 engine.dllかを気にしたせん。これはSendPacketを呌び出しSendPacket しかし無駄です
  2. Protect SはSendPacketに぀いおengine.dllしたせん戻りアドレスはengine.dll内にある必芁があり、呌び出しはメむンスレッドから行われる必芁がありたす
  3. Protect Sは、 SendPacket関数の匕数がどのアドレス空間にあるかを気にしたせん

そしお、ここに治療法がありたす

  1. SendPacket関数を呌び出すずきの停の返信アドレス
  2. 枡された匕数の停のアドレス空間
  3. メむンスレッドから呌び出したす

どうやっおやるの ずおも簡単です engine.dll内の空きスペヌスを芋぀けおアラむメントから完党に適合する、そこに1぀のスプリングボヌドず小さなバッファヌを配眮するだけで十分です。 蚀葉から行動に移りたしょう

 BYTE *Remove = (BYTE *)GetProcAddress(hEngine, "?Remove@?$TArray@E@@QAEXHH@Z"); Remove += *(DWORD *)(Remove + 1) + 5; pckMsk = (char *)Remove + 0x74; //max 44 chars with zero (43 without). You can find more. VirtualProtectEx(hMain, pckMsk, 1, PAGE_EXECUTE_READWRITE, &tmpProtect); // 

44バむトの長さで最初に䜿甚可胜なスペヌスが芋぀かりたしたさらに怜玢できたす。 バッファがそこに眮かれ、そこに文字列が曞き蟌たれ、最初の実際には2番目の匕数でSendPacketに枡されたす。

返信先をどうしたすか engine.dll内のスプリングボヌドをハンドラヌにengine.dllするだけで十分です engine.dllを呌び出した埌SendPacketコントロヌルはスプリングボヌドに移動し、そこからハンドラヌに移動したす。 どのように芋えたすか このように

 BYTE* RequestRestart = (BYTE *)GetProcAddress(hEngine, "?RequestRestart@UNetworkHandler@@UAEXAAVL2ParamStack@@@Z"); RequestRestart += *(DWORD *)(RequestRestart + 1) + 5; retAddr_handler_Render = RequestRestart + 0x2b; trmpAddr = (DWORD)fixupStack_Render - ((DWORD)retAddr_handler_Render + 5); VirtualProtectEx(hMain, retAddr_handler_Render, 1, PAGE_READWRITE, &tmpProtect); *retAddr_handler_Render = 0xE9; *(DWORD *)(retAddr_handler_Render + 1) = trmpAddr; VirtualProtectEx(hMain, retAddr_handler_Render, 1, PAGE_EXECUTE, &tmpProtect); 

fixupStack_Render自䜓

 void __declspec(naked) fixupStack_Render() { __asm { add esp, [fixupSize] //SendPacket has cdecl convention mov esp, ebp //prolog of pop ebp ///////handler_Render ret //ret to the end of wrapper_Render } } 

fixupSizeずは䜕ですか SendPacket呌び出すSendPacket

 fixupSize = 12; //4 (push eax) + 4 (push [pckMsk]) + 4 (push 0x46) __asm { mov ecx, [unh] mov eax, [ecx + 0x48] mov ecx, [eax] mov edx, [ecx + 0x68] //SendPacket push 0x46 push [pckMsk] push eax push [retAddr_handler_Render] //trampoline to fixupStack_Render jmp edx } 

可倉数のパラメヌタヌを枡すため、スタックをクリアする必芁がありたす。 fixupStack_RenderプロシヌゞャのコヌドfixupStack_Renderこれを実行fixupStack_Renderたす。 もちろん、 SendPacket自䜓はメむンスレッドからSendPacket必芁があり、前述の゚クスポヌトされたRender関数はこの目的のために行いたす。

クラむアントぞのパッケヌゞの送信


同様に実装されたす。

着信パケットず発信パケットの眮換


䞊蚘のむンタヌセプトをうたく孊習しなかった関数の匕数を倉曎するだけで十分です。

完党に忘れおしたった


  1. すべおがテストされたサヌバヌ-Pirta
  2. 申請曞は間奏蚘録に基づいお曞かれたした
  3. ゚クスポヌトテヌブルの亀換時に保護Sが誓う

゚ピロヌグ


少なくずも䞀床は私を助けおくれたフォヌラムTの各メンバヌに感謝したす。 バグを探し、サヌバヌを耇補しおいたした。 たた、セキュリティ開発者Sにも、このvraytapを䜜成する理由を教えおくれおありがずう。 そしおもちろん、蚘事を最埌たで読んだhabrのナヌザヌに。

完党な゜ヌス添付 klats

パッケヌゞのビデオデモ


これに別れを告げたす。

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


All Articles