2006/01/24(火)DLL Injection
MG遊んでるうちにはちらっと書いたけど、
やっぱりこのディスプレイに320x240はちょっときついなと思って。
掲示板を見て何を思い立ったか、どうにかして画面を大きくできないかと考えた。
が、結局さじなげた。以下はその軌跡。失敗談なので悪しからず。
追記: コメント欄で協力してくださったhoshu氏のおかげで実現しました。
制作者側で調整して貰っちゃうことは簡単なのだけど、お勉強も兼ねて。
(お勉強も兼ねてと言えば何しても許されると思ってるヤツ一名
基本的には redraw 1 の直前タイミングで320x240の別Bufferにgcopyして、
元のウィンドウにgzoomして戻すだけでいいはずだ。
というわけでそういう手段をとってみよう。それにはどうするか。。
……一般的なところで、gdi32.dllをラップするDLLを作りそうなもんだけど、
いい加減なんかのためにその手のDLLを作るのが嫌だったので、
DLL Injectionとか、あれこれ調べながらやってみた。
他のプロセスにLoadLibrary「させる」手法。
とりあえずDLLを書いて、DLLを注入するプログラムを書いて……。
アタッチ→FindWindowしてMoveWindow(ウィンドウサイズを変更)
普通のプログラムで行けば、WM_PAINTが飛んできたところで再描画だから、
その時呼ばれるのはBeginPaintとEndPaintか。
インポートテーブルを書き換えて、この2つのAPIをフック。
アタッチ時に320x240のビットマップを持ったHDCを作っておいて、
BeginPaint時は内部でそのダミーのHDCを返却。
EndPaintが呼ばれたタイミングで、やっとBeginPaintしダミーのHDCからStretchBlt!
うまく行くかに思われたが、全然機能しなかった。
あれ、なんで動かないの?ω
実際、BeginPaint EndPaintは、画面が隠れた時ぐらいにしか呼ばれていないorz
WM_PAINTも飛んでない。というか、メッセージなんも飛んでない……。
HSPは画面更新時をWM_PAINTに頼ってないんだろう。(←ソースコード持ってない
え、じゃあ、どうやって画面描画してるんだ?
InvalidateRectも呼ばれてないっぽいし……。
内部でタイマーをイベントで持ってて、
インポートテーブル使わないでGetProcAddressからポインタを得てAPI呼んでる……?
なんで普通そんな回りくどいことしないだろうに……
でも、他に画面更新の仕方を知らない自分は頭に「?」を浮かべるしかない。
ためしに、GetDCとかも張ってみたが……
HDC WINAPI Hook_GetDC(HWND hWnd){return OriginalGetDC(hWnd);}
↑落ちる。え、なんで落ちんのorz
OriginalGetDCはWINAPIで宣言した関数ポインタ型にGetProcAddress。
特に問題ないような気がする。
落ちるんだから気がするだけなんだろうけど、うーん……。
ちなみに、似たようにReleaseDCも落ちる。謎ぃ。
ここで初めてHSPDXFIX.dllの存在に気づく。
名前からしてDirectXプラグインだなぁ。こん中?
HSPのプラグインはスクリプトの中で明示的ロードされるので、
インポートテーブル書き換えたところで……動くのかな?
その時は動かないような気がして、ラップDLLを作ってしまった。
HSP2のプラグインは引数4個て決まってるから正規表現であっさり作れる。
enum { ……, num_es_ini, …… }; typedef int (WINAPI *F)(int,int,int,int); F g_pfn[100]; …… HSPDXFIX_API int WINAPI es_ini(int p1, int p2, int p3, int p4){ return g_pfn[num_es_ini](p1,p2,p3,p4); } ……
で、es_syncに対して似たようなのを仕込んでビルドして……実行。
落ちる! それも g_pfn[num_es_ini]の中で、
0x0000100のメモリがreadになれませんでしたとか言ってくる。
えええー、なんで落ちんのorz
さっきといい今といい、なんかラップの仕方間違ってんだろうか?
この辺でさじ投げたっす。自分、解析は向いてないっすねorz
そして、他の人が一切使えなそうな情報しか書かないのも、物書きも向いてないω
参考にした → DLL Injection
(……なにそれ
やね先生の美咲本買ってみようかな。