Уголок OpenSource

В этом топике будут выкладываться некоторые полезные инструменты (преимущественно с исходником) и просто интересные примеры кода. Их можно использовать при разработке собственной защиты на основе Guardant API, а также при диагностике электронных ключей.

Желание поделиться собственными наработками и опытом приветствуется!

Все необходимо сопровождать кратким описанием: что это, для чего и как может быть использовано. Автор ответственен за актуальность и сопровождение собственного кода. Критика со стороны не принимается. Только вопросы и предложения по дальнейшей разработке и развитию.

Все свое предлагается публиковать под лицензией WTFPL.

Доступно для скачивания:

  • structures.h - некоторые константы и структуры из документации

  • writemask - библиотека для формирования маски ключа вручную (кроссплатформенная)

  • chknsk - утилита для поиска ключей и получения информации о них (кроссплатформенная)

  • codeutil - утилита для загрузки и вызова загружаемого кода (windows)

  • grdinfotool - утилита для сбора базовых сведений при техподдержке и диагностике (linux)

  • ECC_Gen - генератор ключевых пар для алгоритма ECC160 (windows)

  • libgrdapi.a - библиотека Guardant API 5.52 для linux

  • GrdWine - проект библиотеки GrdWine для работы с ключами в среде Wine

Re: Уголок OpenSource

Заголовочный файл structures.h с определениями констант и структур, которых нет в grdapi.h, но которые встречаются в документации.

Re: Уголок OpenSource

Библиотека writemask с исходником и примером использования на C++, проектом для MSVS9.
Предназначена для формирования маски ключа вручную (как массива байтов) для последующей записи в ключ при помощи Guardant API.

Re: Уголок OpenSource

Консольная утилита chknsk с исходником на C (кроссплатфоремнный код), проектом MSVS9 и makefile.
Предназначена для поиска и получения информации об установленных ключах Guardant. Удобно искать HID ключи, так как не требуется установка драйвера.

Re: Уголок OpenSource

Утилита codeutil с исходником на С# и проектом MSVS10.
Предназначена для работы с загружаемым кодом. Умеет записывать в ключ маску в формате NSD (версии до 5.52), находить в ней ячейки с загружаемым кодом, записывать в ключ свой код в формате GCEXE (в выбранный дескриптор загружаемого кода, в соответствии с маской), а также выполнять этот загружаемый код, подавая ему на вход произвольные данные.

Re: Уголок OpenSource

Консольная утилита grdinfotool (для linux) с исходником на C и makefile.
Предназначена для получения информации о прописанных правилах для ключей и базовых сведений о системе.

Re: Уголок OpenSource

Консольная утилита ECC160_PairGenerator без исходника (EXE).
Предназначена для генерации ключевых пар для алгоритма ECC160, реализованного в электронных ключах.

Re: Уголок OpenSource

Библиотека Guadrant API 5.52 для linux (x86, x86_64).
Взята из DK и выложена отдельно для удобства разработчиков под linux.

Re: Уголок OpenSource

Проект динамической библиотеки GrdWine для работы с ключами под Wine.
Взят из DK и выложен отдельно для удобства разработчиков и конечных пользователей, работающих под Wine.

Re: Уголок OpenSource

Пример для записи маски в ключ с помощью Guardant API (из SDK 7.0) на Embarcadero RAD Studio XE7.

Re: Уголок OpenSource

Пример загружаемого кода с генератором случайных чисел по алгоритму Вихрь Мерсенна (MT19937) http://rgho.st/6tmRygx85.
Подробнее об алгоритме - https://ru.wikipedia.org/wiki/Вихрь_Мерсенна

Обратить внимание на #define START_SEED 0x00001105

В примере генерируется массив из 10 даблов. Тестовые значения:
0.81733006001853614000
0.99906089971751466000
0.51035437255873217000
0.13153290984489324000
0.03541634837990075700
0.99246953450899322000
0.62570870356301511000
0.06259194576707481600
0.41071051112625528000
0.13477367491805314000

Re: Уголок OpenSource

Пример загружаемого кода с реализацией алгоритмов проверки цифровой подписи и обмена открытыми ключами по алгоритму Diffie-Hellman на эллиптических кривых ECC-256 (кривая NIST).
Ссылка на загрузку - http://rgho.st/8PKBPYCmV.

Файл main.c достаточно подробно прокомментирован.

Re: Уголок OpenSource

Реализуйте, пожалуйста, на форуме функционал "спойлер".

Тогда можно было бы здесь размещать достаточно объемный и полезный исходный код, не замусоривая ветку, и без опасения, что ресурс, с которого можно загрузить данные, перестанет быть доступен.

Re: Уголок OpenSource

