flat assembler
Message board for the users of flat assembler.

Index > Tutorials and Examples > WindowProc via ScanMap

Author
Thread Post new topic Reply to topic
TightCoderEx



Joined: 14 Feb 2013
Posts: 58
Location: Alberta
TightCoderEx 28 Jun 2013, 00:46
This procedure is a generic handler for windows procedures, sub or super classed. This also allows dynamic changing of application characteristics, just by eliminating an entry point or having it execute a different procedure. This can be accomplished as long as the map resides in writable memory.

The map is quite simple.
Code:
   MMap         dd      0                       ; Default windows procedure
                dd      ( MMapEnd - $ ) / 6     ; Number of pointers in map

        ; These will always be 6 byte sets.

                dw      WM_DESTROY
                dd      Quit_App
   MMapEnd:
    


The entry point should be aligned.

Code:
                align   32
; --------------------------------------------------------------------------------------------
  MainWndProc:  mov     esi, MMap
                jmp     ScanMap
    


Then the procedure is called.

Code:
                align   8
; --------------------------------------------------------------------------------------------
;       hWnd Msg wParam & lParam are @ esp + 4 at this point

      ScanMap:  lodsd                           ; Default proc is window is sub or super class
                mov     ebx, eax
                lodsd                           ; # of handlers in map
                mov     ecx, eax

        ; Scan map for any matching messages

           @@:  lodsw                           ; Message #
                cmp     [esp + 8], eax          ; Is it message currently being processed
                lodsd                           ; Get pointer to handler
                jz      .Handle
                loopnz  @B                      ; Continue till list is exhaused

        ; Application is not handling this message so execute default processing

           @@:  or      ebx, ebx                ; EBX = Pointer to windows default proc
                jnz     .Subed
                jmp      [DefWindowProc]        ; Not sub or super classed

        ; Push the extra parameter required by API

       .Subed:  pop     eax                     ; Grab return address
                push    ebx                     ; lpPrevWndFunc
                push    eax                     ; Replace return address
                jmp     [CallWindowProc]        ; Execute windows default procedure

      .Handle:  lea     esi, [esp + 12]         ; Points to wParam & lParam
                call    eax                     ; Execute handler
                jc      @B                      ; CF = 1 if default processing still required

        ; Kernel looks after cleaning up stack

                xor     eax, eax
                ret     16
    


The only change I'm contemplating in the future is to put all the handlers in numeric order and then bail as soon the one in the map is greater than what we're looking for.

For those that follow my posts, you may have noticed I've reverted to 32 bit again. There is no inherent advantage to using 64 bit at this point and I find that convoluted calling mythology just a little to hard to swallow.


Description:
Download
Filename: PEView.ASM
Filesize: 4.12 KB
Downloaded: 783 Time(s)

Post 28 Jun 2013, 00:46
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 28 Jun 2013, 01:15
TightCoderEx wrote:
The entry point should be aligned.
Code:
                align   32    
Why align like this?


TightCoderEx wrote:
Code:
        ; Scan map for any matching messages

           @@:  lodsw                           ; Message #
                cmp     [esp + 8], eax          ; Is it message currently being processed
                lodsd                           ; Get pointer to handler
                jz      .Handle
                loopnz  @B                      ; Continue till list is exhaused    
"lodsw" only updates the AX portion of EAX, whereas the following 'lodsd" updates the upper portion of EAX. Perhaps you should use a word compare instead?
Code:
cmp [esp+8],ax    
Post 28 Jun 2013, 01:15
View user's profile Send private message Visit poster's website Reply with quote
TightCoderEx



Joined: 14 Feb 2013
Posts: 58
Location: Alberta
TightCoderEx 28 Jun 2013, 02:28
Quote:

Why align like this?
Convenience. As I don't use symbols, it's easier to remember where things are and those entry points don't change with minor changes above that point.

Quote:

Perhaps you should use a word compare instead?
Good catch and especially in the case where it's a sub/super classed window. At the first iteration the high order bits would have some extraneous value like 773c and it would miss the first handler in the list. After the second iteration, high order EAX would be 0040 as all handlers will be in code section.

Arrow I think my choice for speed consideration will be to change the message number in map to a 32 bit value instead.

Code:
   MMap         dd      0                       ; Default windows procedure
                dd      ( MMapEnd - $ ) / 8     ; Number of pointers in map

        ; These will always be 6 byte sets.

                dd      WM_DESTROY
                dd      Quit_App
   MMapEnd:
    


Code:
           @@:  lodsd                           ; Message #
                cmp     [esp + 8], eax          ; Is it message currently being processed
                lodsd                           ; Get pointer to handler
                jz      .Handle
                loopnz  @B                      ; Continue till list is exhaused
    
Post 28 Jun 2013, 02:28
View user's profile Send private message Visit poster's website Reply with quote
uart777



