我正在使用CreateRemoteProcess将一些汇编代码注入远程进程(64位),然后加载一个dll,但我得到LoadLibraryA内的C0000005 EXCEPTION_ACCESS_VIOLATION加载我的.dll文件的调用。
这里是注入的汇编代码(地址在下面的屏幕截图中是不同的,但这些地址是在写入之前相对于远程内存地址计算的):
MOV RCX,2A0DFF0020 MOV RAX,<kernel32.LoadLibraryA> CALL RAX MOV RCX,RAX MOV RDX,2A0DFF0030 MOV RAX,<kernel32.GetProcAddress> CALL RAX MOV QWORD PTR DS:[2A0DFF0010],RAX MOV RCX,2A0DFF0040 MOV RAX,<kernel32.LoadLibraryA> CALL RAX CMP RAX,0 JNZ 2A0DFF024D XOR CL,CL MOV RDX,2A0DFF00C0 MOV R8,2A0DFF00B0 MOV CL,10 MOV RAX,QWORD PTR DS:[2A0DFF0010] CALL RAX XOR CL,CL MOV RAX,<kernel32.FatalExit> CALL RAX MOV QWORD PTR DS:[2A0DFF0000],RAX MOV RCX,RAX MOV RDX,2A0DFF00A0 MOV RAX,<kernel32.GetProcAddress> CALL RAX CMP RAX,0 JNZ 2A0DFF02A7 XOR CL,CL MOV RDX,2A0DFF0140 MOV R8,2A0DFF00B0 MOV CL,10 MOV RAX,QWORD PTR DS:[2A0DFF0010] CALL RAX XOR CL,CL MOV RAX,<kernel32.FatalExit> CALL RAX MOV RCX,2A0DFF0000 XOR DL,DL MOV RAX,<kernel32.FreeLibraryAndExitThread> CALL RAX
下面是CALL崩溃之前的寄存器和内存的截图(还有突出显示的汇编代码!), 这里是实际崩溃的截图
我正在尝试注入的完整的DLL(只是一个testing):
#include <windows.h> __declspec(dllexport) void init(void) { return; } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; }
我使用以下命令编译了最新的tcc 64位dll:
tcc -o "test.dll" -shared testdll.c
这里是注入代码,我剥离了所有的error handling:
//AlignedStream is a stream wrapper that supports aligning memory, //in this case to 16 Byte borders data = new AlignedStream(new MemoryStream()); //adding the strings to the stream (using Encoding.ASCII.GetBytes) System.Diagnostics.Process.EnterDebugMode(); var process = Interop.OpenProcess ( Interop.ProcessAccessFlags.CreateThread | Interop.ProcessAccessFlags.VirtualMemoryOperation | Interop.ProcessAccessFlags.VirtualMemoryWrite | Interop.ProcessAccessFlags.QueryInformation | Interop.ProcessAccessFlags.QueryLimitedInformation, false, processId ); var asmsize = GetAsmSize(); var RemoteMemory = Interop.VirtualAllocEx( process, IntPtr.Zero, new UIntPtr((ulong)asmsize + (ulong)data.Length), Interop.AllocationType.Commit | Interop.AllocationType.Reserve, Interop.MemoryProtection.ExecuteReadWrite ); //Adding the assembler to the stream (as raw bytes in code) var bytes = data.ToArray(); var oldProtect = Interop.VirtualProtectEx ( process, RemoteMemory, new UIntPtr((ulong)bytes.LongLength), Interop.MemoryProtection.ExecuteReadWrite ); var written = Interop.WriteProcessMemory ( process, RemoteMemory, bytes, new UIntPtr((ulong)bytes.LongLength) ); Interop.VirtualProtectEx ( process, RemoteMemory, new UIntPtr((ulong)bytes.LongLength), oldProtect ); Interop.FlushInstructionCache ( process, RemoteMemory, new UIntPtr((ulong)bytes.LongLength) ); var thread = Interop.CreateRemoteThread ( process, IntPtr.Zero, UIntPtr.Zero, IntPtr.Add(RemoteMemory, asmOffset), IntPtr.Zero, Interop.ThreadCreation.Default ); var result = Interop.WaitForSingleObject(thread, Interop.INFINITE); Interop.VirtualFreeEx ( process, RemoteMemory, UIntPtr.Zero, Interop.FreeType.Release ); System.Diagnostics.Process.LeaveDebugMode(); Interop.CloseHandle(process);
我确信.dll,目标进程和注入器都是64位的,并且注入器以pipe理员权限运行。 当加载一个只调用LoadLibrary的testing项目时,dll加载得很好。
我试图解决它的事情:
我尝试使用LoadLibraryW来代替它,并在同一点上崩溃(从我在debugging器中看到,LoadLibraryA实际上调用LoadLibraryExW在某一点,就像LoadLibraryW)。
我之前发现的所有类似问题的问题都归结为没有写入目标进程的数据,但正如您在屏幕截图中所看到的,它绝对存在。
我尝试了使用不同的进程,看它是否是特定于记事本,因为它在系统目录中,没有成功。
我尝试使用vc ++构build的dll
我完全没有想法。 也许这是我的汇编代码中的一个简单的错误,我无法find(对汇编很不熟练)。 为什么会发生这种崩溃,并且可以采取哪些措施来防止它?
你没有遵循标准的调用约定。 特别是(但不限于)您没有对齐堆栈,因此在LoadLibrary
函数内对齐的SSE移动指令MOVAPS
故障。 为了解决当前的问题,你可以在你的代码的开头执行AND RSP, -16
。 您还可以添加标准功能序言( PUSH RBP; MOV RBP, RSP
)和尾声( MOV RSP, RBP; POP RBP; RET
)。
但是,您应该注意遵循调用约定的所有特性(例如为参数分配溢出空间)来创建正确的代码,而不仅仅是正常工作的代码。