Log in

View Full Version : Need help with win32 asm


Nebob
January 10th, 2003, 00:10
I have a simple program that I want to modify. When this program starts, it displays a window with a few buttons. The user must click one of these buttons, at which point stuff happens. I want to modify the program so that the button is automatically "clicked", and user intervention is not required. I'm having a great deal of trouble coming up with the right method to achieve this.

In winmain, I have code that calls:

GetSystemInfo
FindWindowA
SetForegroundWindow


and so on when the program first starts. When this is done, the program calls "init_main_wnd":

call init_main_wnd

If this fails, we do a whole bunch of error checks to find out what wen't wrong (can't register window class, etc) and bail out.

Now at the beginning of init_main_wnd, we have:

Code:

.text:00415C10 push ebp
.text:00415C11 mov ebp, esp
.text:00415C13 sub esp, 30h
.text:00415C16 mov [ebp+WNDCLASSEX.cbClsExtra], 0
.text:00415C1D mov [ebp+WNDCLASSEX.cbSize], 30h
.text:00415C24 mov [ebp+WNDCLASSEX.cbWndExtra], 0
.text:00415C2B push 0Fh ; nIndex
.text:00415C2D call GetSysColorBrush
.text:00415C33 mov [ebp+WNDCLASSEX.hbrBackground], eax
.text:00415C36 push 7F00h ; lpCursorName
.text:00415C3B push 0 ; hInstance
.text:00415C3D call LoadCursorA
.
.
.

And so on. Later, we have:

Code:

.text:00415C79 mov [ebp+WNDCLASSEX.hInstance], edx
.text:00415C7C mov [ebp+WNDCLASSEX.lpfnWndProc], offset msg_handler

Which is important, since this is our message pump.

In msg_handler, we have a long series of:

cmp [ebp+Msg_], some_msg_here
jxx handler


Then later, we have:

.text:00416D9F cmp [ebp+Msg_], WM_COMMAND
.text:00416DA9 jz button


This is the code that compares the msg with 111h and handles the case for *any* button. Because there is more than just one, when we follow the jz, we have:

Code:

.text:00416E71 button: ; CODE XREF: msg_handler+49j
.text:00416E71 mov ecx, ds:lpParameter
.text:00416E77 mov edx, [ebp+arg_C]
.text:00416E7A cmp edx, [ecx+320h]
.text:00416E80 jnz usrname_btn
.text:00416E86 cmp ds:dword_4377D8, 0
.text:00416E8D jnz stop_btn
.text:00416E93 mov [ebp+var_4], 0
.text:00416E9A jmp short start_btn

Here we finally find the handler we need, "start_btn".

"start_btn" jumps to a chunk of code that creates a new thread:

Code:

.text:00416ECD push ecx ; lpThreadId
.text:00416ECE push 0 ; dwCreationFlags
.text:00416ED0 mov edx, ds:lpParameter
.text:00416ED6 push edx ; lpParameter
.text:00416ED7 push offset cthread ; lpStartAddress
.text:00416EDC push 0 ; dwStackSize
.text:00416EDE push 0 ; lpThreadAttributes
.text:00416EE0 call CreateThread

At offset "cthread", we have the proc that calls the actual computation routines for the thread.

Code:

.text:00417B20 cthread proc near ; DATA XREF: msg_handler+177o
.text:00417B20
.text:00417B20 arg_0 = dword ptr 8
.text:00417B20
.text:00417B20 push ebp
.text:00417B21 mov ebp, esp
.text:00417B23 mov eax, [ebp+arg_0]
.text:00417B26 push eax
.text:00417B27 call sub_401B10
.text:00417B2C add esp, 4
.text:00417B2F xor eax, eax
.text:00417B31 pop ebp
.text:00417B32 retn 4
.text:00417B32 cthread endp

From there on, we get into FP code which doesn't interest us.

I've tried patching absolute jumps to various pieces of code at various locations in order to achieve this result, but I've been unsuccessful -- my program always crashes or errors out. What is the proper method to achieve something like this, and where should I put it?

Kayaker
January 10th, 2003, 01:34
Hiya

