-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)
当在 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)