C/C++知识点之压缩壳的实现相关细节
小标 2019-05-31 来源 : 阅读 1099 评论 0

摘要:本文主要向大家介绍了C/C++知识点之压缩壳的实现相关细节,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了C/C++知识点之压缩壳的实现相关细节,通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

C/C++知识点之压缩壳的实现相关细节

加壳 原理:
改变原始OEP的指向 指向壳程序  壳程序可以添加其它程序 如弹密码框  只有密码正确就运行(只是所有函数动态加载)


typedef int (WINAPI *LPMESSAGEBOX)(HWND, LPCTSTR, LPCTSTR, UINT); //MessageBoxW
typedef DWORD(WINAPI *LPGETPROCADDRESS)(HMODULE, LPCSTR);         // GetProcAddress
typedef HMODULE(WINAPI *LPLOADLIBRARYEX)(LPCTSTR, HANDLE, DWORD); // LoadLibaryEx
typedef HMODULE(WINAPI *GETModuleHandle)(
    _In_opt_ LPCTSTR lpModuleName
    );
typedef BOOL(WINAPI* SHOWWINDOW)(
    _In_ HWND hWnd,
    _In_ int  nCmdShow
    );
typedef BOOL(WINAPI* GteMessage)(
    _Out_    LPMSG lpMsg,
    _In_opt_ HWND  hWnd,
    _In_     UINT  wMsgFilterMin,
    _In_     UINT  wMsgFilterMax
    );
typedef LRESULT(WINAPI* DISpatchMessage)(
    _In_ const MSG *lpmsg
    );
typedef ATOM(WINAPI* REGisterClass)(
    _In_ const WNDCLASS *lpWndClass
    );
typedef HWND(WINAPI *CREateWindowEx)(
    _In_     DWORD     dwExStyle,
    _In_opt_ LPCTSTR   lpClassName,
    _In_opt_ LPCTSTR   lpWindowName,
    _In_     DWORD     dwStyle,
    _In_     int       x,
    _In_     int       y,
    _In_     int       nWidth,
    _In_     int       nHeight,
    _In_opt_ HWND      hWndParent,
    _In_opt_ HMENU     hMenu,
    _In_opt_ HINSTANCE hInstance,
    _In_opt_ LPVOID    lpParam
    );
typedef VOID(WINAPI* POSTQuitMessage)(
    _In_ int nExitCode
    );
typedef LRESULT(WINAPI* DEFWindowProc)(
    _In_ HWND   hWnd,
    _In_ UINT   Msg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    );
typedef BOOL(*UPDateWindow)(
    _In_ HWND hWnd
    );
typedef int (WINAPI* GETWindowText)(
    _In_  HWND   hWnd,
    _Out_ LPTSTR lpString,
    _In_  int    nMaxCount
    );
typedef int (WINAPI* GETWindowTextLength)(
    _In_ HWND hWnd
    );
typedef HWND(WINAPI* GETDlgItem)(
    _In_opt_ HWND hDlg,
    _In_     int  nIDDlgItem
    );
typedef BOOL(WINAPI* SETWindowText)(
    _In_     HWND    hWnd,
    _In_opt_ LPCTSTR lpString
    );
typedef BOOL(WINAPI* TRanslateMessage)(
    _In_ const MSG *lpMsg
    );
typedef LPVOID(WINAPI *MYVIRTUALALLOC)(
    _In_opt_ LPVOID lpAddress,
    _In_     SIZE_T dwSize,
    _In_     DWORD  flAllocationType,
    _In_     DWORD  flProtect
    );
typedef BOOL(WINAPI *MYVIRTUALFREE)(
    _In_ LPVOID lpAddress,
    _In_ SIZE_T dwSize,
    _In_ DWORD  dwFreeType
    );
typedef HMODULE(WINAPI *MYLOADLIBRARY)(
    _In_ LPCSTR lpLibFileName
    );
