跳至主要内容

手工加壳Demo- C++Version

http://ift.tt/2AAEutK
// 手动加壳demo.cpp : 定义控制台应用程序的入口点。
//




#include "stdafx.h"
#include <windows.h>
#include <string.h>




typedef struct _StubConf
{
    IMAGE_NT_HEADERS ntheader;

}STUBCONF;


class PeFile
{
public:
    PeFile();
    ~PeFile();
    bool OpenFile(const char*FilePath);
    bool InitHdrs();
    PIMAGE_SECTION_HEADER addSection(const char * secName, DWORD dwSecSzie);
    PIMAGE_SECTION_HEADER getSection(const char* secName);
    DWORD Size2ALi(DWORD  dwSize, DWORD dwALi);
    void peclose();
    void setOpe(DWORD newOep);
    LPVOID peGetProcAddress(const char* szFnName);
    DWORD RVATOOFFSET(DWORD rva);
    ULONG_PTR getfileBuff();
    PIMAGE_NT_HEADERS getNtHeader();
    PIMAGE_OPTIONAL_HEADER getOptionHeader();
    void fixStubReloc(DWORD oldImageBase,
        DWORD newImageBase,
        DWORD oldSectionRva,
        DWORD newSectionRva);
    void setSecData(IMAGE_SECTION_HEADER* pScn, void* pSectionData, DWORD dwSectionSize);
    bool saveas(const char *filepath);
private:
    PIMAGE_DOS_HEADER m_pDosHdr;
    PIMAGE_NT_HEADERS m_pNtHdr;
    PIMAGE_OPTIONAL_HEADER m_pOpHdr;
    PIMAGE_FILE_HEADER m_pFileHdr;
    PIMAGE_SECTION_HEADER m_pFirSecHdr;
    DWORD m_dwFile;
    DWORD m_FileSize;
    char* m_FileBuff;
};

PeFile::PeFile()
{
    m_FileBuff = NULL;
}

PeFile::~PeFile()
{
    peclose();
}

bool PeFile::OpenFile(const char*FilePath)
{
    HANDLE hFile = CreateFileA(FilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("文件不存在");
        CloseHandle(hFile);
        return false;
    }
    DWORD dwHigh = 0;
    m_FileSize = GetFileSize(hFile, &dwHigh);
    m_FileBuff = new char[m_FileSize] {};
    DWORD dwRealy = 0;
    ReadFile(hFile, m_FileBuff, m_FileSize, &dwRealy, NULL);
    CloseHandle(hFile);
    if (dwRealy == m_FileSize)
    {
        printf("打开%s成功\n", FilePath);
    }
    return true;
}

bool PeFile::InitHdrs()
{
    m_pDosHdr = (PIMAGE_DOS_HEADER)m_FileBuff;
    if (m_pDosHdr->e_magic!=IMAGE_DOS_SIGNATURE)
    {
        printf("不是有效的PE文件\n");
        return false;
    }
    m_pNtHdr =(PIMAGE_NT_HEADERS) (m_pDosHdr->e_lfanew + (ULONG_PTR)m_pDosHdr);
    if (m_pNtHdr->Signature!=IMAGE_NT_SIGNATURE)
    {
        printf("不是有效的PE文件\n");
        return false;
    }
    m_pFileHdr = (PIMAGE_FILE_HEADER)&m_pNtHdr->FileHeader;
    m_pOpHdr = (PIMAGE_OPTIONAL_HEADER)&m_pNtHdr->OptionalHeader;

    //然后是第一区段头
    m_pFirSecHdr = IMAGE_FIRST_SECTION(m_pNtHdr);
    return true;
}

