一个简单的EXE外壳,PE加壳工具热乎的

2018年10月10日 222点热度 0人点赞 0条评论

简单的EXE外壳,只有 初级的功能,壳子程序是一段ShellCode,会弹出来一个消息框,可以处理一下做一个exe的加密工具;也可以该吧改吧,做一个完善的壳子。

《加密与解密(第三版)》中的壳子是用汇编写的,没写过几行汇编,所以就用C实现了,开始加完壳子不能运行,用X64dbg调了半个小时才找到。志同道合的朋友如果需要可以拿去使用。不说废话,上代码。

加壳程序:

* Copyright (c) 2018 initm.com All rights reserved.
* 作者: 梦回起点
* 功能: 软件加壳
* 邮件: i@initm.com
* 描述: 软件加壳,并为加壳后的软件增加一个消息框
* 限制: 1.目前只有保护导入表的功能
*       2.只能加密32位exe文件
*       3.只能处理节表有空余位置的文件
* 声明:1.水能载舟,亦能覆舟。这段代码改一下就是一个EXE加密工具、外壳;同样加点功能也会变成木马、病毒。我劝你善良
*       2.代码可以在注明出处的情况下无条件复制,传播。
* 完成时间: 2018-10-10 10:18
*/


/*
// 存放壳子运行需要数据及保存的导入表和重定位表的信息等  存放ShellCode尾部,相当于从end函数的地方开始写
// 保存当前镜像的基地址
*/ 
///////////////////////////ShellCode 在这里////////////////////////
// DWORD pImageBase ;这个镜像基址因为只加密exe所以没啥用。dll重定位需要使用,但是没做这个功能
// DWORD nOEP  ;原来程序的入口点
// DWORD nImportNowRVA ;现在导入表的RVA  就是原区段最后的rva+shellcode的大小+sizeof(DWORD)*4
// DWORD nImportRVA ;这个是原来的导入表的RVA