wchar_t g_wcbuf100[100] = { 0 };
wchar_t g_MIMA100[100] = L"haidragon";
wchar_t wStrtext[100] = L"请输入密码";
_declspec(thread) int g_num;
/////////////////////////////////////////////////////////////
//初始化
LPGETPROCADDRESS    g_funGetProcAddress         = nullptr;
LPLOADLIBRARYEX     g_funLoadLibraryEx          = nullptr;
HMODULE             hModuleKernel32             = nullptr;
HMODULE             hModuleUser32               = nullptr;
GETModuleHandle     g_funGetModuleHandle        = nullptr;
LPMESSAGEBOX        g_funMessageBox             = nullptr;
CREateWindowEx      g_funCreateWindowEx         = nullptr;
POSTQuitMessage     g_funPostQuitMessage        = nullptr;
DEFWindowProc       g_funDefWindowProc          = nullptr;
GteMessage          g_funGetMessage             = nullptr;
REGisterClass       g_funRegisterClass          = nullptr;
SHOWWINDOW          g_funShowWindow             = nullptr;
UPDateWindow        g_funUpdateWindow           = nullptr;
DISpatchMessage     g_funDispatchMessage        = nullptr;
GETWindowText       g_funGetWindowText          = nullptr;
GETWindowTextLength g_funGetWindowTextLength    = nullptr;
GETDlgItem          g_funGetDlgItem             = nullptr;
SETWindowText       g_funSetWindowText          = nullptr;
TRanslateMessage    g_funTranslateMessage       = nullptr;
MYVIRTUALALLOC      g_VirtualAlloc              = nullptr;
MYVIRTUALFREE       g_VirtualFree               = nullptr;
MYLOADLIBRARY    g_LoadLibraryA                 = nullptr;

DWORD g_dwImageBase;
DWORD g_oep;
void start();
PACKINFO g_PackInfo = { (DWORD)start };
//获取kernel32模块加载基址
DWORD GetKernel32Base()
{
    DWORD dwKernel32Addr = 0;
    __asm
    {
        push eax
        mov eax, dword ptr fs : [0x30] // eax = PEB的地址
        mov eax, [eax + 0x0C]          // eax = 指向PEB_LDR_DATA结构的指针
        mov eax, [eax + 0x1C]          // eax = 模块初始化链表的头指针InInitializationOrderModuleList
        mov eax, [eax]                 // eax = 列表中的第二个条目
        mov eax, [eax + 0x08]          // eax = 获取到的Kernel32.dll基址(Win7下获取的是KernelBase.dll的基址)
        mov dwKernel32Addr, eax
        pop eax
    }

    return dwKernel32Addr;
}

