将 32 位图像从 64 位应用程序映射到 32 位进程

-1 c++ windows code-injection dll-injection windows-10

我试图找出一种方法(通过 loadlibrary 或最好手动)将 32 位图像(dll)从 64 位运行应用程序映射到 32 位进程。有任何想法吗?

目前,注入/映射一切看起来都在工作,但是在使用仅创建消息框的空 dll 进行测试时,它实际上并没有创建消息框。当来自 32 位应用程序时,注入工作正常。

这是我用 LoadLibrary 测试的方法

EnsureElevation( ); // ensures that we're run as admin and that we have debug privs

// messy code because it's test code
LPVOID LoadLib = ( LPVOID )GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "LoadLibraryA" );

HANDLE Proc = OpenProcess( PROCESS_ALL_ACCESS, false, GetProcessID( L"target.exe" ) );
std::cout << Proc << '\n';
std::cout << "Proc Error: 0x" << std::hex << GetLastError( ) << '\n'; // 0x0

LPVOID RemoteString = VirtualAllocEx( Proc, NULL, strlen( R"(C:\Users\Username\Desktop\MessageBox.dll)" ), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE );
std::cout << RemoteString << '\n';
std::cout << "String Error: 0x" << std::hex << GetLastError( ) << '\n'; // 0x0

std::cout << WriteProcessMemory( Proc, RemoteString, R"(C:\Users\Username\Desktop\MessageBox.dll)", strlen( R"(C:\Users\Username\Desktop\MessageBox.dll)" ), NULL ) << '\n';
std::cout << "Write Error: 0x" << std::hex << GetLastError( ) << '\n'; // 0x0

std::cout << CreateRemoteThread( Proc, NULL, NULL, ( LPTHREAD_START_ROUTINE )LoadLib, ( LPVOID )RemoteString, NULL, NULL ) << '\n';
std::cout << "Create Error: 0x" << std::hex << GetLastError( ) << '\n'; // 0x0
Run Code Online (Sandbox Code Playgroud)

RbM*_*bMm 5

当在 wow64 进程中创建线程时,它无论如何都开始以 64 位模式执行 - 从LdrInitializeThunk64 位ntdll.dll.

在这里面,当进程是 wow64 时,Run64IfContextIs64函数被调用 - 系统尝试确定 - 线程必须在本机或 wow64 上下文中执行。这是通过检查胎面起始地址来完成的 - 如果它在本机 dll 中(当前是ntdll.dll, wow64.dll, wow64win.dll, wow64cpu.dll) - 系统以本机(64 位模式)运行它。调用图是

在此处输入图片说明

在调试器中,我们可以看到下一个调试打印:

<pid>:<tid> Found inside *.dll
<pid>:<tid> InitialPC <rip> is within a native dll.  Running native context unchanged.
Run Code Online (Sandbox Code Playgroud)

特殊情况是 InitialPC 位于 64 位 kernel32.dll 或 64 位 user32.dll(查找DllsToRemap)内 -在本机 dll内Run64IfContextIs64称为MapContextAddress64TO32系统检查地址。在某些情况下(例如DebugBreak)系统尝试将其重定向到 32 位 kernel32.dllDebugBreak并在 wow64 模式下执行,但是..这里的错误 - 崩溃了。在大多数情况下 - 系统重定向地址从 64 位kernel32.dll(或user32.dll)到Wow64pBreakPoint(非导出函数)内wow64.dll。此函数在本机(64 位模式)中执行 -int 3如果附加调试器,则调用(断点)。在这之后简单地终止线程。在调试输出中我们可以查看

<pid>:<tid> InitialPC <rip> found in the space reserved for 64-bit kernel32.dll
Run Code Online (Sandbox Code Playgroud)

然而,这正是您的情况 - 您传递了LoadLibraryAinside 64-bit 的地址kernel32.dll。这当然是错误的。

否则(如果 PC 不在 64 位模块内) - 系统在 wow64 上下文中执行此线程,我们在这里需要什么

在此处输入图片说明

<pid>:<tid> ThunkStartupContent64TO32: Original InitialPC <rip>, StartupAddress <eip>, Arg1 <pv>
<pid>:<tid> ThunkStartupContext64TO32: Thunking RTL user thread start
Run Code Online (Sandbox Code Playgroud)