//增加区段
PIMAGE_SECTION_HEADER PeFile::addSection(const char * secName, DWORD dwSecSzie)
{
    DWORD dwNowNumbersOfSec = m_pFileHdr->NumberOfSections;
    if (dwNowNumbersOfSec>=13)
    {
        return NULL;
    }
    if (m_FileBuff==NULL)
    {
        return NULL;
    }
    //对区段进行更改
    PIMAGE_SECTION_HEADER pNewSec, pOldSec;
    pOldSec = m_pFirSecHdr+ dwNowNumbersOfSec-1;
    pNewSec = m_pFirSecHdr + dwNowNumbersOfSec;
    //首先设置名字
    memcpy(pNewSec->Name, secName, 8);
    //然后就是设置各种大小
    //需要设置virtualsize
    //sizefoRawData
    //virtualaddress
    //PointerToRawData
    //SizeOfImage
    //文件的大小
    //修改charactristics
    //区段的个数
    //

    pNewSec->Misc.VirtualSize = dwSecSzie;
    
    pNewSec->SizeOfRawData = Size2ALi(dwSecSzie, m_pOpHdr->FileAlignment);

    //Pointer2RawData 肯定是上一个区段的P2RD+SORD
    pNewSec->PointerToRawData = pOldSec->PointerToRawData + pOldSec->SizeOfRawData;

    //virtuallAddress
    //是上一个区段的地址加上对其后的大小
    pNewSec->VirtualAddress = pOldSec->VirtualAddress + Size2ALi(pOldSec->SizeOfRawData, m_pOpHdr->SectionAlignment);

    //
    pNewSec->Characteristics = 0xE0000060;//默认设置为REW属性

    ++m_pFileHdr->NumberOfSections;

    //设置映像的大小
    m_pOpHdr->SizeOfImage = pNewSec->VirtualAddress + pNewSec->SizeOfRawData;

    //扩充pe文件缓冲区
    char *pNewBuff = new char[m_FileSize + pNewSec->SizeOfRawData]{};
    memcpy(pNewBuff, m_FileBuff, m_FileSize);
    delete[] m_FileBuff;
    m_FileBuff = pNewBuff;
    //重新初始化头部
    InitHdrs();
    //然后找到这个区段
    pNewSec = m_pFirSecHdr + m_pFileHdr->NumberOfSections - 1;

    //增加文件大小
    m_FileSize += pNewSec->SizeOfRawData;
    return pNewSec;

}

PIMAGE_SECTION_HEADER PeFile::getSection(const char* secName)
{

    PIMAGE_SECTION_HEADER pSec = m_pFirSecHdr;
    for (DWORD i = 0;i<m_pFileHdr->NumberOfSections;i++)
    {
        char szname[10] = {};
        memcpy(szname, pSec->Name, 8);
        szname[8] = 0;
        if (strcmp(szname,secName)==0)
        {
            //说明找到了
            return pSec;

        }
        pSec++;
    }
    return NULL;
}

DWORD PeFile::Size2ALi(DWORD dwSize, DWORD dwALi)
{
    if (dwSize%dwALi==0)
    {
        return dwSize;
    }
    return (dwSize / dwALi + 1)*dwALi;
}

void PeFile::peclose()
{
    if (m_FileBuff != NULL)
    {
        delete m_FileBuff;
        m_FileBuff = NULL;
    }
}

void PeFile::setOpe(DWORD newOep)
{
    m_pOpHdr->AddressOfEntryPoint = newOep;
}

//遍历导出表
LPVOID PeFile::peGetProcAddress(const char* szFnName)
{
    //遍历导出表
    PIMAGE_EXPORT_DIRECTORY pExpDir =NULL;
    pExpDir = (PIMAGE_EXPORT_DIRECTORY)(RVATOOFFSET(m_pOpHdr->DataDirectory[0].VirtualAddress) + (ULONG_PTR)m_pDosHdr);

    //然后开始遍历导出表
    char* pName = NULL;
    DWORD * pEnt = (DWORD*)(RVATOOFFSET(pExpDir->AddressOfNames)+(ULONG_PTR)m_pDosHdr);

    for (DWORD i =0;i<pExpDir->NumberOfNames;i++)
    {
        pName = (char*)(RVATOOFFSET(pEnt[i]) + (ULONG_PTR)m_pDosHdr);
        if (strcmp(pName, szFnName)==0)
        {
            //说明找到名字了
            //开始找导入名称序号表
            WORD * pEot = (WORD*)(RVATOOFFSET(pExpDir->AddressOfNameOrdinals) + (ULONG_PTR)m_pDosHdr);
            int or = pEot[i];
            //然后找到地址
            DWORD * pEat = (DWORD*)(RVATOOFFSET(pExpDir->AddressOfFunctions) + (ULONG_PTR)m_pDosHdr);
            return (LPVOID)pEat[or];
        }
    }

    return NULL;
}



DWORD PeFile::RVATOOFFSET(DWORD rva)
{
    IMAGE_SECTION_HEADER* pScnHdr;
    pScnHdr = m_pFirSecHdr;
    for (int i = 0; i < m_pFileHdr->NumberOfSections; ++i) {
        if (rva >= pScnHdr[i].VirtualAddress
            && rva < pScnHdr[i].VirtualAddress + pScnHdr[i].SizeOfRawData) {
            return rva - pScnHdr[i].VirtualAddress + pScnHdr[i].PointerToRawData;
        }
    }
    return -1;

}


ULONG_PTR PeFile::getfileBuff()
{
    return (ULONG_PTR)m_FileBuff;
}

PIMAGE_NT_HEADERS PeFile::getNtHeader()
{

    return m_pNtHdr;
}

