win32非常低级别的程序集 - 应用程序启动问题

时间:2012-02-24 11:23:41

标签: api winapi assembly user32

我正在忙于使用表单和按钮编译程序集中的win32程序...问题是Windows在ram中修改我的变量。这个地方是我的hInstance和hwnd变量的商店。我找到了一种解决方法,但它不是一个优雅的解决方案。我想知道为什么windows会修改我的变量,也可以找到描述应用程序启动的文档。

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个变量。如果我用windowsVarx切换最后8个变量的位置,那么它仍然会修改hwnd,hwnd2 ...而不修改windowsVarx。其中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 个答案:

答案 0 :(得分:1)

你的问题解释不是很清楚。但是你应该记住,通过调用系统调用,你的寄存器中可能确实会有不同的值。我不了解Windows,但是在amd64 Linux上,内核(执行系统调用)只需要保留寄存器r12及以上的值。所有其他寄存器中的值可能会更改,因此从系统调用返回后很可能不会相同。

为了解决这个问题,只需在调用系统之前将变量存储在函数的堆栈中即可。

答案 1 :(得分:1)

Windows似乎正在修改您的数据,但正如其他人所指出的那样,代码中的错误或其他一些损坏更可能导致问题。

人们几乎不可能从片段中确定整个程序的运行时行为,而汇编中的编程几乎总是会导致在使用高级语言时很少出现的问题。

最好的建议是使用调试器并逐步执行代码或对要修改的变量设置数据断点。数据断点旨在使程序停止执行数据修改的指令。

您还可以查看覆盖变量的数据的实际值 - 它可能会为您提供有关内存被覆盖的位置或原因的一些线索。

人们讽刺的原因是,在你的第二句话中,你认为Windows应该归咎于你的程序不起作用。在许多情况下,指责操作系统是开发人员不理解某些内容或不愿意接受他们犯了错误的好兆头。最终结果几乎总是别人指出错误。

答案 2 :(得分:0)

为什么在调用CreateControls后向esp添加4?你正在将1个dword推入堆栈,CreateControls不会清理堆栈本身吗?你写了那个功能?如果它确实用ret 4 * 1之类的东西调整堆栈然后添加esp,那么4就是搞砸了所有东西。那段代码对我们没有任何帮助,而且那里有很多不受欢迎的mov和jmps

@David Heffernan谢谢我刚刚开始在大会上编写我的所有程序,并且很清楚需要保存的寄存器以及何时不需要保存它们,只是因为编译器会保存所有寄存器序言,并不代表它是正确的。

答案 3 :(得分:0)

我从哪里开始?您的代码格式很难阅读。希望Uni不会教你。无论如何,你的WindowProc非常错误。在您处理的每条消息之后,您不要调用DefWindowProc,大多数消息只是在eax中返回0。

在调用CreateControls之后,只要在CreateControls结束时再执行4或者返回4 * NumOfParamsPassed,就不需要添加esp,4。

我修复了你的WindowProc,现在显示了窗口。我还删除了许多不需要的mov。

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!!!!!