Movie Collector – pitva

Zveřejněno , upraveno - holoubekm Přidat komentář bez kategorie

Do třetice všeho dobrého, čeká nás pitva programu, která bude zase o krok zajímavější než předchozí dvě. Dnes budeme zkoukat poslední z rezenzovaných správců filmotéky Movie Collector v nejnovější verzi.

Na webu výrobce udává, že se jedná o trialware, budeme tedy v programu hledat kontrolu licence.

Po spuštění nás přivítá dialogové okno s žádostí o vložení licence.

Když prejdeme do kroku Unlock Software, jsme požádáni o vložení licenčních údajů a přihlášení. Navíc si ve spodní části okna všimněte tlačítek Check ConnectionProxy. Znamená to tedy, že nejspíš máme co dělat s programem, který řeší licenci pomocí komunikace se serverem.

Další reference na licencování programu

Použijeme ozkoušený Wireshark a pokusíme se zachytit komunikaci se serverem při přihlašování.

Zachycená komunikace programu a licenčního serveru.

Vidíme, že program skutečně komunikuje se serverem – nejdůležitější řádek je v programu označen. Odpověď na tento dotaz se nachází o dva řádky níž. Program sice posílá data na nezabezpečeném portu 80 pomocí požadavku GET, ale přesto data nějakým způsobem šifruje. Tímto způsobem další údaje asi nezjistíme. 🙁 Přejdeme tedy k analýze programu.

Otevřeme .exe soubor v Exeinfo PE a hned vidíme na čem jsme.

Program byl vytvořen v jazyce a frameworku Borland Delphi 2014 XE7

Jazyk Embarcadro Delphi je na poměry našeho seriálu kompilovaný. To pro nás znamená, že spustitelný soubor má klasický Portable Executable (PE) formát.  Oproti předchozím pitvám najednou zkoumáme kompilovaný program a musíme tomu přizpůsobit další kroky. Důležitou informací je, že program je určen pro platformu x86. to znamená, že je 32 bitový. Použijeme některý z klasických Win32 dekompilátorů a debuggerů.

To, že program byl vytvořen v jazyce Delphi znamená, že nás čeká daleko víc práce, zejména při čtení dekompilovaného programu. Na druhou stranu jsem program v Delphi vybral záměrně, existuje totiž výborný program Interactive Delphi Reconstructor (IDR). Je to disassembler, dekompilátor a hlavně rekonstruktor tříd a formulářů.

Co to znamená?

  • disassembler – program převádějící strojový kód do asembleru – tj. z binárního zápisu se dostaneme o úroveň výš
  • dekompilátor – program převádějící strojový kód, nebo assembler do vyššího programovacího jazyka

Rekonstrukce je založena na tom, že .exe soubor má určitou strukturu, kterou kompilátor pečlivě dodržuje. Pokud bychom narazili na program psaný v assembleru ručně, žádný dekompilátor ani rekonstruktor by nám práci neusnadnil.

Licenční formulář dekompilovaný v programu IDR

Soubor MovieCollector otevřeme v IDR a necháme ho vyřádit. Ve výstupu dostaneme seznam použitých datových typů, tříd a metod a navíc i použitých formulářů. To je velká výhra, protože základní funkcionalitu můžeme odhadnout z vyššího programovacího jazyka a nemusíme se trápit s assemblerem.

Ale konec řečí a jdeme na to. Musíme najít formulář, který nás nutí do nákupu licence. Po chvilce hledání najdeme fmSubscriptionInfo. Dále nás zajímá, která metoda se zavolá při použití tlačíka Login. Když trochu zapátráme po vlastnostech formálářů v Delphi, zjistíme, že ovládání GUI funguje na bázi událostí, které jsou automaticky volány frameworkem. Dále víme, že obsluhy událostí se nastavují pro každé okno v metodě OpenForm.

Otevřeme si metodu TfmSubscriptionInfo.OpenForm a vidíme, že jsou postupně do registru eax kopírovány ukazatele na objekty a na offset 0x124 jsou kopírovány handlery událostí.

Kopírování metod obsluhujících událost OnClick pro jednotlivé prvky GUI.

Projdeme jednotlivé metody a najdeme tu obsluhující tlačítko Login. V těle jedné z jich navíc najdeme volání TLicenseManager.CheckSubscriptionOnline. To by mohlo znamenat, že veškeré ověřování licencí se děje na jednom místě. Přesně tak to také je. Všechny důležité metody – od přihlášení uživatele, přes jeho ověření a získání licence jsou právě v této třídě TLicenseManager.

Zanalyzujeme jednotlivé metody, zejména CheckSubscriptionOnline. Zajímavé věci se dějí v sub_0172A198, která má starost komunikaci se serverem. Postupně vidíme, že funkci vytvoří XML zprávu pro server, připraví URL a inicializuje HTTP klienta. Následuje odeslání a čekání na odpověď. V poslední části těla najdeme i kontroly návratových hodnot a zprávy od serveru. Z dat je vytvořena nová instance třídy TLicense, která je zkontrolována a případně předána dále do programu.

Někde v této metodě bude zároveň nejspíše probíhat šifrování odchozích a příchozích zpráv na server.

A jak dál?

  • Můžeme vyčíst, jak program šifruje a dešifruje data, zachytit zprávu a pokusit se ji podvrhnout pomocí vlastního serveru.
  • Kromě toho můžeme upravit program tak, aby data nešifroval, což by nám usnadnilo spoustu s analýzou šifrování.
  • Upravit program tak, aby se kontrole licence úplně vyhnul.

