Хак для Rigol 2000 серии

Оборудование
Помните известный хак, позволявший сделать из 50МГц осциллографа Rigol (DS1052) 100МГц версию (DS1102) с помощью всего пары команд?

Как оказалось, история повторилась и с новыми осциллографами Rigol 2000 и теперь можно из DS2072 (70МГц) за 800$ сделать DS2202 (200МГц) за $1600 просто введя пароль, сгенерированный кейгеном. Кроме того, кейген открывает опциональные декодеры протоколов, которые тоже стоят денег.

Rigol 2000 hack

Хак разработали на форуме EEVBlog, декодируя передачу данных между процессором и EEPROMом.

В Rigol используется эллиптическая криптография (вид асимметричного шифрования). Ошибка Rigol заключалась в том, что они не верно выбрали параметры для криптоалгоритма, в частности, для модуля использовали не простое число. Из-за этого, ключ относительно легко подобрался. Хороший урок по криптографии вышел :)

Исходники кейгена
/*
** rigol ds2000 keygen / cybernet & the-eevblog-users
**
** to compile this you need MIRACL from [url]https://github.com/CertiVox/MIRACL[/url]
** download the master.zip into a new folder and run 'unzip -j -aa -L master.zip'
** then run 'bash linux' to build the miracle.a library
**
** BUILD WITH:
**
** gcc rikey.c -I../MIRACL ../MIRACL/miracl.a -o rikey
**
** adapt -I and path to miracl.a to your environment
**
** more info: https://www.eevblog.com/forum/testgear/sniffing-the-rigol's-internal-i2c-bus/
**
** then fetch private key from EEV Blog and put into "private_key[]=" below, do not prefix with 0x
** supply your serial and wanted options, and enjoy !
**
**
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "miracl.h"

#define RIGOL_DS2000

// START OF SETTINGS FOR ECC
#ifdef RIGOL_DS2000
 unsigned char private_key[]="8.....";   // <- RILOL FILL ME (no 0x prefix !)
 unsigned char prime1[]="AEBF94CEE3E707";
 unsigned char prime2[]="AEBF94D5C6AA71";
 unsigned char curve_a[]="2982";
 unsigned char curve_b[]="3408";
 unsigned char point1[]="7A3E808599A525";
 unsigned char point2[]="28BE7FAFD2A052";
#endif
// END OF SETTINGS FOR ECC

unsigned char codemap_ee00d0[]={ 0x0, 0x0, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
                                 0x0, 0x0, 0x0,  0x0,  0x0,  0x0,  0x0,  0x0,  0x1,  0x2,
                                 0x3, 0x4, 0x5,  0x6,  0x7,  0x0,  0x8,  0x9,  0xa,  0xb,
                                 0xc, 0x0, 0xd,  0xe,  0xf,  0x10, 0x11, 0x12, 0x13, 0x14,
                                 0x15,0x16, 0x17 };

unsigned char codemap_20688e[]={ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,  /* 0-9 = 0x30 */
                                 0x37, 0x37, 0x37, 0x37, 0x37, 0x37 };                        /* A-F = 0x37 */


unsigned char vb[]={'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9'};

void show_help(void)
{
 printf("./rikey <DSA2XXXXXXXXX> <OPTS>\n\n");
 printf("<DSA2XXXXXXXXX> -  serial number of device\n");
 printf("<OPTS> - \n");
 printf("\t\tDSA? for permanent options\n");
 printf("\t\tVSA? for temporary options\n");
 printf("\n\n");
}
/*
** take serial and options make sha1 hash out of it
*/
static void hashing(unsigned char *opt_str,big hash)
{ /* compute hash function */
    char *p;
    char h[20];
    int ch;
    sha sh;
    shs_init(&sh);
    p=opt_str;
    while(*p)
    {
       shs_process(&sh,*p);
       p++;
    }
    shs_hash(&sh,h);
    bytes_to_big(20,h,hash);
}
/*
** sign the secret message (serial + opts) with the private key
*/
int ecssign(unsigned char *serial, unsigned char *opt, unsigned char *lic1, unsigned char *lic2)
{
    FILE *fp;
    char ifname[50],ofname[50];
    big a,b,p,q,x,y,d,r,s,k,hash;
    epoint *g;
    long seed;
    int bits;
    miracl *mip;
    unsigned char *serial_options;

/* get public data */
    mip=mirsys(0x320, 0x10);   /* Use Hex internally */
    mip->IOBASE=16;
    a=mirvar(0);
    b=mirvar(0);
    p=mirvar(0);
    q=mirvar(0);
    x=mirvar(0);
    y=mirvar(0);
    d=mirvar(0);
    r=mirvar(0);
    s=mirvar(0);
    k=mirvar(0);
    hash=mirvar(0);

    instr(p,prime1);     /* modulus        */
    instr(a,curve_a);     /* curve parameters */
    instr(b,curve_b);
    instr(q,prime2);     /* order of (x,y) */
    instr(x,point1);     /* (x,y) point on curve of order q */
    instr(y,point2);

/* randomise */
    seed=1;
    irand(seed);

    ecurve_init(a,b,p,MR_PROJECTIVE);  /* initialise curve */
    g=epoint_init();

    if (!epoint_set(x,y,0,g)) /* initialise point of order q */
    {
        printf("1. Problem - point (x,y) is not on the curve\n");
        exit(0);
    }

/* calculate r - this can be done offline,
   and hence amortized to almost nothing   */
    bigrand(q,k);
    ecurve_mult(k,g,g);      /* see ebrick.c for method to speed this up */
    epoint_get(g,r,r);
    divide(r,q,q);

/* get private key of signer */
    instr(d, private_key);

/* calculate message digest */
    serial_options=calloc(128,1);
    strcpy(serial_options, serial);
    strcat(serial_options, opt);
    hashing(serial_options,hash);

/* calculate s */
    xgcd(k,q,k,k,k);
    mad(d,r,hash,q,q,s);
    mad(s,k,k,q,q,s);

    cotstr(r,lic1);
    cotstr(s,lic2);
    return 0;
}