PIMAGE_OPTIONAL_HEADER PeFile::getOptionHeader()
{
    return m_pOpHdr;
}

void PeFile::fixStubReloc(DWORD oldImageBase, DWORD newImageBase, DWORD oldSectionRva, DWORD newSectionRva)
{
    //
    // 修复stub部分的重定位数据
    // 地址是三段式的, 由 加载基址 + 段首RVA + 段内偏移
    // stub是一个dll,它的代码要从dll中移植到exe中,默认加载基址发生了改变
    // 然后stub将被当成一个新区段被移植到exe中的新区段中,段首RVA也发生了
    // 改变, 因此 , 需要将那些使用了VA地址的代码修正.
    // 那些使用了VA地址的代码的地址都被保存到了重定位表中
    // 修复的过程,就相当于遍历重定位表,将重定位项修正.
    //
    IMAGE_BASE_RELOCATION* pRelTab;
    pRelTab = (IMAGE_BASE_RELOCATION*)
        (RVATOOFFSET(m_pOpHdr->DataDirectory[5].VirtualAddress) + getfileBuff());

    /*!
    * \brief 重定位块的偏移结构
    */
    struct TypeOffset {
        WORD Offset : 12;  // (1) 大小为12Bit的重定位偏移
        WORD Type : 4;    // (2) 大小为4Bit的重定位信息类型值
    };

    while (pRelTab->SizeOfBlock != 0) {
        TypeOffset* tofs;
        DWORD count;
        count = (pRelTab->SizeOfBlock - 8) / 2;

        tofs = (TypeOffset*)(pRelTab + 1);
        for (DWORD i = 0; i < count; ++i) {
            if (tofs[i].Type == 3) {

                SIZE_T* pFixVa = (SIZE_T*)(RVATOOFFSET(tofs[i].Offset + pRelTab->VirtualAddress) + getfileBuff());
                // 替换加载基址
                *pFixVa -= oldImageBase; // 默认加载基址
                *pFixVa += newImageBase; // 新的加载基址
                                         // 替换段首RVA
                *pFixVa -= oldSectionRva; // 旧的区段段首RVA
                *pFixVa += newSectionRva; // 新的区段段首RVA
            }
        }

        // 找到下一个重定位块
        pRelTab = (IMAGE_BASE_RELOCATION*)
            ((SIZE_T)pRelTab + pRelTab->SizeOfBlock);
    }
}

void PeFile::setSecData(IMAGE_SECTION_HEADER* pScn, void* pSectionData, DWORD dwSectionSize)
{
    memcpy(m_FileBuff + pScn->PointerToRawData,
        pSectionData,
        dwSectionSize);
}

bool PeFile::saveas(const char *filepath)
{
    HANDLE hFile = INVALID_HANDLE_VALUE;
    hFile = CreateFileA(filepath,
        GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        printf("文件不存在");
        return false;
    }
    DWORD size;
    WriteFile(hFile, m_FileBuff, m_FileSize, &size, NULL);
    CloseHandle(hFile);

    return true;
}

int main()
{
    printf("输入加壳程序的路径:");
    char path[MAX_PATH] = {};
    gets_s(path, MAX_PATH);
    PeFile pePacked;
    PeFile peStub;

    pePacked.OpenFile(path);

    if (!peStub.OpenFile("stub.dll"))
    {
        printf("打开stub dll 失败\n");
        system("pasue");
        return -1;
    }
    if (!pePacked.InitHdrs())
    {
        system("pause");
        return -1;
    }
    if (!peStub.InitHdrs())
    {
        system("pause");
        return -1;
    }
    
    PIMAGE_SECTION_HEADER pStubSec = peStub.getSection(".text");
    if (pStubSec==NULL)
    {
        printf("获取stub 的 .text段失败\n");
        system("pause");
        return -1;
    }
    //然后就是对区段进行增加
    PIMAGE_SECTION_HEADER pNewSec = pePacked.addSection("demo", pStubSec->SizeOfRawData);
    if (pNewSec ==NULL)
    {
        printf("添加区段失败\n");
        system("pause");
        return -1;
    }
    

    //对区段增加玩之后,就是吧stub的text段中的数据全部拷贝的新的区段中
    //但是在拷贝前,还需要做
    /*
        更改oep
"       拷贝数据
        保存文件
    */
    STUBCONF *pSutbConf = NULL;
    DWORD dwStubConfRva =(DWORD) peStub.peGetProcAddress("g_StubConf");
    if (dwStubConfRva == 0)
    {
        printf("g_StubConf 查找失败\n");
        system("pause");
        return -1;
    }
    pSutbConf = (STUBCONF*)(peStub.RVATOOFFSET(dwStubConfRva) + peStub.getfileBuff());
    //对结构体进行赋值
    pSutbConf->ntheader = *pePacked.getNtHeader();

    //然后就是获取stub的入口函数
    DWORD dwNewOep = (DWORD)peStub.peGetProcAddress("GetStart");
    dwNewOep -= pStubSec->VirtualAddress;
    dwNewOep += pNewSec->VirtualAddress;
    pePacked.setOpe(dwNewOep);

    //去除被加壳程序的重定位项
    pePacked.getOptionHeader()->DllCharacteristics &= (~0x40);

    //修复重定位项
    peStub.fixStubReloc(peStub.getOptionHeader()->ImageBase,
        pePacked.getOptionHeader()->ImageBase,
        pStubSec->VirtualAddress,
        pNewSec->VirtualAddress);

    //拷贝stub.dll的代码段到被加壳程序的新区段中
    pePacked.setSecData(pNewSec, (void*)(pStubSec->PointerToRawData + peStub.getfileBuff()),
        pStubSec->SizeOfRawData);

    
    pePacked.saveas("ergouzi.exe");
    pePacked.peclose();

    system("pause");
    return 0;
}


