1

Тема: JScript: парсинг исполняемого файла

Саму проблему помогли решить на форуме ТС (нескриптовым методом), а это я уже после разбирался:

var
 b=new ActiveXObject('Microsoft.XMLDOM').createElement('binObj'),
 d=false,    // DLL?
 f=new ActiveXObject('Scripting.FileSystemObject'),
 n,        // имя файла (аргумент)
 s=new ActiveXObject('ADODB.Stream'),
 t;        // temporary
b.dataType='bin.hex';
s.type=1;
s.open();

if(WScript.Arguments.length&&f.fileExists(WScript.Arguments(0)))n=WScript.Arguments(0);
else fa('Файл не найден!');

if(f.getFile(n).size<256)fa('Не исполняемый');    //*

s.loadFromFile(n);
b.nodeTypedValue=s.read(64);        // читаем заголовок (64 байта)
// b.text — hex строка

t=b.text.substr(0,4);            // берём первые 2 байта (сигнатура)

if(t=='5a4d')fa('DOS 16 ZM (exe)');    //* ZM — не актуально?
if(t!='4d5a')fa('Не исполняемый');    // не MZ

// теперь у нас есть файл, и он, вроде как, исполняемый

t=b.text.substr(48,2);            // берём байт по смещению 0x18 (24)
if('0x'+t<64)fa('DOS 16 MZ (exe)');    // адрес relocation table

t=fb(60);                // берём 4 байта по смещению 0x3C (60)
// здесь находится адрес заголовка PE
if(f.getFile(n).size<256+t)fa('Неизвестный формат');

s.Position=t;
b.nodeTypedValue=s.read(24);        // читаем заголовок PE (24 байта)

t=1*('0x'+b.text.substr(23*2,2));    // берём последний байт (Characteristics)
if(t&32)d=true;                // да, это DLL

t=b.text.substr(0,4);            // берём первые 2 байта (сигнатура)
if(t=='4e45')fa('Win 16 NE '+fc());    // NE
if(t=='4c45')fa('Win 16 LE (VxD)');    //* LE — не актуально?
if(t=='4c58')fa('OS2 16 LX (VxD)');    //* LX — не актуально?
if(t=='5733')fa('Win 16 W3 '+fc());    //* W3 — не актуально?
if(t=='5734')fa('Win 32 W4 (VMM)');    //* W4 — не актуально?
if(t!='5045')fa('Неизвестный формат');            // не PE
if(b.text.substr(4,4)!='0000')fa('Неизвестный формат');    //* неправильный PE?

// теперь, похоже, наш файл ещё и PE

// дополнительный заголовок PE:
// заголовок COFF        28 байт?
// заголовок NT            64 байта
// массив директорий данных    128 байт?

b.nodeTypedValue=s.read(20);        // читаем 20 байт дополнительного заголовка PE
if(b.text.substr(2,2)=='02')        // если 64 бита (PE32+), на этом и закончили
 fa('Win 64 PE+ '+fc());

// теперь мы знаем, что наш файл PE и он 32 бита
// осталось проверить на дотнетность

s.Position+=(208-20);
// перешли на смещение D0 (208) от начала дополнительного заголовка
b.nodeTypedValue=s.read(8);
// здесь должен быть The CLR header address and size

t=fb(4);                // берём 4 байта по смещению 0x04 (4)

if(t)fa('DotNet PE '+fc());        // если размер CLR заголовка > 0 значит, .Net
else fa('Win 32 PE '+fc());        // иначе — Win32PE


function fa(e){s.close();WScript.echo(n+'\n'+e);WScript.quit();}// Выход с сообщением
function fb(e){                            // вычисление двордов (DWORD)
  return(
   1*('0x'+b.text.substr(2*e,2))+
   256*('0x'+b.text.substr(2*e+2,2))+
   65536*('0x'+b.text.substr(2*e+4,2))+
   16777216*('0x'+b.text.substr(2*e+6,2))
  );
}
function fc(){return(d?'(dll)':'(exe)');}