iResEditor.jsの使い方

[目次]

1. ファイルの読み込み
2. ファイルの書き込み
3. 各クラスの詳細
    TResEditor
    TPEAnalyst

はじめに

iResEditor.jsは ダウンロード してあなたの環境に設置して下さい。

ここでは基本的な使い方をご紹介しますが、ある程度の「PEフォーマット」「各リソースフォーマット」の知識がないと、このクラスライブラリを扱うのは難しいかも知れません。

1. ファイルの読み込み

実行ファイルを読み込んで結果をブラウザのコンソールに出力します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="zip.min.js"></script>
<script src="iResEditor.js"></script>
<script>

function onDragOver(event){ 
  event.preventDefault(); 
} 
  
function onDrop(event){
  onAddFile(event);
  event.preventDefault(); 
}  

function onAddFile(event) {
  var files;
  var reader = new FileReader();
  var filename;
  
  if(event.target.files){
    files = event.target.files;
  }else{ 
    files = event.dataTransfer.files;   
  }    

  reader.onload = function (event) {
    var stream = new Uint8Array(reader.result);  
    
    try{
      
      // PEファイルの読み込み
      var ResEditor = new TResEditor(filename);
      ResEditor.LoadFromStream(stream,true,true);  
      
      // コンソールに出力
      console.log(ResEditor);   
      
    }catch(e){
      alert('Error : ' + e);
    }
  };
  
  if (files[0]){    
    filename = files[0].name;
    reader.readAsArrayBuffer(files[0]); 
    document.getElementById("inputfile").value = '';
  }
}        
</script>  
</head>
<body ondrop="onDrop(event);" ondragover="onDragOver(event);"> 
<div style="height:500px;width:500px;">
  <input type="file" id="inputfile" onchange="onAddFile(event);" >
</div>
</body>
</html> 

[結果]

次の図はChromeでのコンソールです。
※コンソールを表示するにはブラウザでF12キーを押します。

Editプロパティにあるリソースは編集可能です。

PEAnalystプロパティは実行ファイルのヘッダ情報とリソース、インポート、エキスポート情報などが格納されます。

2. ファイルの書き込み

次のコードは「Menu,Dialog,String Table」の全てのリソースに「add」の文字列を追加します。編集が完了したらファイルを出力します。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="zip.min.js"></script>
<script src="iResEditor.js"></script>
<script>

function onDragOver(event){ 
  event.preventDefault(); 
} 
  
function onDrop(event){
  onAddFile(event);
  event.preventDefault(); 
}  

function onAddFile(event) {
  var files;
  var reader = new FileReader();
  var filename;
  
  if(event.target.files){
    files = event.target.files;
  }else{ 
    files = event.dataTransfer.files;   
  }    

  reader.onload = function (event) {
    var stream = new Uint8Array(reader.result);  
    var addString = ' add'; // 追加する文字列
    
    try{
      
      // PEファイルの読み込み
      var ResEditor = new TResEditor(filename);
      ResEditor.LoadFromStream(stream,true,true);  
      
      console.log(ResEditor);
      
      if(ResEditor.PEAnalyst.IsPacked){
        alert('このファイルは圧縮されています。');
        return;
      }
            
      if(ResEditor.Edit.Menu.length   === 0 &&
         ResEditor.Edit.Dialog.length === 0 &&
         ResEditor.Edit.String.length === 0){
        alert('このファイルには編集可能なリソースはありません。');
        return;
      }
        
      // 全ての「Menu」の文字列を変更する  
      var Menu = ResEditor.Edit.Menu;
      if(Menu.length !==0){    
        for(var i=0;i<Menu.length;i++){    
          for(var j=0;j<Menu[i].resObject.Items.length;j++){
            // セパレータ以外
            if(Menu[i].resObject.Items[j].menuText !== '-'){
              Menu[i].resObject.Items[j].menuText = Menu[i].resObject.Items[j].menuText + addString;
            }
          } 
        }
      }else{
        console.log('Menu None');
      } 
      
      // 全ての「Dialog」の文字列を変更する  
      var Dialog = ResEditor.Edit.Dialog;
      if(Dialog.length !==0){    
        var DS_SETFONT = 64;
         
        for(var i=0;i<Dialog.length;i++){    
          
          // 通常版と拡張版
          var DlgTemplate,DlgItemTemplate;
          if(Dialog[i].resObject.DlgTemplate){
            DlgTemplate = Dialog[i].resObject.DlgTemplate;
            DlgItemTemplate = Dialog[i].resObject.DlgItemTemplate;
          }else{
            DlgTemplate = Dialog[i].resObject.DlgTemplateEx;
            DlgItemTemplate = Dialog[i].resObject.DlgItemTemplateEx;        
          }
          
          // 親ウインドウの文字列の変更
          DlgTemplate.title = DlgTemplate.title + addString;
          
          // フォントがある場合
          if((DlgTemplate.style & DS_SETFONT) === DS_SETFONT){
            // フォント名の変更
            // DlgTemplate.typeface = 'font name';
            // フォントサイズの変更
            // DlgTemplate.pointsize = 8;
          }
          
          // コントロール    
          for(var j=0;j<DlgItemTemplate.length;j++){
            // 文字列型
            if(typeof DlgItemTemplate[j].title === "string"){ 
              DlgItemTemplate[j].title = DlgItemTemplate[j].title + addString;
            } 
          } 
        }
      }else{
        console.log('Dialog None');
      }       
      
      // 全ての「String Table」の文字列を変更する  
      var StringTable = ResEditor.Edit.String;
      if(StringTable.length !==0){   
        for(var i=0;i<StringTable.length;i++){
          for(var j=0;j<StringTable[i].resObject.ID.length;j++){
            // NULL以外
            if(StringTable[i].resObject.Value[j] !== ''){
              StringTable[i].resObject.Value[j] = StringTable[i].resObject.Value[j]  + addString;
            }
          } 
        } 
      }else{
        console.log('String Table None');
      } 
      
      // この1つのメソッドでも保存できます。
      // ただし、IE/Edgeではセキュリティ制限でダウンロードできません。
      // ResEditor.SaveToFile('test.exe');
            
      var zip = new Zlib.Zip();    
      var stream = ResEditor.SaveToStream();
      
      // 拡張子の取得 
      var ext = ResEditor.FileName.split('.');
      ext = '.' + ext[ext.length-1];
        
      // ZIP(無圧縮)
      zip.addFile(stream,{'filename': PE_ConvertArray('test' + ext),
                          'compressionMethod':Zlib.Zip.CompressionMethod.STORE});
      var compressed = zip.compress();
      
      // ダウンロード
      var F = new TFileStream();
      F.WriteStream(compressed);
      F.SaveToFile('test.zip'); 
        
    }catch(e){
      alert('Error : ' + e);
    }
  };
  
  if (files[0]){    
    filename = files[0].name;
    reader.readAsArrayBuffer(files[0]); 
    document.getElementById("inputfile").value = '';
  }
}        
</script>  
</head>
<body ondrop="onDrop(event);" ondragover="onDragOver(event);"> 
<div style="height:500px;width:500px;">
  <input type="file" id="inputfile" onchange="onAddFile(event);" >