The post 手工加壳Demo- C++Version appeared first on cole.

http://ift.tt/eA8V8J reverse engineering, pack, shell pack December 06, 2017 at 01:36PM

评论

此博客中的热门博文

反Hook 之自己实现GetProcAddress和LoadLibraryA(c++ version)

http://ift.tt/2AocAD0 // 课上练习.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <windows.h> //要实现的功能: /* 自己实现GerProcAddress LoadLibraryA */ //思路: /* GerProcAddress和LoadLibraryA都是在Kernel32.dll中的 首要的任务就是找到Kernel32.dll,然后遍历IAT就能找到这两个函数 现在首要的难点就是如何找到kernel32.dll() 通过dll的加载顺序可以找到,而且虽然需要使用未文档化的API,但是好在windgb可以直接看,而且用到的也并不是很多 懒得去晚上搜了,直接自己实现一个得了,作为演示,能用就行(最好还是搜一个正规的结构体) */ /* 0: kd> dt _TEB /a nt!_TEB +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB //首先实现部分TEB结构体,因为只需要用的PEB的部分,所以实现到这就ok了 */ //构建 TEB typedef struct _TEB { //保证0x30是peb的结构体就ok了 struct _tem { DWORD a1; DWORD a2; DWORD a3; DWORD a4; DWORD a5; DWORD a6; DWORD a7; DWORD a8; DWORD a9; DWORD a10; ...

IDA动态调试ELF中遇到的问题(1)

https://ift.tt/2Gxnf2F 遇到 got SIGCHLD singal(child status has changed)...这种提示 singal fork了子进程 直接点yes,然后继续单步执行,出来提示 pass to application就行了 内存查看 用od习惯了之后,凡事都想右键看一下内存,但是IDA中好像没有那么如意, 目前只是在栈中右键发现有查看hex的选项 动态调试的时候的nop ida保存动态调试的时候修改的数据 方法一:在程序运行的时候保存 The post IDA动态调试ELF中遇到的问题(1) appeared first on cole . https://ift.tt/2q9Qf5g WHATEVER April 05, 2018 at 09:44AM

数据库(MySQL)编程之数据库和表的基本操作

http://ift.tt/2gOXg6X     数据库和表的基本操作 操作前的基本知识 基本 sql语句不区分大小写(关键字建议用大小写),但字符串常量区分大小写 sql语句可单行或多行书写,以; 结尾 关键字不能跨行或简写 可以用空格或者缩进来提高可读性 注释 sql标准 /**/ : 多行注释 "--":单行注释 mysql 标准: "#":单行注释 "COMMENT":为字段或列添加注释 创建和查看数据库 创建数据库 模板 CREATE DATABASE [IF NOT EXISTS ] db_name create_specification: IF NOT EXITSTS : 检查数据库是否存在,如果存在就不创建 creat_specification :创建条件 CHARACTER SET: 制定数据聚采用的字符集 COLLATE :制定数据库字符集的比较方式 DEFAULT :表示默认内容,即使没有制定该项,也有默认的值 # 创建数据库使用字符集为 UTF-8 ,使用规则为 uftf_bin CREATE DATABASE db_name DEFAULT CHARACTER SET utf8 COLLATE uft8_bin; 一般默认的数据库就是utf8 和utf8_bin的比较方式,因此一般创建数据库的时候都用 CREATE DATABASE db_name mysql> create database testdb; Query OK, 1 row affected (0.02 sec) 查看数据库 命令 SHOW DATABASES     mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sakila | | sys | | testdb | |...