//获取GetProcAddress的基址
DWORD GetGPAFunAddr()
{
    DWORD dwAddrBase = GetKernel32Base();

    // 1. 获取DOS头、NT头
    PIMAGE_DOS_HEADER pDos_Header;
    PIMAGE_NT_HEADERS pNt_Header;
    pDos_Header = (PIMAGE_DOS_HEADER)dwAddrBase;
    pNt_Header = (PIMAGE_NT_HEADERS)(dwAddrBase + pDos_Header->e_lfanew);

    // 2. 获取导出表项
    PIMAGE_DATA_DIRECTORY   pDataDir;
    PIMAGE_EXPORT_DIRECTORY pExport;
    pDataDir = pNt_Header->OptionalHeader.DataDirectory;
    pDataDir = &pDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT];
    pExport = (PIMAGE_EXPORT_DIRECTORY)(dwAddrBase + pDataDir->VirtualAddress);

    // 3、获取导出表的必要信息
    DWORD dwModOffset = pExport->Name;                                  // 模块的名称
    DWORD dwFunCount = pExport->NumberOfFunctions;                      // 导出函数的数量
    DWORD dwNameCount = pExport->NumberOfNames;                         // 导出名称的数量

    PDWORD pEAT = (PDWORD)(dwAddrBase + pExport->AddressOfFunctions);   // 获取地址表的RVA
    PDWORD pENT = (PDWORD)(dwAddrBase + pExport->AddressOfNames);       // 获取名称表的RVA
    PWORD pEIT = (PWORD)(dwAddrBase + pExport->AddressOfNameOrdinals);  //获取索引表的RVA
    // 4、获取GetProAddress函数的地址
    for (DWORD i = 0; i < dwFunCount; i++)
    {
        if (!pEAT[i])
        {
            continue;
        }

        // 4.1 获取序号
        DWORD dwID = pExport->Base + i;

        // 4.2 变量EIT 从中获取到 GetProcAddress的地址
        for (DWORD dwIdx = 0; dwIdx < dwNameCount; dwIdx++)
        {
            // 序号表中的元素的值 对应着函数地址表的位置
            if (pEIT[dwIdx] == i)
            {
                //根据序号获取到名称表中的名字
                DWORD dwNameOffset = pENT[dwIdx];
                char * pFunName = (char*)(dwAddrBase + dwNameOffset);

                //判断是否是GetProcAddress函数
                if (!strcmp(pFunName, "GetProcAddress"))
                {
                    // 获取EAT的地址 并将GetProcAddress地址返回
                    DWORD dwFunAddrOffset = pEAT[i];
                    return dwAddrBase + dwFunAddrOffset;
                }
            }
        }
    }
    return -1;
}
//初始化API
bool InitializationAPI()
{
    g_num;//使用tls变量,产生tls节表
    //初始化
    g_funGetProcAddress              = (LPGETPROCADDRESS)   GetGPAFunAddr();
    g_funLoadLibraryEx               = (LPLOADLIBRARYEX)    g_funGetProcAddress((HMODULE)GetKernel32Base(), "LoadLibraryExW");
    hModuleKernel32                  =                      g_funLoadLibraryEx(L"Kernel32.dll", NULL, NULL);
    hModuleUser32                    =                      g_funLoadLibraryEx(L"user32.dll", NULL, NULL);
    g_LoadLibraryA                   = (MYLOADLIBRARY)      g_funGetProcAddress(hModuleKernel32, "LoadLibraryA");
    g_funGetModuleHandle             = (GETModuleHandle)    g_funGetProcAddress(hModuleKernel32, "GetModuleHandleW");
    g_VirtualAlloc                   = (MYVIRTUALALLOC)     g_funGetProcAddress(hModuleKernel32, "VirtualAlloc");
    g_VirtualFree                    = (MYVIRTUALFREE)      g_funGetProcAddress(hModuleKernel32, "VirtualFree");
    g_funMessageBox                  = (LPMESSAGEBOX)       g_funGetProcAddress(hModuleUser32, "MessageBoxW");
    g_funCreateWindowEx              = (CREateWindowEx)     g_funGetProcAddress(hModuleUser32, "CreateWindowExW");
    g_funPostQuitMessage             = (POSTQuitMessage)    g_funGetProcAddress(hModuleUser32, "PostQuitMessage");
    g_funDefWindowProc               = (DEFWindowProc)      g_funGetProcAddress(hModuleUser32, "DefWindowProcW");
    g_funGetMessage                  = (GteMessage)         g_funGetProcAddress(hModuleUser32, "GetMessageW");
    g_funRegisterClass               = (REGisterClass)      g_funGetProcAddress(hModuleUser32, "RegisterClassW");
    g_funShowWindow                  = (SHOWWINDOW)         g_funGetProcAddress(hModuleUser32, "ShowWindow");
    g_funUpdateWindow                = (UPDateWindow)       g_funGetProcAddress(hModuleUser32, "UpdateWindow");
    g_funDispatchMessage             = (DISpatchMessage)    g_funGetProcAddress(hModuleUser32, "DispatchMessageW");
    g_funGetWindowText               = (GETWindowText)      g_funGetProcAddress(hModuleUser32, "GetWindowTextW");
    g_funGetWindowTextLength         = (GETWindowTextLength)g_funGetProcAddress(hModuleUser32, "GetWindowTextLengthW");
    g_funGetDlgItem                  = (GETDlgItem)         g_funGetProcAddress(hModuleUser32, "GetDlgItem");
    g_funSetWindowText               = (SETWindowText)      g_funGetProcAddress(hModuleUser32, "SetWindowTextW");
    g_funTranslateMessage            = (TRanslateMessage)   g_funGetProcAddress(hModuleUser32, "TranslateMessage");

    g_dwImageBase                    = (DWORD)g_funGetModuleHandle(NULL);
    g_oep                            = g_PackInfo.TargetOepRva + g_dwImageBase;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////

LRESULT CALLBACK WindowProc(
    _In_ HWND   hwnd,
    _In_ UINT   uMsg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
) {

    switch (uMsg)
    {
    case WM_CREATE: {
        wchar_t wStr[20] = L"窗口回调函数触发";
        wchar_t wStr2[20] = L"haha";
        g_funMessageBox(NULL, wStr, wStr2, NULL);
        /////////////////////////////////////////////////////////////////////////////////////
        DWORD dwStyle = ES_LEFT | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE;
        DWORD dwExStyle = WS_EX_CLIENTEDGE | WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR;
        HWND hWnd = g_funCreateWindowEx(
            dwExStyle, //dwExStyle 扩展样式
            L"Edit", //lpClassName 窗口类名
            wStrtext, //lpWindowName 窗口标题
            dwStyle, //dwStyle 窗口样式
            150, //x 左边位置
            100, //y 顶边位置
            200, //nWidth 宽度
            20, //nHeight 高度
            hwnd, //hWndParent 父窗口句柄
            (HMENU)0x1002, //ID
            g_funGetModuleHandle(0), //hInstance 应用程序句柄
            NULL //lpParam 附加参数
        );
        return 0;
        /////////////////////////////////////////////////////////////////////////////////
    }
    case WM_COMMAND: {
        WORD wId = LOWORD(wParam);
        WORD wCode = HIWORD(wParam);
        HANDLE hChild = (HANDLE)lParam;
        if (wId == 0x1001 && wCode == BN_CLICKED)
        {

            HWND hwndCombo = g_funGetDlgItem(hwnd, 0x1002);
            int cTxtLen = g_funGetWindowTextLength(hwndCombo);
            g_funGetWindowText(hwndCombo, g_wcbuf100, 100);

            wchar_t wStr[20] = L"按钮触发";
            wchar_t wStr2[20] = L"haha";
            g_funMessageBox(NULL, wStr, wStr2, NULL);
            wchar_t wStr3[20] = L"";
            if (decide() == 1) {
                //g_funPostQuitMessage(0);
                g_funShowWindow(hwnd, SW_HIDE);
                //运行壳代码
                FusedFunc((DWORD)AllFunc);
                //_asm jmp g_PackInfo.TargetOep;
                wchar_t wStr[20] = L"密码正确!!!";
                wchar_t wStr2[20] = L"haha";
                g_funMessageBox(NULL, wStr, wStr2, NULL);
                _asm jmp g_oep;
            }
            else {
                wchar_t wStr[20] = L"密码错误请重新输入!!!";
                wchar_t wStr2[20] = L"haha";
                g_funMessageBox(NULL, wStr, wStr2, NULL);
            }
            g_funSetWindowText(hwndCombo, wStr3);
            return 1;
        }
        break;
    }
    case WM_CLOSE:
    {
        g_funPostQuitMessage(0);
        //return 0;
        break;
    }

    }
    // 返回默认的窗口处理过程
    return g_funDefWindowProc(hwnd, uMsg, wParam, lParam);
}
void CtrateWin() {

    MSG msg = { 0 };
    wchar_t wStr[20] = L"allenboy";
    wchar_t wStr2[20] = L"haha";
    g_funMessageBox(NULL, wStr, wStr2, NULL);
    // 先注册窗口类
    WNDCLASS wcs = {};
    wcs.lpszClassName = L"dragon";
    wcs.lpfnWndProc = WindowProc;
    wcs.hbrBackground = (HBRUSH)(COLOR_CAPTIONTEXT + 1);
    /////////////////////////////////////////////////////////////////////////////////////////
    //RegisterClass
    //RegisterClass(&wcs);
    g_funRegisterClass(&wcs);
    //#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
        //nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
//注册窗口
//CreateWindowEx

//窗口类名一定要与上面的一致
    HWND hWnd = g_funCreateWindowEx(0L, L"dragon", L"haidragon", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
        500, 200, 500, 500,
        NULL, NULL, NULL, NULL);
    // 三种风格  WS_OVERLAPPEDWINDOW  WS_POPUPWINDOW  WS_CHILDWINDOW

    g_funCreateWindowEx(0L, L"BUTTON", L"ok", WS_CHILD | WS_VISIBLE,
        200, 150,// 在父窗口的客户区的位置,
        100, 50,// 宽 高
        hWnd,// 父窗口
        (HMENU)0x1001,// 如果是顶层窗口 就是菜单句柄 子窗口就是本身的ID
                      //GetModuleHandle
        g_funGetModuleHandle(0), NULL);

    //ShowWindow(hWnd, SW_SHOW);
    g_funShowWindow(hWnd, SW_SHOW);
    g_funUpdateWindow(hWnd);
    /*while (GetMessage(&msg, 0, 0, 0))
    {
    DispatchMessage(&msg);
    }*/
    while (g_funGetMessage(&msg, 0, 0, 0))
    {

        //DispatchMessage(&msg);
        g_funTranslateMessage(&msg);
        g_funDispatchMessage(&msg);
    }
}


效果图

加密代码段 简单异或


//对代码段进行加密
void PEpack::Encode()
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)m_pNewBuf;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + m_pNewBuf);
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);
    // 定位到代码段,并将每个段加密
    pSection = pSection + m_codeIndex;
    PCHAR pStart = pSection->PointerToRawData + m_pNewBuf;
    for (int i = 0; i < (pSection->Misc.VirtualSize); i++)
    {
        pStart[i] ^= 0x20;
    }

}
////////////壳中解密//////////////////////
//解密
void Decode()
{

    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)g_dwImageBase;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + g_dwImageBase);
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);

    // 找到.text段,并解密
    while (TRUE)
    {
        if (!strcmp((char*)pSection->Name, ".text"))
        {
            PCHAR pStart = pSection->VirtualAddress + (PCHAR)g_dwImageBase;
            for (int i = 0; i < pSection->Misc.VirtualSize; i++)
            {
                pStart[i] ^= 0x20;
            }
            break;
        }
        pSection = pSection + 1;
    }
}


