首页
社区
课程
招聘
[原创]SimpleDpack_C++编写32位与64位shellcode压缩壳_PE结构与壳的原理讲解
发表于: 2021-2-26 17:55 34665

[原创]SimpleDpack_C++编写32位与64位shellcode压缩壳_PE结构与壳的原理讲解

2021-2-26 17:55
34665

by devseed,此篇教程同时发在论坛和我的博客上,完整源码见我的github

正好赶上元宵节写完了,祝大家元宵节快乐~
写教程不易,希望大家来给我的github点个star~

5年前,初入逆向,看着PE结构尤其是IAT一头雾水,对于脱壳原理理解不深刻,于是就用c++自己写了个简单的加壳工具(SimpleDpack)。最近回顾发现以前代码写的挺乱的,于是重构了一下代码,规范了命名和拆分了几个函数,使得结构清晰,稍微拓展一下支持64位。虽然这个toy example程序本身意义不大,但是通过这个程序可以来熟悉PE结构和加壳原理,深刻理解各种指针和内存分布等操作,对于初学者非常有帮助。于是我打算以此例来讲解Windows PE结构,谈谈加壳原理、编写shellcode等方法,解决方案和一些技巧等。

来讲述PE结构的教程虽然已经有很多了,但好多都是偏向于理论,很多东西不去文件中自己看看很不容易理解。这里将结合PE实例来分析其结构与作用。由于32位程序PE结构分析很多了,此处以64位程序为例分析 。其实pe64也就ImageBaseVAIATOFT等、堆栈大小等是ULONGLONG,其他和pe32基本保持一致。

Windows PE的数据结构定义在winnt.h头文件里,大体可以归纳下列几点:

具体细节可以看此图(来源于网络)

pe_structure

OptionalHeader的最后,有DataDirectory[16],定义了PE文件各 Directory的RVAsize,如下:

DLL导出表头,一般在.rdata.edata

里面有三个表的指针(RVA),都是数组形式存储(每个表里的项地址上是连续的),

上面这个看着有点抽象,来用user32.dll举个例子,可以手动的计算段内偏移。

IMAGE_EXPORT_DIRECTORY结构如下图,

user32_export

之后可以根据上表段内偏移来看查看函数RVA表函数名称RVA表,如下:

user32_export_ables

DLL导入表,一般在.rdata.idata

描述了若干个导入的DLL(IMAGE_IMPORT_DESCRIPTOR),每个DLL导入若干个函数(IMAGE_THUNK_DATA)

若干个IMAGE_IMPORT_DESCRIPTOR项组成数组,描述导入的若干个DLL,以全0项结尾

IMAGE_IMPORT_DESCRIPTOR结构中有IMAGE_THUNK_DAT数组指针(RVA),同样以全0项结尾。结构内含有其导入DLL中的函数信息指针(RVA)。两个数组指针如下:

OriginalFirstThunk(OFT)表:导入函数的函数序数、名称表,AddressOfData指针(RVA)指向IMAGE_IMPORT_BY_NAME结构

FirstThunk(FT)表:运行前的内容和OriginalFirstThunk一样,运行时加载为各函数的VA,即IAT

IMAGE_IMPORT_DESCRIPTOR中的一项,上面用section offset表示的,这里就用file offset表示了, 如下图所示:

user32_importdescripter

加载前OFT表和FT(IAT)表内容相同,都是指向IMAGE_IMPORT_BY_NAME结构,里面有序号和函数名。b1148h的file offset为b1148h-91000h + 8fe00h = aff48h,如下图所示。

user32_OFT_FT

即为我们所说的IAT表,多在.rdata

IAT表存储了各DLL函数的运行时地址VA(IAT在data directory中的声明并不是必要的,主要在运行时调用)。

程序运行前,IAT表的值与OFT表的值一样(即上一节说的运行前FT表与OFT表内的值一样)

编译器会把动态库函数用call [imagebase + iat + offset]这种内存间接寻址,即

call -> IAT(FT) -> func_addr

这个IMAGE_DIRECTORY_ENTRY_IATIMAGE_DIRECTORY_ENTRY_IMPORT的概念还挺绕的,为了形象说明,下面再以user32.dll为例分析,这次来分析x64的IATIAT的首项(64位每项占8字节)RVA91c58h,正好是FT指向的RVA,其值(b1148h)在程序加载前和OFT一样 。

user32_IAT_rva

user32_import_directory

user32_IAT_addr

