-3

フォームとボタンを使用してアセンブリでwin32プログラムをプログラミングするのに忙しい...問題は、ウィンドウがRAMの変数を変更することです。場所は、hInstance 変数と hwnd 変数のストアでした。回避策を見つけましたが、エレガントな解決策ではありません。ウィンドウが変数を変更する理由を知りたいのですが、アプリケーションの起動を説明するドキュメントを見つけることもできますか?

MyWndProc: 
push EBP 
mov EBP, ESP 
mov eax, [EBP + 12] 
cmp eax, WM_DESTROY 
jne MyWndProc_j2 
push 0 
call PostQuitMessage 
jmp MyWndProc_j1 

MyWndProc_j2: 
cmp eax, WM_CREATE 
jne MyWndProc_j1 
mov eax, [EBP+8] 
push eax 
call CreateControls 
add esp, 4 

MyWndProc_j1: 
mov eax, [EBP + 20] 
push eax 
mov eax, [EBP + 16] 
push eax 
mov eax, [EBP + 12] 
push eax 
mov eax, [EBP + 8] 
push eax 
call DefWindowProcA 
pop EBP 
ret 

segment .data 

Wtitle db 'My Window',0 
ClassName db 'myWindowClass',0 

editClass db 'EDIT',0 
buttonName db 'OK',0 
buttonClass db 'BUTTON',0 
textName db 'My textbox',0 
textClass db 'edit',0 

formEdit db 'This is just a mem test', 0 

windowsVar1 dd 0 
windowsVar2 dd 0 
windowsVar3 dd 0 
windowsVar4 dd 0 
windowsVar5 dd 0 
windowsVar6 dd 0 
windowsVar7 dd 0 
windowsVar8 dd 0 

aMsg dd 0 
hwnd dd 0 
hwnd2 dd 0 
hwnd3 dd 0 
hInstance dd 0 
old_proc dd 0 
nCmdShow dd 0 
hfDefault dd 0 

MyWndProc は、Windows からのコールバック関数です。Windows からの 27 回目の呼び出しで、最後の 7 つの変数を変更します。最後の 8 つの変数の位置を windowsVarx で切り替えても、windowsVarx を変更せずに hwnd、hwnd2 を変更します。x は 1 ~ 8 です

CreateControls: 
push EBP 
mov EBP, ESP 

push 0 
push 0 
call GetModuleHandleA 
push eax 
push IDC_MAIN_BUTTON 
mov eax, [EBP+8] ;hwnd 
push eax 
push 24 
push 100 
push 220 
push 50 
mov eax, WS_CHILD 
or eax, BS_DEFPUSHBUTTON 
or eax, WS_TABSTOP 
or eax, WS_VISIBLE 
push eax 
push buttonName 
push buttonClass 
push 0 
call CreateWindowExA 
mov [hwnd2], eax 

push DEFAULT_GUI_FONT 
call GetStockObject 
mov [hfDefault], eax 

push 0 
mov eax, [hfDefault] 
push eax 
push WM_SETFONT 
mov eax, [hwnd2] 
push eax 
call SendMessageA 

push 0 
push 0 
call GetModuleHandleA 
push eax 
push IDC_MAIN_EDIT 
mov eax, [EBP+8] ;hwnd 
push eax 
push 100 
push 200 
push 100 
push 50 
mov eax, WS_CHILD 
or eax, ES_MULTILINE 
or eax, ES_AUTOVSCROLL 
or eax, ES_AUTOHSCROLL 
or eax, WS_VISIBLE 
push eax 
push 0 
push editClass 
push WS_EX_CLIENTEDGE 
call CreateWindowExA 
mov [hwnd3], eax 

push 0 
mov eax, [hfDefault] 
push eax 
push WM_SETFONT 
mov eax, [hwnd3] 
push eax 
call SendMessageA 

push Wtitle 
push 0 
push WM_SETTEXT 
mov eax, [hwnd3] 
push eax 
call SendMessageA 

pop EBP 
ret 

次の関数は、収集してディスパッチするメッセージ ループです。

MyMessageLoop:
push 0
push 0
push 0
push aMsg
call GetMessageA
cmp eax, 0
je MyMessageLoop_j1
push aMsg
call TranslateMessage
push aMsg
call DispatchMessageA
jmp MyMessageLoop
MyMessageLoop_j1:
ret
4