// 壳子导入表的存储结构复制的《加密与解密(第三版)》中的那个结构
// ImportTable	 DD	AddressFirst - ImportTable; OriginalFirstThunk
// DD	0, 0; TimeDataStamp, ForwardChain
// AppImpRVA1	 DD	DllName - ImportTable; Name
// AppImpRVA2	 DD	AddressFirst - ImportTable; FirstThunk
// DD	0, 0, 0, 0, 0
// AddressFirst	 DD	FirstFunc - ImportTable; 指向IMAGE_tHUNK_DATA
// AddressSecond	 DD	SecondFunc - ImportTable; 指向IMAGE_tHUNK_DATA
// AddressThird	 DD	ThirdFunc - ImportTable; 指向IMAGE_tHUNK_DATA
// DD	0
// DllName		 DB	'KERNEL32.dll'
// DW	0
// FirstFunc	 DW	0
// DB	'GetProcAddress', 0
// SecondFunc	 DW	0
// DB	'GetModuleHandleA', 0
// ThirdFunc	 DW	0
// DB	'LoadLibraryA', 0
// ImportTableEnd  LABEL	DWORD
// 原来的导入表结构如下
// |(PDWORD)FirstThunk|(PDWORD)functionCount|(PBYTE)dllName or (PDWORD) number|(PBYTE)functionName(...X functionCount)|(PDWORD)FirstThunk|...

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
//这里就是ShellCode的代码编译出来的硬编码,这个只是加壳
PCHAR ShellCode = "\x55\x8B\xEC\xE8\x08\x00\x00\x00\x5D\xC3\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x0C\xC7\x45\xFC\x00\x00\x00\x00\x8D\x45\xFC\x89\x45\xFC\x8B\x4D\xFC\x83\xC1\x08\x89\x4D\xFC\x8B\x55\xFC\x8B\x02\x83\xE8\x08\x89\x45\xFC\xB9\x10\x10\x1F\x00\x81\xE9\x00\x10\x1F\x00\x03\x4D\xFC\x89\x4D\xFC\xBA\xA0\x12\x1F\x00\x81\xEA\x10\x10\x1F\x00\x03\x55\xFC\x89\x55\xF8\x8B\x45\xF8\x50\xB9\xB0\x10\x1F\x00\x81\xE9\x10\x10\x1F\x00\x03\x4D\xFC\x51\xE8\x3F\x00\x00\x00\x83\xC4\x08\x89\x45\xF4\xFF\x55\xF4\x8B\xE5\x5D\xC3\xCC\xCC\x55\x8B\xEC\x51\xC7\x45\xFC\x00\x00\x00\x00\x8B\x45\x08\x03\x45\xFC\x0F\xBE\x08\x85\xC9\x74\x0B\x8B\x55\xFC\x83\xC2\x01\x89\x55\xFC\xEB\xE8\x8B\x45\xFC\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x3C\x8B\x45\x0C\x83\xC0\x10\x89\x45\xD4\x8B\x4D\xD4\x83\xC1\x28\x89\x4D\xE8\xBA\x04\x00\x00\x00\x6B\xC2\x00\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xD8\xB8\x04\x00\x00\x00\xC1\xE0\x00\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xD0\xB8\x04\x00\x00\x00\xD1\xE0\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xC8\x6A\x00\xFF\x55\xD0\x89\x45\xEC\x8B\x45\x0C\x8B\x48\x04\x89\x4D\xC4\x8B\x55\x0C\x8B\x45\xEC\x03\x42\x08\x89\x45\xFC\x8B\x4D\x0C\x8B\x55\xEC\x03\x51\x0C\x89\x55\xF0\xC7\x45\xF8\x00\x00\x00\x00\x8B\x45\xFC\x83\x38\x00\x0F\x84\x5D\x01\x00\x00\x6B\x4D\xF8\x14\x8B\x55\xF0\x8B\x45\xFC\x8B\x00\x89\x44\x0A\x10\x6B\x4D\xF8\x14\x8B\x55\xF0\x8B\x45\xEC\x03\x44\x0A\x10\x89\x45\xDC\x8B\x4D\xFC\x8B\x51\x04\x89\x55\xCC\x6B\x45\xF8\x14\x8B\x4D\xF0\xC7\x44\x01\x04\x00\x00\x00\x00\x6B\x55\xF8\x14\x8B\x45\xF0\xC7\x44\x10\x08\x00\x00\x00\x00\x8B\x4D\xFC\x83\xC1\x08\x89\x4D\xE4\x8B\x55\xE4\x2B\x55\xEC\x6B\x45\xF8\x14\x8B\x4D\xF0\x89\x54\x01\x0C\x8B\x55\xE4\x52\xE8\xDF\xFE\xFF\xFF\x83\xC4\x04\x8B\x4D\xFC\x8D\x54\x01\x09\x89\x55\xFC\xC7\x45\xF4\x00\x00\x00\x00\xEB\x09\x8B\x45\xF4\x83\xC0\x01\x89\x45\xF4\x8B\x4D\xF4\x3B\x4D\xCC\x0F\x8D\xB9\x00\x00\x00\x8B\x55\xE4\x52\xFF\x55\xC8\x89\x45\xE0\x83\x7D\xE0\x00\x74\x65\x8B\x45\xFC\x8B\x08\x81\xE1\x00\x00\x00\xF0\x81\xF9\x00\x00\x00\xF0\x75\x26\x8B\x55\xFC\x8B\x02\x25\xFF\xFF\xFF\x0F\x50\x8B\x4D\xE0\x51\xFF\x55\xD8\x8B\x55\xF4\x8B\x4D\xDC\x89\x04\x91\x8B\x55\xFC\x83\xC2\x04\x89\x55\xFC\xEB\x2A\x8B\x45\xFC\x50\x8B\x4D\xE0\x51\xFF\x55\xD8\x8B\x55\xF4\x8B\x4D\xDC\x89\x04\x91\x8B\x55\xFC\x52\xE8\x4E\xFE\xFF\xFF\x83\xC4\x04\x8B\x4D\xFC\x8D\x54\x01\x01\x89\x55\xFC\xEB\x3F\x8B\x45\xF4\x8B\x4D\xDC\xC7\x04\x81\x00\x00\x00\x00\x8B\x55\xFC\x8B\x02\x25\x00\x00\x00\xF0\x3D\x00\x00\x00\xF0\x75\x0B\x8B\x4D\xFC\x83\xC1\x04\x89\x4D\xFC\xEB\x16\x8B\x55\xFC\x52\xE8\x0D\xFE\xFF\xFF\x83\xC4\x04\x8B\x4D\xFC\x8D\x54\x01\x01\x89\x55\xFC\xE9\x32\xFF\xFF\xFF\x8B\x45\xF8\x83\xC0\x01\x89\x45\xF8\xE9\x97\xFE\xFF\xFF\x8B\x45\xEC\x03\x45\xC4\x8B\xE5\x5D\xC3\xCC\xCC\xCC";
//这个可以弹出一个MessageBox,ShellCode中的代码对应的就是这个
PCHAR ShellCodeMessage = "\x55\x8B\xEC\xE8\x08\x00\x00\x00\x5D\xC3\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x0C\xC7\x45\xFC\x00\x00\x00\x00\x8D\x45\xFC\x89\x45\xFC\x8B\x4D\xFC\x83\xC1\x08\x89\x4D\xFC\x8B\x55\xFC\x8B\x02\x83\xE8\x08\x89\x45\xFC\xB9\x10\x10\x38\x01\x81\xE9\x00\x10\x38\x01\x03\x4D\xFC\x89\x4D\xFC\xBA\x40\x13\x38\x01\x81\xEA\x10\x10\x38\x01\x03\x55\xFC\x89\x55\xF8\x8B\x45\xF8\x50\xB9\xB0\x10\x38\x01\x81\xE9\x10\x10\x38\x01\x03\x4D\xFC\x51\xE8\x3F\x00\x00\x00\x83\xC4\x08\x89\x45\xF4\xFF\x55\xF4\x8B\xE5\x5D\xC3\xCC\xCC\x55\x8B\xEC\x51\xC7\x45\xFC\x00\x00\x00\x00\x8B\x45\x08\x03\x45\xFC\x0F\xBE\x08\x85\xC9\x74\x0B\x8B\x55\xFC\x83\xC2\x01\x89\x55\xFC\xEB\xE8\x8B\x45\xFC\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\xCC\xCC\x55\x8B\xEC\x83\xEC\x64\x8B\x45\x0C\x83\xC0\x10\x89\x45\xD0\x8B\x4D\xD0\x83\xC1\x28\x89\x4D\xE8\xBA\x04\x00\x00\x00\x6B\xC2\x00\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xDC\xB8\x04\x00\x00\x00\xC1\xE0\x00\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xCC\xB8\x04\x00\x00\x00\xD1\xE0\x8B\x4D\xE8\x8B\x14\x01\x89\x55\xD4\x6A\x00\xFF\x55\xCC\x89\x45\xEC\xC6\x45\xA8\x55\xC6\x45\xA9\x73\xC6\x45\xAA\x65\xC6\x45\xAB\x72\xC6\x45\xAC\x33\xC6\x45\xAD\x32\xC6\x45\xAE\x2E\xC6\x45\xAF\x64\xC6\x45\xB0\x6C\xC6\x45\xB1\x6C\xC6\x45\xB2\x00\xC6\x45\x9C\x4D\xC6\x45\x9D\x65\xC6\x45\x9E\x73\xC6\x45\x9F\x73\xC6\x45\xA0\x61\xC6\x45\xA1\x67\xC6\x45\xA2\x65\xC6\x45\xA3\x42\xC6\x45\xA4\x6F\xC6\x45\xA5\x78\xC6\x45\xA6\x41\xC6\x45\xA7\x00\x8D\x45\xA8\x50\xFF\x55\xD4\x89\x45\xC8\x8D\x4D\x9C\x51\x8B\x55\xC8\x52\xFF\x55\xDC\x89\x45\xC4\xC6\x45\xB4\x48\xC6\x45\xB5\x65\xC6\x45\xB6\x6C\xC6\x45\xB7\x6C\xC6\x45\xB8\x6F\xC6\x45\xB9\x00\x6A\x00\x8D\x45\xB4\x50\x8D\x4D\xB4\x51\x6A\x00\xFF\x55\xC4\x8B\x55\x0C\x8B\x42\x04\x89\x45\xBC\x8B\x4D\x0C\x8B\x55\xEC\x03\x51\x08\x89\x55\xFC\x8B\x45\x0C\x8B\x4D\xEC\x03\x48\x0C\x89\x4D\xF0\xC7\x45\xF8\x00\x00\x00\x00\x8B\x55\xFC\x83\x3A\x00\x0F\x84\x5E\x01\x00\x00\x6B\x45\xF8\x14\x8B\x4D\xF0\x8B\x55\xFC\x8B\x12\x89\x54\x01\x10\x6B\x45\xF8\x14\x8B\x4D\xF0\x8B\x55\xEC\x03\x54\x01\x10\x89\x55\xD8\x8B\x45\xFC\x8B\x48\x04\x89\x4D\xC0\x6B\x55\xF8\x14\x8B\x45\xF0\xC7\x44\x10\x04\x00\x00\x00\x00\x6B\x4D\xF8\x14\x8B\x55\xF0\xC7\x44\x0A\x08\x00\x00\x00\x00\x8B\x45\xFC\x83\xC0\x08\x89\x45\xE4\x8B\x4D\xE4\x2B\x4D\xEC\x6B\x55\xF8\x14\x8B\x45\xF0\x89\x4C\x10\x0C\x8B\x4D\xE4\x51\xE8\x44\xFE\xFF\xFF\x83\xC4\x04\x8B\x55\xFC\x8D\x44\x02\x09\x89\x45\xFC\xC7\x45\xF4\x00\x00\x00\x00\xEB\x09\x8B\x4D\xF4\x83\xC1\x01\x89\x4D\xF4\x8B\x55\xF4\x3B\x55\xC0\x0F\x8D\xBA\x00\x00\x00\x8B\x45\xE4\x50\xFF\x55\xD4\x89\x45\xE0\x83\x7D\xE0\x00\x74\x66\x8B\x4D\xFC\x8B\x11\x81\xE2\x00\x00\x00\xF0\x81\xFA\x00\x00\x00\xF0\x75\x27\x8B\x45\xFC\x8B\x08\x81\xE1\xFF\xFF\xFF\x0F\x51\x8B\x55\xE0\x52\xFF\x55\xDC\x8B\x4D\xF4\x8B\x55\xD8\x89\x04\x8A\x8B\x45\xFC\x83\xC0\x04\x89\x45\xFC\xEB\x2A\x8B\x4D\xFC\x51\x8B\x55\xE0\x52\xFF\x55\xDC\x8B\x4D\xF4\x8B\x55\xD8\x89\x04\x8A\x8B\x45\xFC\x50\xE8\xB2\xFD\xFF\xFF\x83\xC4\x04\x8B\x4D\xFC\x8D\x54\x01\x01\x89\x55\xFC\xEB\x3F\x8B\x45\xF4\x8B\x4D\xD8\xC7\x04\x81\x00\x00\x00\x00\x8B\x55\xFC\x8B\x02\x25\x00\x00\x00\xF0\x3D\x00\x00\x00\xF0\x75\x0B\x8B\x4D\xFC\x83\xC1\x04\x89\x4D\xFC\xEB\x16\x8B\x55\xFC\x52\xE8\x71\xFD\xFF\xFF\x83\xC4\x04\x8B\x4D\xFC\x8D\x54\x01\x01\x89\x55\xFC\xE9\x31\xFF\xFF\xFF\x8B\x45\xF8\x83\xC0\x01\x89\x45\xF8\xE9\x96\xFE\xFF\xFF\x8B\x45\xEC\x03\x45\xBC\x8B\xE5\x5D\xC3\xCC\xCC\xCC\xCC\xCC\xCC\xCC";
//两段ShellCode各自的字节数
#define SHELLCODESIZE 672
#define SHELLCODEMESSAGESIZE 832