我们在IDA中找到一处调用IAT第一项的call,即下图call cs:PatBlt。由于是64位汇编,call和jmp只能是对于于此RIP的+-2g地址空间跳转。即此处call (44 FF 15)后四字节(8e bb 06 00)为下一条指令地址和间接寻址内存的相对地址,即6bb8eh+260cah = 91c58h,正好是IAT的第一项地址。

user32_IAT_call

user32_IAT_addrida

重定向表,多在.reloc

记载了需要重定向的地址,在DLL中或是开启ASLR后,基址改变,通过此表来修改地址以匹配新的基址。

如下图,RVA=b20a0h中存储的地址需要重定向,因为F0 CE 02 80 01 00 00 00 00是以18000000000h为基址的VA,程序运行前需要重定向到对应基址。

user32_reloc

section header为PE头的最后一部分,里面储存的各个区段的File OffsetRVASizeCharacteristics等。RVAFile Offset地址转换要来查此表。关于区段头注意:

数据结构如下:

这部分主要就是根据结构,和偏移,来用指针指向对应的数据,详见CPEinfo类。

上一节说了好多,其实并不难,就是PE结构有一些地方比较绕,因此来分析了实际PE文件的几个部分。熟悉了PE结构,接下来开始谈谈加壳相关的了。

加壳主要有两部分:负责压缩修改等写入exe的加壳程序、嵌入exe的负责解压还原等操作的壳程序本身。

加壳程序作用:将区段压缩等原来的数据结构写入exe,重建PE结构等;把原程序OEP等参数重定向在壳内,重定向壳shellcode的地址等。

壳的作用:大体上来讲就是还原源程序各区段代码,同时模拟windows对程序的初始化,比如IAT表的载入等。

对于压缩壳,我们壳内的索引需要有

落实到代码上,在dPackType.h

压缩我们采取开源算法LZMA,简单wrapper一下,将LZMA的参数与解压大小等放到压缩数据头即可。其他方面如加密、反调试、花指令什么的暂不考虑,不过在这个我定义的框架下也很好添加。

shellcode一般都是用汇编去编写,但是我们要同时去做32位和64位程序,就要写两份汇编了。因此我们采取用c来编写shellcode,必要的地方加入汇编即可。同时,为了方便将shellcode附加到源程序上,我们采取将shellcode编译为DLL,这样就可以通过reloc方便的调整基址了。

在我们这个简单的压缩壳中,主要的是四部分:

为了方便扩展,比如说加密,添加stolen oep等,前后分别加上BeforeUnpack()AfterUnpack()空函数。此部分的完整代码在simpledpackshell.cppshellcode64.asm

直接用VirtualQueryExVirtualAllocEx即可

VirtualProtect申请写权限,解压代码到缓冲区再memcpy到制定位置即可,之后再恢复原来的保护权限。注意这里new的缓冲区一定要够,否则运行的时候会出现heap损坏等exception。同时,我们引入DPACK_SECTION_RAWDPACK_SECTION_DLZMA宏来作为压缩标志。

DPACK_SHELL_INDEX这个结构记载了原程序IAT,我们需要LoadLibraryGetProcAddress手动得到函数的地址,再写入源IAT中。

这个最简单的方法就是用push和ret实现了,我们用g_orgOep来表示源OEP的地址。

加壳程序主要进行下面方面的处理:

下面挑重点说一些操作,加壳程序完整代码在CSimpleDpack,对PE进行修改的代码见CPEedit

由于我们的shellcode在DLL中,因此可以直接LoadLibrary载入,GetProcAddress可以获取g_dpackShellIndex这个我们导出的壳的索引结构。对shellcode进行重定向和IAT的处理如下:

我们需要把一些信息调到壳上,还有最后一定要关掉ASLR,因为壳内跳转到OEP是硬编码的,不能让基址变化。

最后就是根据索引合并各个缓存区了,这里我们把shellcode和压缩数据都放到了最后一个区段,之后把PE缓存区根据FileAlignment保存即可。

由于64位的相关教程比较少,这里来说说如何同时支持64位和32位。

其实64位和32位结构很相似,也就是涉及到VAsize是ULONGLONG类型,大部分名称微软已经帮我们用宏重定向了64还是32位结构;还有一个麻烦事,在visual studio里面64位程序是没法开启内联汇编的。

关于64位数据类型不一样的地方,我们可以用宏_WIN64来区分是否64此程序,这样我们编译64位加壳程序后就能解析64位程序加壳了。比如说:

关于64位visual studio无法内联汇编,我们要:

至此,我们的程序可以同时支持64位和32位了。

 
|DOS header // e_lfanew
|NT header
  |file header // NumberOfSections, SizeOfOptionalHeader(x86=0xe0, x64=0xf0)
  |optional header
    |... //AddressOfEntryPoint(oep), ImageBase, SizeOfImage, SizeOfHeaders
    |data directory[16] //IMAGE_DIRECTORY_ENTRY_EXPORT, ..._IMPORT, ..._IAT
|section headers[n]
|DOS header // e_lfanew
|NT header
  |file header // NumberOfSections, SizeOfOptionalHeader(x86=0xe0, x64=0xf0)
  |optional header
    |... //AddressOfEntryPoint(oep), ImageBase, SizeOfImage, SizeOfHeaders
    |data directory[16] //IMAGE_DIRECTORY_ENTRY_EXPORT, ..._IMPORT, ..._IAT
|section headers[n]
 
typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
 
typedef struct _IMAGE_DATA_DIRECTORY { 
    DWORD   VirtualAddress; 
    DWORD   Size; 
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
 
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory, .edata
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory, .idata
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory , .rsrc
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory , .pdata
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table, .reloc
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data , 0
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of Global Ptr
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory , 线程局部存储
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11  // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table (.data)
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor
typedef struct _IMAGE_OPTIONAL_HEADER {
    ...
    IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
 
typedef struct _IMAGE_DATA_DIRECTORY { 
    DWORD   VirtualAddress; 
    DWORD   Size; 
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
 
#define IMAGE_DIRECTORY_ENTRY_EXPORT          0   // Export Directory, .edata
#define IMAGE_DIRECTORY_ENTRY_IMPORT          1   // Import Directory, .idata
#define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   // Resource Directory , .rsrc
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   // Exception Directory , .pdata
#define IMAGE_DIRECTORY_ENTRY_SECURITY        4   // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   // Base Relocation Table, .reloc
#define IMAGE_DIRECTORY_ENTRY_DEBUG           6   // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   // Architecture Specific Data , 0
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   // RVA of Global Ptr
#define IMAGE_DIRECTORY_ENTRY_TLS             9   // TLS Directory , 线程局部存储
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11  // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT            12   // Import Address Table (.data)
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   // COM Runtime descriptor
 
typedef struct _IMAGE_EXPORT_DIRECTORY { //Export Directory Table
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name; //  the name of the DLL, RVA
    DWORD   Base; // The starting ordinal number for exports in this image, usually 1
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // Export Address Table, RVA from base of image
    DWORD   AddressOfNames;         // Export Name Pointer Table, RVA
    DWORD   AddressOfNameOrdinals;  // Export Ordinal Table, RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
typedef struct _IMAGE_EXPORT_DIRECTORY { //Export Directory Table
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name; //  the name of the DLL, RVA
    DWORD   Base; // The starting ordinal number for exports in this image, usually 1
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // Export Address Table, RVA from base of image
    DWORD   AddressOfNames;         // Export Name Pointer Table, RVA
    DWORD   AddressOfNameOrdinals;  // Export Ordinal Table, RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
 
 
 
 
 
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;    // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;          
    DWORD   ForwarderChain; //index of the first forwarder reference, -1 if no
    DWORD   Name;             // RVA to the name of dll
    DWORD   FirstThunk;      // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
 
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE
        DWORD Function;             // PDWORD, va of the function, in ft, oat
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME, in oft
    } u1;
} IMAGE_THUNK_DATA32;
 
typedef struct _IMAGE_THUNK_DATA64 {
    union {
        ULONGLONG ForwarderString;  // PBYTE
        ULONGLONG Function;         // PDWORD, va of the function, in ft, oat
        ULONGLONG Ordinal;
        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME, in oft
    } u1;
} IMAGE_THUNK_DATA64;
 
typedef struct _IMAGE_IMPORT_BY_NAME { //in oft
    WORD    Hint;
    CHAR   Name[1]; // char *Name
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
    union {
        DWORD   Characteristics;    // 0 for terminating null import descriptor
        DWORD   OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
    } DUMMYUNIONNAME;
    DWORD   TimeDateStamp;          
    DWORD   ForwarderChain; //index of the first forwarder reference, -1 if no
    DWORD   Name;             // RVA to the name of dll
    DWORD   FirstThunk;      // RVA to IAT (if bound this IAT has actual addresses)
} IMAGE_IMPORT_DESCRIPTOR;
typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
 
typedef struct _IMAGE_THUNK_DATA32 {
    union {
        DWORD ForwarderString;      // PBYTE
        DWORD Function;             // PDWORD, va of the function, in ft, oat
        DWORD Ordinal;
        DWORD AddressOfData;        // PIMAGE_IMPORT_BY_NAME, in oft
    } u1;
} IMAGE_THUNK_DATA32;
 
typedef struct _IMAGE_THUNK_DATA64 {
    union {
        ULONGLONG ForwarderString;  // PBYTE
        ULONGLONG Function;         // PDWORD, va of the function, in ft, oat
        ULONGLONG Ordinal;
        ULONGLONG AddressOfData;    // PIMAGE_IMPORT_BY_NAME, in oft
    } u1;
} IMAGE_THUNK_DATA64;
 
typedef struct _IMAGE_IMPORT_BY_NAME { //in oft
    WORD    Hint;
    CHAR   Name[1]; // char *Name
} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
 
 
 
 
 
 
 
 
 
 
 
typedef struct _IMAGE_BASE_RELOCATION { // it has multi base relocation block,
    DWORD   VirtualAddress; // rva of this base relocation area
    DWORD   SizeOfBlock; //The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow.
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;  //Each base relocation block starts with this struct
 
typedef struct TypeOffset // after one base_relation, it has multi typeoffset
{
    WORD offset : 12;            //偏移值
    WORD type    : 4;            //重定位属性(方式), 高4
    // IMAGE_REL_BASED_ABSOLUTE 0  The base relocation is skipped,used to pad a block.
    // IMAGE_REL_BASED_HIGHLOW 3 The base relocation applies all 32 bits of the difference to the 32-bit field at offset. va = offset + base_rva + imagebase
    // IMAGE_REL_BASED_DIR64 10 for 64bit
}TypeOffset,*PTypeOffset
typedef struct _IMAGE_BASE_RELOCATION { // it has multi base relocation block,
    DWORD   VirtualAddress; // rva of this base relocation area
    DWORD   SizeOfBlock; //The total number of bytes in the base relocation block, including the Page RVA and Block Size fields and the Type/Offset fields that follow.
//  WORD    TypeOffset[1];
} IMAGE_BASE_RELOCATION;  //Each base relocation block starts with this struct
 
typedef struct TypeOffset // after one base_relation, it has multi typeoffset
{
    WORD offset : 12;            //偏移值
    WORD type    : 4;            //重定位属性(方式), 高4
    // IMAGE_REL_BASED_ABSOLUTE 0  The base relocation is skipped,used to pad a block.
    // IMAGE_REL_BASED_HIGHLOW 3 The base relocation applies all 32 bits of the difference to the 32-bit field at offset. va = offset + base_rva + imagebase
    // IMAGE_REL_BASED_DIR64 10 for 64bit
}TypeOffset,*PTypeOffset
 
typedef struct _IMAGE_SECTION_HEADER { //0x28 bytes, the last is all zero
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; // 8  bytes, null end
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress; //rva (, relative to the image base)
  DWORD SizeOfRawData; // The size of the initialized data on disk, in bytes
  DWORD PointerToRawData; // fileoffset of the section data
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers; // for debug line number
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;//IMAGE_SCN_MEM_EXECUTE 0x20000000,IMAGE_SCN_MEM_READ 0x40000000, IMAGE_SCN_MEM_WRITE 0x80000000
} IMAGE_SECTION_HEADER, *PIMAGE_SWECTION_HEADER;
typedef struct _IMAGE_SECTION_HEADER { //0x28 bytes, the last is all zero
  BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; // 8  bytes, null end
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress; //rva (, relative to the image base)
  DWORD SizeOfRawData; // The size of the initialized data on disk, in bytes
  DWORD PointerToRawData; // fileoffset of the section data
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers; // for debug line number
  WORD  NumberOfRelocations;
  WORD  NumberOfLinenumbers;
  DWORD Characteristics;//IMAGE_SCN_MEM_EXECUTE 0x20000000,IMAGE_SCN_MEM_READ 0x40000000, IMAGE_SCN_MEM_WRITE 0x80000000
} IMAGE_SECTION_HEADER, *PIMAGE_SWECTION_HEADER;
PIMAGE_NT_HEADERS CPEinfo::getNtHeader(LPBYTE pPeBuf)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pPeBuf;
    return (PIMAGE_NT_HEADERS)(pPeBuf + pDosHeader->e_lfanew);
}
 
PIMAGE_FILE_HEADER CPEinfo::getFileHeader(LPBYTE pPeBuf)
{
    return &getNtHeader(pPeBuf)->FileHeader;
}
 
PIMAGE_OPTIONAL_HEADER CPEinfo::getOptionalHeader(LPBYTE pPeBuf)
{
    return &getNtHeader(pPeBuf)->OptionalHeader;
}
 
PIMAGE_DATA_DIRECTORY CPEinfo::getImageDataDirectory(LPBYTE pPeBuf)
{
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = getOptionalHeader(pPeBuf);
    return pOptionalHeader->DataDirectory;
}
 
PIMAGE_SECTION_HEADER CPEinfo::getSectionHeader(LPBYTE pPeBuf)
{
    PIMAGE_NT_HEADERS pNtHeader = getNtHeader(pPeBuf);
    return (PIMAGE_SECTION_HEADER)((LPBYTE)pNtHeader + sizeof(IMAGE_NT_HEADERS));
}
 
PIMAGE_IMPORT_DESCRIPTOR CPEinfo::getImportDescriptor(LPBYTE pPeBuf, bool bMemAlign = true)
{
    PIMAGE_DATA_DIRECTORY pImageDataDirectory = getImageDataDirectory(pPeBuf);
    DWORD rva =  pImageDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    DWORD offset = bMemAlign ? rva: rva2faddr(pPeBuf, rva);
    return (PIMAGE_IMPORT_DESCRIPTOR)(pPeBuf + offset);
}
 
PIMAGE_EXPORT_DIRECTORY CPEinfo::getExportDirectory(LPBYTE pPeBuf, bool bMemAlign = true)
{
    PIMAGE_DATA_DIRECTORY pImageDataDirectory = getImageDataDirectory(pPeBuf);
    DWORD rva = pImageDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    DWORD offset = bMemAlign ? rva : rva2faddr(pPeBuf, rva);
    return (PIMAGE_EXPORT_DIRECTORY)(pPeBuf + offset);
}
 
DWORD CPEinfo::getOepRva(LPBYTE pPeBuf)
{
    if (pPeBuf == NULL) return 0;
    if (isPe(pPeBuf) <= 0) return 0;
    return getOptionalHeader(pPeBuf)->AddressOfEntryPoint;
}
 
WORD CPEinfo::getSectionNum(LPBYTE pPeBuf)
{
    return getFileHeader(pPeBuf)->NumberOfSections;
}
PIMAGE_NT_HEADERS CPEinfo::getNtHeader(LPBYTE pPeBuf)
{
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pPeBuf;
    return (PIMAGE_NT_HEADERS)(pPeBuf + pDosHeader->e_lfanew);
}
 
PIMAGE_FILE_HEADER CPEinfo::getFileHeader(LPBYTE pPeBuf)
{
    return &getNtHeader(pPeBuf)->FileHeader;
}
 
PIMAGE_OPTIONAL_HEADER CPEinfo::getOptionalHeader(LPBYTE pPeBuf)
{
    return &getNtHeader(pPeBuf)->OptionalHeader;
}
 
PIMAGE_DATA_DIRECTORY CPEinfo::getImageDataDirectory(LPBYTE pPeBuf)
{
    PIMAGE_OPTIONAL_HEADER pOptionalHeader = getOptionalHeader(pPeBuf);
    return pOptionalHeader->DataDirectory;
}
 
PIMAGE_SECTION_HEADER CPEinfo::getSectionHeader(LPBYTE pPeBuf)
{
    PIMAGE_NT_HEADERS pNtHeader = getNtHeader(pPeBuf);
    return (PIMAGE_SECTION_HEADER)((LPBYTE)pNtHeader + sizeof(IMAGE_NT_HEADERS));
}
 
PIMAGE_IMPORT_DESCRIPTOR CPEinfo::getImportDescriptor(LPBYTE pPeBuf, bool bMemAlign = true)
{
    PIMAGE_DATA_DIRECTORY pImageDataDirectory = getImageDataDirectory(pPeBuf);
    DWORD rva =  pImageDataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    DWORD offset = bMemAlign ? rva: rva2faddr(pPeBuf, rva);
    return (PIMAGE_IMPORT_DESCRIPTOR)(pPeBuf + offset);
}
 
PIMAGE_EXPORT_DIRECTORY CPEinfo::getExportDirectory(LPBYTE pPeBuf, bool bMemAlign = true)
{
    PIMAGE_DATA_DIRECTORY pImageDataDirectory = getImageDataDirectory(pPeBuf);
    DWORD rva = pImageDataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
    DWORD offset = bMemAlign ? rva : rva2faddr(pPeBuf, rva);
    return (PIMAGE_EXPORT_DIRECTORY)(pPeBuf + offset);
}
 
DWORD CPEinfo::getOepRva(LPBYTE pPeBuf)
{
    if (pPeBuf == NULL) return 0;
    if (isPe(pPeBuf) <= 0) return 0;
    return getOptionalHeader(pPeBuf)->AddressOfEntryPoint;
}
 
WORD CPEinfo::getSectionNum(LPBYTE pPeBuf)
{
    return getFileHeader(pPeBuf)->NumberOfSections;
}
 
#include <Windows.h>
#ifndef _DPACKPROC_H
#define _DPACKPROC_H
#define MAX_DPACKSECTNUM 16 // 最多可pack区段数量
#include "lzma\lzmalib.h"
 
typedef struct _DLZMA_HEADER
{
    size_t RawDataSize;//原始数据尺寸(不含此头)
    size_t DataSize;//压缩后的数据大小
    char LzmaProps[LZMA_PROPS_SIZE];//原始lzma的文件头
}DLZMA_HEADER, *PDLZMA_HEADER;//此处外围添加适用于dpack的lzma头
 
typedef struct _DPACK_ORGPE_INDEX   //源程序被隐去的信息,此结构为明文表示,地址全是rva
{
#ifdef _WIN64
    ULONGLONG ImageBase;            //源程序基址
#else
    DWORD ImageBase;            //源程序基址
#endif
    DWORD OepRva;                //原程序rva入口
    DWORD ImportRva;            //导入表信息
    DWORD ImportSize;
}DPACK_ORGPE_INDEX, * PDPACK_ORGPE_INDEX;
 
#define DPACK_SECTION_RAW 0
#define DPACK_SECTION_DLZMA 1
 
typedef struct _DPACK_SECTION_ENTRY //源信息与压缩变换后信息索引表是
{
    //假设不超过4g
    DWORD OrgRva; // OrgRva为0时则是不解压到原来区段
    DWORD OrgSize;
    DWORD DpackRva;
    DWORD DpackSize;
    DWORD Characteristics;
    DWORD DpackSectionType; // dpack区段类型
}DPACK_SECTION_ENTRY, * PDPACK_SECTION_ENTRY;
 
typedef struct _DPACK_SHELL_INDEX//DPACK变换头
{
    union
    {
        PVOID DpackOepFunc;  // 初始化壳的入口函数(放第一个元素方便初始化)
        DWORD DpackOepRva;  // 加载shellcode后也许改成入口RVA
    };
    DPACK_ORGPE_INDEX OrgIndex;
    WORD SectionNum;                                    //变换的区段数,最多MAX_DPACKSECTNUM区段
    DPACK_SECTION_ENTRY SectionIndex[MAX_DPACKSECTNUM];        //变换区段索引, 以全0结尾
    PVOID Extra;                                    //其他信息,方便之后拓展
}DPACK_SHELL_INDEX, * PDPACK_SHELL_INDEX;
 
size_t dlzmaPack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize);
size_t dlzmaUnpack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize);
#endif
#include <Windows.h>
#ifndef _DPACKPROC_H
#define _DPACKPROC_H
#define MAX_DPACKSECTNUM 16 // 最多可pack区段数量
#include "lzma\lzmalib.h"
 
typedef struct _DLZMA_HEADER
{
    size_t RawDataSize;//原始数据尺寸(不含此头)
    size_t DataSize;//压缩后的数据大小
    char LzmaProps[LZMA_PROPS_SIZE];//原始lzma的文件头
}DLZMA_HEADER, *PDLZMA_HEADER;//此处外围添加适用于dpack的lzma头
 
typedef struct _DPACK_ORGPE_INDEX   //源程序被隐去的信息,此结构为明文表示,地址全是rva
{
#ifdef _WIN64
    ULONGLONG ImageBase;            //源程序基址
#else
    DWORD ImageBase;            //源程序基址
#endif
    DWORD OepRva;                //原程序rva入口
    DWORD ImportRva;            //导入表信息
    DWORD ImportSize;
}DPACK_ORGPE_INDEX, * PDPACK_ORGPE_INDEX;
 
#define DPACK_SECTION_RAW 0
#define DPACK_SECTION_DLZMA 1
 
typedef struct _DPACK_SECTION_ENTRY //源信息与压缩变换后信息索引表是
{
    //假设不超过4g
    DWORD OrgRva; // OrgRva为0时则是不解压到原来区段
    DWORD OrgSize;
    DWORD DpackRva;
    DWORD DpackSize;
    DWORD Characteristics;
    DWORD DpackSectionType; // dpack区段类型
}DPACK_SECTION_ENTRY, * PDPACK_SECTION_ENTRY;
 
typedef struct _DPACK_SHELL_INDEX//DPACK变换头
{
    union
    {
        PVOID DpackOepFunc;  // 初始化壳的入口函数(放第一个元素方便初始化)
        DWORD DpackOepRva;  // 加载shellcode后也许改成入口RVA
    };
    DPACK_ORGPE_INDEX OrgIndex;
    WORD SectionNum;                                    //变换的区段数,最多MAX_DPACKSECTNUM区段
    DPACK_SECTION_ENTRY SectionIndex[MAX_DPACKSECTNUM];        //变换区段索引, 以全0结尾
    PVOID Extra;                                    //其他信息,方便之后拓展
}DPACK_SHELL_INDEX, * PDPACK_SHELL_INDEX;
 
size_t dlzmaPack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize);
size_t dlzmaUnpack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize);
#endif
#include <Windows.h>
#include "dpackType.h"
size_t dlzmaPack(LPBYTE pDstBuf,LPBYTE pSrcBuf,size_t srcSize)
{
    size_t dstSize = -1; //最大的buffersize, 为0会出错
    size_t propSize = sizeof(DLZMA_HEADER);
    PDLZMA_HEADER pDlzmah=(PDLZMA_HEADER)pDstBuf;
 
    LzmaCompress(pDstBuf+sizeof(DLZMA_HEADER), &dstSize,
                 pSrcBuf, srcSize,
                 pDlzmah->LzmaProps, (size_t *)&propSize,
                 -1 ,0, -1, -1, -1, -1, -1);
 
    pDlzmah->RawDataSize = srcSize;
    pDlzmah->DataSize = dstSize;
    return dstSize;
}
 