/*
** convert string to uppercase chars
*/
unsigned char *strtoupper(unsigned char *str)
{
    unsigned char *newstr, *p;
    p = newstr = (unsigned char*) strdup((char*)str);
    while((*p++=toupper(*p)));
    return newstr;
}

/*
**
*/
unsigned char code_map_206846(unsigned char i)
{
 if ((i >= 'A') && (i <= 'F')) return(i-0x37);
 if ((i >= '0') && (i <= '9')) return(i-0x30);
 return(0x0);
}

/*
** Encryption Routine 1
*/
unsigned char *lic_code_map(unsigned char *lic_skipped)
{
 unsigned char lv1,lv2;
 unsigned char b1_mapped, b1_shifted, b1_remapped;
 unsigned char b2_mapped, b2_shifted, b2_remapped;
 unsigned char b3_mapped, b3_shifted, b3_remapped;
 unsigned char b4_mapped, b4_shifted, b4_remapped;
 unsigned char b5_shifted, b5_remapped;
 unsigned char *lic_mapbytes;

 lic_mapbytes=calloc(28, 1);
 if (!lic_mapbytes) return(0);
lv1=lv2=0;
 while(lv1 < strlen((unsigned char*)lic_skipped))
 {
    b1_mapped =  codemap_ee00d0[ *(lic_skipped+lv1) - 0x30 ];
    b1_shifted = (b1_mapped / 2) & 0xf;
    b1_remapped = b1_shifted + codemap_20688e[b1_shifted];
    lic_mapbytes[lv2++]=b1_remapped;
    b1_mapped = b1_mapped & 0x1;

    b2_mapped =  codemap_ee00d0[ *(lic_skipped+lv1+1) - 0x30 ];
    b2_shifted =  ((b1_mapped << 0x3) | (b2_mapped / 4)) & 0xF;
    b2_remapped = b2_shifted + codemap_20688e[b2_shifted];
    lic_mapbytes[lv2++]=b2_remapped;

    b3_mapped = codemap_ee00d0[ *(lic_skipped+lv1+2) - 0x30 ];
    b3_shifted = ((b3_mapped / 8) | ( (b2_mapped & 0x3) << 2 )) & 0xF;
    b3_remapped = b3_shifted + codemap_20688e[b3_shifted];
    lic_mapbytes[lv2++]=b3_remapped;

    b4_mapped = codemap_ee00d0[ *(lic_skipped+lv1+3) - 0x30 ];
    b4_shifted = ((b4_mapped / 16 ) |((b3_mapped & 0x7) << 0x1)) & 0xf;
    b4_remapped = b4_shifted + codemap_20688e[b4_shifted];
    lic_mapbytes[lv2++]=b4_remapped;

    b5_shifted = b4_mapped & 0xF;
    b5_remapped = b5_shifted + codemap_20688e[b5_shifted];
    lic_mapbytes[lv2++]=b5_remapped;

    lv1 = lv1 + 4;
  }
  return(lic_mapbytes);
}

