flat assembler
Message board for the users of flat assembler.

Index > Windows > Win32 programming without includes

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
pal



Joined: 26 Aug 2008
Posts: 227
pal
Razz Yeah.

Just a question (not related to my first post, decided to post here instead of creating a new topic; mods can dissolve this if they do so wish) about Windows stuctures. I'm creating a dialog and I don't want to have any of the FASM includes ie load API's etc. I know how you load the API's from a few examples, but I cant figure out how you define structures. From what I've read with the includes you can use say:

Code:
    struct WNDCLASS
        style           dd ?
        lpfnWndProc     dd ?
        cbClsExtra      dd ?
        cbWndExtra      dd ?
        hInstance       dd ?
        hIcon           dd ?
        hCursor         dd ?
        hbrBackground   dd ?
        lpszMenuName    dd ?
        lpszClassName   dd ?
    ends
    


But it wont work with no includes. Should I be creating like a label and in the label have all of the members of the structure (ie style,lpfnWndProc etc.) or what?

Cheers for any help, pal.
Post 29 Aug 2008, 13:00
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17350
Location: In your JS exploiting you and your system
revolution
pal: Have a look at struc in the fasm manual. Like this:
Code:
struc abc {
 .x dd ?
 .y dd ?
}    
Post 29 Aug 2008, 13:18
View user's profile Send private message Visit poster's website Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Yeah I see. I would like to have done it without macro's to be honest but I dunno how thats possible. As I am creating a window and if I have no includes should I too replace a proc endp with a macro then?

Out of curiosity; there is obviously a way to do this without proc and without macro's, but I cant figure it out seeing as in my window callback prodecure parameters are passed to it. Am I correct in thinking that if I specify a label as my callback procedure then the parameters passed to be will be located at (on the stack):

hWnd -> [EBP+8]
uMsg -> [EBP+C]
wParam -> [EBP+10]
lParam -> [EBP+14]

If so, and as they are on the stack does that mean I could use them by doing the following:

Code:
mov   ax,ss:[ebp+8]    


Or something as such to move say ebp+8 (hWnd) to a register or whatever?
Post 29 Aug 2008, 14:15
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17350
Location: In your JS exploiting you and your system
revolution
Parameters in STDCALL (used in most Windows APIs) are pushed reverse order onto the stack. So you can access directly with something like "mov eax,[esp+8]". But of course you can set ebp to the stack beginning at entry and use the code you posted above "mov eax,[ebp+8]". Although using the macro proc makes all the finicky offset and label value calculations for you. I recommend you use the macro simply to make your job easier.
Post 29 Aug 2008, 14:22
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
mov eax, [ebp+8] is enough. Here another convinient way

Code:
winproc:
virtual at ebp+8
  .hWnd dd ?
  .uMsg dd ?
  .wParam dd ?
  .lParam dd ?
end virtual

  push ebp
  mov  ebp, esp

  mov  eax, [.hWnd] ; EAX because HWND is dword sized and no SS because DS segment covers the entire 4 GB space like all the other segment registers do (except for FS and GS).

  leave
  ret 4*4 
    


I'll move the posts to "Win32 programming without includes" later.
Post 29 Aug 2008, 14:28
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
OK, I think I'm coming to understanding this more. hWnd, uMsg, wParam and lParam are all dwords hence they are all at a +4 value of ebp (dword = 4 bytes). So I tried to make a really basic dialog using something like this (the code is below), but the thing fucked up badly. It was trying to include d0.dll for some reason then h0.dll (when I added a message box for some error handling) and I have no idea where it got the idea to do that from.

Code:
format PE GUI 4.0
entry start

section '.data' data readable writeable
    cClass      db  'WINDOWFASM',0
    hWnd        dd  ?
    uMsg        dd  ?
    wParam      dd  ?
    lParam      dd  ?
    NULL        equ 0

