Log in

View Full Version : Code Injection with Code Snippet Creator: W32Dasm + Mouse Wheel support


Kayaker
November 2nd, 2002, 10:39
Hi All,

A while back I added mouse wheel support to my Win98 Winhlp32.exe file, basically because I was tired of not being able to mouse scroll in the Win32 Programmers Reference. I thought this would make a good project, but then I found out the Win2K and above versions of winhlp32.exe had mouse wheel support already built in. Damn MS anyway for stealing my idea! ;-) Aha, then I realized W32Dasm doesn't have mouse wheel scroll capabilities either, so this has now become the target for this project.

Usually I build a patch directly in Softice with the a(ssemble) command, which allows me to test and modify it on the go, then dump the bytes and insert them into the file with a hex editor and/or rebuild it using HIEW. This time however I decided to try out Iczelion's Code Snippet Creator, and I must admit to being very impressed. So this is a combination project which can deal with code injection/patching as a whole, as well as learning how to use this nifty tool.

What we want to do is find a spot in the Windows messaging queue in W32Dasm where we can insert a jmp to our patch code. The patch code itself will contain the new code to test for and handle the WM_MOUSEWHEEL message. The messaging queue is where messages such as WM_COMMAND and others are processed. This is the first hurdle to overcome for those who have never delved into or patched this area before. Finding and recognizing this code and understanding roughly what it is doing is the first step. I'd recommend focussing on trying to find where WM_COMMAND itself is handled. This message is called, for one, when a Menu item is selected and has a constant value of 111h, so a BMSG breakpoint can be used to break on it. From the BMSG break there are techniques to trace directly to the start of the messaging queue. If you are unsure how, I would suggest as a start looking at the Menu Enabling Project we had some time ago and Clandestiny's tutorial (on the main site) that came out of that, the techniques are discussed in there.