unsigned char * find_match5(unsigned char *code5)
{
  unsigned char c1,c2,c3,c4;
  unsigned char *input;
  unsigned char *lic_mapbytes;
  input=calloc(40,1);

  /* lets bruteforce it ;-) */
  for (c1=0;c1<sizeof(vb);c1++) {
   for (c2=0;c2<sizeof(vb);c2++) {
    for (c3=0;c3<sizeof(vb);c3++) {
     for (c4=0;c4<sizeof(vb);c4++) {
      input[0]=vb[c1];
      input[1]=vb[c2];
      input[2]=vb[c3];
      input[3]=vb[c4];
      input[4]='\0';
      lic_mapbytes=lic_code_map(input);
      if (!strcmp(lic_mapbytes, code5))
      {
           return(input);
      }
     }
    }
   }
  }
  return(0); // no match
}

int main(int argc, char *argv[0])
{
 unsigned char *options,*lic1_code, *lic2_code, *lic_all;
 unsigned char *out,*chunk,*temp,*final;
 unsigned char *lic1_key, *lic2_key;
 unsigned char *serial;
 int            v,i=0;

 if (strlen(private_key)<14)
 {
  printf("\n\n");
  printf("set the private_key variable on top of this file\n");
  printf("you can find it here: https://www.eevblog.com/forum/testgear/sniffing-the-rigol's-internal-i2c-bus/msg264690/#msg264690\n");
  printf("\n\n");
  exit(-1);
 }

 if (argc != 3)
 {
  show_help();
  exit(-1);
 }
 serial=strtoupper((unsigned char*)argv[1]);
 options=strtoupper((unsigned char*)argv[2]);
 if (strlen(serial)<13)
 {
   printf("\nINVALID SERIAL LENGTH\n");
   show_help();
   exit(-1);
 }
 if (strlen(options)!=4)
 {
   printf("\nINVALID OPTIONS LENGTH\n");
   show_help();
   exit(-1);
 }
printf("serial:           %s\n", serial);
 printf("options:          %s\n", options);
 /* sign the message */
 lic1_code=calloc(64,1);
 lic2_code=calloc(64,1);
 ecssign(serial,options,lic1_code, lic2_code);
 printf("lic1-code:        %s\n", lic1_code);
 printf("lic2-code:        %s\n", lic2_code);

 lic_all=calloc(128,1);
 temp=calloc(128,1);
 chunk=calloc(6,1);
 final=calloc(128,1);
 lic1_key=calloc(20,1);
 lic2_key=calloc(20,1);
 strcpy(lic_all, lic1_code);
 strcat(lic_all, "0");
 strcat(lic_all, lic2_code);
 printf("target-code:      %s\n", lic_all);

 // split in 5 byte groups and run bruteforce
 // run or lic1_code
 strcat(lic1_code,"0");
 while(i<=strlen(lic1_code))
 {
   memcpy(chunk,lic1_code+i,5);
   out=find_match5(chunk);
   if (out)
   {
    strcat(temp, out);
   }
   i=i+5;
 }
 strcpy(lic1_key, temp);

 // run for lic2_code
 strcpy(temp,"");
 i=0;
 while(i<strlen(lic2_code))
 {
   memcpy(chunk,lic2_code+i,5);
   if (strlen(chunk)<5)
   {
    for(v=0;v<5-strlen(chunk);v++)
     strcat(chunk,"0");
   }
   out=find_match5(chunk);
   if (out)
   {
    strcat(temp, out);
   }
   i=i+5;
 }
strcpy(lic2_key, temp);
 strcpy(temp, lic1_key);
 strcat(temp, lic2_key);
 // now add the options
 memcpy(final, temp, 1);
 final[1]=options[0];
 memcpy(final+2, temp+1,7);
 final[9]=options[1];
 memcpy(final+10, temp+8,7);
 final[17]=options[2];
 memcpy(final+18, temp+15,7);
 final[25]=options[3];
 memcpy(final+26, temp+22,4);
 printf("----------------------------------------------------\n");
 printf("your-license-key: ");
 for(i=0;i<strlen(final);i++)
 {
  if (i%7==0 && i>0) printf("-");
  printf("%c", final[i]);
 }
 printf("\n");
 printf("----------------------------------------------------\n");
}

4 комментария

avatar
Здесь обновленный код, pastebin.com/AzWgnGq8
avatar
Прикольно, хотя мне для начала хоть бы ds1052 где-нибудь найти за адекватную цену, наши торгаши, сволочи, на него наценку ставят под 200-300%, а с Китая за честные 300 баксов заказывать как-то стремно.
:(
Комментарий отредактирован 2013-07-27 22:38:50 пользователем iEugene0x7CA
avatar
А тут:
www.scienceprog.com/did-i-just-increased-ds1022cd-bandwidth-four-times/#more-3846
инструкция по переделке DS1022CD (20 мгц) в DS1102CD (100 мгц) путем нажатия нескольких кнопок
Комментарий отредактирован 2013-07-28 20:58:33 пользователем ivasi
avatar
эта штука стоит больше, чем я за месяц зарабатываю… надо менять источники дохода…
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.