section '.code' code readable executable
    start:
        ; Get handle
        push    NULL
        call    [GetModuleHandle]
        ; Create a window
        push    0
        push    WndProc
        push    0 ; HWND_DESKTOP
        push    37
        push    eax
        call    [DialogParamBox]
        ret
    
    WndProc:
        mov     eax,[esp+08h]
        mov     [hWnd],eax
        mov     eax,[esp+0Ch]
        mov     [uMsg],eax
        mov     eax,[esp+10h]
        mov     [wParam],eax
        mov     eax,[esp+14h]
        mov     [lParam],eax
        ; Got the params now lets see the message
        cmp     [uMsg],10 ; WM_CLOSE
        je      wmClose
        
        wmDefault:
            push    [lParam]
            push    [wParam]
            push    [uMsg]
            push    [hWnd]
            call    [DefWindowProc]
            jmp     wmEnd
        wmClose:
            push    1
            push    [hWnd]
            call    [EndDialog]
        wmEnd:
            ret 

section '.idata' import data readable writeable
    dd  0,0,0,RVA kernel_table,RVA kernel_name
    dd  0,0,0,RVA user_name,RVA user_table
    dd  0,0,0,0,0
    
    kernel_table:
        GetModuleHandle dd  RVA _GetModuleHandle
    user_table:
        DefWindowProc   dd  RVA _DefWindowProc
        EndDialog       dd  RVA _EndDialog
        DialogParamBox  dd  RVA _DialogParamBox
        
    kernel_name db  'KERNEL32.DLL',0
    user_name   db  'USER32.DLL',0
    
    _GetModuleHandle dw 0
        db  'GetModuleHandleA',0
    
    _DefWindowProc  dw 0
        db  'DefWindowProcA',0
    _EndDialog      dw 0
        db  'EndDialog',0
    _DialogParamBox dw 0
        db  'DialogParamBoxA',0

section '.reloc' fixups data readable discardable
    


I decided to use DialogBoxParamA instead of CreateWindowExA so that I didn't have to use a macro to define the WNDCLASS(EX) structure. I know hWnd should really be called hWndDlg but meh. Also I wasn't able to move the item from the stack directly to my memory locations; I had to move it to eax first then from eax to the memory location.

Any help apprechiated.
Post 29 Aug 2008, 15:54
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17350
Location: In your JS exploiting you and your system
revolution
You must use [esp+4] for the first parameter if you don't push a value onto the stack. The [ebp+8] is used when the original ebp is pushed onto the stack.
Post 29 Aug 2008, 16:00
View user's profile Send private message Visit poster's website Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
OK; I think I understand. I read some articles on the net, I don't really understand why this is happening too much but I apprechiate it. From what I've gathered esp is the stack pointer to the top address of the stack, but I don't understand the difference between that and ebp. When you mentioned about the origional ebp being pushed onto the stack, is that to preserve the value or what?

Also any idea why the program is crashing upon trying to load the DLL which it shouldn't be. I'm assuming for some reason trying to load kernel32.dll or user32.dll its getting a malformed string somehow which it is trying to load. Does this website have an IRC channel by the way?
Post 29 Aug 2008, 18:14
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17350
Location: In your JS exploiting you and your system
revolution
pal wrote:
Also any idea why the program is crashing upon trying to load the DLL which it shouldn't be. I'm assuming for some reason trying to load kernel32.dll or user32.dll its getting a malformed string somehow which it is trying to load.
You are passing bogus values to DefWindowProc because you have used the wrong offsets with esp, so any seemingly random behaviour could happen.
Post 29 Aug 2008, 22:44
View user's profile Send private message Visit poster's website Reply with quote
Frank



Joined: 17 Jun 2003
Posts: 100
Frank
pal wrote:
Code:
    dd  0,0,0,RVA kernel_table,RVA kernel_name
    dd  0,0,0,RVA user_name,RVA user_table
    

Mere eye-balling suggests that one of the above lines must be wrong, note the different order of xxx_table and xxx_name.

pal wrote:
Code:
        db  'DialogParamBoxA',0
    

DialogBoxParamA?
Post 30 Aug 2008, 12:55
View user's profile Send private message Reply with quote
asmcoder



Joined: 02 Jun 2008
Posts: 784
asmcoder
[content deleted]


Last edited by asmcoder on 14 Aug 2009, 14:56; edited 1 time in total
Post 30 Aug 2008, 14:48
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Cheers for the replies. Cant believe that I was spelling DialogBoxParam DialogParamBox Shocked Also about putting user_table and user_name the wrong way around.

asmcoder: So your saying I should be using:

Code:
section '.idata' import readable     


And by "db 0,0,'export',0 " I assume your talking about replacing lines such as:

Code:
    _EndDialog      dw 0
        db  'EndDialog',0 
    


With that; or am I mistaken.