//对齐
size_t AlignSize(const size_t&amp; size, const DWORD&amp; align)
{
    return (size + align - 1) / align * align;
}

//转换一个rva到指针
PCHAR RVA2Ptr(PCHAR pHeader, const DWORD&amp; rva)
{
    return pHeader + rva;
}

/*******************************************************************************/
/*             ImportSaveAndClear用来保存并清空原来的导入表                      */
/* |(PDWORD)FirstThunk|(PDWORD)functionCount|(PBYTE)dllName|(PBYTE)functionName*/
/* char* pBuffer 存放这个结构的地址                                             */
/* PIMAGE_IMPORT_DESCRIPTOR pImport 程序导入表的地址                            */
/* char* lpHeader 文件内存中展开的首地址                                        */
/*******************************************************************************/
size_t ImportSaveAndClear(PCHAR pBuffer, PIMAGE_IMPORT_DESCRIPTOR pImport, PCHAR lpHeader)
{
    IMAGE_IMPORT_DESCRIPTOR empty;
    memset(&amp;empty, 0, sizeof(empty));
    PCHAR pBackBuffer = pBuffer;
    
    //如果是最后一个了,那么返回
    while (0 != memcmp(pImport, &amp;empty, sizeof(empty))){
        //保存FristThunk
        *(PDWORD)pBuffer = pImport-&gt;FirstThunk;
        pBuffer += sizeof(DWORD);
        //保存函数的个数
        PDWORD pCount = (PDWORD)pBuffer;
        pBuffer += sizeof(DWORD);
        //保存dll名字
        PCHAR name = (PCHAR)RVA2Ptr(lpHeader, pImport-&gt;Name);
        memcpy(pBuffer, name, strlen(name));
        pBuffer += strlen(name) + 1;

        PIMAGE_THUNK_DATA pIAT = (PIMAGE_THUNK_DATA)RVA2Ptr(lpHeader, pImport-&gt;FirstThunk);
        int nCount(0);
        for (nCount; pIAT-&gt;u1.AddressOfData; nCount++, pIAT++) {
            if (pIAT-&gt;u1.AddressOfData &amp; (0x1 &lt;&lt; 31)) {//如果是按照编号导出的 *(PDWORD)(pBuffer) = pIAT-&gt;u1.AddressOfData | 0xF0000000;
                pBuffer += sizeof(DWORD);
            }
            else {
                PIMAGE_IMPORT_BY_NAME name = (PIMAGE_IMPORT_BY_NAME)RVA2Ptr(lpHeader, pIAT-&gt;u1.AddressOfData);
                memset(pIAT, 0, sizeof(IMAGE_THUNK_DATA));
                memcpy(pBuffer, name-&gt;Name, strlen((LPCSTR)name-&gt;Name));
                pBuffer += strlen((LPCSTR)name-&gt;Name) + 1;
                memset(name, 0, sizeof(IMAGE_IMPORT_BY_NAME) + strlen((LPCSTR)name-&gt;Name));
            }
            
        }
        *pCount = nCount;//写入这个dll一共有多少个函数
        memset(pImport, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));
        pImport++;
    }
    (*(PDWORD)pBuffer) = 0;//写入一个结尾的标记
    pBuffer += sizeof(DWORD);
    return pBuffer - pBackBuffer;
}