size_t dlzmaUnpack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize)
{
    PDLZMA_HEADER pdlzmah = (PDLZMA_HEADER)pSrcBuf;
    size_t dstSize = pdlzmah->RawDataSize;//release版不赋初值会出错,由于debug将其赋值为cccccccc很大的数
    LzmaUncompress(pDstBuf, &dstSize,//此处必须赋最大值
                  pSrcBuf + sizeof(DLZMA_HEADER), &srcSize,
                  pdlzmah->LzmaProps, LZMA_PROPS_SIZE);
    return dstSize;
}
#include <Windows.h>
#include "dpackType.h"
size_t dlzmaPack(LPBYTE pDstBuf,LPBYTE pSrcBuf,size_t srcSize)
{
    size_t dstSize = -1; //最大的buffersize, 为0会出错
    size_t propSize = sizeof(DLZMA_HEADER);
    PDLZMA_HEADER pDlzmah=(PDLZMA_HEADER)pDstBuf;
 
    LzmaCompress(pDstBuf+sizeof(DLZMA_HEADER), &dstSize,
                 pSrcBuf, srcSize,
                 pDlzmah->LzmaProps, (size_t *)&propSize,
                 -1 ,0, -1, -1, -1, -1, -1);
 
    pDlzmah->RawDataSize = srcSize;
    pDlzmah->DataSize = dstSize;
    return dstSize;
}
 