These are buttons on a window as opposed to a dialog, and not toolbar buttons? I assume they're ownerdrawn with the 'BUTTON' class then, you don't see that too often, I've only seen examples. In either case you might be able to handle it with the same strategy of sending a wm_command message with the control ID of the button, sometime during startup but after the button has been created. Even if this is a created button, I think GetDlgCtrlID will still get you the control ID if you pass it the hwnd of the button. Or you might be able to send wm_lbuttondown/up directly to the control hwnd which should initiate the wm_command message you need.

You might be able to dispense with all that and just invoke your own CreateThread with the pointer to the thread function that's going to be called anyway once you press the button. Once the thread is created it should return to wherever you called it from so (hopefully) you shouldn't have any stack crashes. Making sure you preserve any CloseHandle (hThread) / ExitThread calls. Since all you really want to do is have this code run automatically this might be the most direct route. I think a small patch with a few lines of your own code is in order

Cheers,
Kayaker

Nebob
January 10th, 2003, 04:40
Truth is, I'm not entirely sure. It *looks* like a dialog to me, but the code seems to indicate that it's a window. Would the fact that I can't find any resource files for the dialog/window indicate that it was created through code instead of a resource compiler? I guess it doesn't really matter. The button is not on a menu; in fact, it's just a regular pushbutton that you'd find on a dialog or property page.

The "directly calling createthread" approach was the first one I tried. Unfortunately, that doesn't work for this reason: when you click the button, it doesn't only start a new thread -- instead, it starts timers, updates displays and toggles it's own caption from start to stop. If I bypass all that, the program doesn't work correctly.

Sending a WM_COMMAND to the button has its problems as well. The window between the button's creation and the entry to the main translate/dispatch loop is extremely small and doesn't seem to offer me any opportunity to insert additional code. I considered creating a new section in the file, but code injection is admittedly something I'm very hazy on.

Two questions: Can code snippet creator help me with this?

and

Is it possible to write a small external utility that starts the process, waits for the right time, sends the message then terminates itself? What are the functions that I would need? (I can RTFM myself )

ZaiRoN
January 10th, 2003, 13:18
Hi Nebob,
Quote:
I considered creating a new section in the file, but code injection is admittedly something I'm very hazy on...Can code snippet creator help me with this?
I suggest you to use Code Snippet Creator. It's *maybe* the most powerful tool for add code: the only thing you have to do is ...to write the needed code. Everything else is up to CSC. Use this little tool is very simple, it has also a good help. However, in the mini project area, there is a thread developed by Kayaker (that has stolen the idea to me ahahah ) to learn to use CSC:
Code Injection with Code Snippet Creator: W32Dasm + Mouse Wheel support (http://www.woodmann.net/forum/showthread.php?threadid=4089)
You may try to do the project and see how it's easy to add code.
Quote:
Is it possible to write a small external utility that starts the process, waits for the right time, sends the message then terminates itself? What are the functions that I would need? (I can RTFM myself )
Writing a kind of loader you should solve the problem.
Fundamentally, you have to follow these steps:
1) Create and run the process using CreateProcess.
2) Wait until the application is not totally loaded using WaitForInputIdle function.

Your dialog is now loaded and you have to send the right message.

3) First of all you need to know the handle of the dialog and then, the handle of the button.
You can use FindWindow (or FindWindowEx) to retrieve the handle of the process and, GetDlgItem to retrieve the handle of the button.
4) After that, you have only need to send the message: SendMessage, handle_button, WM_LBUTTONDOWN, 0, 0

Basically, I think, it's all you need to solve the problem.
To use this function is very easy; check them in Windows32 Programming Reference or at MSDN. Of course, if you have problem, tell us.

regards,
ZaiRoN

Nebob
January 10th, 2003, 13:44
Final edit:

I used ZaiRoN's solution.

CreateProcess() -> WaitForInputIdle() -> FindWindow() to find the main window -> FindWindowEx() to find the button -> SendMessage(WM_LMOUSEDOWN) -> SendMessage(WM_LMOUSEUP)

Works like a treat. Thanks for all your help.