Joined: 17 Jan 2012
Posts: 369
uart777 28 Jun 2013, 02:42
Quote:
I think my choice for speed consideration will be to change the message number in map to a 32 bit value instead.
Congratulations, you made your program a millionth of a second faster Smile Dude, you need to learn economics. You remind me of my neighbors who spend $3,000+ a month on crack (5-10 kids) then say "Look, I saved a $1 on toilet paper!" Smile LOL!
Post 28 Jun 2013, 02:42
View user's profile Send private message Reply with quote
typedef



Joined: 25 Jul 2010
Posts: 2909
Location: 0x77760000
typedef 28 Jun 2013, 03:43
uart777 wrote:
"Look, I saved a $1 on toilet paper!" Smile LOL!


LOLWTF... You might as well use your hands... Shocked
Post 28 Jun 2013, 03:43
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 28 Jun 2013, 03:55
I have always liked the idea of using tables instead of a long string of 'cmp' instruction. But I have never been satisfied with having to update my code in two places to insert an extra function. I.e. the need to insert the new function and to also update the table to point to it. So perhaps a macro could make it more convenient?
Code:
macro AddFunction ID,func,[params] {
 common
 proc func,params
;code to add ID to the function table
}

AddFunction WM_DESTROY,Quit_App,exit_code
;...
endp

AddFunction WM_PAINT,Paint_App,hwnd,...
;...
endp

;code to place the function table
PlaceTable    
There have been posted here previously table building macros which could do the trick of building the tables, but with the new virtual address spaces there might be a better solution available also. Anyhow, the point being everything is added (or deleted) in one place within the code. Less errors, more productivity.
Post 28 Jun 2013, 03:55
View user's profile Send private message Visit poster's website Reply with quote
TightCoderEx



Joined: 14 Feb 2013
Posts: 58
Location: Alberta
TightCoderEx 28 Jun 2013, 05:40
Quote:

So perhaps a macro could make it more convenient?
Definitely a worthwhile consideration, but first I have to get my mind wrapped around FASM in principal and even more importantly 64 bit. When I have the 64 bit version working, I will want to take a closer look at your example. Even in the mid 80's I didn't use macros, even though the earlier versions of ML were called Macro Assemblers, therefor the macro concept is pretty foreign to me.
Post 28 Jun 2013, 05:40
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 28 Jun 2013, 08:19
The code path of multiple CMP/JZ pairs can be almost 100% predicted in both memory load and execution path. Whereas, your suggested method uses more memory and cannot be predicted (both the branch and the data load).
Post 28 Jun 2013, 08:19
View user's profile Send private message Visit poster's website Reply with quote
AsmGuru62



Joined: 28 Jan 2004
Posts: 1619
Location: Toronto, Canada
AsmGuru62 28 Jun 2013, 10:31
I am not sure this smart contraption will make the procedure faster than simple CMP/JE.
Also, can someone find a message which will be coming quick enough to make this
optimization worthy?
I can think of something repainting every mouse move to be most dense.
And mouse moves are not coming every pixel -- maybe every few pixels, so not fast enough IMO.
To deal with such case, I would put WM_PAINT and WM_MOUSEMOVE at the top
of CMP/JE chain.
Post 28 Jun 2013, 10:31
View user's profile Send private message Send e-mail Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20303
Location: In your JS exploiting you and your system
revolution 28 Jun 2013, 10:39
Optimising a WindowProc is not the right way to think about this IMO. I can't think of a case where the main bottleneck would ever be the WindowProc.
Post 28 Jun 2013, 10:39
View user's profile Send private message Visit poster's website Reply with quote
TightCoderEx



Joined: 14 Feb 2013
Posts: 58
Location: Alberta
TightCoderEx 28 Jun 2013, 12:13
bitRAKE, AsmGuru62 and revolution each of your most recent posts are of the same theme and I concur as I most often purport cycles and byte savings as the theory behind what I do. In this case, those consideration took a back seat to aesthetics if you will from a human perspective, but most importantly the ability to dynamically modify application characteristics on the fly. Self modifying code and overlays were a thing I used quite often and maybe that's just something I haven't got my head wrapped around yet with the kind of resources of today.

In 64 bit, it seems the pain is not worth the gain especially considering there is no gain to be had in the first place.
Post 28 Jun 2013, 12:13
View user's profile Send private message Visit poster's website Reply with quote
bitRAKE



Joined: 21 Jul 2003
Posts: 4024
Location: vpcmpistri
bitRAKE 28 Jun 2013, 23:17
It does demonstrate a translative quality between code and data. Many programmers don't understand that code is data (data is code) in this sense, and it's inherent to many types of optimization. Jump tables, compiled sprites, and state machines; are all examples of this quality, too.

_________________
¯\(°_o)/¯ “languages are not safe - uses can be” Bjarne Stroustrup
Post 28 Jun 2013, 23:17
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< 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-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.