将.NET 4.0库注入非托管应用程序,clr.dll中无限循环

发布于 2024-12-04 01:51:52 字数 6249 浏览 4 评论 0 原文

我正在尝试将 .net 库注入到托管应用程序中,但在使用 ollydbg 进行一些调试后它似乎不起作用,我发现它无限循环。如果我强行退出循环,一切都会正常。我已经创建了一个解决方法(请参阅下面的代码),但我怀疑这是否应该是这样!

循环从执行时开始: hr = pClrHost->Start();

注入器代码

    static void Main(string[] args)
    {
        //Has to be 32Bit app, not sure why yet, x86 should work in x64 apps
        Process np = Process.GetProcessesByName("notepad")[0];

        string dllpath = @"c:\Loader.dll";
        string corepath = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.System), "mscoree.dll");

        if (!File.Exists(corepath))
        {
            //No .NET
        }

        //Open Process for write access
        IntPtr PID = OpenProcess(PROCESS_ALL_ACCESS, false, np.Id);

        //Allocate memory
        IntPtr addr = (IntPtr)VirtualAllocEx(PID, IntPtr.Zero, (uint)dllpath.Length + 1, 0x1000, 4);
        if (addr == IntPtr.Zero)
        {
            //return false;
        }

        //Write DLL path into process memory
        int wrote = WriteProcessMemory(PID, addr, System.Text.Encoding.ASCII.GetBytes(dllpath), (uint)dllpath.Length +1, IntPtr.Zero);
        IntPtr hRemoteThread = IntPtr.Zero;

        uint temp;
        //Start new thread @ LoadLibraryA with path to library as parameter
        hRemoteThread = CreateRemoteThread(PID, IntPtr.Zero, 0, (IntPtr)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"), addr, 0, out temp);

        if (hRemoteThread == IntPtr.Zero)
        {
            //return false;
        }

        System.Threading.Thread.Sleep(1000);

        //**WORK AROUND**
        //Force loop to exit, Will cause the messagebox to show up
        wrote = WriteProcessMemory(PID, (IntPtr)0x6D8EC91A, new byte[1]{ 0xEB}, (uint)1, IntPtr.Zero);

        //Clean up
        VirtualFreeEx(PID, addr, (uint)dllpath.Length + 1, FreeType.Release);

        //return true;
    }

C++ .Net 加载器代码

#pragma comment(lib,"MSCorEE.lib") 

#include <mscoree.h>
#include <metahost.h>

ICLRRuntimeHost* pClrHost = NULL;

int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
    case DLL_PROCESS_ATTACH:
        {
                // Get the policy object, so we can determine which runtime to use.
                    ICLRMetaHostPolicy* pMetaHostPolicy     = NULL;
                    HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not create a ICLRMetaHostPolicy object!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    ICLRRuntimeInfo* pRuntimeInfo = NULL;
                    // Get the runtime info object. Allow the assembly to tell US what runtime to use.
                    DWORD pcchVersion = 0;
                    DWORD dwConfigFlags = 0;
                    hr = pMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, 
                                                                L"C:\\Test.dll", NULL,
                                                                NULL, &pcchVersion,
                                                                NULL, NULL, &dwConfigFlags,
                                                                IID_ICLRRuntimeInfo,
                                                                (LPVOID*)&pRuntimeInfo);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not create an ICLRRuntimeInfo object.", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    // Allow the runtime to load .NET 2.0 mixed-mode libraries. (This covers 2.0-3.5 SP1)
                    hr = pRuntimeInfo->BindAsLegacyV2Runtime();

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not bind as legacy v2 runtime.", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrHost);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not get an instance of ICLRRuntimeHost!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    hr = pClrHost->Start();

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Failed to start the CLR!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    DWORD dwRet = 0;
                    // Execute the Main func in the domain manager, this will block indefinitely.
                    // (Hence why we're in our own thread!)
                    hr = pClrHost->ExecuteInDefaultAppDomain(
                                                L"C:\\Test.dll",    // Executable path
                                                L"Test.bc",
                                                L"InjectedMain",
                                                L"Hello World!",
                                                &dwRet);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Failed to execute in the default app domain!", L"Injection - Error", MB_OK);
                        return 1;
                    }
        }
    break;

    case DLL_THREAD_ATTACH:  break;
    case DLL_THREAD_DETACH:  break;
    case DLL_PROCESS_DETACH: break;
}
//FreeLibraryAndExitThread(hInstance, 0);
return true;
}

.Net 测试代码

public class bc
{
    public static int InjectedMain(string args)
    {
        try
        {
            MessageBox.Show(args);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        return 0;
    }
}

调试器中所述循环的图像

I am trying to inject a .net library into a managed app, but it didn't seem to work after some debugging with ollydbg i found it to be looping infinitely. If i forcefully exit the loop it all works. I have created a work around (See code below) but i doubt this is the way it should be!

The loop start when executing: hr = pClrHost->Start();

Injector code