Как указано в документации, под Wine (Linux) не требуется устанавливать "стандартные" драйверы ключей, а требуется совсем другое. Недокументированным способом определения среды Wine является определения наличия метода wine_get_version() в ntdll.dll.


Функция для писателей инсталлятров:

1. Delphi

function IsWinePresent(): boolean;
var
  fHandle: HMODULE;
begin
  Result := False;
  fHandle := GetModuleHandle('ntdll.dll');
  if fHandle = 0 then Exit;
  Result :=  Assigned(GetProcAddress(fHandle, 'wine_get_version'));
end;

2. NSIS

Function IsItWine ; Если Wine, то возвращает в $0 не 0, иначе - 0.
  System::Call "kernel32::GetModuleHandle(t 'ntdll.dll') i .s"
  System::Call "kernel32::GetProcAddress(i s, t 'wine_get_version') i .r0"
FunctionEnd

Пример использования (полный код инсталлятора NSIS):

OutFile "tst01.exe"
 
Section

  Push $0

  Call IsItWine 
    IntCmp $0 0 notWine
      MessageBox MB_OK "Wine"
      Goto next 
    notWine:
      MessageBox MB_OK "Not Wine"
    next:
  Pop $0
  
SectionEnd

Function IsItWine ; Если Wine, то возвращает в $0 не 0, иначе - 0.
  System::Call "kernel32::GetModuleHandle(t 'ntdll.dll') i .s"
  System::Call "kernel32::GetProcAddress(i s, t 'wine_get_version') i .r0"
FunctionEnd

Re: Уголок OpenSource

Фиксация изменения состава USB устройств.

unit grdKeyDetector;

interface

uses
  Messages, Windows;

const

  GUID_CLASS_USBHUB: TGUID = '{f18a0e88-c30c-11d0-8815-00a0c906bed8}';
  GUID_CLASS_USB_DEVICE: TGUID = '{A5DCBF10-6530-11D2-901F-00C04FB951ED}';
  GUID_CLASS_USB_HOST_CONTROLLER: TGUID = '{3ABF6F2D-71C4-462a-8A92-1E6861E6AF27}';

  DBT_DEVTYP_DEVICEINTERFACE = $00000005; // device interface class
  DBT_DEVICEARRIVAL           = $8000; // system detected a new device
  DBT_DEVICEREMOVECOMPLETE    = $8004; // device is gone


type

  _DEV_BROADCAST_DEVICEINTERFACE_A = record
    dbcc_size: DWORD;
    dbcc_devicetype: DWORD;
    dbcc_reserved: DWORD;
    dbcc_classguid: TGUID;
    dbcc_name: array [0..0] of AnsiChar;
  end;
TDevBroadcastDeviceInterface = _DEV_BROADCAST_DEVICEINTERFACE_A;
PDevBroadcastDeviceInterface = ^_DEV_BROADCAST_DEVICEINTERFACE_A;



  TDeviceOperation = (doInsert, doRemove);
  TDeviceChangeEvent = procedure(Sender: TObject; VID, PID: Word; const Serial, GUID:
    string; Operation: TDeviceOperation) of object;


  TgrdKeyDetector = class(TObject)
  private
    FWndHandle: HWND;
    FClassGUID: TGUID;
    FNotifyHandle: Pointer;
    FOnChange: TDeviceChangeEvent;

    procedure SetClassGUID(const Value: TGUID);
    procedure Close;
    procedure Open;
    procedure WndProc(var aMsg: TMessage);
    function ParseDeviceName(Mask, Text: string; Params: array of Pointer): Boolean;
  protected
    procedure DoDeviceChange(Event: Integer; Device: PDevBroadcastDeviceInterface);


  public
    constructor Create;
    destructor Destroy; override;
    property ClassGUID: TGUID read FClassGUID write SetClassGUID;
    property OnChange: TDeviceChangeEvent read FOnChange write FOnChange;
  end;

implementation

uses
  Forms, SysUtils, Classes;

constructor TgrdKeyDetector.Create;
begin
  inherited;
  FWndHandle := AllocateHWnd(WndProc);
  FClassGUID := GUID_CLASS_USB_DEVICE;
  Open;

end;

destructor TgrdKeyDetector.Destroy;
begin
  Close;
  DeallocateHWnd(FWndHandle);

end;

procedure TgrdKeyDetector.DoDeviceChange(Event: Integer;
  Device: PDevBroadcastDeviceInterface);
var
  VID, PID: Word;
  Serial, GUID: string;
const
  USBDeviceNameMask = '\\?\USB#Vid_%x&Pid_%x#%s#%s';