I changed the code and have tried a few things now but I'm getting the same results; I've tried:

Code:
mov     eax,dword [esp+04h] (with and without dword)
pop     eax
mov     eax,dword [ebp+08h] (with and without dword and after pushing ebp)
    


But none of them work. If I do use mov instead of pop does that mean I have to realign esp so that the values are no longer on the stack, as I am not actually pop'ing them but just copying them aren't I?
Post 31 Aug 2008, 11:45
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 17350
Location: In your JS exploiting you and your system
revolution
See the code that LocoDelAssembly posted above. If you are getting confused with esp then start by using ebp instead the way LocoDelAssembly suggests.
Post 31 Aug 2008, 16:56
View user's profile Send private message Visit poster's website Reply with quote
Alphonso



Joined: 16 Jan 2007
Posts: 294
Alphonso
Not sure why your doing it like this, seems a hard way to do it, but if that's what you want then maybe
Code:
format PE GUI 4.0
entry start

section '.data' data readable writeable
    cClass      db  'WINDOWFASM',0
    hWnd        dd  ?
    uMsg        dd  ?
    wParam      dd  ?
    lParam      dd  ?
    NULL        equ 0

section '.code' code readable executable
    start:
        ; Get handle
        push    NULL
        call    [GetModuleHandle]
        ; Create a window
        push    0
        push    WndProc
        push    0 ; HWND_DESKTOP
        push    37                ;--> ID=37 but where is the dialog resource?
        push    eax
        call    [DialogParamBox]
        ret
    
    WndProc:
        mov     eax,[esp+04h]
        mov     [hWnd],eax
        mov     eax,[esp+08h]
        mov     [uMsg],eax
        mov     eax,[esp+0ch]
        mov     [wParam],eax
        mov     eax,[esp+10h]
        mov     [lParam],eax
        ; Got the params now lets see the message
        cmp     [uMsg],10h ; WM_CLOSE   --> 10h not 10
        je      wmClose
        
        wmDefault:
            push    [lParam]
            push    [wParam]
            push    [uMsg]
            push    [hWnd]
            call    [DefWindowProc]
            jmp     wmEnd
        wmClose:
            push    1
            push    [hWnd]
            call    [EndDialog]
        wmEnd:
            mov     eax,0               ;--> all done
            ret

section '.idata' import data readable writeable

    dd  0,0,0,RVA kernel_name ,RVA kernel_table
    dd  0,0,0,RVA user_name   ,RVA user_table
    dd  0,0,0,0,0
    
    kernel_table:
        GetModuleHandle dd  RVA _GetModuleHandle
                        dd  0                      ;End of table
    user_table:
        DefWindowProc   dd  RVA _DefWindowProc
        EndDialog       dd  RVA _EndDialog
        DialogParamBox  dd  RVA _DialogParamBox
                        dd  0                      ;End of table

    kernel_name db  'KERNEL32.DLL',0
    user_name   db  'USER32.DLL',0

    _GetModuleHandle    dw 0
        db  'GetModuleHandleA',0

    _DefWindowProc      dw 0
        db  'DefWindowProcA',0
    _EndDialog          dw 0
        db  'EndDialog',0
    _DialogParamBox     dw 0
        db  'DialogBoxParamA',0      ;not ...ParamBox

section '.reloc' fixups data readable discardable    
I guess you already have a dialog resource ID=37.

I'm not so good at this stuff but hope it helps.
Post 31 Aug 2008, 20:47
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Nevermind, I have it now with the esp+4 etc. Cheers for all the help. What was wrong was that when I looked at what Frank said about the two lines, one being wrong and I made them both wrong! I've fixed it now anyway. And yeah Alphonso thats what I'm doing/have now, cheers!
Post 31 Aug 2008, 20:50
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Just a quick follow up question/problem. I have a code which I reckon should be working, so does another coder I showed it too, but the CreateWindowEx() function returns null, and GetLastError() function returns the error 1407 (if I remember correctly), which equates to "Cannot find window class". I have no idea why this is as I am getting a valid atom back from the RegisterClass call. I have tried this with both WNDCLASS and WNDCLASSEX structures, but both failed. The code is:

Code:
format PE GUI
entry start

