问题
If you take a look at the following working code of a simple DLL injection:
//Open the target process with read , write and execute priviledges
Process = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, ID);
//Get the address of LoadLibraryA
LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
// Allocate space in the process for our DLL
Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll)+1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
// Write the string name of our DLL in the memory allocated
WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll)+1, NULL);
// Load our DLL
CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL);
//Let the program regain control of itself
CloseHandle(Process);
The thing confuses me is that GetProcAddress
returns the LoadLibraryA
fucntion address of the current process, how can you pass it as a parameter to CreateRemoteThread
and expect the target process to run it?
回答1:
It works by accident. It is a very common accident, Microsoft makes a great deal of effort to ensure that the operating system DLLs, like kernel32.dll, have a base address that doesn't conflict with any other DLLs. Further enhanced by kernel32.dll getting loaded very early at process initialization so low odds that it has to fight to get its preferred base address.
You'll get away with easily. It is notable that this has gone wrong in the past, there was an XP security update oops that caused gdi32.dll to get relocated and made lots of machines fall over at boot. The correct way is fairly painful, CreateToolhelp32Snapshot() + Module32First/Next() to find the relocation offset isn't great joy. Frankly, you probably ought to not do this at all if the operating system is "weird" like that.
回答2:
LoadLibraryA
lives in kernel32.dll
, a module that is always loaded into every process and happens to also be loaded at the same address in every process.
回答3:
Address Space Layout Randomisation (ASLR) is an anti-exploit mitigation feature handled by Windows, and it allows address relocation to help prevent attackers from determining the address for exploitation of something in memory (stops hard-coding of addresses/offsets). However, Windows modules only change their addresses per session.
If you have a process which uses kernel32.dll (not all processes use kernel32.dll and I'll explain this further in a few minutes), the address to a routine might be 55AA1122 as an example (that's an invalid example address). Now, the next process with kernel32.dll, will have the same address for 55AA1122 for the same routine as the previous.... Only if the processes are both of the same architecture.
32-bit processes will have the same addresses for kernel32.dll exports, among other Windows module exports too (e.g. NTDLL, USER32, etc.). 64-bit processes will have different addresses to the 32-bit processes, however the 64-bit processes will all have the same addresses for the Windows modules, too!
Remote thread creation was not an "accident", Microsoft intentionally implemented it. Why? Microsoft use it a lot during Windows themselves, also for Asynchronous Procedure Calls. Microsoft also hot-patch things often for their own routines as an anti-reversing trick, or if they lose the source code to their own projects, haha.
Now regarding kernel32.dll being loaded into a process, it is only loaded into processes which use the Win32 API. This includes 99% of programs in the world, however it is possible to compile a native process which will not use it. This will however force you to use Native API and no Win32 API completely, and a Windows process called smss.exe does exactly this. You can also compile Native DLLs which don't even have a normal Win32 API DLL Entry routine.
To put it short, the addresses for Windows module routines change once per boot. It'll maintain the same until the next reboot, and so on. 32-bit processes have their own shared addresses of Windows modules for each process, as does 64-bit processes. Therefore, you cannot use LoadLibraryA address of a 64-bit process whilst targeting DLL injection for a 32-bit process, unless you use the 32-bit Kernel32.dll LoadLibraryA address. A better idea would be to use LdrLoadDll anyway, or just shell-code injection of a reflective DLL loader stub.
回答4:
If you launch Visual Studio, create an empty project, add new main.cpp file, write down:
#include <windows.h>
void main()
{
}
And then compile this program, don't expect that the created executable does nothing, it doesn't.
Maybe the Visual C++ compiler didn't write down any command in the object file, because there is no command in the source code, but the linker did write down in the beginning of the main procedure of the executable LoadLibrary
calls to user32.dll
, kernel32.dll
, gdi32.dll
and etc.
So every application that is written in Visual Studio C++ initially make many and the same calls to LoadLibrary
in the same order, no matter what was the source code of this executable.
The source code only determines the commands that should come after the LoadLibrary
calls.
So every Visual Studio C++ application loads LoadLibrary
of kernel32.dll
in the beginning of the execution and so LoadLibrary
has the same entry point or address in all processes relative to the process address.
Theoretically you can make the injector, the malicious program that attempts to inject your program, fail if you link some kernel32.lib that doesn't load kernel32.dll's LoadLibrary
procedure into the memory of your program.
The injector cannot cause your program to dynamically during execution loads some dll if your program cannot dynamically during execution load dll, because the procedure that supposes to do this, LoadLibrary
, does not present in the process memory.
Therefore the remote thread created by the injector cannot execute LoadLibrary
that doesn't exist in the victim's memory.
But this is possible that the attacker will VirtualAllocEx to create some block in the victim's memory, WriteProcessMemory some executable code and then CreateRemoteThread to execute it.
来源:https://stackoverflow.com/questions/22750112/dll-injection-with-createremotethread