Menu Enabling Project (http://www.woodmann.net/forum/showthread.php?threadid=126)

There are other messages you could use and other ways to find the proper code area, including deadlisting, keying in on recognizable message constants such as "111h" for example, but whatever works for you.


What I'll do is supply the MASM code snippet that I used to develop the patch, or you can develop your own. Most of what you need to know about handling WM_MOUSEWHEEL is in the Win32 Programmers Reference, or you can go to MSDN for more info. If you do use the Snippet Creator you will need MASM installed of course. This isn't a complete copy and paste, you'll need to change what needs to be changed to get the right hWnd and wParam values for the real target, plus W32Dasm is a little peculiar actually, so this patch isn't necessarily as easy as it might seem.

Without giving too much else away, here is a generalized snippet that I developed in a test listview app before turning it into a patch, change what you see fit. There are more sophisticated ways to handle WM_MOUSEWHEEL but this was sufficient for my purposes. Every scroll of the mouse wheel up or down advances the page 3 lines (set in the loop). If the shift key is also held down then it's a full page scroll, this is a bit of an improvement on the standard routine that I just personally like.

Code:

; ListViewClassName db "SysListView32",0
; (example has nothing to do with W32Dasm but you may want
; to use a class name in your code)

.ELSEIF uMsg == WM_MOUSEWHEEL ; constant = 20Ah

; invoke FindWindowEx, hWnd, NULL, ADDR ListViewClassName, NULL
; WM_MOUSEWHEEL is sent to the Parent window, I needed the
; listview Child window for the SendMessage calls.
; This may not be the case with W32Dasm, check out what's
; happening! In any case, EAX is now the hWnd of the Listview
; itself (I think in W32Dasm it's a Listbox).


mov edx, wParam
mov ebx, edx
and ebx, 0ffffh
; LOWORD is returned in ebx, indicates if virtual key held down
sar edx, 16
; HIWORD is returned in edx, +ve value scroll up, -ve down

.IF SDWORD PTR edx < 0 ; Negative value of high-order word = wheel down

.if ebx == MK_SHIFT ; SHIFT key is down (0004h)

invoke SendMessage, eax, WM_VSCROLL, SB_PAGEDOWN, 0

.else
mov ebx, 3 ; scroll 3 lines for each wheel movement

.while ebx != 0
invoke SendMessage, eax, WM_VSCROLL, SB_LINEDOWN, 0
dec ebx
.endw
.endif

.ELSE ; Positive value of high-order word = wheel up

.if ebx == MK_SHIFT ; SHIFT key is down (0004h)

invoke SendMessage, eax, WM_VSCROLL, SB_PAGEUP, 0

.else
mov ebx, 3

.while ebx != 0
invoke SendMessage, eax, WM_VSCROLL, SB_LINEUP, 0
dec ebx
.endw
.endif

.ENDIF
.ENDIF


As for setting up and using Code Snippet Creator, if you decide to use it, the help file should be enough, but we can deal with problems if they arise. If you happen not to have a mouse with a wheel then you could always assign line/page scrolling functionality to W32Dasm with a hotkey instead (handle WM_KEYDOWN). If there are any questions don't be afraid to ask, there are many who can help with this. I know ZaiRoN has wanted to do a Code Snippet Creator project for a while

Good luck and have fun.

Cheers,
Kayaker

ZaiRoN
November 2nd, 2002, 22:17
Quote:
I know ZaiRoN has wanted to do a Code Snippet Creator project for a while
grr, you have stolen my fantastic idea

Joking apart, great job Kayaker! I really enjoyed this project and i'm planning to add more mouse_features

regards,
ZaiRoN

Kayaker
November 3rd, 2002, 01:25
Quote:
Originally posted by ZaiRoN
grr, you have stolen my fantastic idea



Heh, borrowed, ZaiRoN, borrowed... As Mammon_ gives us this fine code of ethics in his idc scripting examples (available at CrackZ btw), "use, steal, change, but do not claim."

Hopefully this will be the first of many such projects. Snippet Creator makes it SO convenient to develop complex patches by simply coding them in in the familiar environment of Masm32. Please pass on any other feature snippets anyone comes up with, so we can develop Zuprgut tools of the trade ;-)

Regards,
Kayaker

ZaiRoN
November 3rd, 2002, 15:52
You are forgiven this time
Zuprgut !?! what does it mean?

ZaiRoN

Kayaker
November 3rd, 2002, 16:24
Quote:
Originally posted by ZaiRoN
You are forgiven this time
Zuprgut !?! what does it mean?

ZaiRoN


Lol, thanks

Zuprgut? Something I stole, er borrowed, from the SuperBPM doc. Doesn't seem to be too common a term, German for 'super good' maybe? Klingon perhaps?

Kayaker

ZaiRoN
November 3rd, 2002, 17:11
Quote:
Klingon perhaps?

hihihi, maybe!
Have you ever tryed the Klingon google version?
No!?! Go to google and click on 'preferences'; choose klingon interface language and see with your eyes

ZaiRoN

ZaiRoN
November 3rd, 2002, 22:21
I was playing with the new wheel's feature and I noticed a strange thing regarding down direction. When I move the wheel very fast (in down direction) the page, instead of scroll down, scrolls up. At first, I thought the problem resides in my implementation, a little bit different from yours. I didn't use the signed dword in the first if-statement but a simple 0x78h check; so, I have tryed your code but it doesn't work, the scroll is always in only one direction: up. The weird thing is that I have made an asm proggie for test wm_mousewheel and both methods (my and yours) works perfectly... I'm not able to give an answer to the problem; it's only my problem or it happens to you too?

ZaiRoN

Kayaker
November 4th, 2002, 01:58
Hmm, weird.

No, I can spin the mouse wheel up or down fast until my finger falls off with no odd behavior. As I mentioned, WDasm is a little peculiar, and so is how you're supposed to handle WM_MOUSEWHEEL:

The WM_MOUSEWHEEL message is sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.

You may have noticed the WM_MOUSEWHEEL message is sent twice, hence the patch is called twice, once with the hwnd of the listbox and then with the hwnd of the parent window. I'm not sure why this is, if it's because the two controls have the same class name (I thought about changing one of them to check), or whether it may have something to do with what the above description implies. In an asm test app there is only 1 message sent (with the parent hwnd) that I can detect, and this you handle through uMsg.


How are you returning from the patch (and where did you place the jump)? Normally in an inline patch of this sort I might restore the stack and return directly to Kernel code from whence the msg handling call came (the call from between K32Thk1632Prolog -> K32Thk1632Epilog) rather than returning to program code and running unnecessary instructions.

But with WDasm this wasn't really feasible (notice the msg params aren't directly accessible from EBP within the main message handling routine that your patch accesses, but are pointed to in an address within EBP, kind of an indirection, plus there's a lot of other code run before ever restoring the proper stack and returning to Kernel code). So I just returned to the address after the patch jump, but preserved the flags (and registers of course) so the program would continue on and follow the normal code flow for an *unhandled* WM_MOUSEWHEEL message. Eventually DefWindowProc is called and is handled in whatever default manner Windows chose.

The fact that there are 2 hwnds processed in your patch doesn't really matter too much I think because in one of the cases the SendMessage calls will simply fail and no scrolling will occur (when it processes the Child window hwnd). If you don't want this redundant code to run then use FindWindowExA to filter out the incorrect one (returns 0 instead of a valid child hwnd).

I don't what else it might be unless your mouse is sending bogus signals. I'm using a Logitech cordless. Here's my Snippet Creator settings:

[OPTIONS]
SNIPPET_VA=401000
PATCHOPTION=1
REDIRECT=2
REDIRECT_VA=490E7A ; directly on cmp esi, 111
RETURN=1
RETURN_VA=490E80
RESTORE=0
TARGET=...\W32Dasm\W32dsm89.exe


Kayaker

ZaiRoN
November 4th, 2002, 14:04
I have found where the problem resides: wParam !!!
Directly from w32 help:
The value of the high-order word of wParam. Indicates the distance that the wheel is rotated, expressed in multiples or divisions of WHEEL_DELTA, which is 120.

I -superficially- thought that the only possible two values could be +120/-120...

ZaiRoN

ZaiRoN
November 4th, 2002, 19:21
For those who had already added the wheel features, I would like to suggest another task. Maybe it's not very useful but always fun.

I'm thinking to add another button to the 'W32Dasm Alphabetical List of Imported Functions' dialog. What will this button do? We will use this button to run the win32.hlp reference guide and to display the page of the selected imported function.

I don't have tried yet but I think that (if you want) you can follow these guidelines:

1. add the new button:
the easiest task of the project, you should know how to add a button (i.e. resource hacker)

2. find the routine where messages (relative to this dialog) are handled:
windasm uses a weird method to work with messages and maybe this could be not easy, don't know. Maybe a look to the other dialog functions will help you to find the routine (i.e. OpenClipboard function)

3. add code to:
- get the name of the selected Api. This snippet will help you:
Code:
invoke SendMessage, hListBox, LB_GETCURSEL, 0, 0
invoke SendMessage, hListBox, LB_GETTEXT, eax, ADDR Where_To_Save_The_Selected_Text
- run Win32.hlp guide.
Every .hlp file are runned using win32hlp.exe file. This .exe file allows you to specify some input parameters, I don't put the list here...use google .
Here is an example on how to run Win32 guide and to display the MessageBox page:

win32hlp.exe -k MessageBox c:\...path...\Win32.hlp

We know how to run the reference but we don't know yet how to run the win32hlp.exe file.
To run files, there are some different ways. Windasm uses CreateProcess function to debug processes so we can simply use this function


For now, I don't have other ideas.
If you have any comments, questions or other things about this project, don't hesitate to come out

ZaiRoN

crUsAdEr
November 9th, 2002, 04:50
hmm...

forgive me but u guys are too fast... been busy for a few days n boom.. the project is already finished ... anyway.. i would like to work on something slightly differently... i would like to add more feature on revirgin or imprec through the right click mouse button...

Can you give me some hint on how to start? i am quite lost on which msg to catch n handle still...

thanx,
crUsAdEr