size_t dlzmaUnpack(LPBYTE pDstBuf, LPBYTE pSrcBuf, size_t srcSize)
{
    PDLZMA_HEADER pdlzmah = (PDLZMA_HEADER)pSrcBuf;
    size_t dstSize = pdlzmah->RawDataSize;//release版不赋初值会出错,由于debug将其赋值为cccccccc很大的数
    LzmaUncompress(pDstBuf, &dstSize,//此处必须赋最大值
                  pSrcBuf + sizeof(DLZMA_HEADER), &srcSize,
                  pdlzmah->LzmaProps, LZMA_PROPS_SIZE);
    return dstSize;
}
 
#ifdef _WIN64
void dpackStart()
#else
__declspec(naked) void dpackStart()//此函数中不要有局部变量
#endif
{
    BeforeUnpack();
    MallocAll(NULL);
    UnpackAll(NULL);
    g_orgOep = g_dpackShellIndex.OrgIndex.ImageBase + g_dpackShellIndex.OrgIndex.OepRva;
    LoadOrigionIat(NULL);
    AfterUnpack();
    JmpOrgOep();
}
#ifdef _WIN64
void dpackStart()
#else
__declspec(naked) void dpackStart()//此函数中不要有局部变量
#endif
{
    BeforeUnpack();
    MallocAll(NULL);
    UnpackAll(NULL);
    g_orgOep = g_dpackShellIndex.OrgIndex.ImageBase + g_dpackShellIndex.OrgIndex.OepRva;
    LoadOrigionIat(NULL);
    AfterUnpack();
    JmpOrgOep();
}
void MallocAll(PVOID arg)
{
    MEMORY_BASIC_INFORMATION mi = { 0 };
    HANDLE hProcess = GetCurrentProcess();
    HMODULE imagebase = GetModuleHandle(NULL);
    for (int i = 0; i < g_dpackShellIndex.SectionNum; i++)
    {
        if (g_dpackShellIndex.SectionIndex[i].OrgSize == 0) continue;
        LPBYTE tVa = (LPBYTE)imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva;
        DWORD tSize = g_dpackShellIndex.SectionIndex[i].OrgSize;
        VirtualQueryEx(hProcess, tVa, &mi, tSize);
        if(mi.State == MEM_FREE)
        {
            DWORD flProtect = PAGE_EXECUTE_READWRITE;
            switch (g_dpackShellIndex.SectionIndex[i].Characteristics)
            {
                case IMAGE_SCN_MEM_EXECUTE:
                    flProtect = PAGE_EXECUTE;
                    break;
                case IMAGE_SCN_MEM_READ:
                    flProtect = PAGE_READONLY;
                    break;
                case IMAGE_SCN_MEM_WRITE:
                    flProtect = PAGE_READWRITE;
                    break;
            }
            if(!VirtualAllocEx(hProcess, tVa, tSize, MEM_COMMIT, flProtect))
            {
                MessageBox(NULL,"Alloc memory failed", "error", NULL);
                ExitProcess(1);
            }
        }
    }  
}
void MallocAll(PVOID arg)
{
    MEMORY_BASIC_INFORMATION mi = { 0 };
    HANDLE hProcess = GetCurrentProcess();
    HMODULE imagebase = GetModuleHandle(NULL);
    for (int i = 0; i < g_dpackShellIndex.SectionNum; i++)
    {
        if (g_dpackShellIndex.SectionIndex[i].OrgSize == 0) continue;
        LPBYTE tVa = (LPBYTE)imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva;
        DWORD tSize = g_dpackShellIndex.SectionIndex[i].OrgSize;
        VirtualQueryEx(hProcess, tVa, &mi, tSize);
        if(mi.State == MEM_FREE)
        {
            DWORD flProtect = PAGE_EXECUTE_READWRITE;
            switch (g_dpackShellIndex.SectionIndex[i].Characteristics)
            {
                case IMAGE_SCN_MEM_EXECUTE:
                    flProtect = PAGE_EXECUTE;
                    break;
                case IMAGE_SCN_MEM_READ:
                    flProtect = PAGE_READONLY;
                    break;
                case IMAGE_SCN_MEM_WRITE:

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 17
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  kanxue   +2.00 2021/02/27 感谢分享~
最新回复 (10)
雪    币: 1176
活跃值: (1269)
能力值: ( LV12,RANK:380 )
在线值:
发帖
回帖
粉丝
2
支持一个 
源码拿来 我抄了 (手动滑稽
2021-2-26 17:59
0
雪    币: 50161
活跃值: (20625)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
3
感谢分享!
2021-2-27 13:40
0
雪    币: 1378
活跃值: (3067)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
即6bb8eh+260cah 这句要么前面写上 0x 要么把后面的h去了吧..我看了好久看不到这两个值哪里来的,,都给我看懵了.
2021-3-2 17:54
0
雪    币: 1378
活跃值: (3067)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
陆陆续续终于看完了,非常不错的贴子...我好像会脱壳了,哈``
2021-4-28 19:54
0
雪    币: 1042
活跃值: (550)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
文章先收藏一波,非常详细。
2021-4-28 20:49
0
雪    币: 7465
活跃值: (4196)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark一下回头看
2021-4-28 21:05
0
雪    币: 300
活跃值: (2532)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark
2022-3-30 13:54
0
雪    币: 1
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
向大佬学习!向大佬低头!
2022-7-7 20:46
0
雪    币: 5029
活跃值: (4798)
能力值: ( LV10,RANK:171 )
在线值:
发帖
回帖
粉丝
10
感谢分享!
2022-10-11 15:21
0
雪    币: 260
活跃值: (405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
 大佬, DWORD shellEndtRva = m_shellpe.getSectionHeader()[3].VirtualAddress; // rsrc
这一句代码有问题吧,第三个section 是 .pdata节,并不是 .rsrc
2022-10-18 00:34
0
游客
登录 | 注册 方可回帖
返回
//