4 に答える 4

1

Windows がデータを変更しているように見えるかもしれませんが、他の人が指摘しているように、コードのバグまたはその他の破損が問題を引き起こしている可能性が高いです。

スニペットからプログラム全体の実行時の動作を判断することはほとんど不可能であり、アセンブリでのプログラミングは、ほとんどの場合、高水準言語を使用する場合にはめったに見られない問題を引き起こします。

最良のアドバイスは、デバッガーを使用して、コードをステップ実行するか、変更する変数にデータ ブレークポイントを設定することです。データ ブレークポイントは、データ変更を実行する命令でプログラムを停止するように設計されています。

また、変数を上書きしているデータの実際の値を調べることもできます。これにより、メモリが上書きされている場所や理由についての手がかりが得られる場合があります。

人々の皮肉の理由は、2 番目の文で、プログラムが機能しないのは Windows のせいだと想定しているためです。多くの場合、オペレーティング システムのせいにするのは、開発者が何かを理解していないか、間違いを認めたくないという良い兆候です。最終的な結果は、ほとんどの場合、他の誰かが間違いを指摘することです。

于 2012-02-24T15:25:24.287 に答える
1

あなたの問題の説明はあまり明確ではありません。ただし、システム コールを呼び出すと、実際にはレジスタに異なる値が格納される可能性があることを覚えておく必要があります。Windows についてはわかりませんが、amd64 Linux では、カーネル (システム コールを実行する) はレジスタの値を保持するためだけに必要ですr12。他のすべてのレジスタの値は変更される可能性があるため、システム コールから戻った後はおそらく同じではありません。

これを改善するには、システムを呼び出す前に関数のスタックに変数を格納するだけです。

于 2012-02-24T13:00:47.550 に答える
0

CreateControls の呼び出し後に esp に 4 を追加するのはなぜですか? スタックに 1 つの dword をプッシュしていますが、CreateControls はスタック自体をクリーンアップしませんか? あなたはその関数を書きましたか?ret 4*1 のようなものでスタックを調整する場合は、esp, 4 を追加するとすべてが台無しになります。コードのスニペットは私たちには何もしません。さらに、そこには不要なmovsとjmpsがたくさんあります

@David Heffernanに感謝します。10年以上前にアセンブリですべてのプログラムを書き始めたばかりで、コンパイラがすべてのレジスタをプロローグに保存するという理由だけで、どのレジスタを保存する必要があるか、いつ保存する必要がないかをよく知っています。正しいとは限りません。

于 2012-02-25T18:41:28.760 に答える
0

どこから始めればよいですか?あなたのコードのフォーマットは非常に読みにくいです。ユニがあなたにそれを教えていないことを願っています。とにかく、あなたの WindowProc は非常に間違っていました。処理するすべてのメッセージの後、DefWindowProc を呼び出さないでください。ほとんどのメッセージは、eax で 0 を返すだけです。

CreateControls を呼び出した後、CreateControls の最後に ret 4 または ret 4 * NumOfParamsPassed を実行する限り、esp, 4 を追加する必要はありません。

WindowProc を修正したところ、ウィンドウが表示されるようになりました。また、多くの不要な動きを削除しました。

MyWndProc:
    push    ebp
    mov     ebp, esp

    mov     eax, dword ptr[ebp + 3 * 4] ; same as [ebp + 12]
    cmp     eax, WM_CREATE
    je      _CREATE
    cmp     eax, WM_CLOSE
    je      _CLOSE

PassThrough:    
    push    dword ptr[ebp + 5 * 4]; same as [ebp + 20]
    push    dword ptr[ebp + 4 * 4]; same as [ebp + 16]
    push    dword ptr[ebp + 3 * 4]; same as [ebp + 12]
    push    dword ptr[ebp + 2 * 4]; same as [ebp + 8]
    call    DefWindowProc
    jmp     _DONE

_CLOSE:
    push    0
    call    PostQuitMessage
    jmp     _RET0

_CREATE:
    push    dword ptr[ebp + 2 * 4]
    call    CreateControls
    ;add     esp, 4

_RET0:
    xor     eax, eax

_DONE:
    pop     ebp
    ret     4 * 4 ; <----- you were missing this!!!!!
于 2012-02-26T18:20:28.243 に答える