压缩(除tls 表  资源表 与 头除外 这里先于拷贝壳的重定位表 不然也会被压缩 就运行不起来了 )
压缩时的问题有 资源段问题  tls段问题
首先 运行时很会用到 资源 同时当运行壳代码之前会启动线程,因些就会用到tls数据段
所以这俩个都不压 其它全部压然后 放到最后,同时在压缩的时候重建PE(也就是后面的往上移)
最重的一点是在所有操作前 保存相关节与节的前后顺序与在原来大小和压缩后的大小等等


效果图

压缩 (同时重建PE)


//压缩PE文件

void PEpack::CompressPE(PPACKINFO &pPackInfo)
{
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)m_pNewBuf;
    PIMAGE_NT_HEADERS pNt = (PIMAGE_NT_HEADERS)(pDos->e_lfanew + m_pNewBuf);
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);

    // 用于记录压缩区段的个数
    pPackInfo->PackSectionNumber = 0;

    // 1.1 获取文件头的大小,并获取除资源段,tls之外段的文件中的总大小
    DWORD SecSizeWithOutResAndTls = 0;
    PIMAGE_SECTION_HEADER pSectionTmp1 = pSection;
    BOOL isFirstNoEmptySec = TRUE;
    DWORD dwHeaderSize = 0;
    //先计算要拷贝的总大小
    for (SIZE_T i = 0; i < pNt->FileHeader.NumberOfSections; i++)
    {
        // 用于获得第一个非空区段的文件偏移,也就是文件头大小
        if (isFirstNoEmptySec && pSectionTmp1->SizeOfRawData != 0)
        {
            dwHeaderSize = pSectionTmp1->PointerToRawData;
            isFirstNoEmptySec = FALSE;
        }
        // 用于获取 非 rsrc/tls段的总大小
        if (pSectionTmp1->VirtualAddress != m_pResSectionRva &&
            pSectionTmp1->VirtualAddress != m_pTlsSectionRva)
        {
            SecSizeWithOutResAndTls += pSectionTmp1->SizeOfRawData;
        }
        pSectionTmp1 = pSectionTmp1 + 1;
    }
    // 1.2 读取要压缩的段到内存
    // 申请内存
    PCHAR memWorked = new CHAR[SecSizeWithOutResAndTls];
    // 已经拷贝的内存大小
    DWORD dwCopySize = 0;
    // 保存这些区段到内存
    PIMAGE_SECTION_HEADER pSectionTmp2 = pSection;
    //再次循环
    for (SIZE_T i = 0; i < pNt->FileHeader.NumberOfSections; i++)
    {
        //判断是否为tls与资源表
        if (pSectionTmp2->VirtualAddress != m_pResSectionRva &&
            pSectionTmp2->VirtualAddress != m_pTlsSectionRva)
        {
         //开始拷贝
            memcpy_s(memWorked + dwCopySize, pSectionTmp2->SizeOfRawData,
                m_pNewBuf + pSectionTmp2->PointerToRawData, pSectionTmp2->SizeOfRawData);
            dwCopySize += pSectionTmp2->SizeOfRawData;
        }
        pSectionTmp2 = pSectionTmp2 + 1;
    }
    // 1.3 压缩,并获取压缩后的大小(文件对齐在添加区段中进行)
    LONG blen;
    PCHAR packBuf = Compress(memWorked, SecSizeWithOutResA    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程