Подведем итоги по ультралайтам

Sep 09, 2008 19:00

Ну что можно подытожить по теме. Наверное, в первую очередь я получил что хотел. Дело закрыто.
Теперь по пунктам:
1. Стала полностью понятна структура данных на билете
2. Стало понятно, что собой представляет эта "контрольная сумма". Это действительно хэш данных, записанных на билете. Механизм вычисления достаточно сложен и, если бы мне в руки не попали бы метрошные смарттековские программы, я бы никогда не узнал, как это работает. И никто бы не узнал. Для генерации КС используются данные билета и специальный ключ. Восстановить ключ из данных билета и контрольной суммы невозможно.
3. Ключи в метро достаточно часто меняют. По крайней мере стали сейчас это делать. Те ключи, которые у меня на руках (июнь 2006) уже не актуальны. Тем более, ходят слухи, что грядут еще более фундаментальные изменения, нежели простая смена ключей.

Какие из этого выводы? Что ж, система оказалась стойкой к атакам, анализу и подбору. В этом ребята из смарттека молодцы. Взломать эту систему, основываясь на общедоступных данных (билетики из помойки) невозможно.
Смарттековцы профуфлындились в том, что сами программы никак не защтщены от реверсинга и, при помощи того же IDA, всю подноготную видно от края и до края. С другой стороны, система создана так, что даже если ты каким-то образом получил то, чего нинада, простой сменой ключей эта проблема решается моментально. Другое дело, что страна-то у нас какая? Правильно, страна у нас бандитская. По этому, если у бандитов появится канал, через который они смогут получать своевременно программы и ключи, то смена алгоритмов и защита кода обфускатором, а также отказ от использования рантайм-библиотек решили бы проблему, я считаю. Ко всему прочему, хорошо бы было прикрепить каждую программу на аппаратном уровне к своему считывателю или использовать какие-нибудь хорошие донглы, это не тяжело. Тогда кража софта стала бы просто бесполезной. В общем, есть еще куда работать в плане безопасности.

Вот на этой ноте, пожалуй, будем считать тему с ультралайтами законченой. Если кому-то интересно, могу написать парочку статеек в журналы, тут вроде-бы некоторые были не против :)

С другой стороны, бурный и эпичный конец дела с ультралайтами породил начало нового моего исследования -- теперь я возьмусь за Mifare Classic, т.к. во время реверсинга метрошных программ я открыл, по ходу дела, несколько оооочень интересных подробностей относительно этих карт и их использования в метро, автобусах и троллейбусах. Пока ничего говорить не буду, так что ждите публикаций.

Ну и вот вам всем немного кода, который я на скорую руку сляпал после нескольких дней неторопливого реверсинга. На картинке в предыдущем посту работает именно этот код. Функции импортируются из смарттековских рантайм библиотек:

unit _Test_MainU;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

function LoadKeys(Obj: pointer; KeyFile: AnsiString): byte; external 'SmLayout.bpl' index 140;
function SetTicketType(Obj: pointer; AppCode: integer; CardCode: integer): byte; external 'SmLayout.bpl' index 137;
procedure SelFirstKey(Obj: pointer); external 'SmLayout.bpl' index 139;
procedure SelNextKey(Obj: pointer); external 'SmLayout.bpl' index 138;
function GetKey(Obj: pointer): pointer; external 'SmLayout.bpl' index 141;

function CalcHashCode(Key: pointer; {32b key}
                      TicketData: pointer; {4b OTP, 16b header:p4-7, 8b data:p8-9, 4b data:p11}
                      TicketDataSize: integer; {32}
                      CalcMethod: byte; {-1=CalcCryptCode probably old method,
                                          0=using first part of hash table,
                                          1=using second part of hash table}
                      UltralightSerial: pointer {7b UL serial, 8 byte is always 0x00}): integer; stdcall; external 'SmLayout.bpl' index 5;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var Obj: array[0..63] of byte;
    ResB: byte;
    ResI: cardinal;
    KeyAddr: pointer;
    KeyBuffer: array[0..31] of byte;
    Method: byte;

const

UlSerial: array[0..7] of byte = ($04, $C6, $B2, $C1, $FF, $02, $80, $00); //Серийник УЛ

UlData: array[0..31] of byte = (
    $00, $00, $00, $00, $41, $89, $60, $00, $9F, $23, $A8, $18, $42, $00, $00, $00,
    $00, $00, $00, $00, $17, $C8, $1E, $00, $00, $01, $04, $A8,
    $00, $00, $00, $00
); //Данные билетика

begin
FillChar(Obj, 64, 0); //Это у нас будет экземпляр класса TKeyRef. Типа :) 64 байта просто от балды.
LoadKeys(@Obj, 'c:\softplat\db\keys.d'); //Эта функция подгружает и расшифровывает файл с ключами
SetTicketType(@Obj, 262, 150); //Эта функция выбирает кейринг из файла на основе типа билета
SelFirstKey(@Obj); //Эта функция выбирает первый ключ в кейринге
//SelNextKey(@Obj); //Эта -- следующий
KeyAddr := GetKey(@Obj); //Эта отдает нам адрес ключа в памяти. Рамер -- 34 байта. Первые два, видимо, версия ключа
if KeyAddr = nil then //Если адреса нету, то ключи закончились
begin
  ShowMessage('Хуй тебе! Ключи кончились.');
  exit;
end;
CopyMemory(@KeyBuffer, Pointer(Integer(KeyAddr)+2), 32); //Копируем себе ключ, без версии (первые 2 байта)
ResI := CalcHashCode(@KeyBuffer, @UlData, 32, Obj[4+16], @UlSerial); //Немного уличной магии
//З.Ы. Как я понял, режим, на данный момент, это номер используемого ключа, т.е. Obj[4+16]
ShowMessage('Hash: '+IntToHex(ResI, 8)); //... и получаем пиздюлей от сотрудников метрополитена.
//Компания Смартек тоже получает пиздюлей. Занавес.
end;

end.
Previous post Next post
Up