/*******************************************************************************/
/*                           AddSection用来增加一个新节                         */
/* 没有考虑节表位置不够的情况,这种情况需要特殊处理的                              */
/* PIMAGE_SECTION_HEADER pImport 需要插入位置的地址                             */
/* DWORD size 需要插入的节的大小                                                */
/* DWORD rva内存中的偏移位置                                                    */
/* DWORD rvaAlign内存中的对齐大小                                               */
/* DWORD foa文件中的偏移位置                                                    */
/* DWORD fileAlign文件炸的对齐大小                                              */
/*******************************************************************************/
DWORD AddSection(PIMAGE_SECTION_HEADER pImport, DWORD size, DWORD rva,  DWORD rvaAlign, DWORD foa, DWORD fileAlign)
{//增加一个空余的节,如果没有地方,那么返回失败,这个可以修改的,可以合并现有节的,但是时间有限,不实现了
    IMAGE_SECTION_HEADER empty;
    memset(&amp;empty, 0, sizeof(IMAGE_SECTION_HEADER));
    //如果找到空余的段
    if (0 != memcmp(&amp;pImport[1], &amp;empty, sizeof(IMAGE_SECTION_HEADER))) {
        return 0;
    }
    pImport-&gt;Name[0] = 0;
    pImport-&gt;Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE;
    pImport-&gt;SizeOfRawData = AlignSize(size, fileAlign);
    pImport-&gt;PointerToRawData = foa;
    pImport-&gt;Misc.VirtualSize = AlignSize(size, rvaAlign);
    pImport-&gt;VirtualAddress = rva;

    return pImport-&gt;Misc.VirtualSize;
}

