1

Тема: VBScript: Контрольная сумма, хэш и т.д.

Возможно, я в очередной раз изобретаю велосипед, но два выходных, проведенных в гугле, яндексе и MSDN, вынуждают обратиться за помощью. Суть проблемы: необходимо из скрипта, по возможности быстро, получить некий уникальный идентификатор файла. CRCx, MDx, SHAx - всё равно. Можно даже что-нибудь экзотическое. Совместимость с чем-либо не интересует. Главное:
1. идентификатор должен измениться при любом изменении файла (маловероятные случаи с заменой всего содержимого файла на другое, но имеющее тот же хэш - не рассматриваем);
2. идентификатор должен зависеть только от содержимого файла, и не зависеть от его полного/краткого имени, дат и атрибутов;
3. поучать его надо из скрипта (предпочтительнее JScript), но средствами винды без дополнительных бинарных файлов. Без регистрации dll. Расчет средствами JS тоже не вариант: уж очень долго в скрипте выполняется побайтовая обработка файлов, а хотелось бы побыстрее.
Может, что-то подобное уже где-то было? Просто я не смог найти?
Сейчас есть решение, проверяющее размер и дату изменения. Работало около года, но на прошлой неделе этого оказалось недостаточно... Это я на случай, если кто хочет предложить проверку по размеру и дате. Такая проверка останется, а вот если и то, и другое совпадает - проверить ещё и на содержимое.

2

Re: VBScript: Контрольная сумма, хэш и т.д.

VBScript: Вычисление хэша MD5 файла.

3 (изменено: Serge Yolkin, 2013-02-11 12:11:35)

Re: VBScript: Контрольная сумма, хэш и т.д.

Мда. То, что доктор прописал. И работает, вроде, шустро. Ещё раз огромное спасибо.
Надеюсь, полученая в ходе самостоятельных поисков информация хотя бы расширит мой кругозор...

Ещё один вопрос: хотел перевести пример на JScript, но наткнулся на незнакомую конструкцию (наверное, это смешно, но я бейсика не знаю и с такой конструкцией ранее не встречался)

var
 objHashedData=WScript.createObject("CAPICOM.HashedData"),
 objStream=WScript.createObject("ADODB.Stream");
objHashedData.Algorithm=3;
// SHA1    = 0
// MD2     = 1
// MD4     = 2
// MD5     = 3
// SHA 256 = 4
// SHA 384 = 5
// SHA 512 = 6

with(objStream){
  type=1;
  open();
  loadFromFile("Path\fileName.ext");

//    Следующий код надо перевести на JS:

//    Do Until .EOS
//        objHashedData.Hash .Read(1024)
//    Loop

  close();
}

WScript.echo("MD5 Hash: [" & objHashedData.Value & "]")

4

Re: VBScript: Контрольная сумма, хэш и т.д.

Как-то так (не проверялось):

while (!EOS) {
    objHashedData.Hash(Read(1024));
}

5

Re: VBScript: Контрольная сумма, хэш и т.д.

Ну просто безразмерное спасибо.
Вот что получилось:

function hash(algorithm,file){
  var
   objHashedData=WScript.createObject('CAPICOM.HashedData'),
   strAlgorithm,
   begin,
   end,
   time;

  objHashedData.algorithm=algorithm;

  switch(algorithm){
// алгоритмы упорядочены по быстродействию:
// MD4 — самый быстрый, MD2 — неприлично медленный
   case 2:strAlgorithm='MD4';break;    
   case 3:strAlgorithm='MD5';break;    
   case 0:strAlgorithm='SHA1';break;    
   case 4:strAlgorithm='SHA 256';break;    
   case 5:strAlgorithm='SHA 384';break;    
   case 6:strAlgorithm='SHA 512';break;    
   case 1:strAlgorithm='MD2';break;    
  }

  begin=new Date();

  with(new ActiveXObject('ADODB.Stream')){
    type=1;
    open();
    loadFromFile(file);
    while(!EOS)objHashedData.hash(read(1024));
    close();
  }

  end=new Date();
  time=end-begin;

  return(strAlgorithm+' Hash: ['+objHashedData.Value+']\n'+time);
}

WScript.echo(hash(2,'C:\\Windows\\System32\\MRT.exe'));

Получается - самый быстрый алгоритм - MD4, его и буду использовать...

6 (изменено: Serge Yolkin, 2013-02-12 17:54:08)

Re: VBScript: Контрольная сумма, хэш и т.д.

Опа! На семёрке объект CAPICOM.HashedData не создаётся. Т.е. стабильного способа получения контрольной суммы / хэша файла из скрипта в винде, похоже, нет. Прийдётся посмотреть на консольные утилиты...

7

Re: VBScript: Контрольная сумма, хэш и т.д.

А у меня создаётся, но только если запускать скрипт 32-битной версией WScript (которая в SysWOW64). Видимо, класс существует только в 32-битном варианте.

8

Re: VBScript: Контрольная сумма, хэш и т.д.

Пока не уверен в закономерности, но на W7Pro x32 - работает, на x64 - действительно работает в WScript'32 (сам не догадался, думал - не работает), а вот на домашних (васик и премиум) - нет. Нет, говорит, такого скриптабельного объекта. Пробовал создавать System.Security.Cryptography.MD5CryptoServiceProvider, объект, вроде, создаётся, но не помнит собственных методов: по typeof говорит "обжект", а методы не поддерживает.

9 (изменено: Serge Yolkin, 2013-02-12 21:44:46)

Re: VBScript: Контрольная сумма, хэш и т.д.

[off]
На глаз - с десяток бинарников (.exe, .dll, ...) в свежеустановленной винде имеют реализации подобных алгоритмов (мне же всё равно, какой именно алгоритм). И, блин, из скриптов они недоступны! Видимо, вся безопасность сразу накроется медным тазом, если я узнаю контрольную сумму какого-нибудь файла.
[/off]

Может, где написано, что так нельзя? Я бы и не мучился. На MSDN и у них же в social ничего не обнаружил. Если там кто-нибудь зарегистрирован, задали бы вопрос...

10 (изменено: Serge Yolkin, 2013-02-16 13:28:42)

Re: VBScript: Контрольная сумма, хэш и т.д.

Свою проблему я решил с помощью костылей и протезов, просто пара замечаний по предыдущим постам:
1. При чтении бинарника с помощью ADODB.Stream type=1 быстрее всего получается, если "порция" равна размеру блока на устройстве. В моём случае read(8192) - для флэхи и read(4096) - для HDD. Что, в общем, логично.
2. Массив байтов я получил (кривовато и медленно, но получил):

var vFile=[];
with(new ActiveXObject('ADODB.Stream')){
  type=1;
  open(),loadFromFile('test');
// test - имя файлика (без расширения) для экспериментов
// лежит в папке скрипта, размер 20-30 байт, чтобы пошустрее,
// создаётся в hex редакторе, чтобы разные комбинации проверять
  while(!EOS)vFile.push(read(1));
  close();
}
WScript.echo(typeof(vFile[0]));

Забавно то, что дальше этот массив средствами JS я обработать не смог. Тип элементов массива - unknown, поэтому JS не считает это ни строкой (никакие методы для строк не работают), ни чилом - арифметика тоже не пашет. По echo пытается показать соответствующий символ, но, если байт из диапазона 0x7f - 0x9f, не показывает ничего...

11

Re: VBScript: Контрольная сумма, хэш и т.д.

Serge Yolkin пишет:

Тип элементов массива - unknown, поэтому JS не считает это ни строкой (никакие методы для строк не работают), ни чилом - арифметика тоже не пашет.

Фактически vFile[0] возвращает тип VT_ARRAY | VT_UI1, содержащий указатель на структуру SAFEARRAY, а в ней лежит указатель на байт. Т.е. получается, что каждый байт содержится в своём персональном массиве размером в один элемент.

12 (изменено: Serge Yolkin, 2013-02-16 18:49:48)

Re: VBScript: Контрольная сумма, хэш и т.д.

YMP: а как из этого массива в массиве получить доступ к байту? Брутальное vFile[0][0] не прокатило (да я и надеялся...), vFile[0].length - null или не является объектом.

13 (изменено: Serge Yolkin, 2013-08-26 22:06:28)

Re: VBScript: Контрольная сумма, хэш и т.д.

Коллега VitAliS обратил внимание на утилиту certutil, и, хотя сделал он это по несколько совсем другому поводу, всё равно спасибо ему большое. Правда, к той задаче, по ходу решения которой создавалась эта тема, я в ближайшее время не вернусь, но, тем не менее, набросал себе на память:

<?xml version="1.0" encoding="utf-8"?>
<package>
  <job id="help" version="0.81">
    <script type="text/jscript" language="JScript">
      WScript.Arguments.ShowUsage();
    </script>
    <runtime><description>Hash-to-Name</description><example> — эта справка
    wscript //job:run hash2name.wsf [HA] file/folder [file/folder...]
    HA: /SHA1, /SHA256, /SHA384, /SHA512, /MD2, /MD4, /MD5
        добавить к имени файла контрольную сумму,
        вычисленную по соответствующему алгоритму
    wscript //job:run hash2name.wsf /clear file/folder [file/folder...]
        удалить контрольную сумму из имени файла</example>
    </runtime>
  </job>
  <job id="run" version="0.7">
    <object id="f" progid="Scripting.FileSystemObject" />
    <object id="s" progid="WScript.Shell" />
    <script type="text/jscript" language="JScript"><![CDATA[

      var a;    // HashAlgorithm

      if(WScript.Arguments.length){
        switch(WScript.Arguments(0).toUpperCase()){
         case '/SHA1':a='SHA1';break;
         case '/SHA256':a='SHA256';break;
         case '/SHA384':a='SHA384';break;
         case '/SHA512':a='SHA512';break;
         case '/MD2':a='MD2';break;
         case '/MD4':a='MD4';break;
         case '/MD5':a='MD5';break;
         case '/CLEAR':a='0';break;
         default:fc();
        }
        for(var i=1;i<WScript.Arguments.length;i++){
          fa(WScript.Arguments(i));
        }
      }else fc();

      function fa(e){
        if(f.FolderExists(e)){
          with(new Enumerator(f.GetFolder(e).subFolders)){
            while(!atEnd()){
              fa(item().path);
              moveNext();
            }
          }
          with(new Enumerator(f.GetFolder(e).files)){
            while(!atEnd()){
              fb(item().path);
              moveNext();
            }
          }
        }else if(f.FileExists(e))fb(f.getFile(e).path);
      }

      function fb(e){
        s.run('cscript //job:exec "'+WScript.scriptFullName+'" '+a+' "'+e+'"',0,true);
      }

      function fc(){
        s.run(WScript.scriptFullName);
        WScript.quit();
      }

    ]]></script>
  </job>
  <job id="exec" version="0.4">
    <object id="f" progid="Scripting.FileSystemObject" />
    <object id="s" progid="WScript.Shell" />
    <script type="text/jscript" language="JScript"><![CDATA[

      var
       a,
       b=f.getFile(WScript.Arguments(1)),
       c=f.getBaseName(b).replace(/\s*\[((SHA)|(MD))\d{1,3}\s*[a-fA-F0-9]+\]$/i,'');

      if(WScript.Arguments(0)!='0'){
        with(s.exec('CertUtil -hashfile "'+b.path+'" '+WScript.Arguments(0)).stdOut){
          skipLine();
          a=readLine().replace(/\s/g,'');
        }b.name=c+' ['+WScript.Arguments(0)+' '+a+'].'+f.getExtensionName(b);
      }else b.name=c+'.'+f.getExtensionName(b);

    ]]></script>
  </job>
</package>

14 (изменено: Yurachb, Вчера 17:57:35)

Re: VBScript: Контрольная сумма, хэш и т.д.

Serge Yolkin пишет: Расчет средствами JS тоже не вариант: уж очень долго

Есть такой метод: String1.localeCompare(String2), работающий с файлами в несколько десятков мегабайт и весьма шустро.
Здесь есть компаратор на JS, достоверно сравнивающий массивы файлов только по содержимому (предусмотрено копирование требуемых [изменившихся] файлов...):
https://img0.liveinternet.ru/images/att … 9_hram.zip

2×1000 файлов (2×7285861 знаков) это моё HTA приложение сравнило за 4.7 с, а 2×44 файла (2×561357 знаков) – за 0.37 с.

Если Касперский станет „бузить”, то здесь ответ, почему:
http://forum.script-coding.com/viewtopic.php?id=13519

15

Re: VBScript: Контрольная сумма, хэш и т.д.

А вариант с использованием System.Security.Cryptography не подходит ?

https://stackoverflow.com/questions/101 … lassic-asp
https://en.wikibooks.org/wiki/Visual_Ba … ing_in_VBA

Передумал переделывать мир. Пашет и так, ну и ладно. Сделаю лучше свой !