LoginSignup
0
0

バイナリファイルを16進ダンプ/逆変換するスクリプトをささっと作る

Last updated at Posted at 2024-01-14

0. はじめに

とある事情でバイナリファイル(実行プログラム)をイジることになった。バイナリエディタを使えば一発なのだが,インストールが面倒なのとテキスト形式で変更前後の差分を残しておきたいということで

  • バイナリを16進数ダンプするスクリプト
  • 16進数ダンプをバイナリに戻すスクリプト

の二つを同時に作ることにした。

1. 基本方針

バイナリファイルの読み書きには ADODB.Stream オブジェクトを使う。

バイナリファイルの一括読み込み
var	stream = WScript.CreateObject("ADODB.Stream");
stream.Type = 1;				/* 1:adTypeBinary */
stream.Open();
stream.LoadFromFile(filename);
var	bin = stream.Read(-1);		/* -1:adReadAll */
stream.Close();
バイナリファイルの一括書き込み
var	stream = WScript.CreateObject("ADODB.Stream");
stream.Type = 1;				/* 1:adTypeBinary */
stream.Open();
stream.Write(bin);
stream.SaveToFile(filename, 2);	/* 2:adSaveCreateOverWrite */
stream.Close();

問題は,こうして読み込んだバイナリデータ,あるいは書き込むときに用意するバイナリデータのいずれも JavaScript の既存のデータ型としてアクセスすることはできないということだ。バイナリデータと16進数テキストの相互変換には MSXML2.DOMDocument オブジェクトを使う。

var	document = WScript.CreateObject("MSXML2.DOMDocument");
var	element = document.createElement("hex");
element.dataType = "bin.hex";

こうして宣言した element オブジェクトに対して nodeTypedValue メンバにバイナリデータを書き込むと明示的な変換メソッドを呼び出さなくても text メンバを参照するだけで16進数文字列を取得することができる。また逆に text メンバに16進数文字列を書き込むだけで nodeTypedValue メンバを参照すればバイナリデータが得られる。

ちなみに element.Type = "bin.base64" とすると,BASE64文字列のエンコード/デコードが可能になる。

2. 基本仕様

16進数ダンプのデータは逆変換の手間を考えてデータのみとする。すなわちアドレス無し,ASCII文字列も無しとする。なお,16進数ダンプは見易いように1バイトごとに空白,16バイトごとに改行を挟むが,逆変換時はその限りではなく,フリーフォーマットとする。※単純にスペースやタブ,改行コードは無視する。

16進数ダンプのサンプル
4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00
b8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 f0 00 00 00
0e 1f ba 0e 00 b4 09 cd 21 b8 01 4c cd 21 54 68

/* 以下略 */

3. 実装コード

BIN2HEX.JS の実装コード

BIN2HEX.JS
//------------------------------------------------------------------------------
// メイン関数
//------------------------------------------------------------------------------
function main(args) {
	//--------------------------------------------------------------------------
	// ヘルプメッセージ
	//--------------------------------------------------------------------------
	if(args.Count < 2) {
		WScript.StdErr.WriteLine("Usage: bin2hex(.js) [input(.hex)] [output(.bin)]");
		return false;
	}
	//--------------------------------------------------------------------------
	// 入力ファイルのチェック
	//--------------------------------------------------------------------------
	var	fs = WScript.CreateObject("Scripting.FileSystemObject");
	if(!fs.FileExists(args(0))) {
		WScript.StdErr.WriteLine("ファイル " + args(0)+ " は存在しません!!");
		return false;
	}
	//--------------------------------------------------------------------------
	// 入力ファイル(バイナリファイル)の一括読み込み
	//--------------------------------------------------------------------------
	var	stream = WScript.CreateObject("ADODB.Stream");
	stream.Type = 1;	/* 1:adTypeBinary */
	stream.Open();
	stream.LoadFromFile(args(0));
	var	bin = stream.Read(-1);	/* -1:adReadAll */
	stream.Close();
	//--------------------------------------------------------------------------
	//出力ファイル(テキストファイル)の書き込み
	//--------------------------------------------------------------------------
	var	document = WScript.CreateObject("MSXML2.DOMDocument");
	var	element = document.createElement("hex");
	element.dataType = "bin.hex";
	element.nodeTypedValue = bin;
	var	ts = fs.CreateTextFile(args(1), true);
	var	s = element.text;
	for(var i = 0; i < s.length; i += 32 ) {
		var	t = s.substr(i, 32);
		var	a = [];
		for(var j = 0; j < t.length; j += 2)
			a.push(t.substr(j, 2));
		ts.WriteLine(a.join(" "));
	}
	ts.Close();
	return true;
}
//------------------------------------------------------------------------------
// メイン関数の呼び出し
//------------------------------------------------------------------------------
var	args = WScript.Arguments.Unnamed;
var	ret = main(args);
try {
	WScript.Quit(ret);
} catch(e) {
	/* 何もしない */
}

HEX2BIN.JS の実装コード

HEX2BIN.JS
//------------------------------------------------------------------------------
// メイン関数
//------------------------------------------------------------------------------
function main(args) {
	//--------------------------------------------------------------------------
	// ヘルプメッセージ
	//--------------------------------------------------------------------------
	if(args.Count < 2) {
		WScript.StdErr.WriteLine("Usage: hex2bin(.js) [input(.hex)] [output(.bin)]");
		return false;
	}
	//--------------------------------------------------------------------------
	// 入力ファイル(テキストファイル)の存在チェック
	//--------------------------------------------------------------------------
	var	fs = WScript.CreateObject("Scripting.FileSystemObject");
	if(!fs.FileExists(args(0))) {
		WScript.StdErr.WriteLine("ファイル " + args(0) + " は存在しません!!");
		return false;
	}
	//--------------------------------------------------------------------------
	// 入力ファイル(テキストファイル)の一括読み込み
	//--------------------------------------------------------------------------
	var	ts = fs.OpenTextFile(args(0));
	var	buf = ts.ReadAll();
	ts.Close();
	//--------------------------------------------------------------------------
	// 余分な空白・改行コードを取り除く
	//--------------------------------------------------------------------------
	buf = buf.replace(/\s/g, "");
	//--------------------------------------------------------------------------
	// 出力ファイル(バイナリファイル)の一括書き込み
	//--------------------------------------------------------------------------
	var	stream = WScript.CreateObject("ADODB.Stream");
	var	doc = WScript.CreateObject("MSXML2.DOMDocument");
	var	element = doc.createElement("hex");
	element.dataType = "bin.hex";
	element.text = buf;
	stream.Type = 1;	/* 1:adTypeBinary */
	stream.Open();
	stream.Write(element.nodeTypedValue);
	stream.SaveToFile(args(1), 2);	/* 2:adSaveCreateOverWrite */
	stream.Close();
	return true;
}
//------------------------------------------------------------------------------
// メイン関数の呼び出し
//------------------------------------------------------------------------------
var	args = WScript.Arguments.Unnamed;
var	ret = main(args);
try {
	WScript.Quit(ret);
} catch(e) {
	/* 何もしない */
}

4. 参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0