интересуюсь возможностью извлечь sha1 хеши из \windows\system32\catroot\{xxxx}\*.CAT файлов. Это возможно сделать прямым разбором CAT-файла, без использования CryptoAPI или внешних программ (sigcheck, chktrust, sigverif итд) ? информация которую удалось найти: http://www.cs.auckland.ac.nz/~pgut001/pubs/authenticode.txt http://blog.didierstevens.com/2008/01/11/the-case-of-the-missing-digital-signatures-tab/ http://msdn.microsoft.com/en-us/library/ms537359(VS.85).aspx
Это обычный ASN1-файл в формате DER. C:\OpenSSL\bin\openssl.exe asn1parse -inform DER -in admt.cat -dump >s Код (Text): 0:d=0 hl=4 l=23514 cons: SEQUENCE 4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData 15:d=1 hl=4 l=23499 cons: cont [ 0 ] 19:d=2 hl=4 l=23495 cons: SEQUENCE 23:d=3 hl=2 l= 1 prim: INTEGER :01 26:d=3 hl=2 l= 11 cons: SET 28:d=4 hl=2 l= 9 cons: SEQUENCE 30:d=5 hl=2 l= 5 prim: OBJECT :sha1 37:d=5 hl=2 l= 0 prim: NULL 39:d=3 hl=4 l=14076 cons: SEQUENCE 43:d=4 hl=2 l= 9 prim: OBJECT :1.3.6.1.4.1.311.10.1 54:d=4 hl=4 l=14061 cons: cont [ 0 ] 58:d=5 hl=4 l=14057 cons: SEQUENCE 62:d=6 hl=2 l= 12 cons: SEQUENCE 64:d=7 hl=2 l= 10 prim: OBJECT :1.3.6.1.4.1.311.12.1.1 76:d=6 hl=2 l= 16 prim: OCTET STRING 0000 - 42 32 d2 f1 ac 84 d5 4f-96 29 10 7a 79 5f d8 41 B2.....O.).zy_.A 94:d=6 hl=2 l= 13 prim: UTCTIME :070217141518Z 109:d=6 hl=2 l= 14 cons: SEQUENCE 111:d=7 hl=2 l= 10 prim: OBJECT :1.3.6.1.4.1.311.12.1.2 123:d=7 hl=2 l= 0 prim: NULL 125:d=6 hl=4 l=13934 cons: SEQUENCE 129:d=7 hl=4 l= 294 cons: SEQUENCE 133:d=8 hl=2 l= 82 prim: OCTET STRING 0000 - 30 00 36 00 37 00 44 00-45 00 41 00 44 00 43 00 0.6.7.D.E.A.D.C. 0010 - 35 00 35 00 34 00 42 00-34 00 30 00 37 00 34 00 5.5.4.B.4.0.7.4. 0020 - 42 00 30 00 41 00 36 00-44 00 43 00 42 00 35 00 B.0.A.6.D.C.B.5. 0030 - 44 00 39 00 46 00 45 00-31 00 39 00 37 00 30 00 D.9.F.E.1.9.7.0. 0040 - 38 00 41 00 41 00 41 00-30 00 38 00 36 00 35 8.A.A.A.0.8.6.5 0052 - <SPACES/NULS> 217:d=8 hl=3 l= 207 cons: SET <skipped> 22971:d=5 hl=4 l= 543 cons: cont [ 1 ] 22975:d=6 hl=4 l= 539 cons: SEQUENCE 22979:d=7 hl=2 l= 9 prim: OBJECT :countersignature 22990:d=7 hl=4 l= 524 cons: SET 22994:d=8 hl=4 l= 520 cons: SEQUENCE 22998:d=9 hl=2 l= 1 prim: INTEGER :01 23001:d=9 hl=3 l= 135 cons: SEQUENCE 23004:d=10 hl=2 l= 121 cons: SEQUENCE 23006:d=11 hl=2 l= 11 cons: SET 23008:d=12 hl=2 l= 9 cons: SEQUENCE 23010:d=13 hl=2 l= 3 prim: OBJECT :countryName 23015:d=13 hl=2 l= 2 prim: PRINTABLESTRING :US 23019:d=11 hl=2 l= 19 cons: SET 23021:d=12 hl=2 l= 17 cons: SEQUENCE 23023:d=13 hl=2 l= 3 prim: OBJECT :stateOrProvinceName 23028:d=13 hl=2 l= 10 prim: PRINTABLESTRING :Washington 23040:d=11 hl=2 l= 16 cons: SET 23042:d=12 hl=2 l= 14 cons: SEQUENCE 23044:d=13 hl=2 l= 3 prim: OBJECT :localityName 23049:d=13 hl=2 l= 7 prim: PRINTABLESTRING :Redmond 23058:d=11 hl=2 l= 30 cons: SET 23060:d=12 hl=2 l= 28 cons: SEQUENCE 23062:d=13 hl=2 l= 3 prim: OBJECT :organizationName 23067:d=13 hl=2 l= 21 prim: PRINTABLESTRING :Microsoft Corporation 23090:d=11 hl=2 l= 35 cons: SET 23092:d=12 hl=2 l= 33 cons: SEQUENCE 23094:d=13 hl=2 l= 3 prim: OBJECT :commonName 23099:d=13 hl=2 l= 26 prim: PRINTABLESTRING :Microsoft Timestamping PCA 23127:d=10 hl=2 l= 10 prim: INTEGER :614752BA000000000004 23139:d=9 hl=2 l= 7 cons: SEQUENCE 23141:d=10 hl=2 l= 5 prim: OBJECT :sha1 23148:d=9 hl=2 l= 93 cons: cont [ 0 ] 23150:d=10 hl=2 l= 24 cons: SEQUENCE 23152:d=11 hl=2 l= 9 prim: OBJECT :contentType 23163:d=11 hl=2 l= 11 cons: SET 23165:d=12 hl=2 l= 9 prim: OBJECT :pkcs7-data 23176:d=10 hl=2 l= 28 cons: SEQUENCE 23178:d=11 hl=2 l= 9 prim: OBJECT :signingTime 23189:d=11 hl=2 l= 15 cons: SET 23191:d=12 hl=2 l= 13 prim: UTCTIME :070218085632Z 23206:d=10 hl=2 l= 35 cons: SEQUENCE 23208:d=11 hl=2 l= 9 prim: OBJECT :messageDigest 23219:d=11 hl=2 l= 22 cons: SET 23221:d=12 hl=2 l= 20 prim: OCTET STRING 0000 - dd 6f d8 80 ca 0d d2 d2-27 ef ed 9d fa d3 f7 8a .o......'....... 0010 - bd 12 74 3c ..t< 23243:d=9 hl=2 l= 13 cons: SEQUENCE 23245:d=10 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 23256:d=10 hl=2 l= 0 prim: NULL 23258:d=9 hl=4 l= 256 prim: OCTET STRING 0000 - 5e 27 6e 30 ea fe 16 fc-63 94 eb 08 9b b8 e8 16 ^'n0....c....... 0010 - f7 37 3d c1 e3 dc 69 76-52 2f 56 94 7d f4 82 44 .7=...ivR/V.}..D 0020 - 3d 19 a6 5b 7e 07 69 81-7c 25 ac 68 72 01 4f 38 =..[~.i.|%.hr.O8 0030 - 05 08 1c 67 a8 45 07 dd-57 97 d7 8b 79 66 f0 27 ...g.E..W...yf.' 0040 - e0 7e 76 14 6a 7b 60 99-d1 ad f6 c5 79 d0 61 85 .~v.j{`.....y.a. 0050 - 44 2a eb a6 3e 75 6b 03-e8 70 4a 1c cb a7 78 8d D*..>uk..pJ...x. 0060 - 73 05 f6 f7 f3 a1 b0 47-8e 2f 89 b3 f1 9f 9a 26 s......G./.....& 0070 - 11 6f 0b f2 9a a4 be 23-2e 7c ac 30 b8 7b b5 f4 .o.....#.|.0.{.. 0080 - 22 3c c8 c0 cc d5 17 87-2f f2 ce 13 ba 94 ae ee "<....../....... 0090 - 2d 64 64 aa b7 8e 70 8f-9d c5 8a de ca 06 a8 6f -dd...p........o 00a0 - bc 22 c9 74 23 4a 03 14-f6 5a 70 6e 4d b1 1a fb .".t#J...ZpnM... 00b0 - 48 2d d2 0c 7c 72 9e 25-41 b7 d6 ae f5 59 b2 8c H-..|r.%A....Y.. 00c0 - 2d 00 fd dc 39 a9 09 26-df e4 92 51 4b 16 74 af -...9..&...QK.t. 00d0 - 19 c3 93 08 c3 a3 89 7b-22 aa d9 87 dc 36 9b f1 .......{"....6.. 00e0 - 85 01 62 55 7f 7f 79 e2-24 24 d1 49 c3 d0 8a 2f ..bU..y.$$.I.../ 00f0 - 2c a9 a2 d8 cc 0b 91 45-48 53 fb 5b 23 81 c0 f1 ,......EHS.[#...
Спасибо reverser, дампит прекрасно! только хеши из этого CAT не совпадают ни с одним подсчитанным "в лоб", например с sigcheck.exe -h :-( например хеш acpi.sys должнен находится в NT5.CAT, но такого хеша там нет
Похоже хэш, вычисляемый sigcheck, не подходит для .cat файлов. Утилитка отсюда даёт подходящий хэш. Из Google Groups: "A C14n pre-processing is done of the files before being hashed, this removes the variable (per machine) bits of the data so that the signatures can validate accross machines; remember some bits in the pe header get modified periodically we wouldnt want the signature to get invalidated. Ones that are static do not have c14n done against them which is why some match. " В доке по PE упоминается только пропускание полей Checksum и Certificate Table, но похоже этого недостаточно.
Ok, спасибо reverser Проблема в том, что необходимо сверить хеши без помощи CryptoAPI, а без знания алгоритма вычисления (какие поля отбрасывать) это невозможно. В каком направлении мне двигаться? Пробовать вырезать поля из хидера и считать хеш до тех пор пока не совпадет? Поля Checksum, OEM Identifier/OEM Information, Machine, Time/Date Stamp, Characteristics, что-нибудь из optional header? - что он хочет этим сказать, что переносе на другую машину меняется бинарник? Это для меня новая информация. Особенно слово "periodically" - интересно.
Посмотрел внутренности wintrust.dll. С виду вроде всё по спецификации - хэшится весь файл за исключением Checksum и записи Certificate Table в Directory. Код (Text): int __stdcall MapIt(HANDLE hFile, struct _LOADED_IMAGE *loadedImage) { HANDLE _mapping; // eax@1 void *v3; // ebx@1 struct _LOADED_IMAGE *_loadedImage; // esi@2 int result; // eax@4 DWORD _filesize; // eax@2 char v7; // zf@2 _mapping = CreateFileMappingA(hFile, 0, 2u, 0, 0, 0); v3 = _mapping; if ( _mapping ) { _loadedImage = loadedImage; loadedImage->MappedAddress = (PUCHAR)MapViewOfFile(_mapping, 4u, 0, 0, 0); CloseHandle(v3); _filesize = GetFileSize(hFile, 0); v7 = _loadedImage->MappedAddress == 0; _loadedImage->SizeOfImage = _filesize; if ( !v7 ) { if ( CalculateImagePtrs(_loadedImage) ) { _loadedImage->hFile = (HANDLE)-1; return 1; } UnmapViewOfFile(_loadedImage->MappedAddress); } result = 0; } else { result = 0; } return result; } bool __stdcall imagehack_AuImageGetDigestStream(HANDLE hFile, int a2, int hashproc, int hashparam) { WORD v4; // ax@2 PIMAGE_NT_HEADERS v5; // esi@4 DWORD *_pSignatureDirectoryRecord; // edi@6 DWORD v7; // ecx@7 int sig_len; // ebx@7 DWORD sig_offset; // esi@7 ULONG iSection; // ecx@13 int section_end; // eax@15 struct _IMAGE_SECTION_HEADER *_curSection; // eax@15 DWORD section_start; // edx@15 EXCLUDE_LIST this; // [sp+3Ch] [bp-50h]@1 struct _LOADED_IMAGE loaded_image; // [sp+Ch] [bp-80h]@1 DWORD dwErrCode; // [sp+70h] [bp-1Ch]@2 CPPEH_RECORD ms_exc; // [sp+74h] [bp-18h]@2 DWORD v19; // [sp+6Ch] [bp-20h]@2 PIMAGE_NT_HEADERS v20; // [sp+60h] [bp-2Ch]@5 DWORD *v21; // [sp+68h] [bp-24h]@7 DWORD _sig_offset; // [sp+58h] [bp-34h]@7 int _sig_len; // [sp+54h] [bp-38h]@7 ULONG v24; // [sp+64h] [bp-28h]@14 DWORD v25; // [sp+50h] [bp-3Ch]@15 int v26; // [sp+4Ch] [bp-40h]@15 PIMAGE_NT_HEADERS v27; // [sp+5Ch] [bp-30h]@26 EXCLUDE_LIST__EXCLUDE_LIST(&this); if ( MapIt(hFile, &loaded_image) ) { dwErrCode = ERROR_INVALID_PARAMETER; ms_exc.disabled = 0; v19 = 0; v4 = loaded_image.FileHeader->OptionalHeader.Magic; if ( v4 != IMAGE_NT_OPTIONAL_HDR32_MAGIC && v4 != IMAGE_NT_OPTIONAL_HDR64_MAGIC || !EXCLUDE_LIST__Init(&this, &loaded_image, hashproc, hashparam) ) goto error_exit; v5 = loaded_image.FileHeader; if ( loaded_image.FileHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC ) { v20 = loaded_image.FileHeader; if ( !EXCLUDE_LIST__Add(&this, (char *)loaded_image.FileHeader + 88, 4) ) goto error_exit; _pSignatureDirectoryRecord = &v5->OptionalHeader.DataDirectory[4].VirtualAddress; } else { v27 = loaded_image.FileHeader; if ( !EXCLUDE_LIST__Add(&this, (char *)loaded_image.FileHeader + 88, 4) ) goto error_exit; _pSignatureDirectoryRecord = &v5->OptionalHeader.DataDirectory[6].VirtualAddress; } v21 = _pSignatureDirectoryRecord; v7 = v5->OptionalHeader.SizeOfHeaders; v19 = v5->OptionalHeader.SizeOfHeaders; sig_offset = *_pSignatureDirectoryRecord; _sig_offset = *_pSignatureDirectoryRecord; sig_len = *(_pSignatureDirectoryRecord + 1); _sig_len = *(_pSignatureDirectoryRecord + 1); if ( sig_offset && sig_len ) { if ( sig_offset > loaded_image.SizeOfImage || sig_len + sig_offset != loaded_image.SizeOfImage || sig_len + sig_offset < sig_offset || sig_offset < v7 ) goto error_exit; iSection = 0; while ( 1 ) { v24 = iSection; if ( iSection >= loaded_image.NumberOfSections ) break; _curSection = &loaded_image.Sections[iSection]; section_start = _curSection->PointerToRawData; v25 = _curSection->PointerToRawData; section_end = section_start + _curSection->SizeOfRawData; v26 = section_end; if ( section_start && sig_offset < section_end ) goto error_exit; ++iSection; } } if ( EXCLUDE_LIST__Add(&this, _pSignatureDirectoryRecord, 8) ) { if ( EXCLUDE_LIST__Add(&this, &loaded_image.MappedAddress[sig_offset], sig_len) ) { EXCLUDE_LIST__Emit(&this, loaded_image.MappedAddress, loaded_image.SizeOfImage); dwErrCode = 0; } } error_exit: ms_exc.disabled = -1; UnmapViewOfFile(loaded_image.MappedAddress); SetLastError(dwErrCode); EXCLUDE_LIST___EXCLUDE_LIST(&this); return dwErrCode == 0; } SetLastError(ERROR_INVALID_PARAMETER); EXCLUDE_LIST___EXCLUDE_LIST(&this); return 0; } Возможно, как-то по-особенному происходит хэширование.
Доброго времени. Для меня тоже тема актуальна. Не будучи кодером (лужу, паяю, компутеры починяю), взялся писать програмку. В числе прочего хочется проверять по каталогу безопасности файлы. Чтобы работало в WinPE-образной среде, без CryptoAPI. В будущем, возможно вообще не в win32 (мало ли). Если кто-то знает о готовой реализации, поделитесь, пожалуйста, инфой. А пока я пытаюсь победить PE-хидер. В WinHex правлю тот же acpi.sys, забиваю сигнатуру нулями - signtool verify утверждает, что все ОК. Следовательно, "верной дорогой идем, товарищи". А вот Certificate Table как находить - не соображу. Хоть прогу пиши, которая меняет байт за байтом и парсит вывод signtool verify. Я бы так и сделал, да потом сообразил, что адрес для разных файлов разным будет . До кучи - пытался найти закономерность в файлах *.CAT. Нашел, что через 9 байт после каждого блока <<<Obsolete>>> находится хэш. Может, есть более детальная инфа? Например, относительные офсеты на следующий блок. Абсолютных, вроде бы нет(написал таки прогу, которая считывает дворды и проверяет, не есть ли это число, равное текущей позиции плюс/минус 1000 байт, всяко больше длины "блока"). Ничего не нарыл. Вот на такие извраты приходится идти.
Вот отсюда http://209.85.229.132/search?q=cache:IvCnX_k6HekJ:download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx+sha1+%22Certificate+Table%22+Checksum+exclude&hl=ru&ct=clnk&cd=1&gl=ru Hashing the PE Header, omitting the file's checksum and the Certificate Table entry in Optional Header Data Directories PEBrowse кажет, что у файла acpi.sys нет секции data в "Optional Header". Где порылась собака, и где порыться мне?