Pokud bychom chtěli vytvořit vlastní server, který by podvrhl zprávy skutečného serveru, pak bychom mohli udělat následující.

  • Odstranit z programu šifrování
  • Zachytit zprávu jdoucí na server
  • Pomocí debuggeru projít kód a vyčíst jaká struktura odpovědi je očekávaná
  • Vytvořit lokální server, případně proxy a přesměrovat komunikaci na něj

Buď – vytvoříme si server

Pokud jsme hračičkové, můžeme si s vytvořit vlastní licenční server a použít tak relativně neobvyklou techniku. Tento postup jsem vyzkoušel a díky tomu zjsitil, jakým způsobem je v programu pracováno s řetězci, s licencí a jak to všechno funguje jako celek.

Jako první jsem zachytil komunikaci se serverem pomocí debuggeru a odstranil šifrovací a dešifrovací rutiny.

Upravená nešifrovaná odpověď serveru (crafted). Zkráceno.

Pak následovalo upravení odpovědi od serveru. Jako poslední krok jsem v jazyce C# vytvořil jednoduchý HTTP server, který odesílá podvržené odpovědi.

Běžící instance vytvořeného serveru.
Program přijal licenci

No a ty vole! Ono to funguje. Program podvrženou licenci přijme a chová se jako ve verzi Pro. Údaje jsou navíc uloženy v registrech a stačí proto server použít pouze jednou.

Nebo – odstraníme kontrolu licence

Proč bychom měli psát vlastní licenční server, když můžeme odstanit kontrolu licence z programu přímo?

Řekne se to jednoduše, ale je to vůbec možné?

Z podstaty věci není možná nahradit instrukci za jinou zabírající více paměti. V opačném případě by bylo nutné relokovat části programu a všechno by se neúměrně zkomplikovalo.

Začneme tak, že odstraníme kontrolu licence, která je prováděna v metodě TLicenseManager.Check(). Mimo další akce metoda načte klíče z registrů a zkontroluje je, případně nastaví typ funkční licence a vrátí příznak úspěchu, či neúspěchu. To, že je to metoda, znamená, že je do funkce nutné předat ukazatel na volaný objekt. Ten se ve volací konvenci Delphi předává v registru eax. V eax tedy máme při vstupu do funkce uložen pointer na TLicenseManager.

Červeně označené instrukce byly nahrazeny v programu x64dbg

K úpravě použijeme debugger x64dbg, který kromě očekávaných vlastností zvládá i úpravu a patchování databáze. To pro nás znamená, že umožňuje nahradit instrukce za jiné. Při zkoumání třídy v IDR zjistíme, že typ licence je v objektu uložen na offsetu 0x24. Reálně tedy musíme nastavit v objektu tLicenseManager správný typ licence a vrátit správnou hodnotu. Metoda Check() je uložena na adrese 0x01728554, všechny úpravy tak provedeme zde.

01728554 | mov byte ptr ds:[eax+24], 3
01728558 | mov eax, 1 
0172855D | ret

První řádek uloží typ do licence manageru. Jedná se o typ enum, o kterém nám IDR prozradí, že má členy (lctNone, lctSubscribed, lctStandard, lctPro, lctObsolete, lctExpired). Proto zkopírujeme hodnotu 3. Další řádek uloží do registru eax hodnotu 1, ten se totiž v konvenci Delphi používá pro přenos návratové hodnoty z funkce.

Nesmíme ale zapomenout na to, že metoda dělala ještě další věci. Zejména načítala z registrů hodnotu uživatelského jména a licenčního klíče. Pokud tedy tuto metodu zakážeme a program se na jiném místě pokusí hodnoty přečíst, může dereferencovat prázdnout paměť, či náhodnou hodnotu. Abychom tomu zabránili, najdeme reference na objekty typu TLicense.

Ze struktury postupně vyčteme, že všechny reference vedou na formulář, se kterým jsme naši analýzu začínali, tj. TfmSubscriptionInfo. Odstraníme tedy načítání tohoto formuláře a to přímo v metodě OpenForm. Zrovna tenhle formulář nám v programu chybět nebude :).

Do těla OpenForm hned na první adresu 0x10AAF58 umístíme dvě instrukce

010AAF58 | mov eax, 1
010AAF5D | ret

Tyto vložené instrukce reálně provádějí return 1;, registr eax totiž slouží v Delphi pro přenost návratové hodnoty z funkce.

Calling convention je součást ABI, která předepisuje jakým způsobem jsou volány funkce na úrovni assembleru, tzn. jak jsou předávány parametry, návratové hodnoty. Kdo a kdy uklízí zásobník.

Funkce sice bude zavolána, ale místo toho, aby udělala kontrolu licence, vrátí hodnotu 1. To můžeme udělat, když víme, že funkce nevolá žádné další důležité metody, jako jsou konstruktory, přiřazení globálních proměných apod.

Nakonec vyexportujeme soubor a pokusíme se ho spustit.

Úspěch! Program nehlásí žádnou závadu, chová se jako Pro verze a licenční formulář nelze otevřít – to je prostě radost.

Dnes jsme tak konečně analyzovali a upravili komplikovanější program, který nebyl vytvořen pro .NET.

Použité nástroje:

  • Exeinfo PE – univerzální analyzátor a detektor (free)
  • Wireshark – analyzátor síťového toku (free)
  • Interactive Delphi Reconstructor – disassembler a dekomplikátor programů vytvořených v jazyce Delphi (free)
  • x64dbg – výborný disassembler, assembler a debugger (free)

PS. Nezapomeňte, že vše děláme čistě pro radost.

Vložit komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *