Společnost FTDI ve svém nejnovějším obvodu FT232R , určenému ke konverzi rozhraní USB a UART, implementovala na první pohled velmi příjemnou vlastnost, a to unikátní identifikační číslo, označované jako FTDIChip-ID. Taktéž nabízí dva projekty, FTDIChip-ID Projects a SafeGuard-IT Projects , s nimiž je možné identifikační čísla využívat v uživatelských aplikacích. Dokonce existuje verze obvodu v podobě USB klíče , sloužící pouze jako hardwarový bezpečnostní klíč. V katalogových listech a na webových stránkách vypadá identifikace obvodu velmi slibně a bezpečně, takže jistě nejeden vývojář začne uvažovat, zda-li tuto nabídnutou vlastnost nevyužije pro ochranu svých produktů proti nelegálnímu kopírování či klonování.
Kde se bere FTDIChip-ID
Jelikož se nikde nevyskytují podrobnější informace ohledně implementace identifikačního čísla, ze kterých by bylo možné posoudit, zda-li se skutečně jedná o věc bezpečnou a vhodnou k ochraně duševního vlastnictví, vrhnul jsem se na pole zpětného inženýrství. K analýze posloužila malá aplikace s jedním voláním funkce FTID_GetChipIDfromHandle() z knihovny FTChipID.dll. S debuggerem jsem snadno odhalil funkci identifikace FTDIChip-ID a možnosti, jak toto unikátní a neměnné číslo lehce změnit.
Součástí obvodu FT232R je i na čipu integrovaná paměť EEPROM obsahující základní nastavení obvodu (např. typ obvodu, USB VID a PID, USB sériové číslo, identifikace výrobce, popis produktu apod.) a také oblast vyhrazenou pro uživatelská data, ale to není vše. Na adresách 0x43 a 0x44 se nachází 32bitové sériové číslo čipu, které se zapisuje během jeho výroby a je neměnné. Čipy za sebou jdoucí v balící pásce mají po sobě jdoucí sériová čísla, v mém případě např. 0x70157ECA až 0x70157EDE. Samozřejmě by funkce FTID_GetChipIDfromHandle(), a jí podobné, mohly přímo vracet sériové číslo čipu, ale to by bylo asi příliš do očí bijící, takže se přečtené sériové číslo ještě zkrášluje. V přiloženém výpisu testovacího programu čtenář najde přesný postup výpočtu čísla FTDIChip-ID z přečteného sériového čísla čipu (funkce My_GetChipIDFromHandle() a BitShuffling()).
Pokud má čtenář k dispozici adaptér s obvodem FT232R, může si testovací aplikaci vyzkoušet přímo v praxi (přiložen spustitelný soubor FTChipID.exe). Před spuštěním je nutné nainstalovat ovladač verze 2.04.06 a doplnit knihovnu FTChipID.dll, která je k dispozici na webových stránkách společnosti FTDI.
Po spuštění programu z konzole se zobrazí následující výpis:
Number of FTDI devices is: 1 Dev 0: ID............. 4036001 LocId.......... 22 SerialNumber... 12R6UDE9 Description.... USB-SP Driver version. 00040000 Library version 00030112 FTDIChip-ID.... FF2CFDD5 FTDI Chip SN... 40117A33 My__Chip-ID.... FF2CFDD5
Ve kterém jsou kromě základních informace o obvodu uvedené i položky: FTDI Chip SN (sériové číslo čipu), FTDIChip-ID (FTDIChip-ID přečtené funkcí FTID_GetChipIDfromHandle()) a My__Chip-ID (FTDIChip-ID přečtené vlastní funkcí My_GetChipIDFromHandle()). Je vidět, že obě přečtená čísla FTDIChip-ID se shodují.
Testovací aplikace pro čtení FTDIChip-ID
#include#include #include "ftd2xx.h" #include "FTChipID.h" BYTE BitShuffling (BYTE bSN) { return ((((((((bSN & 0x2) << 0x1) | (bSN & 0xF8)) << 0x3) | (bSN & 0x1)) << 1) | ((((((bSN >> 2) & 0x10) | (bSN & 0x87)) >> 0x1) | (bSN & 0x30)) >> 1)) & 0xff); } FT_STATUS My_GetChipIDFromHandle ( FT_HANDLE ftHandle, DWORD *MyChipID ) { DWORD dwChipSerialNumber; WORD wTemp; if (FT_ReadEE (ftHandle, 0x43, &wTemp) != FT_OK) return (FT_EEPROM_READ_FAILED); dwChipSerialNumber = wTemp; if (FT_ReadEE (ftHandle, 0x44, &wTemp) != FT_OK) return (FT_EEPROM_READ_FAILED); dwChipSerialNumber |= wTemp << 16; printf (" FTDI Chip SN... %08X\n", dwChipSerialNumber); *MyChipID = ((BitShuffling (dwChipSerialNumber & 0xff) << 24) | (BitShuffling ((dwChipSerialNumber >> 8) & 0xff) << 16) | (BitShuffling ((dwChipSerialNumber >> 16) & 0xff) << 8) | (BitShuffling ((dwChipSerialNumber >> 24) & 0xff) << 0)) ^ 0xA5F0F7D1; return (FT_OK); } void main ( void ) { FT_DEVICE_LIST_INFO_NODE *devInfo; FT_HANDLE ftHandle; DWORD numDevs, dwTemp, dwChipID; WORD i; if (FT_CreateDeviceInfoList (&numDevs) == FT_OK) { printf ("Number of FTDI devices is: %d\n",numDevs); devInfo = (FT_DEVICE_LIST_INFO_NODE*) malloc (sizeof(FT_DEVICE_LIST_INFO_NODE) * numDevs); if (FT_GetDeviceInfoList (devInfo, &numDevs) == FT_OK) { for (i = 0; i < numDevs; i++) { printf ("Dev %d:\n", i); printf (" ID............. %x\n", devInfo[i].ID); printf (" LocId.......... %x\n", devInfo[i].LocId); printf (" SerialNumber... %s\n", devInfo[i].SerialNumber); printf (" Description.... %s\n", devInfo[i].Description); if (FT_OpenEx ((PVOID) devInfo[i].LocId, FT_OPEN_BY_LOCATION, &ftHandle) == FT_OK) { FT_GetDriverVersion (ftHandle, &dwTemp); printf (" Driver version. %08X\n", dwTemp); FT_GetLibraryVersion (&dwTemp); printf (" Library version %08X\n", dwTemp); /* tisk FTDIChip-ID pomoci funkce z knihovny FTChipID.dll */ if (FTID_GetChipIDFromHandle (ftHandle, &dwChipID) == FT_OK) printf (" FTDIChip-ID.... %08X\n", dwChipID); /* tisk FTDIChip-ID pomoci primeho cteni obsahu pameti EEPROM */ if (My_GetChipIDFromHandle (ftHandle, &dwChipID) == FT_OK) printf (" My__Chip-ID.... %08X\n", dwChipID); FT_Close (ftHandle); } else printf ("Error - FT_OpenEx()\n"); } } else printf ("Error - FT_GetDeviceInfoList()\n"); free (devInfo); } else printf ("Error - FT_CreateDeviceInfoList()\n"); }
Změna FTDIChip-ID
Změnit sériové číslo jeho přepsáním v interní paměti EEPROM není prakticky možné. Domnívám se, že sériové číslo se zapisuje do paměti v rámci finální kontroly funkce obvodu, kterou výrobce aktivuje vývodem TEST. Samozřejmě zjistit, jak se s obvodem pracuje v rámci jeho kontroly by bylo velmi obtížné, ne-li nemožné.
Druhá možnost tedy je, změnit přečtené sériové číslo v programové oblasti. V následujícím výpisu je symbolicky uveden běh volání funkce FTID_GetChipIDfromHandle() z uživatelské aplikace.
{ Aplikace volani FTID_GetChipIDFromHandle() z FTChipID.dll { obsluha FTID_GetChipIDFromHandle() v FTChipID.dll volani FT_ReadEE (0x43) z ftd2xx.dll { obsluha FT_ReadEE() v ftd2xx.dll volani FT_IoCtl() z ftd2xx.dll { obsluha FT_IoCtl() v ftd2xx.dll volani DeviceIoControl z KERNEL32.dll { obsluha DeviceIoControl v KERNEL32.dll volani obsluhy funkce IoCtrl v ovladaci FT232R } } } volani FT_ReadEE (0x44) z ftd2xx.dll { obsluha FT_ReadEE() v ftd2xx.dll volani FT_IoCtl() z ftd2xx.dll { obsluha FT_IoCtl() v ftd2xx.dll volani DeviceIoControl z KERNEL32.dll { obsluha DeviceIoControl v KERNEL32.dll volani obsluhy funkce IoCtrl v ovladaci FT232R } } } Prepocet serioveho cisla na FTDIChip-ID }
Možností, jak změnit již přečtené sériové číslo, se nabízí celá řada, přičemž jejich použitelnost je dána způsobem implementace v uživatelské aplikaci. Pro ilustraci pouze uvedu: úplná simulace funkce knihovny FTChipID.dll, zásah do kódu knihovny FTChipID.dll (knihovna vykazuje jisté známky ochrany proti úpravám), zásah do kódu knihoven ftd2xx.dll či KERNEL32.dll a v neposlední řadě úprava samotného ovladače.
Pro demonstraci lehkosti změny čteného sériového čísla čipu, resp. čísla FTDIChip-ID, jsem upravil knihovnu ftd2xx.dll. Z uvedeného výpisu je zřejmé, že stačí upravit obsluhu funkce čtení obsahu interní paměti EEPROM tak, že v případě čtení adres 0x43 a 0x44 se nevrací skutečně přečtený obsah, ale požadované číslo. V následujícím výpisu je uveden disasemblovaný kód obsluhy funkce FT_ReadEE. A v dalším výpisu je uvedena provedená změna kódu. Opět si čtenář může v praxi vyzkoušet funkci upravené knihovny. Programem FTD2XX_ModifChipID_hw.exe upravenou knihovnu ftd2xx.dll (určeno pro knihovnu z ovladače verze 2.04.06) stačí nakopírovat do adresáře s testovacím programem FTChipID.exe. Po spuštění se objeví již zmiňovaný výpis, ale s tím rozdílem, že čtený FTDIChip-ID bude vždy 0xDEDABABA. Činnost upravené knihovny si čtenář samozřejmě může vyzkoušet i se svými aplikacemi.
Výpis neupravené funkce FT_ReadEE
00202B50 FT_ReadEE /$ 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] 00202B54 |. 6A 00 PUSH 0 00202B56 |. 8D4424 10 LEA EAX,DWORD PTR SS:[ESP+10] 00202B5A |. 50 PUSH EAX 00202B5B |. 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C] 00202B5F |. 6A 02 PUSH 2 00202B61 |. 51 PUSH ECX 00202B62 |. 6A 04 PUSH 4 00202B64 |. 8D5424 1C LEA EDX,DWORD PTR SS:[ESP+1C] 00202B68 |. 52 PUSH EDX 00202B69 |. 68 80002200 PUSH FTD2XX.00220080 00202B6E |. 50 PUSH EAX 00202B6F |. E8 ECFAFFFF CALL FTD2XX.FT_IoCtl 00202B74 \. C2 0C00 RETN 0C
Výpis upravené funkce FT_ReadEE (skutečná implementace je poněkud odlišná)
00202B44 <FT_ReadEE_Save> /> 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] 00202B48 |. 51 PUSH ECX 00202B49 |. EB 09 JMP SHORT <FTD2XX.FT_ReadEE_Cont> 00202B4B | 90 NOP 00202B4C | 90 NOP 00202B4D | CC INT3 00202B4E | CC INT3 00202B4F | CC INT3 00202B50 FT_ReadEE |$^EB F2 JMP SHORT <FTD2XX.FT_ReadEE_Save> 00202B52 | 90 NOP 00202B53 | 90 NOP 00202B54 <FT_ReadEE_Cont> |> 6A 00 PUSH 0 00202B56 |. 8D4424 14 LEA EAX,DWORD PTR SS:[ESP+14] 00202B5A |. 50 PUSH EAX 00202B5B |. 8B4424 10 MOV EAX,DWORD PTR SS:[ESP+10] 00202B5F |. 6A 02 PUSH 2 00202B61 |. 51 PUSH ECX 00202B62 |. 6A 04 PUSH 4 00202B64 |. 8D5424 20 LEA EDX,DWORD PTR SS:[ESP+20] 00202B68 |. 52 PUSH EDX 00202B69 |. 68 80002200 PUSH FTD2XX.00220080 00202B6E |. 50 PUSH EAX 00202B6F |. E8 ECFAFFFF CALL FTD2XX.FT_IoCtl 00202B74 |. E8 98FCFFFF CALL <FTD2XX.FT_ReadEE_ModifChipID> 00202B79 |. 59 POP ECX 00202B7A \. C2 0C00 RETN 0C FT_ReadEE_ModifChipID: cmp BYTE PTR DS:[ESP+010h],043h jz FT_ReadEE_ModifChipID_43 cmp BYTE PTR DS:[ESP+010h],044h jz FT_ReadEE_ModifChipID_44 ret ; cetlo se z adresy 43h, coz je LSB ChipSN FT_ReadEE_ModifChipID_43: push EAX mov EAX,DWORD PTR SS:[ESP+8] mov WORD [EAX],05678h ; modifikace precteneho LSB ChipSN pop EAX ret ; cetlo se z adresy 44h, coz je MSB ChipSN FT_ReadEE_ModifChipID_44: push EAX mov EAX,DWORD PTR SS:[ESP+8] mov WORD [EAX],01234h ; modifikace precteneho MSB ChipSN pop EAX ret
SafeGuard-IT a USB klíč
Další projekt nabízený společností FTDI je SafeGuard-IT. Jedná se o využití asymetrického šifrování s dvojicí klíčů, veřejným a soukromým. Nejprve se vygeneruje dvojice klíčů – soukromý a veřejný, poté se do uživatelské části interní paměti EEPROM zapíše signatura; zašifrované sériové číslo čipu s využitím soukromého klíče. Uživatel dostane do ruky čip v podobě adaptéru či klíčenky a veřejný klíč, pomocí kterého se v uživatelské aplikaci ověří, zda-li zapsaná signatura v klíči odpovídá veřejnému klíči. Využití této metody má tu výhodu, že stačí jedna verze aplikačního programu pro všechny uživatele a řeší se pouze distribuce veřejných klíčů.
Knihovna SafeGuard-IT.dll je již velmi dobře chráněna proti nežádoucím úpravám, jenže vše opět stojí na čtení sériového čísla čipu funkcí FT_ReadEE. Popsanou úpravou čtení obsahu interní paměti EEPROM tedy dokážeme velmi snadno klonovat obvody FT232R s uloženou signaturou. Abychom klon mohli udělat, musíme mít v ruce klonovaný čip, resp. musíme znát obsah jeho interní paměti EEPROM.
Vzhledem k tomu, že pro práci s USB klíčem se používají stejné ovladače jako pro práci s obvodem FT232R, domnívám se, že se po technické stránce jedná o obvod FT232R zapouzdřený do podoby klíčenky a tudíž platí vše výše uvedené. Porovnávat možnosti USB klíče společnosti FTDI s klíči firem Aladdin (HASP 4), Rainbow (Sentinel SuperPro), Eutronsec (SmartKey) apod., je zbytečná práce. Jedná se o naprosto nesrovnatelné produkty.
FT245R a jeho FTDIChip-ID
S obvodem FT245R (konvertor rozhraní USB a paralelního) jsem neměl možnost pracovat, nicméně z popisu uvedeném v katalogovém listu a z faktu, že používá stejné ovladače jako FT232R soudím, že identifikační číslo a způsob jeho čtení je řešeno shodně s FT232R, a tudíž také platí vše výše uvedené.
Závěr
FT232R je bezpochyby špičkový obvod usnadňující mnohým vývojářům život a umožňující vznik řady zajímavých aplikací. Sériové číslo čipu FT232R uložené v jeho interní paměti EEPROM je bezpochyby výborná vlastnost například pro identifikaci výrobků, ale rozhodně to není prvek, na kterém by bylo vhodné stavět bezpečnostní opatření.Download & Odkazy
- FT232R - USB UART IC http://www.ftdichip.com/Products/FT232R.htm
- FTDIChip-ID™ Projects http://www.ftdichip.com/Projects/FTDIChip-ID.htm
- SafeGuard-IT Projects http://www.ftdichip.com/Projects/SafeGuard-IT.htm
- USB-Key http://www.ftdichip.com/Products/EvaluationKits/USB-Key.htm
Komentáře
Pěkný výsledek.
Dobrá práce. Jak se dalo tušit, takové zabezpečení nemůže nefungovat. Zvláštní, že do takovéhle hračky někdo jde, přestože výrobce neřekne, jak to funguje - takové kupování zajíce v pytli.
Ad SafeGuard-IT: podle popisu výrobce to vypadá, že je to zranitelné stejným způsobem. Ta asymetrická kryptografie v SafeGuard-IT jen zjednodušuje používání, ale stále závisí na nevyčítatelnosti toho tajemství v chipu.
Autor zaměňuje pojmy
Autor sám přiznává, že se mu nepodařilo přepsat EEPROM, tedy FTDI-Chip v hardware evidentně unikátní je. To, co zde prezentuje, je tuctové hacknutí .DLL tedy autor zaměňuje pojmy, i když výsledek pro nadřazenou aplikaci je identický, prostě FTDI-Chip se dá "měnit".
V praxi, když už útočník umí měnit kód ve spustitelných souborech, nebude se otravovat s funkcí FT_ReadEE, ale rovnou si v .EXE aplikace najde příslušné
FTID_GetChipIDFromHandle (ftHandle, &dwChipID);
if (dwChipID == MojeTajnaHodnota)
a nahradí ho klasickým 5-ti bytovým hackem JMP xxx
A co se týká srovnání s ostatními produkty, tak je to v tomto smyslu všechno stejný šmejd a proti útočníkovi schopného měnit spustitelný kód není šance se ubránit s vyjímkou drahého HW klíče vykonávající části aplikace, respektive zákazníkovi je v HW klíči fakticky vnucen malý počítač.
Skvělý komentář
na firemních stránkách společnosti FTDI stojí tato věta: „The FTDIChip-ID is a permanent, unique number programmed into each IC during production that cannot be changed by the end user“; na unikátnost identifikačního čísla se zde hledí z pohledu konečného uživatele, takže je potřeba brát v úvahu vše, co může konečný uživatel činit. Dokonce byla tato věta psána tak, že konečný uživatel nemůže žádnými prostředky FTDIChip-ID změnit. Nejde ale o věty a slova, ale jde o to, co tyto věty a slovo vyvolají v mysli vývojáře řešícího problematiku ochrany svého nápadu a své práce.
Krom přesného mechanismu tvorby identifikačního čísla FTDIChip-ID, také skutečně prezentuji tuctové cracknutí jedné knihovny .dll, a o to právě jde! Právě jedno tuctové cracknutí obejde případný bezpečnostní prvek důvěřivého vývojáře.
Implementace případného ochranného mechanizmu metodou if (dwChipID == MojeTajnaHodnota) je samozřejmě nejjednodušší a také asi bohužel nejčastější. Pokud např. vývojář použije projekt SafeGuard-IT nebo chráněný program pomocí identifikačního čísla zakryptuje, bude se muset případný útočník s funkcí FT_ReadEE zabývat v té či oné podobě. Buď kvůli tvorbě klonu nebo kvůli dekryptování programu.
Předpokládám, že autor komentáře zná možnosti citovaných HW klíčů, tak může veřejně tvrdit, že se jedná o „všechno stejný šmejd“.
Opravdu trefná je ovšem věta „s vyjímkou drahého HW klíče vykonávající části aplikace, respektive zákazníkovi je v HW klíči fakticky vnucen malý počítač“! Jsme na stránkách serveru věnujícímu se z větší části HW problematice a je tedy možné očekávat, že většina vývojářů používá obvod FT232 jako převodník rozhraní mezi PC a vlastní HW aplikací, ve které nezřídka nějaký ten mikropočítač již je. Pokud si tedy hypotetický vývojář na počátku vývoje svého nového projektu přečte, že je možné jedním tuctovým cracknutím .dll obejít FTDIChip-ID, bude přemýšlet o jiném způsobu zabezpečení. A opravdu zákazníkovi nezřídka nutí malý počítač, a zákazník za něj rád zaplatí, protože jinak si např. diagnostiku svého nového vozu se sběrnicemi CAN neudělá. A když už si ten malý počítač koupí a zaplatí, bude ideální tento mikropočítač použít i pro ochranu produktu. Tento příklad s diagnostickým adaptérem jsem uvedl záměrně, Ti co se v této oblasti trochu pohybují, jistě dobře vědí, jaký se kolem klonů diagnostických adaptérů pro automobily točí obchod a kolik to autory stojí marného úsilí, mimo jiné i proto, protože právě zakládají ochranu svého produktu proti klonování na FTDIChip-ID.
Ještě jednou se vrátím k řádce if (dwChipID == MojeTajnaHodnota) – táto řádka je typickým výsledkem návrhu zabezpečení tvořeného v okamžiku, kdy je vlastní produkt již hotov! Pokud vývojář není programátorský laik, pokud si cení své práce a pokud integruje ochranné mechanismy do svého vývoje ve všech jeho etapách, nikdy takovouto řádku nepoužije.
ftd2xx.dll Kde ho získať
Kde môžem získať tohto súboru?
Nemám žiadny súbor na webe "2006-04-02" dostať.
Rád by som na tomto projekte, ale väčšina.
Vďaka za vašu pomoc.