begin
  if (Device.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE) and Assigned(FOnChange)
    and ParseDeviceName(USBDeviceNameMask, PChar(@Device.dbcc_name), [@VID, @PID,
    @Serial, @GUID]) then
    case Event of
      DBT_DEVICEARRIVAL: FOnChange(Self, VID, PID, Serial, GUID, doInsert);
      DBT_DEVICEREMOVECOMPLETE: FOnChange(Self, VID, PID, Serial, GUID, doRemove);
    end;
end;

procedure TgrdKeyDetector.Close;
begin
  if FNotifyHandle <> nil then
    UnregisterDeviceNotification(FNotifyHandle);
end;

procedure TgrdKeyDetector.Open;
var
  Info: TDevBroadcastDeviceInterface;
begin
  Info.dbcc_size := SizeOf(TDevBroadcastDeviceInterface);
  Info.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
  Info.dbcc_classguid := FClassGUID;
  FNotifyHandle := RegisterDeviceNotification(FWndHandle, @Info,
    DEVICE_NOTIFY_WINDOW_HANDLE); end;

function TgrdKeyDetector.ParseDeviceName(Mask, Text: string;
  Params: array of Pointer): Boolean;
var
  PText, PMask, First: PChar;
  V, Index: Integer;
  Token: Boolean;
  Ch: Char;
begin
  Result := False;
  Text := Trim(Text);
  if (Text = '') or (Mask = '') then Exit;
  PText := PChar(Text);
  PMask := PChar(Mask);
  Token := False;
  Index := 0;
  while PMask^ <> #0 do begin
    if Token then begin
      Token := False;
      case UpCase(PMask^) of
        'X': begin
            if not (PText^ in ['0'..'9', 'a'..'f', 'A'..'F']) then Exit;
            V := 0;
            repeat
              case PText^ of
                '0'..'9': V := V * 16 + Ord(PText^) - Ord('0');
                'a'..'f': V := V * 16 + Ord(PText^) - Ord('a') + 10;
                'A'..'F': V := V * 16 + Ord(PText^) - Ord('A') + 10;
              else
                Break;
              end;
              if V > MaxWord then Exit;
              Inc(PText);
            until False;
            if Index > High(Params) then Exit;
            PWord(Params[Index])^ := V;
            Inc(Index);
          end;
        'S': begin
            First := PText;
            Ch := UpCase(PMask[1]);
            while (PText^ <> #0) and (UpCase(PText^) <> Ch) do
              Inc(PText);
            if Index > High(Params) then Exit;
            SetString(PString(Params[Index])^, First, PText - First);
            Inc(Index);
          end;
        '%': begin
            if PText^ <> '%' then Exit;
            Inc(PText);
          end;
      else
        Exit;
      end
    end
    else
      if PMask^ = '%' then
        Token := True
      else
        if UpCase(PMask^) <> UpCase(PText^) then
          Exit
        else
          Inc(PText);
    Inc(PMask)
  end;
  Result := True;
end;

procedure TgrdKeyDetector.SetClassGUID(const Value: TGUID);
begin
  if not IsEqualGUID(FClassGUID, Value) then begin
    FClassGUID := Value;
    Close;
    Open;
  end;
end;

procedure TgrdKeyDetector.WndProc(var aMsg: TMessage);
begin
  with aMsg do
    if (Msg = WM_DEVICECHANGE)
      and ((wParam = DBT_DEVICEARRIVAL) or (wParam = DBT_DEVICEREMOVECOMPLETE)) then try
      DoDeviceChange(wParam, PDevBroadcastDeviceInterface(lParam));
    except
      if Assigned(ApplicationHandleException) then
        ApplicationHandleException(Self)
      else
        raise;
    end
    else
      DefWindowProc(FWndHandle, Msg, wParam, lParam);
end;
end.

Как использовать:

uses
  ...grdKeyDetector;
...
  TfrmMain = class(TForm)
  private
    fKD: TgrdKeyDetector;
    procedure KOnChanged(Sender: TObject; VID, PID: Word;
      const Serial, GUID: string; Operation: TDeviceOperation);
  public
    procedure Start();
    procedure Stop();
  public
    { Public declarations }
  end;
...
procedure TfrmMain.Start();
begin
  if not Assigned(fKD) then begin
    fKD := TgrdKeyDetector.Create;
    fKD.OnChange := KOnChanged;
  end;
end;

procedure TfrmMain.Stop();
begin
  if Assigned(fKD) then
    FreeAndNil(fKD);
end;

procedure TfrmMain.KOnChanged(Sender: TObject; VID, PID: Word; const Serial,
  GUID: string; Operation: TDeviceOperation);
var
  fStr: string;
begin
  case Operation of
    doInsert: fStr := ' Inserted!';
    doRemove: fStr := 'Removed!';
  end;
  ShowMessage(fStr);
end;