</div>
</body>
</html> 

3. 各クラスの詳細

コアクラスはTPEAnalystです。TResEditorはTPEAnalstのラッパークラスです。

[TResEditor]

プロパティ用途
(Edit)編集可能なリソース(Menu,Dialog,String Table)
※resNameID,resLangIDは変更不可。
FileName読み込んだファイル名。
OS実行ファイルの対象OS。(32bit or 64bit)
PEAnalystTPEAnalyst

※()のプロパティは設定により存在しない場合があります。

メソッドLoadFromStream(AStream, ResourceFlg [,PackedFlg])
用途実行ファイルを読み込みます。
引数AStream : Uint8Array
ResourceFlg : true Editプロパティを追加する
PackedFlg : true 実行ファイルの圧縮判定をする(省略はtrue)
戻り値なし

メソッドSaveToStream()
用途TResEditor.Editの内容で実行ファイルをストリームで出力します。
引数なし
戻り値Uint8Array

メソッドSaveToFile(FileName)
用途TResEditor.Editの内容で実行ファイルを出力します。
引数FileName: ファイル名
戻り値なし

メソッドSaveImportTEXT(FileName)
用途全てのインポート情報をテキスト形式で出力する。
引数FileName: ファイル名
戻り値true : 成功 false : 失敗

メソッドSaveExportCSV(FileName)
用途全てのエキスポート情報をCSV形式で出力する。
引数FileName: ファイル名
戻り値true : 成功 false : 失敗

メソッドExtractBinFile(ZipFileName)
用途全てのリソースをバイナリファイル(RAW)で出力する。
引数ZipFileName: ZIPファイル名
戻り値true : 成功 false : 失敗

[TPEAnalyst]

プロパティ用途
Exportエキスポート情報
IMAGE_COFF_HEADERIMAGE_COFF_HEADER構造体
IMAGE_DOS_HEADERIMAGE_DOS_HEADER構造体
IMAGE_OPTIONAL_HEADERIMAGE_OPTIONAL_HEADER構造体
IMAGE_SECTION_HEADERIMAGE_SECTION_HEADER構造体
Importインポート情報
(IsPacked)実行ファイルが圧縮されているかのフラグ(true or false)
※簡易判定なのでUPXとAsPackにしか対応していません。
※TResEditor.LoadFromStreamでPackedFlgをtrueにした場合にこのプロパティが使用できます。
(Resource)リソース
※このリソースは読み込み専用です。
StreamTReadStream。実行ファイルの内容を読み取ります。

※()のプロパティは存在しない場合があります。

その他

次のサンプルはブログで公開しています。

リソースをRCファイルへ変換する
リソースをRESファイルへ変換する
コードセクションを抽出する
データセクションを抽出する
全てのセクションを抽出する
隠しコードを取得する
リソースをTreeViewで表示する

スポンサーリンク