Process Viewer 1.0.7.0

(UPDATED on 18/09/2008)
    Added: Child Windows on Window Tooltip, Opacity setting for Tooltip Window
(UPDATED on 15/09/2008)
    Added: Window Tooltip, shows window information during 'Find Window' 
(UPDATED on 09/09/2008)
    Added: Modifications and ModifiedMsg added to the Breakpoints.
    Modification: Indicates that which sections of the message will be modified if the Action is AutoChangeParameters.
    ModifiedMsg: If a breakpoint's action is AutoChangeParameters and Modification has the Message bit,
                          then PV will change the incoming message to the given message.
                          For ex: You can change the WM_LBUTTONDOWN to WM_RBUTTONDOWN automatically for the target window.
    Multilanguage: (English, Turkish)

Process Viewer 1.0.7.0 (PV) is ready to download. Download Source Codes | Watch Sample Movie (v1.0.5.0)
Below I try to explain what is PV and how it is working. Also I put some screenshots of the PV.
Breakpoints management window

I finished PV 2 days ago, but I was really very sleepy (it was about 4 AM and I had to go to work in the morning) so I postpone this writing to a later time. Anyway today I have some time to write something about PV. What it is? What it is for? How it works?
First I will explain what PV is then I will try to explain its codes a little bit more.

 What is PV?

I can say that PV is a program like Microsoft Spy++. Unlikely to Spy++ it allows you to edit some properties of the Controls and also allows you to manage its window messages. You can change Text, Visibility, Enabled, Window Styles and Window Ex Styles properties of a control by using PV during runtime. Therewithal you can ignore window messages, change incoming message to a different message or edit parameters of any window messages by putting breakpoints to the control’s window procedure with PV.



How can I use PV?
It is really very simple to use PV. Run PV.exe and you will see the active Processes, currently running in your desktop, in the Windows List at the left of the program. Expand any process which you are interested in. You will see the Windows (Controls) which are belong to that process in a hierarchical list. Whenever you select a Window from the list PV will highlight its area in the screen even the window is not visible at the moment. If a Window is a container window which contains inner windows in it you will see inner windows under the owner (parent) window node, so you can expand parent window and see inner windows of it.