/*******************************************************************************/
/*                           AddShell主功能函数                                */
/*PCHAR szName 需要加壳的文件                                                  */
/*******************************************************************************/
void AddShell(PCHAR szName) 
{
    char tail[409600];
    size_t nShellImportSize(0);
    PCHAR lpSaveData(nullptr);
    size_t nSaveDataSize(0);
    memset(tail, 0, sizeof(tail));//用来存放构造的尾部数据
    //读取文件信息,EntryPoint,ImageBase
    DWORD nShellCodeSize(SHELLCODEMESSAGESIZE);
    //把ShellCode先读出来
    memcpy(tail, ShellCodeMessage, nShellCodeSize);
    PDWORD pImageBase = (PDWORD)&amp;tail[nShellCodeSize];
    PDWORD pEntryPoint = (PDWORD)&amp;tail[nShellCodeSize + sizeof(DWORD)];
    //现在变形的导入表的RVA
    PDWORD pImportNowRVA = (PDWORD)&amp;tail[nShellCodeSize + sizeof(DWORD) * 2];
    //原来导入表的RVA
    PDWORD pImportRVA = (PDWORD)&amp;tail[nShellCodeSize + sizeof(DWORD) * 3];
    
    
    HANDLE hFile = CreateFileA(szName, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
    if (INVALID_HANDLE_VALUE == hFile) {//打开文件失败
        return;
    }
    size_t nFileSize = GetFileSize(hFile, NULL);
    IMAGE_DOS_HEADER dosHeader;
    DWORD dwSize(0);
    if (!ReadFile(hFile, &amp;dosHeader, sizeof(dosHeader), &amp;dwSize, NULL)) {
        CloseHandle(hFile);
        return;
    }
    if (IMAGE_DOS_SIGNATURE != dosHeader.e_magic) {
        CloseHandle(hFile);
        return;
    }
    SetFilePointer(hFile, dosHeader.e_lfanew, 0, FILE_BEGIN);
    IMAGE_NT_HEADERS ntHeader;
    if (!ReadFile(hFile, &amp;ntHeader, sizeof(ntHeader), &amp;dwSize, NULL)) {
        CloseHandle(hFile);
        return;
    }
    if (IMAGE_NT_SIGNATURE != ntHeader.Signature) {
        CloseHandle(hFile);
        return;
    }
    *pImageBase = ntHeader.OptionalHeader.ImageBase;
    *pEntryPoint = ntHeader.OptionalHeader.AddressOfEntryPoint;


    SetFilePointer(hFile, 0, 0, FILE_BEGIN);
    //读出PE头
    PCHAR lpBuffer = new CHAR[ntHeader.OptionalHeader.SizeOfImage];
    ReadFile(hFile, lpBuffer, ntHeader.OptionalHeader.SizeOfHeaders, &amp;dwSize, NULL);
    PIMAGE_NT_HEADERS pNtHeader((PIMAGE_NT_HEADERS)(lpBuffer + dosHeader.e_lfanew));

    PIMAGE_SECTION_HEADER pSectionTable((PIMAGE_SECTION_HEADER)((PBYTE)pNtHeader +  + sizeof(ntHeader.Signature) + sizeof(ntHeader.FileHeader) + ntHeader.FileHeader.SizeOfOptionalHeader));
    //处理节表
    size_t nSectionCount(pNtHeader-&gt;FileHeader.NumberOfSections);
    for (size_t i = 0; i &lt; nSectionCount; i++) { pSectionTable[i].SizeOfRawData = AlignSize(pSectionTable[i].SizeOfRawData, pNtHeader-&gt;OptionalHeader.FileAlignment);
        pSectionTable[i].Misc.VirtualSize = AlignSize(pSectionTable[i].Misc.VirtualSize, pNtHeader-&gt;OptionalHeader.SectionAlignment);
        pSectionTable[i].Characteristics |= IMAGE_SCN_MEM_WRITE;
        pSectionTable[i].Characteristics &amp;= ~IMAGE_SCN_MEM_SHARED;
        if (pNtHeader-&gt;FileHeader.NumberOfSections - 1 == i &amp;&amp;
            pSectionTable[i].VirtualAddress + pSectionTable[i].SizeOfRawData &gt; pNtHeader-&gt;OptionalHeader.SizeOfImage) {
            pSectionTable[i].SizeOfRawData = pNtHeader-&gt;OptionalHeader.SizeOfImage - pSectionTable[i].VirtualAddress;
        }
        SetFilePointer(hFile, pSectionTable[i].PointerToRawData, 0, FILE_BEGIN);
        //读取所有的节数据
        ReadFile(hFile, &amp;lpBuffer[pSectionTable[i].VirtualAddress], pSectionTable[i].SizeOfRawData, &amp;dwSize, 0);
    }
    //如果最后有数据
    size_t nSecitonAllSizeFile = pSectionTable[nSectionCount - 1].SizeOfRawData + pSectionTable[nSectionCount - 1].PointerToRawData;
    size_t nSecitonAllSize = pSectionTable[nSectionCount - 1].VirtualAddress + pSectionTable[nSectionCount - 1].Misc.VirtualSize;
    if (nSecitonAllSizeFile &lt; nFileSize) { nSaveDataSize = nFileSize - nSecitonAllSizeFile; lpSaveData = new char[nSaveDataSize]; SetFilePointer(hFile, nSecitonAllSizeFile, 0, FILE_BEGIN); //读取文件数据 ReadFile(hFile, lpSaveData, nSaveDataSize, &amp;dwSize, 0); } //获取导入表数据,构造自己的结构,清除现在的导入表,写入导入表 PIMAGE_IMPORT_DESCRIPTOR pImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RVA2Ptr(lpBuffer, pNtHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
    *pImportRVA = pNtHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    //把原来导入表的数据放进来,写这段的时候太痛苦了,纯体力劳动
    PBYTE pShellImportTable = (PBYTE)&amp;tail[nShellCodeSize + sizeof(DWORD) * 4];
    {//构造壳子的导入表
        PBYTE pPointer = pShellImportTable;
        //把导入表的RVA存起来
        *pImportNowRVA = nSecitonAllSize + nShellCodeSize + sizeof(DWORD) * 4;
        //AddressFirst
        DWORD AddressFirstRVA = *(PDWORD)pPointer = *pImportNowRVA + sizeof(IMAGE_IMPORT_DESCRIPTOR) * 2;
        pPointer += sizeof(DWORD);
        //TimeDataStamp
        *(PDWORD)pPointer = 0;
        pPointer += sizeof(DWORD);
        //ForwardChain
        *(PDWORD)pPointer = 0;
        pPointer += sizeof(DWORD);
        //DllName
        *(PDWORD)pPointer = AddressFirstRVA + sizeof(IMAGE_THUNK_DATA)*4;
        pPointer += sizeof(DWORD);
        //FirstThunk
        *(PDWORD)pPointer = AddressFirstRVA;
        pPointer += sizeof(DWORD);
        memset(pPointer, 0, sizeof(IMAGE_IMPORT_DESCRIPTOR));
        pPointer += sizeof(IMAGE_IMPORT_DESCRIPTOR);
        //IMAGE_tHUNK_DATA-FirstFunc
        ((PIMAGE_THUNK_DATA)pPointer)[0].u1.AddressOfData = AddressFirstRVA + sizeof(IMAGE_THUNK_DATA) * 4 + strlen("KERNEL32.dll") + 3;
        ((PIMAGE_THUNK_DATA)pPointer)[1].u1.AddressOfData = ((PDWORD)pPointer)[0] + strlen("GetProcAddress") + 1 + sizeof(WORD);
        ((PIMAGE_THUNK_DATA)pPointer)[2].u1.AddressOfData = ((PDWORD)pPointer)[1] + strlen("GetModuleHandleA") + 1 + sizeof(WORD);
        ((PIMAGE_THUNK_DATA)pPointer)[3].u1.AddressOfData = 0;
        pPointer += sizeof(IMAGE_THUNK_DATA) * 4;
        memcpy(pPointer, "KERNEL32.dll", strlen("KERNEL32.dll") + 1);
        pPointer += strlen("KERNEL32.dll") + 3;
        //IMAGE_IMPORT_BY_NAME
        ((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint = 0;
        memcpy(&amp;((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Name, "GetProcAddress", strlen("GetProcAddress")+1);
        pPointer += sizeof(((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint) + strlen("GetProcAddress") + 1;
        ((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint = 0;
        memcpy(&amp;((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Name, "GetModuleHandleA", strlen("GetModuleHandleA") + 1);
        pPointer += sizeof(((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint) + strlen("GetModuleHandleA") + 1;
        ((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint = 0;
        memcpy(&amp;((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Name, "LoadLibraryA", strlen("LoadLibraryA") + 1);
        pPointer += sizeof(((PIMAGE_IMPORT_BY_NAME)pPointer)-&gt;Hint) + strlen("LoadLibraryA") + 1;
        nShellImportSize = pPointer - pShellImportTable;
        *pImportNowRVA += nShellImportSize;
        //printf("%d", nShellImportSize);
    }
    size_t ImportSize = ImportSaveAndClear(&amp;tail[nShellCodeSize + sizeof(DWORD) * 4 + nShellImportSize], pImportTable, lpBuffer);
    //增加一个节,将ShellCode和尾部数据填入
    size_t nAddSectionSize = nShellCodeSize + sizeof(DWORD) * 4 + nShellImportSize + ImportSize;
    size_t sectionSize = AddSection(&amp;pSectionTable[nSectionCount], nAddSectionSize, nSecitonAllSize, pNtHeader-&gt;OptionalHeader.SectionAlignment, nSecitonAllSizeFile, pNtHeader-&gt;OptionalHeader.FileAlignment);
    if (0 == sectionSize) {//如果添加节失败了,那么返回
        CloseHandle(hFile);
        delete lpBuffer;
        delete lpSaveData;
        return;
    }
    //修改入口点,镜像大小
    pNtHeader-&gt;OptionalHeader.AddressOfEntryPoint = nSecitonAllSize;
    pNtHeader-&gt;OptionalHeader.SizeOfImage = pNtHeader-&gt;OptionalHeader.SizeOfImage + sectionSize;
    pNtHeader-&gt;OptionalHeader.SizeOfHeaders = AlignSize((char*)&amp;pSectionTable[nSectionCount+1] - lpBuffer, ntHeader.OptionalHeader.FileAlignment);
    pNtHeader-&gt;FileHeader.NumberOfSections += 1;
    pNtHeader-&gt;OptionalHeader.BaseOfCode = nSecitonAllSize;
    pNtHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = nShellImportSize;
    pNtHeader-&gt;OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = nSecitonAllSize + nShellCodeSize + sizeof(DWORD) * 4;
    //把这个文件写入
    //把文件原来的文件清空
    SetFilePointer(hFile, 0, 0, FILE_BEGIN);
    SetEndOfFile(hFile);
    //写入头部
    WriteFile(hFile, lpBuffer, pNtHeader-&gt;OptionalHeader.SizeOfHeaders, &amp;dwSize, 0);
    //写入各个区段信息
    for (int i = 0; i &lt; pNtHeader-&gt;FileHeader.NumberOfSections - 1; i++) {
        SetFilePointer(hFile, pSectionTable[i].PointerToRawData, 0, FILE_BEGIN);
        WriteFile(hFile, RVA2Ptr(lpBuffer, pSectionTable[i].VirtualAddress), pSectionTable[i].SizeOfRawData, &amp;dwSize, 0);
    }
    SetFilePointer(hFile, pSectionTable[pNtHeader-&gt;FileHeader.NumberOfSections - 1].PointerToRawData, 0, FILE_BEGIN);
    WriteFile(hFile, tail, pSectionTable[pNtHeader-&gt;FileHeader.NumberOfSections - 1].SizeOfRawData, &amp;dwSize, 0);
    //写入尾部信息
    if (nSaveDataSize) {
        SetFilePointer(hFile, 0, 0, FILE_END);
        WriteFile(hFile, lpSaveData, nSaveDataSize, &amp;dwSize, 0);
    }
    CloseHandle(hFile);
    delete lpBuffer;
    delete lpSaveData;
}

int main(int argc, char* argv[])
{
    if (argc &lt; 2) {
        printf("请拖动需要加密的文件到本文件上");
        getchar();

        return 0;
    }
    try{
        AddShell(argv[1]);
    }
    catch (std::bad_alloc) {
        printf("内存不足");
    }

    return 0;
}

 

 

 

壳子程序:

* Copyright (c) 2018 initm.com All rights reserved.
* 作者: 梦回起点
* 功能: 软件加壳
* 邮件: i@initm.com
* 描述: 软件加壳,并为加壳后的软件增加一个消息框
* 限制: 1.目前只有保护导入表的功能
*       2.只能加密32位exe文件
*       3.只能处理节表有空余位置的文件
* 声明:1.水能载舟,亦能覆舟。这段代码改一下就是一个EXE加密工具、外壳;同样加点功能也会变成木马、病毒。我劝你善良
*       2.代码可以在注明出处的情况下无条件复制,传播。
* 完成时间: 2018-10-10 10:18
*/
#include "stdafx.h"
#include <windows.h>

void Work();
PBYTE Restore(PBYTE pThisFunction, PBYTE pData);
void End();

typedef int (WINAPI *TMessageBoxA)( _In_opt_ HWND hWnd, _In_opt_ LPCSTR lpText, _In_opt_ LPCSTR lpCaption, _In_ UINT uType);
typedef HMODULE(WINAPI* TGetModuleHandleA)(_In_opt_ LPCSTR lpModuleName);
typedef FARPROC(WINAPI* TGetProcAddress)(__in HMODULE hModule, __in LPCSTR lpProcName);
typedef HMODULE (WINAPI* TLoadLibraryA)(__in LPCSTR lpLibFileName);

/////////////////////////////////ShellCode Start/////////////////////////////////
void Start()
{
    //push    ebp
    //mov     ebp, esp
    Work();//这里得先call一下,否则算不出来函数的地址
    //ret addr
}

/*
// 一般情况下,函数调用后栈中的情况是这个样子的,利用这个结构可以获取到返回地址,进而获取函数首地址
//       ebp-4 第一个变量
// ebp-&gt; old ebp
//       ret addr 
//       args
*/

void Work()
{
    /*
    * 这里这么复杂主要是为了获取本函数的地址和数据的地址
    * 第一个DWORD长度的空间存放ImageBase,就可以根据ImageBase来获取函数了
    */
    /*pThisFunction 在ebp-4的位置,这里根据编译器不同可能会不同*/
    PBYTE pThisFunction = nullptr;
    pThisFunction = (PBYTE)&amp;pThisFunction;
    pThisFunction += 8;/*现在指向的是返回地址*/
    /*8是	push    ebp
            mov     ebp, esp
            call    ?Work@@YAXXZ  三条指令的长度*/
    pThisFunction = (PBYTE)(*(PDWORD)pThisFunction) - 8;/*start的地址*/
    pThisFunction = pThisFunction + (DWORD)((PBYTE)Work - (PBYTE)Start);/*这里就是本函数的地址了*/
    PBYTE pData = pThisFunction + ((DWORD)End - (DWORD)Work);/*这里指向数据了,数据的格式需要定义*/
    //解密恢复原来的数据,返回入口点
    void(__stdcall * pEntryPoint)() = (void(__stdcall*)())Restore(pThisFunction + ((DWORD)Restore - (DWORD)Work), pData);
    //调用入口点
    pEntryPoint();
}

size_t MyStrlen(PCHAR str) {
    int i = 0;
    //找0
    while (str[i]) {
        i++;
    }
    return i;
}

PBYTE Restore(PBYTE pThisFunction, PBYTE pData) 
{
    //现在的导入表  获取当前程序运行时候的导入表
    PIMAGE_IMPORT_DESCRIPTOR  pImageTable = (PIMAGE_IMPORT_DESCRIPTOR)((PDWORD)pData + 4);
    PDWORD pImportFunctionAddr = (PDWORD)(pImageTable + 2);//这里就是导入函数的地址,因为是3个函数,所以一共占有4个DWORD

    TGetProcAddress pGetProcAddress = (TGetProcAddress)pImportFunctionAddr[0];
    TGetModuleHandleA  pGetModuleHandleA= (TGetModuleHandleA)pImportFunctionAddr[1];
    TLoadLibraryA pLoadLibraryA = (TLoadLibraryA)pImportFunctionAddr[2];
    //获取镜像的基地址
    PBYTE pImageBase = (PBYTE)pGetModuleHandleA(NULL);
    
    CHAR szUser32[] = {'U', 's', 'e', 'r', '3', '2', '.', 'd', 'l', 'l', '\0' };
    CHAR szMessageBox[] = {'M', 'e', 's', 's', 'a', 'g', 'e', 'B', 'o', 'x', 'A', '\0'};
    HMODULE hUser32 =  pLoadLibraryA(szUser32);
    TMessageBoxA pMessageBox = (TMessageBoxA)pGetProcAddress(hUser32, szMessageBox);
    CHAR szMessage[] = {'H', 'e', 'l', 'l', 'o', '\0'};
    pMessageBox(NULL, szMessage, szMessage, MB_OK);

    //入口点的rva 存储在偏移为1的地址
    DWORD nEntryPoint = *((PDWORD)pData + 1);
    //现在自定义结构的导入表的首地址
    PBYTE pImportTableNow = (PBYTE)(pImageBase + *((PDWORD)pData + 2));
    PIMAGE_IMPORT_DESCRIPTOR pImportTableRestore = (PIMAGE_IMPORT_DESCRIPTOR)(pImageBase + *((PDWORD)pData + 3));
    //char virtualAlloc[] = { 'V','i','r','t','u','a','l','A','l','l','o','c' };
    //根据函数的地址填充导入表
    //(PDWORD)FirstThunk | (PDWORD)functionCount | (PBYTE)dllName | (PBYTE)functionName(...X functionCount)
    INT j = 0;
    while (*(PDWORD)pImportTableNow)//如果没有到结尾
    {
        pImportTableRestore[j].FirstThunk = *(PDWORD)pImportTableNow;
        PDWORD pIAT = (PDWORD)(pImageBase + pImportTableRestore[j].FirstThunk);//IAT表
        INT count = *((PDWORD)pImportTableNow + 1); //获取这个dll一共导入了多少个函数
        pImportTableRestore[j].TimeDateStamp = 0;
        pImportTableRestore[j].ForwarderChain = 0;
        //赋值名字的RVA
        PBYTE name = (PBYTE)((PDWORD)pImportTableNow + 2);
        pImportTableRestore[j].Name = name - pImageBase;
        pImportTableNow = (PBYTE)((PDWORD)pImportTableNow + 2) + MyStrlen((PCHAR)name) + 1;
        //填充导入函数的地址
        for (INT i = 0; i &lt; count; i++){
            HMODULE hModule = pLoadLibraryA((PCHAR)name);
            if (hModule) {
                //如果是编号
                if (0xF0000000 == (*(PDWORD)pImportTableNow &amp; (0xF0000000))) {
                    pIAT[i] = (DWORD)pGetProcAddress(hModule, (LPCSTR)(*(PDWORD)pImportTableNow &amp; 0xFFFFFFF));
                    pImportTableNow += sizeof(DWORD);
                }else{
                    pIAT[i] = (DWORD)pGetProcAddress(hModule, (PCHAR)pImportTableNow);
                    pImportTableNow += MyStrlen((PCHAR)pImportTableNow) + 1;
                }
                //指向下一个函数
            }
            else {
                pIAT[i] = 0;
                if (0xF0000000 == (*(PDWORD)pImportTableNow &amp; (0xF0000000))) {
                    pImportTableNow += sizeof(DWORD);
                }
                else {
                    pImportTableNow += MyStrlen((PCHAR)pImportTableNow) + 1;
                }
            }
        }
        j++;
    }
    
    /*解密代码段*/
    //不考虑加密算法,先不写了吧
    //调用原函数入口点,这里有一个问题就是会多压入一个返回地址,但是无伤大雅,因为只考虑exe,所以多次进入该函数的情况不存在
    return (pImageBase + nEntryPoint);
}

//////////////////////////////ShellCode End////////////////////////////////////////
void __declspec(naked) End()
{

}


int main()
{
    //将ShellCode写出来 
    HANDLE hFile = CreateFileA("E:\\ShellCode.bin", GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    DWORD dwSize;
    WriteFile(hFile, (LPVOID)Start, (DWORD)((PBYTE)End - (PBYTE)Start), &amp;dwSize, NULL);
    CloseHandle(hFile);

    return 0;
}

 

 

Stupid

一个人用自己的船将他人送到彼岸,那他自己也到达了彼岸。

文章评论