    static void Main(string[] args)
    {
        //Has to be 32Bit app, not sure why yet, x86 should work in x64 apps
        Process np = Process.GetProcessesByName("notepad")[0];

        string dllpath = @"c:\Loader.dll";
        string corepath = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.System), "mscoree.dll");

        if (!File.Exists(corepath))
        {
            //No .NET
        }

        //Open Process for write access
        IntPtr PID = OpenProcess(PROCESS_ALL_ACCESS, false, np.Id);

        //Allocate memory
        IntPtr addr = (IntPtr)VirtualAllocEx(PID, IntPtr.Zero, (uint)dllpath.Length + 1, 0x1000, 4);
        if (addr == IntPtr.Zero)
        {
            //return false;
        }

        //Write DLL path into process memory
        int wrote = WriteProcessMemory(PID, addr, System.Text.Encoding.ASCII.GetBytes(dllpath), (uint)dllpath.Length +1, IntPtr.Zero);
        IntPtr hRemoteThread = IntPtr.Zero;

        uint temp;
        //Start new thread @ LoadLibraryA with path to library as parameter
        hRemoteThread = CreateRemoteThread(PID, IntPtr.Zero, 0, (IntPtr)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA"), addr, 0, out temp);

        if (hRemoteThread == IntPtr.Zero)
        {
            //return false;
        }

        System.Threading.Thread.Sleep(1000);

        //**WORK AROUND**
        //Force loop to exit, Will cause the messagebox to show up
        wrote = WriteProcessMemory(PID, (IntPtr)0x6D8EC91A, new byte[1]{ 0xEB}, (uint)1, IntPtr.Zero);

        //Clean up
        VirtualFreeEx(PID, addr, (uint)dllpath.Length + 1, FreeType.Release);

        //return true;
    }

C++ .Net Loader code

#pragma comment(lib,"MSCorEE.lib") 

#include <mscoree.h>
#include <metahost.h>

ICLRRuntimeHost* pClrHost = NULL;

int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch(dwReason)
{
    case DLL_PROCESS_ATTACH:
        {
                // Get the policy object, so we can determine which runtime to use.
                    ICLRMetaHostPolicy* pMetaHostPolicy     = NULL;
                    HRESULT hr = CLRCreateInstance(CLSID_CLRMetaHostPolicy, IID_ICLRMetaHostPolicy, (LPVOID*)&pMetaHostPolicy);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not create a ICLRMetaHostPolicy object!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    ICLRRuntimeInfo* pRuntimeInfo = NULL;
                    // Get the runtime info object. Allow the assembly to tell US what runtime to use.
                    DWORD pcchVersion = 0;
                    DWORD dwConfigFlags = 0;
                    hr = pMetaHostPolicy->GetRequestedRuntime(METAHOST_POLICY_HIGHCOMPAT, 
                                                                L"C:\\Test.dll", NULL,
                                                                NULL, &pcchVersion,
                                                                NULL, NULL, &dwConfigFlags,
                                                                IID_ICLRRuntimeInfo,
                                                                (LPVOID*)&pRuntimeInfo);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not create an ICLRRuntimeInfo object.", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    // Allow the runtime to load .NET 2.0 mixed-mode libraries. (This covers 2.0-3.5 SP1)
                    hr = pRuntimeInfo->BindAsLegacyV2Runtime();

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not bind as legacy v2 runtime.", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrHost);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Could not get an instance of ICLRRuntimeHost!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    hr = pClrHost->Start();

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Failed to start the CLR!", L"Injection - Error", MB_OK);
                        return 1;
                    }

                    DWORD dwRet = 0;
                    // Execute the Main func in the domain manager, this will block indefinitely.
                    // (Hence why we're in our own thread!)
                    hr = pClrHost->ExecuteInDefaultAppDomain(
                                                L"C:\\Test.dll",    // Executable path
                                                L"Test.bc",
                                                L"InjectedMain",
                                                L"Hello World!",
                                                &dwRet);

                    if (FAILED(hr))
                    {
                        MessageBox(NULL, L"Failed to execute in the default app domain!", L"Injection - Error", MB_OK);
                        return 1;
                    }
        }
    break;

    case DLL_THREAD_ATTACH:  break;
    case DLL_THREAD_DETACH:  break;
    case DLL_PROCESS_DETACH: break;
}
//FreeLibraryAndExitThread(hInstance, 0);
return true;
}

.Net Test Code

public class bc
{
    public static int InjectedMain(string args)
    {
        try
        {
            MessageBox.Show(args);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        return 0;
    }
}

Image of said loop in a debugger

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

韬韬不绝 2024-12-11 01:51:52

解决方案:

删除DllMain,它有限制。
将代码移至导出函数。加载库然后调用导出的函数。

Solution:

Remove DllMain, It has restrictions.
Move code to exported function. Load the library then call the exported function.

猛虎独行 2024-12-11 01:51:52

不确定,因为您描述的场景至少可以说是“某种程度上不寻常”,但我怀疑解决方案位于以下可能性/选项中:

  • 尝试通过 SetDefaultStartupFlags
  • STARTUP_DISABLE_COMMITTHREADSTACK 对我来说看起来非常有希望,因为循环似乎对堆栈和线程做了一些事情...
  • 如果没有什么可以帮助将 DLL 实现为 COM 组件,而 COM 组件又托管 CLR

Not sure since the scenario you describe is to say the least "somehow unusual" but I suspect the solution lies somewhere in the following possibilities/options:

  • Try "playing" with the settings via SetDefaultStartupFlags
  • STARTUP_DISABLE_COMMITTHREADSTACK looks very promising to me since the loop seems to do something with stacks and threads...
  • IF nothing helps implement the DLL as a COM component which in turn hosts the CLR
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文