There is also Find Window button at the top of the PV which will help you to find Controls and select them easily. Just click to the Find Window button and Drag it over the Controls while you are pushing the Left mouse button. PV will highlight the Control region which mouse currently on it. To select a window, release mouse button when the mouse cursor is on that control. Window will be selected automatically in the Windows List. If window is not in the list (this might be, because PV generates Windows List while it is opening so if the window you try to select was created after you opened PV then this window won't be in the list), PV will shows an alert to you that the window is not in the windows list at the moment, if you chose “Yes” button it will automatically refreshes the Windows List and finds your control.

When you select a window from the windows list you will see its properties in the PropertyGrid at the right. You can change Visible, Enabled, Text, WindowStyles and WindowExStyles properties of that window by using PropertyGrid. Also you can change the window’s Bounds, Size and Location by the same way. If you wish to see the Messages of that control, click to the Listen Messages button at the top toolbar. A panel which contains a TextBox will appear at the bottom of the PV which will shows you the messages of that control. If you want to put breakpoints to the current window’s message procedure click to the Edit Breakpoints button. Breakpoint Management window will be shown and you can add breakpoints to that window by using this window. Select a window message from the list (you can filter messages by writing your message name to the filter textbox) to see breakpoint properties for that message. Select your action (None, Ignore, Manuel Edit, Auto Change) by using PropertyGrid for the selected message(s). You can do same things for the other messages which you are interested in. To remove a message breakpoint just set its action to “None”. After you finished you can close the Breakpoints window by clicking “Okey” button. From now on your breakpoints will be activated and whenever a message, which you define an action for that, arrives to that window PV will do the action which you select for that message.

For example; If you chose WM_LBUTTONDOWN, which system sends to the control when mouse left button is down on that control, from the message list and select ‘Ignore’ action then WM_LBUTTONDOWN message will never send to the control. Or if you choose ManuelEditParameters action for the WM_LBUTTONDOWN then PV will shows you Edit Parameters Window to choose your action against this message when this message arrives to the control. Either you can ignore this message or you can change the wParam and lParam parameters of the message. WPARAM (4 bytes) and LPARAM (4 bytes) of a message contain message specific parameters and they have different meanings according to the Message. If we speak about the WM_LBUTTONDOWN message, the parameters will be;
wParam: Indicates whether various Virtual Keys (MK_LBUTTON, MK_RBUTTON, MK_CONTROL, MK_MBUTTON, MK_XBUTTON1, MK_XBUTTON2) are down. WParam can be one or more of these values.
lParam: Lo-Order of the lParam specifies the X-Coordinate of the cursor and Hi-Order of the lParam indicates the Y-Coordinate of the cursor. Here Lo-Order means first 2 bytes of the lParam and Hi-Order means the last 2 bytes of the lParam.
If you choose Manuel Edit Parameters action for the WM_LBUTTONDOWN then you can change the parameters of It whenever system sends this message to the target window. If you choose AutoChangeParameters action then PV will change wParam and lParam of that message automatically as you defined.

Examples with Breakpoints;

Example 1:
 1 – Open Visual Studio .NET
 2 – Select Main Menu of the VS.NET by using Find Window button of the PV.
 3 – Click “Listen Messages” button to start message hook for the main menu
 4 – Click “Edit Breakpoints” button to set breakpoints
 5 – Select WM_LBUTTONDOWN from the message list and select AutoChangeParameters action for this message.
       Set Modifications to the WParam and LParam (Indicates PV will modify only WParam and LParam of a message before it send to the hooked window)
       Set XParam to the 1 (LoWord:1, HiWord:0) and LParam to the 851998 (LoWord:30, HiWord:13). Click Okey button.
 6 – Click anywhere in the Main Menu, you will see that always File menu is shown.
This is because PV change the LParam to the HiWord:13 and LoWord:30 which means (X=30, Y=13) the cursor position is over the File menu. So main menu opens File menu always because it thinks that File menu has been clicked.

Example 2:
1 – Open Visual Studio .NET
 2 – Select Main Menu of the VS.NET by using Find Window button of the PV.
 3 – Click “Listen Messages” button to start message hook for the main menu
 4 – Click “Edit Breakpoints” button to set breakpoints
 5 – Select WM_LBUTTONDOWN from the message list and select AutoChangeParameters action for this message.
       Set Modifications to the Message and set ModifiedMsg to the WM_RBUTTONDOWN. Click Okey button to set the breakpoints.
 6 – Click anywhere in the Main Menu, you will see that even you click to the Left button of the mouse the main menu always opens its Context Menu.
This is because PV change the WM_LBUTTONDOWN message to he WM_RBUTTONDOWN.




I think this is enough for “How We Use PV?” Let us speak about the “How PV do this?”
We can split this question in to two sections. One is “How PV finds Windows?” and second is “How PV Listens and Edit Messages of a Control?”
For the first question PV uses EnumChildWindows method to enumerate child windows of a Window. It first tries to find the Desktop Window’s child windows and then it finds the inner windows. After it finds the windows, it uses GetClassName, GetWindowThreadProcessId and GetParent methods to find the ClassName, ProcessId, ThreadId and Parent Window Handle of these windows. 



For the second question “How PV Listen and Edit Messages of a Control?”; it is a little bit harder than the first section. To make this, first I wrote a C++ (Native) dll which sets hook on WH_CALLWNDPROC for the given window’s thread. Why I wrote this dll with C++? Actually listening a control’s Windows Messages, is simple. Every control has a Window Procedure method which system sends messages to that method. We can learn the address of this method by using GetWindowLong method with the GWL_WNDPROC option. To change the window procedure method of a control is also very simple;
SetWindowLong(windowHandle, GWL_WNDPROC, [our procedure Method]). By using this method we can replace the message procedure method of a control to our method. So whenever system sends a message to this control it will comes to our method and we can do anything we want in this method. To redirect this message to the original window procedure, we can use CallWindowProc function. But the problem with this is; SetWindowLong method works only for the windows which are belongs to same process. It means that we can use this method for the controls which are in the same process with us. So if we want to change windows procedure of a control we have to be in the same process. How we can handle this problem? To handle this problem I wrote a native dll which will be injected to the target process and we will run the SetWindowLong function from that dll within the target process. Injecting a dll to another application is also a pain for us. There are some solutions for this problem;
1 – We can use SetWindowsHookEx method to set a WH_CALLWNDPROC hook. By setting a hook Windows will automatically Loads our hook dll to all processes. But the problem with this method is, we don’t know the target process is .NET or not. So we have to write a native dll for this hook operation. Because if the target process is not .NET this means there is no CLR attached to that process and our .NET dll won’t be worked within this process. When we call SetWindowsHookEx function systems attach the dll, which contains the hook method, to all processes. At this point; you have to know that for each process, system creates a new instance of our dll and attach it to every process.
2 – LoadLibrary method which is in kernel32.dll loads a library to the caller application. So if we make a call to that function within the target process we can load our library to the target application. How we can call LoadLibrary function within another application? To solve this problem we can use CreateRemoteThread function which is in the kernel32.dll. CreateRemoteThread function creates a remote thread within a given process and runs the given method. To use CreateRemoteThread function we have to also know the address of the target method which we want to run in the target processes memory block. Actually this is hard to find the address of a function in a remote application. GetProcAddress function returns the address of a method, but when we call this method this will be the address of that method within our application because again GetProcAddress will return the address of the function according to the caller process memory. But here is a good trick with the LoadLibrary. LoadLibrary method is in the kernel32.dll and kernel32.dll will always load to the same address for all the windows applications according to nature of windows. So if we take the address of the LoadLibrary function within our application’s memory, this address also will be same for other applications too. So we can take the address of the LoadLibrary and call this method by using CreateRemoteThread method within target process. This will load our dll to the target procedure.

Anyway there are too many details about dll injection so I pass it simply for now. May be we can talk about this later more detailed. In PV I have been used the first way to make dll injection. I wrote a C++ (Native) dll which starts WH_CALLWNDPROC hook on the target process. WH_CALLWNDPROC installs a hook procedure which monitors the messages before the system sends them to the destination window. When the first time that system sends a message to our target window we changed the target window’s message procedure method by using SetWindowLong function. Actually we are using hook operation for two cases; one is injecting our native dll to the target process and second triggering procedure changing method (calling SetWindowLong) from that dll. Therefore SetWindowLong function will be called by the target process. As I said above we can do this in some different ways but I chose this way. Because this way needs less native codes than the others and I want to write less native codes in this example.

// In the PV
[DllImport("ProcessViewer.Hooks.dll")]
public static extern int StartHook(IntPtr hWnd, IntPtr notifyWindow);
 
[DllImport("ProcessViewer.Hooks.dll")]
public static extern void EndHook();

// In the native dll

PROCESSVIEWERHOOKS_API int WINAPI StartHook(HWND hWnd, HWND notifyParent)
{
       originalWindowProcedure = 0;
 
       // Load our libary and get its handle
       HINSTANCE phookDll = LoadLibrary((LPCTSTR)_T("ProcessViewer.Hooks.dll"));
 
       EndHook();
 
       hookWindow = hWnd;
       notifyWindow = notifyParent;
 
       // get Thread Id of the Window, which we will hook
       DWORD threadId = GetWindowThreadProcessId(hWnd, NULL);
       // get address of our Hook method in this dll
       HOOKPROC proc = (HOOKPROC)GetProcAddress(phookDll, "MessageHookProcedure");
       // set Hook (This will injects our dll in to all process
       // which are created by the given thread)
       hhk = SetWindowsHookEx(WH_CALLWNDPROC,
                                               proc,
                                               phookDll,
                                               threadId);
 
       return (DWORD)hhk;
}


// this is our WH_CALLWNDPROC hook method
LRESULT CALLBACK MessageHookProcedure(int nCode, WPARAM wParam, LPARAM lParam)
{
       if (originalWindowProcedure == 0)
       {
             // the first time this method is called
             // for the our hooked window, replace its window procedure
             // to our procedure method
             // do this just for the control which we wnat to listen its messages
             CWPSTRUCT* str = (CWPSTRUCT*)lParam;
             if (str->hwnd == hookWindow)
             {
                    // take original windows procedure of this control
                    originalWindowProcedure = GetWindowLong(hookWindow, GWL_WNDPROC);
                    // set new windows procedure
                    SetWindowLong(hookWindow, GWL_WNDPROC, (LONG)OnMessage);
             }
       }
       return CallNextHookEx(hhk, nCode, wParam, lParam);
}

// ends hook operation
PROCESSVIEWERHOOKS_API void WINAPI EndHook()
{
       // if we have been taken procedure of the window,
       // set its procedure to the its original
       if (originalWindowProcedure)
             SetWindowLong(hookWindow, GWL_WNDPROC, originalWindowProcedure);
       if (hhk != NULL)
             UnhookWindowsHookEx(hhk);
       originalWindowProcedure = 0;
       hhk = NULL;
}

From now on any message that system sends to the target window will come to our method because system thinks that window procedure method for that control is our method. Now we need to send this message to the PV to process it. At this point I used VM_COPYDATA message to transfer message to the PV. But to whom I will send this message? I wrote a Listener Control in the PV and I pass its handle to the hook dll while PV starts the hook operation. Hook dll sets this passed handle to a shared variable in it. This way every instance of the native dll has the same value for that variable. So native dll in the target process also has the same variable which holds our listener controls handle. From the native dll which handles the target window’s messages I redirect messages to the Listener Control which is in the PV. Whenever a new WM_COPYDATA messages send to the Listener Control it resolves the original message from the LParam of that message and process it according to our Breakpoints. LParam of the WM_COPYDATA message contains a COPYDATASTRUCT which has original message in it is lpData field.

private class ListenerControl : Control
{
       static int HM_MESSAGE_RESULT;
 
       public ListenerControl()
       {
             HM_MESSAGE_RESULT = NativeMethods.RegisterWindowMessage(
                                                        "ProcessViewer_MessageResult");

             Parent = MainForm;
       }
 
       protected override void WndProc(ref Message m)
       {
             if (m.Msg == (int)NativeMethods.Msgs.WM_COPYDATA)
             {
                    // message was sended by ProcessViewer.Hooks.dll from the Hooked application when
                    // a new message comes to that window
 
                    // LPARAM of this message contains a COPYDATASTRUCT which has HOOK_MSG struct in it
                    NativeMethods.COPYDATASTRUCT cdata = 
                           (NativeMethods.COPYDATASTRUCT)m.GetLParam(
                                             typeof(NativeMethods.COPYDATASTRUCT));
                    // This is the information of the message which is sended to the hooked window
                    NativeMethods.HOOK_MSG msg = (NativeMethods.HOOK_MSG)
                                             Marshal.PtrToStructure(cdata.lpData,
                                                  typeof(NativeMethods.HOOK_MSG));
 
                    // process message and set its result (0 ignore, 1 do nothing,
                    // other values replace parameters)
                    m.Result = MainForm._SubClass.ProcessMessage(m.WParam, ref msg);
                    Marshal.DestroyStructure(m.LParam, typeof(NativeMethods.COPYDATASTRUCT));
             }
             else if (m.Msg == HM_MESSAGE_RESULT 
                    && Properties.Settings.Default.HandleMessageResults)
             {
                    // this message sended by hooked window to give
                    // information about the result of a message
                    MainForm._SubClass.ProcessMessageResult(m.WParam.ToInt32(), m.LParam);
             }
             else
             {
                    base.WndProc(ref m);
             }
       }
}



While PV processing message native dll is waiting for the result and does its action according to this result which comes from the PV. If we don’t have a breakpoint for that message PV returns 1 which means “send message to the original window procedure”.  If we have a breakpoint for this message which the action is “Ignore message”, then PV returns 0 to the native dll and it ignores that message. The hard section of breakpoints is what if we have the “Edit Parameters Manually“ or “Auto Change Parameters” actions for that message. It is hard because we need to transfer changed parameters to the native dll which is running in the target application. We solve this problem by allocating a memory block in the target applications memory by using VirtualAllocEx function. Then we write our changed values to that block by using WriteProcessMemory function. These functions allow us to allocate a memory block in the target application memory block and write to this block. Now we have the address of that memory so we can pass this address to the native dll as the address of new wParam and lParam values. If native dll takes a return value differs from 1 and 0 it knows that this is a memory address which contains new wParam and lParam values. So it reads new values of the parameters from this address and redirects message to the original window procedure by using these parameters. This way we changed the parameters of the message. We can also use this WriteProcessMemory and VirtualAllocEx methods to transfer message from native dll to PV instead of using VM_COPYDATA. But I transfer data by using VM_COPYDATA because VM_COPYDATA message is for transferring data between two processes. Why I don’t use WM_COPYDATA message for transferring result of the message from PV to the native dll instead of using WriteProcessMemory function? The answer is simple. Because I send the incoming message to the PV, by using SendMessage function from window procedure method in the native dll. Thread which calls the SendMessage function will block until it takes a result. So if I try to send return value by using SendMessage to the target window this will be a deadlock.

IntPtr WriteToTargetProcessMemory(IntPtr wParam, IntPtr lParam, NativeMethods.Msgs modifiedMsg)
{
       // Open hooked window's process
       IntPtr hProcess = NativeMethods.OpenProcess( 
                                                 NativeMethods.PROCESS_VM_OPERATION 
                                                 | NativeMethods.PROCESS_VM_READ 
                                                 | NativeMethods.PROCESS_VM_WRITE,
                                                 false, _Window.ProcessId);
       // allocate memory from target proces's memory block
       // 12 bytes : 4 modified msg + 4 wParam + 4 lParam
       IntPtr memAddress = NativeMethods.VirtualAllocEx(hProcess, IntPtr.Zero, 
             12, NativeMethods.MEM_COMMIT, 
             NativeMethods.PAGE_READWRITE);
       if (memAddress == IntPtr.Zero)
             return IntPtr.Zero;
 
       int written = 0;
       // write our new parameter values to the tarhet process memory
       bool hr = NativeMethods.WriteProcessMemory(hProcess, memAddress, 
                                                  new int[] {(int)modifiedMsg, wParam.ToInt32(), 
                                                              lParam.ToInt32()}, 
                                                      12, out written);
       // close handle
       NativeMethods.CloseHandle(hProcess);
 
       if (!hr)
             return IntPtr.Zero;
       return memAddress;
}


// In the native dll
// new window procedure for the selected window
LRESULT CALLBACK OnMessage(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
       // prepare message information, for sending it to our ProcessViewer program
       HOOK_MSG message;
       message.msg = msg;
       message.wParam = wParam;
       message.lParam = lParam;
 
       // this is for the WM_COPYDATA message,
       // WM_COPYDATA transfers data between 2 process by using this structure
       COPYDATASTRUCT cdata;
       cdata.dwData = 0;
       cdata.cbData = sizeof(message);
       cdata.lpData = &message;
 
 
       // send a WM_COPYDATA to our ProcessViewer which will give information about the message
       // to our program
       LRESULT result = SendMessage(notifyWindow, WM_COPYDATA, (WPARAM)hWnd, (LPARAM)&cdata);
       // return values, 1: ignore message, 0 do nothing,
 
      // different from 0 and 1 : memory address of data which contains the changed wParam and lParam
       if (result == 1)
             return 0;
       if (result != 0)
       {
             // if result is not 0 or 1
             // this means we are going to change the wParam and lParam
             // which we write new values of these variables to the
             // address (result indicates this address) in the hooked program's memory
             HOOK_RESULT* hr = (HOOK_RESULT*)result;
             msg = hr->msg;
             wParam = hr->wParam;
             lParam = hr->lParam;
       }
       // send message to original window procedure
       LRESULT ret = CallWindowProc((WNDPROC)originalWindowProcedure, hWnd, msg, wParam, lParam);
       // send message to the ProcessViewer application which 
       // give information about the result of the message
       SendMessage(notifyWindow, HM_MESSAGE_RESULT, msg, ret);
       return ret;
}

This is simply how PV works. Of course we can write this procedure in different ways but as I said above I’m trying to write this example by using .NET.

Anyway it is just a two night’s code and I think it is a good start for Spying windows. Have fun!!!


Related posts

Comments

September 6. 2008 07:35 AM

Özcanım, eline emeğine sağlık benim gibi hook işlemlerine meraklı öğrenmek isteyenler için güzel bir açık kaynak kod projesi bu, Artık bize düşen bunu bir aım daha öteye götürmeye çalışmaktır (:
Eray
September 8. 2008 10:50 PM

Elinize sağlık. Gayet temiz ve güzel bir ürün olmuş.
Muhammed Tahiroğlu
September 9. 2008 01:39 AM

Tesekkur ederim. Kisa zamanda ancak bu kadar oldu. Yavas yavas saniyorum gelisecektir. Elbette baskalarinin da katkilari ile. Yeni bir versiyon yukledim bugun. Bu sayede artik Hook edilen window a gelen herhangi bir mesaji degistirebiliyoruz. Ornegi bir window a gelen WM_LBUTTONDOWN i WM_RBUTTONDOWN a cevir diyebiliyoruz. Yeni versiyonlar oldukca yuklemeye devam edecegim.

Iyi calismalar

Ozcan DEGIRMENCI
October 7. 2008 05:08 PM

Özcan selam,
bence çok kullanışlı bir uygulama. Tabii belli konularda uzmanlaşmış olanlar için. Ama bir noktaya kadar gelenleri de bir adım öteye zıplatacak kadar faydalı bence.

Kim tutar seni Tong

Erkal
October 7. 2008 05:16 PM

Tesekkurler Erkal.

Ya valla su anda cok yogunum, o nedenle ilgilenemiyorum ama yakinda yeni bir versiyon cikartacagim. O versiyonda hangi process in hangi handle lari var (ornegin hangi dosyalari o anda kullaniyor falan filan) goruntulenebilecek. Ama dedigim gibi su yogunluktan bir kurtulayim da sonrasinda artik.

Ozcan DEGIRMENCI
October 15. 2008 07:06 PM

Hello Ozcan,
I'm a C# programmer, before that in vocational school I used Basic, Pascal, Delphi but not C or C++ because of the teacher's unhonest attitude towards the educational system, he has to teach it but cheated the system and especially us.

I've programmed a Process Viewer according to my needs but this is more detailed. I don't know C++, so I cannot program one as yours. To tell you the truth, I have no ambition to learn it. I wanted to learn C++ a few years ago but couldn't find time. At the moment I can do whatever I want by using C# so I have no desire to learn it but I wonder what kind of enhancement does the C++ part apply to your Process Viewer and to programs in general? You described it in your article as "I wrote a C++ (Native) dll which starts WH_CALLWNDPROC hook on the target process. WH_CALLWNDPROC installs a hook procedure which monitors the messages before the system sends them to the destination window. When the first time that system sends a message to our target window we changed the target window’s message procedure method by using SetWindowLong function." We can do its functionality in a function before sending the messages to the destination window. So this description has not satisfied me. I know the importance of C++ and its being nearer to the machine language in the Programmming Languages Tree -as a family tree- and so I know that a programmer knowing C/C++ can do whatever he/she wants but the question is still in my mind: What kind of enhancement does the C++ part apply to your Process Viewer and to programs in general?

Thanks,
Ada

Ada
October 16. 2008 08:49 AM

Merhaba Ada,

Oncelikle sen cok guzel ingilizce sormussun ama ben soruna turkce yanit verecegim. Senin turk oldugunu bildigim icin. Cunku bu konuyu aslinda yukardaki makalede aciklamaya calistim (neden C++ la yazdigimi o kismi) ancak benim ingilizcem cok iyi olmadigi icin cok anlatamamis olabilirim. O nedenle bir de turkce deneyelim.

Dogrudur sen aklindaki bir cok seyi C++'a gerek duymaksizin C# lada yapabiliyorsundur. Ancak bu tabii birazda ihtiyaclarla alakali. Bazi durumlarda ne yazikki .NET gibi virtual machine gerektiren diller bizim istedigimiz seyi bize yaptirmayabilir, yada belkide yaptirir ancak performans yada baska bir kriter acisindan ortaya cikan urun cokda verimli olmayabilir.

Ornegin ben neden ProcessViewer.Hooks.dll inini C++ la yazdim ? Cunku burada asil amacim su; kisaca;

Secilen window'un Mesaj procedure metohodunu degistirip onun yerine kendi yazdigim bir metoda yonlendirmek istedim. Bu sayede o window'a gelen mesajlari kontrol edebilirim. Bunun icin de user32.dll api sindeki SetWindowLong metodunu GWL_WNDPROC paramtresi gecerek kullanmak istedim. Ama sorun su; SetWindowLong sadece ayni process icindeki windowlar icin kullanilabilinir. Yani sole dusun, ben sadece bunu kendi exe'm icindeki window lar icin kullanabilirim. Ama benim istedigim sistemde bulunan tum window'lar icin SetWindowLong u calistirmak. Boylelikle size ornegin Explorer icindeki bir window(control) u secip bana bunun mesajlarini goster yada su mesaja breakpoint koyun dediginizde ben o explorer processi icindeki bir window'un da procedure metodunu degistirip benim kendi exe'm icindeki bir metoda yonlendirmek. Simdi bunu nasil yapacagiz peki ? SetWindowLong sadece o anda calistigi exe'nin windowlarina ulasabiliyor. Bu durumda ben SetWindowLong u eger explorer icinde calistirabilirsem bu durumda oradaki bir window'unda procedure'unu degistirebilirim.

Her neyse bunun icinde benim yapmam gereken o hedef exe icerisine kendime ait bir dll enjecte etmek, daha sonra o dll icinde SetWindowLong u o exe icindeki bir window icin cagirmak ki bunu da o process e yaptirmak lazim ki SetWindowLong o process tarafindan calistirildigi icin SetWindowLong la secilen window'un mesaj procedure u degistirilebilsin.

Burada dll injection dedigimiz baska bir application icine dll enjecte etmek icin bir kac yol var ben onlardan SetWindowHookEx i kullandim. Sisteme (aslinda secilen window'u yaratan thread icin) WH_CALLWNDPROC Hook u set ettim. Bu durumda isletim sistemi benim yerime o Thread tarafindan calistirilan windowlarin processlerine otomatikman benim dll imi gomdu. Iste burada onemli nokta su; eger ben ProcessViewer.Hooks.dll ini .NET le yazmis olsa idim nolacakti?

Hook set ettigimde isletim sistemi benim .NET dll imi alacak ve target process e(ki yukardaki ornekte explorer) enjecte edecekti. Hali ile benim dll'im de orada calisacakti. Peki bir .NET dll i kim tarafindan calistirilir? Calismasi icin ne gerekir? .NET dll leri bildigimiz normal dll ler gibi davranamaz. Onlar iclerinde hala makina diline cevrilmemis kod barindiran ve calismak icin destege ihtiyac duyan dll lerdir. Iste burada devreye CLR girer. CLR'nin sorumlulugu bir process icinde eger .net varsa o process'e attach olup orada o dll'in calismasini saglamak. Kisaca tabii Smile. Hali ile burada ki ornekte explorer process i icerisinde CLR attach edilmis midir? Muhtemelen hayir. Cunku explorer tahminen C++ la yazilmis, .NET olmadigi icinde CLR yi attach etmeden calisan bir process. Hali ile orada CLR yok. Bu nedenle benim kendi .NET le yazdigim hook dll im (ki o process icinde calisip benim adima bazi islemler yapicak) o exe ye yuklendigi an cakilacaktir.

Sebebide o exe icinde CLR olmamasi. Ha CLR yi ona yukleyemezmisin ? Tabii yuklersin. Biraz ugrasirsin CLR attach edersin ivir zivir. Bunun da yollari var. Ama sonucta bu kulagi uzun yoldan tutmak olur. Onun yerine direk makina diline ceviren bir dille hook dll ini yazarsak bu sorunlarla ugrasmayiz. Cunku dll imiz zaten native oldugu icin icine enjecte edildigi tum process lerde calisabilir, ki bizim de burada istedigimiz bu.

Biraz uzun ve saniyorum yine karisik oldu ama, isin ozeti bu sekilde. Simdi bu sadece bir ornek bunun gibi daha bir cok yerde C++ gibi bir dil kullanmak bize oldukca kolayliklar saglayacaktir.

C++ ve C direk makina resourcelarina erisebilecegimiz, kontrolun cogunun programcida oldugu (ozellikle C) dillerdir. Sole dusun memory de istedigimiz gibi at kosturuyoruz. Bunu ne yazikki C# da yapmak biraz riskli ve maliyetli. Ha C# dada pointerlar var, direk memory allocation var ivir zivir ama emin ol butun bu islemler C++ dakilerle yarisamayacak kadar zayif. Zaten o islemleri arka planda yapan kodlar da C++ Smile. Ornegin Marshal.AllocHGlobal diyerek processimizin unmanaged memorysinde bir alan i allocate edebilir. Onu istedigimiz gibi kullanir sonrada geri birakiriz. Ama sonucta bu islemi yapan kodda C ile yazilmis Smile. Yani kernel32.dll deki LocalAlloc procedure'u.

Daha bunun gibi bir cok detay vardir.
Ama sonuc olarak temel sey su (bence); .NET'in dogasi geregi calisabilmesi icin bir baska seye (ornegin windows isletim sistemleri icin CLR) gereklidir. O onun exception management, memory management ..... ivir zivir butun bu islemlerini CLR tarafindan yonetilir. Ancak C++ yada C ile yazilan kodlar icin bu bu sekilde degildir.

Bunun haricinde belki 100 lerce irili ufakli farklilik elbette var. Ornegin C++ da birden fazla sinifdan inheritance varken, .NET te bir sinif sadece tek bir sinifdan tureyebilir gibi, bunlari burada saymiyorum bile. Cunku bu tip seyler baska cozumlerle asilabilir. Aralarinda en temel fark asilamayacak yukardaki yazdigimdir.

Sana tavsiyem C, C++ i kesinlikle birakma. C# oldukca guclu ve daha da guclenecek. Ama C, C++ bilmek sana her zmaan daha buyuk avantajlar getirecektir. Yazmasi biraz daha zor olmasina rahmen bazi durumlarda inanilmaz kolaylik ve guc saglar.

Iyi calismalar

Ozcan DEGIRMENCI
October 16. 2008 10:06 AM

(Y)
Eray
October 16. 2008 12:13 PM

Çok teşekkürler. Benim de farkında olduğum ama saydığım nedenlerle hevesim geçtiği ve C# C/C++'da programlama yapmak daha az zaman aldığı için "C/C++ bilmesen de olur" diyordum kendime. Öğrenmek için önce o isteğin önce gelmesi gerek.
Yazı herkes okuyabilsin diye İngilizce olduğu için ben de İngilizce sormuştum; ama Eray'ın (Y) yorumu ne anlama geliyor anlayamadım.

Ada
October 16. 2008 12:49 PM

(Y) msn de baktigima gore okey anlamina gelen el isareti.

Neyse C++, C bunlar kesinlikle birakilmamasi gereken diller ve kesinlikle insanlarin ogrenmesi gereken diller diye dusunuyorum. Cunku onlarin bizelere sagladigi bir cok avantaj var. Sadece biz su anda yapmis oldugumuz islerimizde .NET bize yeterli oldugu icin bu yanilsamaya kapiliyoruz. Ama yazilim sektoru sadece bizim yaptigimiz, web, windows programlarindan ibaret degil. Cok daha komplike kapsamli islerde bazen sadece bu diller belki daha alt seviyede dillere bile ihtiyac duydugumuz olacaktir.

Ama tabii bunu derken sunu da kacirmamak lazim; Her seyde uzmanlasmak mumkun degildir, o nedenle kendi is alaniniza gore bir dil secip onda uzman olun. Digerlerindende bir seyler ogrenin onlarida bir kenara birakmayin. Ancak C/C++ la herseyi yapabiliriz deyip tamamiyle o yone kaymakda hatali olacaktir. Cunku o dillerinde .NET e gore dezavantajlari var (zaman maliyeti, gelistirm zorlugu gibi) bu nedenle ozellikle turkiyede bulunan yazilim sektoru tarafindan cok tercih edilmezler.

Ozcan DEGIRMENCI
October 16. 2008 02:18 PM

Ada' ya soruyu sorduğu için
Özcan'a detaylı olarak anlattığı için teşekkür etmek istemiştim
(Y) nin burda anlamı bu idi (:
saygılar.

Eray
October 21. 2008 09:20 AM

IM kullanmadığımdan ötürü IM dilinde (: ve ): haricindeki emotion'ların kısaltmasını bilmediğim için sadece ne anlama geldiğini sormuştum.
Bana teşekkür edilmesi mi, sadece Özcan'a teşekkür edilmesi gerekir (:
Ayrıca sorduğum soru C++ ile ilgili olduğu ve ben bu dili bilmediğim için makaleye konsantre olamamıştım. Makalenizde bir sorun yok, sorun benden kaynaklandı. Bu nedenle aynı açıklamayı tercüme etmek ve bu kadar detaylı Türkçe açıklamayı yoğun iş temposunun arasında yapmak zorunda bıraktığım için özür dilerim. İhtiyacım olan açıklama gönderdiğiniz postun yarısı kadar bile değildi; ancak Türkçe açıklamanızın özellikle "Sebebide o exe icinde CLR olmamasi."ndan itibaren olan kısmı İngilizce makalede uygun yerlere eklemeniz sanırım daha iyi olurdu.
Umarım C#'ın gücünün yetmeyeceği C++ kullanmamı gerektirecek bir fonksiyonaliteye ihtiyaç duyarım da C++ öğrenmeye başlarım.

Ada

Add comment


 

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

November 20. 2008 02:09 AM


Search

Calendar

<<  November 2008  >>
MonTueWedThuFriSatSun
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567
View posts in large calendar

Disclaimer

© 2007 - 2008
Ozcan DEGIRMENCI
All rights reserved. The content can be used elsewhere given that the source is properly acknowledged.