section '.data' data readable writeable
    ; Our callback procedure variables
    hWnd        dd  0
    uMsg        dd  0
    wParam      dd  0
    lParam      dd  0
    ; Other variables
    winWnd      dd  ?
    cClassName  db  'FASMDIALOG',0
    cTitle      db  'Window Title',0
    cError      db 260 dup (0) 
    
    ; WNDCLASS
    wCls:
        wCls.style          dd  0
        wCls.lpfnWndProc    dd  WndProc
        wCls.cbClsExtra     dd  0
        wCls.cbWndExtra     dd  0
        wCls.hInstance      dd  0
        wCls.hIcon          dd  0
        wCls.hCursor        dd  0
        wCls.hbrBackground  dd  0
        wCls.lpszMenuName   dd  0
        wCls.lpszClassName  dd  cClassName
        
    ; MSG
    wMsg:
        wMsg.hWnd           dd  0
        wMsg.message        dd  0
        wMsg.wParam         dd  0
        wMsg.lParam         dd  0
        wMsg.time           dd  0
        wMsg.pt.x           dd  0
        wMsg.pt.y           dd  0

section '.code' code readable writeable
    start:  
        push    0
        call    [GetModuleHandle]
        mov     [wCls.hInstance],eax
        ; Load an icon
        push    32512
        push    0
        call    [LoadIcon]
        mov     [wCls.hIcon],eax
        ; Load a cursor
        push    32512
        push    0
        call    [LoadCursor]
        mov     [wCls.hCursor],eax
        ; Register class
        push    wCls
        call    [RegisterClass]
        cmp     eax,0
        je      errGetError
        ; Create a window
        push    0
        push    wCls.hInstance
        push    0
        push    0
        push    200 ; nHeight
        push    300 ; nWidth
        push    16  ; y
        push    16  ; x
        push    0x16CF0000 ; dwStyle (WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU)
        push    cTitle
        push    wCls.lpszClassName
        push    0
        call    [CreateWindowEx]
        cmp     eax,0
        je      errGetError
        mov     [winWnd],eax
        ; Show the window
        push    5
        push    eax
        call    [ShowWindow]
        ; Our message loop
        messageLoop:
            push    0
            push    0
            push    0
            push    wMsg
            call    [GetMessage]
            or      eax,eax
            je      endCode
            ; Translate message
            push    wCls
            call    [TranslateMessage]
            ; Dispatch message
            push    wCls
            call    [DispatchMessage]
            jmp     messageLoop
            
        WndProc:
            push    ebp
            pusha
            mov     ebp,esp
            mov     eax,[ebp+0x8]
            mov     [hWnd],eax
            mov     eax,[ebp+0xC]
            mov     [uMsg],eax
            mov     eax,[ebp+0x10]
            mov     [wParam],eax
            mov     eax,[ebp+0x14]
            mov     [lParam],eax
            xor     eax,eax
            cmp     [uMsg],0x2 ; WM_DESTROY
            je      wmDestroy
            
            wmDefault:
                push    [lParam]
                push    [wParam]
                push    [uMsg]
                push    [hWnd]
                call    [DefWindowProc]
                jmp     wmEnd
            
            wmDestroy:
                push    0
                call    [PostQuitMessage]
                xor     eax,eax
            
            wmEnd:
                popa
                ret
        
        errGetError:
            call    [GetLastError]
            push    0
            push    260
            push    cError
            push    0
            push    eax
            push    0
            push    0x1000 ; FORMAT_MESSAGE_FROM_SYSTEM
            call    [FormatMessage]
            push    0
            push    0
            push    cError
            push    0
            call    [MessageBox]
        
        endCode:
            push    0
            call    [ExitProcess]

section '.idata' import readable
    dd  0,0,0,RVA user_name     ,RVA user_table
    dd  0,0,0,RVA kernel_name   ,RVA kernel_table
    dd  0,0,0,0,0
    
    kernel_table:
        GetModuleHandle     dd  RVA _GetModuleHandle
        FormatMessage       dd  RVA _FormatMessage
        GetLastError        dd  RVA _GetLastError
        ExitProcess         dd  RVA _ExitProcess
        dd  0
    
    user_table:
        MessageBox          dd  RVA _MessageBox
        CreateWindowEx      dd  RVA _CreateWindowEx
        RegisterClass       dd  RVA _RegisterClass
        DispatchMessage     dd  RVA _DispatchMessage
        TranslateMessage    dd  RVA _TranslateMessage
        DefWindowProc       dd  RVA _DefWindowProc
        GetMessage          dd  RVA _GetMessage
        LoadIcon            dd  RVA _LoadIcon
        LoadCursor          dd  RVA _LoadCursor
        PostQuitMessage     dd  RVA _PostQuitMessage
        ShowWindow          dd  RVA _ShowWindow
        dd  0
    
    user_name   db  'USER32.DLL',0
    kernel_name db  'KERNEL32.DLL',0
    
    _GetModuleHandle    dw  0
        db  'GetModuleHandleA',0
    _FormatMessage      dw  0
        db  'FormatMessageA',0
    _GetLastError       dw  0
        db  'GetLastError',0
    _ExitProcess        dw  0
        db  'ExitProcess',0
    
    _MessageBox         dw  0
        db  'MessageBoxA',0
    _CreateWindowEx     dw  0
        db  'CreateWindowExA',0
    _RegisterClass      dw  0
        db  'RegisterClassA',0
    _DispatchMessage    dw  0
        db  'DispatchMessageA',0
    _TranslateMessage   dw  0
        db  'TranslateMessage',0
    _DefWindowProc      dw  0
        db  'DefWindowProcA',0
    _GetMessage         dw  0
        db  'GetMessageA',0
    _LoadIcon           dw  0
        db  'LoadIconA',0
    _LoadCursor         dw  0
        db  'LoadCursorA',0
    _PostQuitMessage    dw  0
        db  'PostQuitMessage',0
    _ShowWindow         dw  0
        db  'ShowWindow',0
    


Any help is apprechiated, Unknown.
Post 03 Sep 2008, 23:31
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Seems that other coder haven't paid you too much attention Wink

push wCls.hInstance > push [wCls.hInstance]
push wCls.lpszClassName > push [wCls.lpszClassName ]

pusha > ; pusha
popa > ; popa
insert "leave" before ret

Code:
            ; Translate message
            push    wCls
            call    [TranslateMessage]
            ; Dispatch message
            push    wCls
            call    [DispatchMessage]
    

To:
Code:
            ; Translate message
            push    wMsg
            call    [TranslateMessage]
            ; Dispatch message
            push    wMsg
            call    [DispatchMessage]
    


Some fixing will still be needed but now it doesn't crash nor hung neither.
Post 03 Sep 2008, 23:56
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Cheers! I cant believe again my error was passing the wrong parameter because of my ignorance Shocked Two things: as for putting [] around the two members of the wCls structure, I looked at one of karl's (I think) examples, and he didn't have brackets around them, but it still worked. I used brackets at first but it wasn't working so I changed it so it was like his... If i use the leave command, don't I need an enter at the beginning of the callback procedure?

Got it working now, I had to move the pusha command to after the mov ebp,esp command. When I had 0 for WNDCLASS.hbrBackground the window was seethrough (except for the frame), is this normal because there is no specified colour?

Cheers, Unknown.
Post 04 Sep 2008, 09:28
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

is this normal because there is no specified colour?

Yes, because there is no background brush. And in fact you don't see through, the window "memorizes" what was in the portion of screen just before the background became visible.

Quote:

I had to move the pusha command to after the mov ebp,esp command


But still your "xor eax, eax" won't make your procedure return zero because popa restores eax too. stdcall procedures (like winproc and, with some exceptions, all the APIs), only need to preserve EBX, ESI, EDI and EBP and ESP must be restored to ESP-number_of_args*4 (in some cases some arguments can be longer than 4, a multiple of 4).

So there is another bug that I haven't seen before, ret must be "ret 16" if you don't apply this change you could have random crashes.

About ENTER, check the manual to see what it does, you'll find out that you already used it without noting it.
Post 04 Sep 2008, 14:24
View user's profile Send private message Reply with quote
pal



Joined: 26 Aug 2008
Posts: 227
pal
Ahh cool. Just a few questions to clear up:

1. I only need to preserve ebp, esp, esi, edi, and ebx during my function, and pop them at the end. In the case of esp I need to subtract 16 (4 params * 4 dwords?). Do I have to do this for all of my functions, as in change esp?

2. As for the ret 16, will I need to put this in any other functions like my one above, obviously if there are only two params then 8 or whatever?
Post 07 Sep 2008, 12:29
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar. Also on YouTube, Twitter.

Website powered by rwasa.