#include "stdafx.h"
#include <windows.h>
#include <iostream>
using std::cin;
DWORD dwOldEip = 0;
DWORD funRemote = 0;
BYTE shellCode[25] = {
0x68, 0x78, 0x56, 0x34, 0x12, //push 12345678h
0x9C, //pushfd
0x60, //pushad
0x6A, 0x00, //push 0
0x6A, 0x00, //push 0
0x6A, 0x00, //push 0
0x6A, 0x00, //push 0
0xB8, 0x78, 0x56, 0x34, 0x12, //mov eax, 12345678h
0xFF, 0xD0, //call eax
0x61, //popad
0x9D, //popfd
0xC3, //ret
};
BOOL ThreadContextTest(DWORD dwProcessId, DWORD dwMemSize)
{
HWND hwnd = FindWindow(NULL, L"Dependency Walker");
if (!hwnd)
return FALSE;
printf("hwnd:%p\n", hwnd);
// 打开进程
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);
if (!hProcess)
return FALSE;
// 获取主线程ID
DWORD dwThreadId = GetWindowThreadProcessId(hwnd, NULL);
printf("dwThreadId:%d\n", dwThreadId);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, dwThreadId);
// 暂停主线程
DWORD dwSuspendCount = SuspendThread(hThread);
printf("暂停线程,任意键恢复线程,dwSuspendCount:%d\n", dwSuspendCount);
CONTEXT stcContext = { CONTEXT_FULL };
if (!GetThreadContext(hThread, &stcContext))
return FALSE;
HMODULE hModule = LoadLibrary(L"User32.dll");
funRemote = (DWORD)GetProcAddress(hModule, "MessageBoxA");
// 获取原始EIP
dwOldEip = stcContext.Eip;
printf("stcContext.Eip:%p\n", stcContext.Eip);
// 申请内存
LPVOID lpAddr = VirtualAllocEx(hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (!lpAddr)
return FALSE;
printf("lpAddr:%p\n", lpAddr);
// 构造shellCode
memcpy(&shellCode[16], &funRemote, 4);
memcpy(&shellCode[1], &dwOldEip, 4);
// 写入内存
BOOL bRet = WriteProcessMemory(hProcess, lpAddr, shellCode, dwMemSize, NULL);
if (!bRet)
return FALSE;
// 设置EIP
stcContext.Eip = (DWORD)lpAddr;
SetThreadContext(hThread, &stcContext);
//system("pause");
DWORD dwResumeCount = ResumeThread(hThread);
printf("恢复线程,dwResumeCount:%d\n", dwResumeCount);
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwLen = sizeof(shellCode);
DWORD dwProcessId = 0;
cin >> dwProcessId;
ThreadContextTest(dwProcessId, dwLen);
system("pause");
return 0;
}
我把执行的代码写成了ShellCode,就是弹一个 MessageBox,但是前面一句和最后一句是重点,第一句是把当前EIP 压栈,最后的RET就是
返回到正确EIP 这个是必须有的,在这里RET指令的内部操作是:栈顶字单元出栈,其值赋给IP寄存器。即实现了一个程序的转移,将栈顶字单元保存
的偏移地址作为下一条指令的偏移地址。
当然也可以把你自己的执行代码写成函数,遇到的问题就是计算函数的大小,一般方法就是搜索特征码Ret(高老湿说滴),然后特征码地址减
去,函数地址,就是大小~~
由于EIP必须在运行的时候才能得到,所以我把获得的EIP直接MEMCOPY到相应shellCode位置。
运行结果: