挂起进程修改eip进行dll注入
(该文件最早发于:http://blog.sina.com.cn/s/blog_6f50984a01013dyx.html,现整理后重发)
启动进程的时候,使用CREATE_SUSPENDED 挂起创建方式创建进程(或者打开存在进程后将其挂起),然后在该进程内申请一块空间,将汇编码写入该空间内,汇编码内容为“加载目标dll,加载完成后跳回原来的进程运行点”。
以创建进程时候进行注入为例:
STARTUPINFOW si = { 0 };
PROCESS_INFORMATION pi = { 0 };
si.cb = sizeof(STARTUPINFOW);
::CreateProcessW(pProcessPath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
CONTEXT ct = { 0 };
ct.ContextFlags = CONTEXT_ALL;
GetThreadContext(pi.hThread, &ct);
DWORD dwSize = sizeof(WCHAR) * 1024;
BYTE *pProcessMem = (BYTE *)::VirtualAllocEx(pi.hProcess, NULL, dwSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
// 将dll 写入申请的内存的偏移100的位置初,留出100个字节大小内存写入汇编码
DWORD dwWrited = 0;
::WriteProcessMemory(pi.hProcess, (pProcessMem + 0x100), pDllPath, (wcslen(pDllPath) + 1) * sizeof(WCHAR), &dwWrited);
FARPROC pLoadLibraryW = (FARPROC)::GetProcAddress(::GetModuleHandle(L"Kernel32"), "LoadLibraryW");
BYTE ShellCode[32] = { 0 };
DWORD *pdwAddr = NULL;
// 先保持下寄存器信息
ShellCode[0] = 0x60; // pushad
ShellCode[1] = 0x9c; // pushfd
ShellCode[2] = 0x68; // push
pdwAddr = (DWORD *)&ShellCode[3]; // ShellCode[3/4/5/6],也就是一个DWORD 的大小
*pdwAddr = (DWORD)(pProcessMem + 0x100); // 指向申请的内存的偏移100处,也就是刚刚写入的dll 路径所在的内存
// 上面三行,等价于 push dll 的地址,为call LoadLibrary 做压参,行数调用做准备
ShellCode[7] = 0xe8;
pdwAddr = (DWORD *)&ShellCode[8]; // ShellCode[8/9/10/11]
*pdwAddr = (DWORD)pLoadLibraryW - (DWORD)(pProcessMem + 7) - 5;
// 上面三行 等价于call LoadLibraryW
// 上面六行汇编码,实际上就是 LoadLibraryW(dllPath) 了
ShellCode[12] = 0x9d; // popfd
ShellCode[13] = 0x61; // popad
ShellCode[14] = 0xe9; // jmp
pdwAddr = (DWORD *)&ShellCode[15]; // ShellCode[15/16/17/18]
*pdwAddr = ct.Eip - (DWORD)(pProcessMem + 14) - 5;
// 跳回原来的地方
::WriteProcessMemory(pi.hProcess, pProcessMem, ShellCode, sizeof(ShellCode), &dwWrited);
ct.Eip = (DWORD)pProcessMem; // 将eip 位置指向shellCode 汇编码
::SetThreadContext(pi.hThread, &ct);
::ResumeThread(pi.hThread);
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
上面的
*pdwAddr = (DWORD)pLoadLibraryW – (DWORD)(pProcessMem + 7) – 5;
*pdwAddr = ct.Eip – (DWORD)(pProcessMem + 14) – 5;
两句的说明,
因为0xe8 (call) 和0xe9(jmp)跳指令,eip改变格式如下:
eip + 5 + x = newEip,其中5为一个字节的指令长度加上四个字节的地址长度
所以得
x = newEip – eip – 5
故得上面两句。
如果不想计算偏移,这段shellCode可以变形一下,就不用计算偏移地址了。
主要做法是用push addr 加上retn 来代替 call。
shellcode如下:(地址用0x90 填充,后面再修正)
BYTE ShellCode[32] =
{
0x60, // [0] pushad
0x9c, // [1] pushfd
// [2 - 6] push XXXX, 这里后四子节待填充为DllPath 地址,等价于传入DllPath 参数
0x68, 0x90,0x90,0x90,0x90,
// [7 - 11] push XXXX, 这里后四子节待填充为调用LoadLibraryW后,需要回到的位置
0x68, 0x90,0x90,0x90,0x90,
// [12 - 16] push XXXX, 待填充为 LoadLibraryW 地址
0x68, 0x90,0x90,0x90,0x90,
0xc3, // [17] retn 这个指令使得跳转到 LoadLibraryW,LoadLibraryW返回地址由上一个指令指出
0x9d, // [18] popfd
0x61, // [19] popad
// [20 - 25]push OldEip 地址
0x68, 0x90,0x90,0x90,0x90,
0xc3, // [25] retn
0x00
};
*((DWORD *)&ShellCode[3]) = (DWORD)(pProcessMem + 0x100); // ShellCode[3/4/5/6] LoadLibraryW 的参数
*((DWORD *)&ShellCode[8]) = (DWORD)pProcessMem+0x12; // ShellCode[8/9/10/11] LoadLibraryW 返回的地址
*((DWORD *)&ShellCode[13]) = (DWORD)pLoadLibraryW; // ShellCode[13/14/15/16] LoadLibraryW的地址
*((DWORD *)&ShellCode[21]) = (DWORD)ct.Eip; // ShellCode[21/22/23/24] ct.Eip的地址
(全文完)
(欢迎转载本站文章,但请注明作者和出处 云域 – Yuccn )