Внедрить управляемую DLL в проблему собственного процесса

Мне нужно создать подкласс элемента управления richedit в программе чата (я пытаюсь создать музыкального бота). Я не знаю, как кодировать на c/c++, но я смог использовать c++ для внедрения управляемого кода в программу чата с помощью CLR Hosting. Но возникает пара проблем. Надеюсь, я смогу получить помощь отсюда.

  1. Мой управляемый код завершит работу после завершения потока. Мне нужно, чтобы он работал
  2. Когда я попытался создать подкласс элемента управления richedit, используя API SetWindowLong и GWL_WNDPROC, программа чата зависла.

Может ли кто-нибудь указать мне правильный способ сделать это? Или это вообще возможно сделать в управляемом коде?

Спасибо


person Tri    schedule 01.02.2010    source источник


Ответы (3)


Такого рода вещи зависят от многих факторов и могут быть трудными для начала. Можете ли вы предоставить более подробную информацию?

На общем уровне для 1: если вы используете ICLRRuntimeHost::ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument) для выполнения своего управляемого кода, тогда управляемое выполнение остановится, как только завершится метод, обозначенный pwzMethodName. Если у вас есть другие задачи, которые вы хотите выполнять постоянно, и вы не хотите, чтобы этот вызов зависал в это время, лучше всего pwzMethodName запустить какую-нибудь функцию программного цикла в другом потоке.

Что касается 2, если вы вводите код в целевой процесс и взаимодействуете с элементами управления, безопасность потоков может быть огромной проблемой. Лично я не использовал API SetWindowLong, но это может быть связано с изменением элементов управления из потока, не являющегося диспетчером.

person jeffora    schedule 01.02.2010
comment
Вот мой код на С++ hr = pClrHost->ExecuteInDefaultAppDomain(LClassLibrary2.dll, LClassLibrary2.Class1, LTest, LMyParameter, &dwRet); - person Tri; 01.02.2010
comment
Вот мой код C# public 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); Показать (msg.ToString()); вернуть CallWindowProc(_OldWndProc, hWnd, msg, wParam, lParam); } - person Tri; 01.02.2010
comment
Как я уже сказал в своем ответе, ExecuteInDefaultAppDomain завершится после выхода ClassLibrary2.Class1.Test. Если этот метод является бесконечным циклом, ExecuteInDefaultAppDomain по сути тоже будет бесконечным циклом. Если вы хотите, чтобы ваш ExecuteInDefaultAppDomain возвращался немедленно, но код .NET продолжал выполняться, вам нужно запустить «основной» поток из функции, которую вы вызываете в ExecuteInDefaultAppDomain. - person jeffora; 01.02.2010
comment
Что касается кода на C#, то при внедрении кода в процесс может возникнуть множество проблем. Ваш hwnd действителен? Если это недопустимая память, это приведет к сбою процесса. Получает ли ваш делегат сбор мусора до того, как его выполнит неуправляемый код? Это приведет к сбою вашего процесса. Обычно к элементам управления можно безопасно получить доступ только из потока диспетчеризации, и если этого не сделать, это может привести к его сбою, я не уверен. Попробуйте подключить отладчик, чтобы получить фактическое исключение. Кроме того, вы можете отредактировать исходный пост, чтобы добавить код в читаемом формате. - person jeffora; 01.02.2010

Вот мой С#

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);
    }


}

А вот мой код C++

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();
}
person Tri    schedule 02.02.2010
comment
Вы не должны вызывать CreateThread в DllMain. Прочтите документацию msdn — вы не должны делать в DllMain многое, что может привести к сбою программы: msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx - person jeffora; 05.02.2010

Другой «более динамичный» способ — написать библиотеку на Managed C++, которую можно внедрить.

Управляемая библиотека C++ может экспортировать собственные функции, чтобы использовать их для загрузки в другой процесс.

Напишите в этой библиотеке Managed C++ только код, позволяющий загружать дополнительные библиотеки.

Эту библиотеку можно повторно использовать для внедрения будущих объектов...

См.: http://www.vbib.be/index.php?name=PNphpBB2&file=viewtopic&p=38982

person vozzie    schedule 16.06.2011