views:

483

answers:

2

I need to subclass a richedit control in a chat program (I am trying to make a musicbot). I dont know how to code in c/c++ but i was able to use c++ to inject a managed code into the chat program using CLR Hosting. But couple problems occurs. Hopefully I can get some help from here.

  1. My managed code would exit after it finished the thread. I need to keep it running
  2. When I tried to subclass the richedit control using SetWindowLong api and GWL_WNDPROC the chat program froze.

Could someone point me to a right way to do this? Or is it even possible to do this in managed code?

Thanks

+1  A: 

This sort of stuff depends on a lot of factors and can be hard to get going. Can you provide more details?

At a general level, for 1: If you are using ICLRRuntimeHost::ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument) to execute your managed code, then the managed execution will stop as soon as the method denoted by pwzMethodName finishes. If you have other tasks you want to do persistently, and don't want to have this call hang in the meantime, your best bet is to have pwzMethodName start up some program loop function on another thread.

As for 2, if you're injecting code into a target process and interacting with controls, thread safety can be a huge issue. I personally haven't used SetWindowLong api but it could be something to do with modifying controls from a non-dispatcher thread.

jeffora
Here is my c++ codehr = pClrHost->ExecuteInDefaultAppDomain(L"ClassLibrary2.dll",L"ClassLibrary2.Class1", L"Test", L"MyParameter",
Tri
Here is my C# codepublic static void Subclasshwnd(IntPtr hWnd){_WndProc = new WndProcDelegate(WndProc);_OldWndProc= SetWindowLongPtr(hWnd, GWL_WNDPROC,Marshal.GetFunctionPointerForDelegate(_WndProc));}public static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam,IntPtr lParam){System.Diagnostics.Debug.WriteLine(msg);Show(msg.ToString());return CallWindowProc(_OldWndProc, hWnd, msg, wParam, lParam);}
Tri
Like I said in my answer, ExecuteInDefaultAppDomain will exit once ClassLibrary2.Class1.Test exit. If this method is an infinite loop, ExecuteInDefaultAppDomain will be an infinite loop too essentially. If you want your ExecuteInDefaultAppDomain to return immediately, but .NET code to continue executing, you need to start a 'main' thread from the function you call in ExecuteInDefaultAppDomain
jeffora
As for your C# code, there are lots of problems you can cause when you are injecting code into a process. Is your hwnd valid? If it is invalid memory, that will crash the process. Does your delegate get garbage collected before the unmanaged code executes it? That will cause your process to crash. Controls can typically only be safely accessed from the dispatch thread, and not doing that might crash it, I'm not sure. Try attaching a debugger to get the actual exception. Also, you could edit your original post to add the code in readable format.
jeffora
A: 

Here is My C#

public class Class1
{

    [DllImport("kernel32", SetLastError = true)]
    public static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("user32.dll", SetLastError = true)]
    public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc,IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)]
    public static extern IntPtr GetWindowLongPtr32(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)]
    public static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
    public static extern int SetWindowLong32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

    [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
    public static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

    public static IntPtr GetWindowLongPtr(IntPtr hWnd, int nIndex)
    {
        if (IntPtr.Size == 8)
            return GetWindowLongPtr64(hWnd, nIndex);
        else
            return GetWindowLongPtr32(hWnd, nIndex);
    }

    public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
    {
        if (IntPtr.Size == 8)
            return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
        else
            return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong));
    }


    public delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);


    public const int GWL_WNDPROC = -4;
    public const int HWND_MESSAGE = -3;
    public const int WM_LBUTTONDOWN = 513;


    public static int Test(String pwzArgument)
    {

        f = new Form1();
        f.Show();

        Process p = Process.GetCurrentProcess();

        string s = "Name: " + p.ProcessName + "\nTitle: " + p.MainWindowTitle +  "\nHandle: " + p.MainWindowHandle.ToString();


        Show(s);

        Show("Started");
        Subclasshwnd(p.MainWindowHandle);
        //For i = 0 To 100000000
        //' Show("Loop", "")
        //Threading.Thread.CurrentThread.Sleep("10000")
        //Next
        return 1;
    }



    public static void Show(string input)
    {
        MessageBox.Show(input);
        f.Settext(input +  "\n");
    }



    public static WndProcDelegate _WndProc;
    public static IntPtr _OldWndProc;
    public static IntPtr _hWnd;
    public static Form1 f;


    public static void Subclasshwnd(IntPtr hWnd)
    {

        _WndProc = new WndProcDelegate(WndProc);
       // _OldWndProc = GetWindowLongPtr(hWnd, GWL_WNDPROC);

       _OldWndProc=  SetWindowLongPtr(hWnd, GWL_WNDPROC,Marshal.GetFunctionPointerForDelegate(_WndProc));

       // Show(_OldWndProc.ToString());
    }

    // this is the new wndproc, just show a messagebox on left button down:
    public static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam,IntPtr lParam)
    {
        System.Diagnostics.Debug.WriteLine(msg);
        Show(msg.ToString());

        return CallWindowProc(_OldWndProc, hWnd, msg, wParam, lParam);
    }


}

And here is my C++ code

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) {

switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
    MessageBox(0, L"Dll Injection Successful! ", L"Dll Injector", MB_ICONEXCLAMATION | MB_OK);      
    CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&StartTheDotNetRuntime, 0, 0, NULL);
    break;

case DLL_THREAD_ATTACH:  break;
case DLL_THREAD_DETACH:  break;
case DLL_PROCESS_DETACH:

    break;
}

return TRUE;

void StartTheDotNetRuntime()

{

ICLRRuntimeHost *pClrHost = NULL;
HRESULT hr = CorBindToRuntimeEx(NULL, L"wks", 0, CLSID_CLRRuntimeHost,IID_ICLRRuntimeHost, (PVOID*)&pClrHost);
hr = pClrHost->Start();

DWORD dwRet = 0;
hr = pClrHost->ExecuteInDefaultAppDomain(L"ClassLibrary2.dll",L"ClassLibrary2.Class1", L"Test", L"MyParameter", &dwRet);   
hr = pClrHost->Stop();    
pClrHost->Release();

}

Tri
You shouldn't call CreateThread in DllMain. Have a read of msdn documentation - there's a lot you shouldn't do in DllMain that can cause program failure: http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx
jeffora