BTCpuSimulate线程后转到LdrInitializeThunk32 位 ntdll.dll 并在 wow64 上下文中照常执行。


所以我们需要代替LoadLibraryA内部 64 位的kernel32.dll地址得到LoadLibraryW内部 32 位的地址kernel32.dll。但是,如果尝试仅使用记录在案的 win32 api,则此任务不仅仅是简单的。我用于此 ntdll api(其中一些未记录)。然而,原样:

PVOID getRVA(PVOID Base, ULONG_PTR BaseAddress, PCSTR Name)
{
    if (PIMAGE_NT_HEADERS32 pinth = (PIMAGE_NT_HEADERS32)RtlImageNtHeader(Base))
    {
        BaseAddress -= pinth->OptionalHeader.AddressOfEntryPoint;

        DWORD Size, exportRVA;
        if (PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)
            RtlImageDirectoryEntryToData(Base, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &Size))
        {
            exportRVA = RtlPointerToOffset(Base, pied);

            DWORD NumberOfFunctions = pied->NumberOfFunctions;
            DWORD NumberOfNames = pied->NumberOfNames;

            if (0 < NumberOfNames && NumberOfNames <= NumberOfFunctions)
            {
                PDWORD AddressOfFunctions = (PDWORD)RtlOffsetToPointer(Base, pied->AddressOfFunctions);
                PDWORD AddressOfNames = (PDWORD)RtlOffsetToPointer(Base, pied->AddressOfNames);
                PWORD AddressOfNameOrdinals = (PWORD)RtlOffsetToPointer(Base, pied->AddressOfNameOrdinals);

                DWORD a = 0, b = NumberOfNames, o;

                do 
                {
                    o = (a + b) >> 1;

                    int i = strcmp(RtlOffsetToPointer(Base, AddressOfNames[o]), Name);

                    if (!i)
                    {
                        DWORD Rva = AddressOfFunctions[AddressOfNameOrdinals[o]];
                        return (ULONG_PTR)Rva - (ULONG_PTR)exportRVA < Size ? 0 : RtlOffsetToPointer(BaseAddress, Rva);
                    }

                    0 > i ? a = o + 1 : b = o;

                } while (a < b);
            }
        }
    }

    return 0;
}

PVOID GetWowLoadLibraryW()
{
    PVOID pv = 0;
    STATIC_OBJECT_ATTRIBUTES(oa, "\\KnownDlls32\\kernel32.dll");
    HANDLE hSection;

    if (0 <= ZwOpenSection(&hSection, SECTION_QUERY|SECTION_MAP_READ, &oa))
    {
        SECTION_IMAGE_INFORMATION sii;
        if (0 <= ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0))
        {
            PVOID BaseAddress = 0;
            SIZE_T ViewSize = 0;
            if (0 <= ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 0, 0, &ViewSize, ViewUnmap, 0, PAGE_READONLY))
            {
                __try {
                    pv = getRVA(BaseAddress, (ULONG_PTR)sii.TransferAddress, "LoadLibraryW");

                } __except( EXCEPTION_EXECUTE_HANDLER) {
                }
                ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
            }
        }
        NtClose(hSection);
    }

    return pv;
}
Run Code Online (Sandbox Code Playgroud)

在这个任务变得微不足道之后:

if (PVOID wowLoadLibraryW = GetWowLoadLibraryW())
{
    //PCWSTR szLibPath = ...

    SIZE_T s = (wcslen(szLibPath) + 1) * sizeof(WCHAR);

    if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, <pid>))
    {
        if (PVOID pv = VirtualAllocEx(hProcess, 0, s, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE))
        {
            if (WriteProcessMemory(hProcess, pv, szLibPath, s, 0))
            {
                if (HANDLE hThread = CreateRemoteThread(hProcess, 0, 0, (PTHREAD_START_ROUTINE)wowLoadLibraryW, pv, 0, 0))
                {
                    CloseHandle(hThread);
                }
            }
        }
        CloseHandle(hProcess);
    }
}
Run Code Online (Sandbox Code Playgroud)