目次

2011年4月14日

falcnvrtを64bitビルド

せっかく64bit環境な訳だし64bit版を作るべくVC2010EE+WindowsSDK7.1環境で設定してビルドをポチっと。
出るわ出るわwarningの山。
ただsize_tが64bit値になっているせいで出ているのが大半で後はDWORD_PTR系程度で簡単にビルド完了。
UNICODEも有効にしてたけどもともとTCHARベースで開発してたおかげでこれまた問題なし。
とりあえず簡単な動作テストはクリアして拍子抜け・・・

デバッグ関数

ただ一つだけ懸念していたのがデバッグ関数。
イース6とフェルガナのconfig.exeから画像抽出するのにデバッグ関数使っていたのが案の定ダメ。
ブレークポイントに引っかからずに起動してしまう。
64bitプロセスから32bitプロセスをデバッグ起動してすんなりいく訳は無いわな。

IMAGE_NT_HEADERS

まず IMAGE_NT_HEADERS の ImageBase を利用していたのだが32bit仕様だと

typedef struct _IMAGE_OPTIONAL_HEADER {
//  ~略~
    DWORD   AddressOfEntryPoint;
    DWORD   BaseOfCode;
    DWORD   BaseOfData;
    DWORD   ImageBase;
    DWORD   SectionAlignment;
//  ~略~
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

なのが64bit仕様だと

typedef struct _IMAGE_OPTIONAL_HEADER64 {
//  ~略~
    DWORD       AddressOfEntryPoint;
    DWORD       BaseOfCode;
    ULONGLONG   ImageBase;
    DWORD       SectionAlignment;
//  ~略~
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

となってて ImageBase が BaseOfData とくっついてULONGLONGに・・・
IMAGE_OPTIONAL_HEADER を IMAGE_OPTIONAL_HEADER32 と明示的に宣言するようにしてこの問題は解決。

Get/SetThreadContext

しかしまだブレークポイントで止まらない。
色々調べてると64bitアプリから32bitアプリ(WOW64で動作)のものに対しては、
SetThreadContextじゃなくWow64SetThreadContextを使えばいいらしい?(日本語の情報が無い・・・)
そこでブレークポイント設定関数を

BOOL SetBreakPoint32(HANDLE hThread, DWORD dwAddress)
{
	CONTEXT ctx = { CONTEXT_DEBUG_REGISTERS };
	GetThreadContext( hThread, &ctx );
	ctx.Dr0 = dwAddress;
	ctx.Dr7 |= 0x00000001;
	return SetThreadContext( hThread, &ctx );
}
BOOL SetBreakPoint64(HANDLE hThread, DWORD dwAddress)
{
	WOW64_CONTEXT ctx = { WOW64_CONTEXT_DEBUG_REGISTERS };
	Wow64GetThreadContext( hThread, &ctx );
	ctx.Dr0 = dwAddress;
	ctx.Dr7 |= 0x00000001;
	return Wow64SetThreadContext( hThread, &ctx );
}

として#ifdef _WIN64で切り替えて使うように変更。
ビルドして試してみると無事ブレークポイントで止まるように!

完成

これで一応falcnvrtの64bit版は完成。
公開はどうしようかな。

あとがき

ただWow64SetThreadContextって対応OSがVista以降なんだけどXP64bit版はどうするんだ?
XPの64bit版も32bitアプリはWOW64で動作のはずだけどこのAPI使えないよなぁ。

~~DISCUSSION~~