SimpleDpack_C++编写shellcode压缩壳
Posted 看雪学院
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SimpleDpack_C++编写shellcode压缩壳相关的知识,希望对你有一定的参考价值。
本文为看雪论坛精华文章
看雪论坛作者ID:devseed
一、分析PE64结构
1、PE文件头总览
NT header包括file header和optional header;
optional header,末尾含有16个元素的data directory数组;
IMAGE_OPTIONAL_HEADER64,里面ImageBase、还有堆栈尺寸类型是ULONGLONG;
紧随着NT header的是各section的headers,数量为fi le header里面的NumberOfSections。
|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]
2、DataDirectory
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;
// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
AddressOfFunctions指向函数RVA表
AddressOfNames指向函数名RVA表(存储字符串指针)、
AddressOfNameOrdinals指向序号表。
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;
(2)IMAGE_DIRECTORY_ENTRY_IMPORT
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;
(3)IMAGE_DIRECTORY_ENTRY_IAT
(4)IMAGE_DIRECTORY_ENTRY_BASERELOC
reloc内包含多个BASE_RELOCATION块。
每个BASE_RELOCATION块内头描述了此块reloc的VirtualAddress(RVA)和SizeOfBlock。
之后块内若干个两字节的TypeOffset,低12位为offset,高4位是type,64位也是两字节。
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
3、Section header
这里SizeOfRawData(文件中的大小)可以为零(比如说动态生成的数据,区段之留个头声明,文件里不需要对应的数据),
SizeOfRawData必须是FileAlignment的整数倍,VirtualSize为实际内存空间(不包括MemoryAlign后的)
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;
4、编程实现解析PE文件头
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;
}
二、壳的数据结构设计
原来区段位置大小
压缩的缓存区位置大小、压缩类型
源程序的OEP、IAT
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
{
ULONGLONG ImageBase; //源程序基址
DWORD ImageBase; //源程序基址
DWORD OepRva; //原程序rva入口
DWORD ImportRva; //导入表信息
DWORD ImportSize;
}DPACK_ORGPE_INDEX, * PDPACK_ORGPE_INDEX;
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);
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;
}
三、壳的shellcode编写
分配解压后的内存(如果把区段头信息也删除了,需要自己分配)
解压缩各区段数据(暂不考虑TLS,rsrc的压缩)
初始化原始的IAT
跳转到原OEP
void dpackStart()
__declspec(naked) void dpackStart()//此函数中不要有局部变量
{
BeforeUnpack();
MallocAll(NULL);
UnpackAll(NULL);
g_orgOep = g_dpackShellIndex.OrgIndex.ImageBase + g_dpackShellIndex.OrgIndex.OepRva;
LoadOrigionIat(NULL);
AfterUnpack();
JmpOrgOep();
}
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:
flProtect = PAGE_READWRITE;
break;
}
if(!VirtualAllocEx(hProcess, tVa, tSize, MEM_COMMIT, flProtect))
{
MessageBox(NULL,"Alloc memory failed", "error", NULL);
ExitProcess(1);
}
}
}
}
2、解压区段
void UnpackAll(PVOID arg)
{
DWORD oldProtect;
ULONGLONG imagebase = g_dpackShellIndex.OrgIndex.ImageBase;
DWORD imagebase = g_dpackShellIndex.OrgIndex.ImageBase;
for(int i=0; i<g_dpackShellIndex.SectionNum; i++)
{
switch(g_dpackShellIndex.SectionIndex[i].DpackSectionType)
{
case DPACK_SECTION_RAW:
{
if (g_dpackShellIndex.SectionIndex[i].OrgSize == 0) continue;
VirtualProtect((LPVOID)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
g_dpackShellIndex.SectionIndex[i].OrgSize,
PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((void*)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
(void*)(imagebase + g_dpackShellIndex.SectionIndex[i].DpackRva),
g_dpackShellIndex.SectionIndex[i].OrgSize);
VirtualProtect((LPVOID)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
g_dpackShellIndex.SectionIndex[i].OrgSize,
oldProtect, &oldProtect);
break;
}
case DPACK_SECTION_DLZMA:
{
LPBYTE buf = new BYTE[g_dpackShellIndex.SectionIndex[i].OrgSize];
if (!dlzmaUnpack(buf,
(LPBYTE)(g_dpackShellIndex.SectionIndex[i].DpackRva + imagebase),
g_dpackShellIndex.SectionIndex[i].DpackSize))
{
MessageBox(0, "unpack failed", "error", 0);
ExitProcess(1);
}
VirtualProtect((LPVOID)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
g_dpackShellIndex.SectionIndex[i].OrgSize,
PAGE_EXECUTE_READWRITE, &oldProtect);
memcpy((void*)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
buf, g_dpackShellIndex.SectionIndex[i].OrgSize);
VirtualProtect((LPVOID)(imagebase + g_dpackShellIndex.SectionIndex[i].OrgRva),
g_dpackShellIndex.SectionIndex[i].OrgSize,
oldProtect, &oldProtect);
delete[] buf;
break;
}
default:
break;
}
}
}
3、初始化源程序的IAT
void LoadOrigionIat(PVOID arg) // 因为将iat改为了壳的,所以要还原原来的iat
{
DWORD i,j;
DWORD dll_num = g_dpackShellIndex.OrgIndex.ImportSize
/sizeof(IMAGE_IMPORT_DESCRIPTOR);//导入dll的个数,含最后全为空的一项
DWORD item_num=0;//一个dll中导入函数的个数,不包括全0的项
DWORD oldProtect;
HMODULE tHomule;//临时加载dll的句柄
LPBYTE tName;//临时存放名字
ULONGLONG tVa;//临时存放虚拟地址
ULONGLONG imagebase = g_dpackShellIndex.OrgIndex.ImageBase;
DWORD tVa;//临时存放虚拟地址
DWORD imagebase = g_dpackShellIndex.OrgIndex.ImageBase;
PIMAGE_IMPORT_DESCRIPTOR pImport=(PIMAGE_IMPORT_DESCRIPTOR)(imagebase+
g_dpackShellIndex.OrgIndex.ImportRva);//指向第一个dll
PIMAGE_THUNK_DATA pfThunk;//ft
PIMAGE_THUNK_DATA poThunk;//oft
PIMAGE_IMPORT_BY_NAME pFuncName;
for(i=0;i<dll_num;i++)
{
if(pImport[i].OriginalFirstThunk==0) continue;
tName=(LPBYTE)(imagebase+pImport[i].Name);
tHomule=LoadLibrary((LPCSTR)tName);
pfThunk=(PIMAGE_THUNK_DATA)(imagebase+pImport[i].FirstThunk);
poThunk=(PIMAGE_THUNK_DATA)(imagebase+pImport[i].OriginalFirstThunk);
for(j=0;poThunk[j].u1.AddressOfData!=0;j++){}//注意个数。。。
item_num=j;
VirtualProtect((LPVOID)(pfThunk),item_num * sizeof(IMAGE_THUNK_DATA),
PAGE_EXECUTE_READWRITE,&oldProtect);//注意指针位置
for(j=0;j<item_num;j++)
{
if((poThunk[j].u1.Ordinal >>31) != 0x1) //不是用序号
{
pFuncName=(PIMAGE_IMPORT_BY_NAME)(imagebase+poThunk[j].u1.AddressOfData);
tName=(LPBYTE)pFuncName->Name;
tVa = (ULONGLONG)GetProcAddress(tHomule, (LPCSTR)tName);
tVa = (DWORD)GetProcAddress(tHomule, (LPCSTR)tName);
}
else
{
//如果此参数是一个序数值,它必须在一个字的低字节,高字节必须为0。
#ifdef _WIN64
tVa = (ULONGLONG)GetProcAddress(tHomule,(LPCSTR)(poThunk[j].u1.Ordinal & 0x0000ffff));
tVa = (DWORD)GetProcAddress(tHomule, (LPCSTR)(poThunk[j].u1.Ordinal & 0x0000ffff));
}
if (tVa == NULL)
{
MessageBox(NULL, "IAT load error!", "error", NULL);
ExitProcess(1);
}
pfThunk[j].u1.Function = tVa;//注意间接寻址
}
VirtualProtect((LPVOID)(pfThunk),item_num * sizeof(IMAGE_THUNK_DATA),
oldProtect,&oldProtect);
}
}
4、跳转到源OEP
__declspec(naked) void JmpOrgOep()
{
__asm
{
push g_orgOep;
ret;
}
}
四、加壳程序的编写
DWORD CSimpleDpack::packPe(const char* dllpath, int dpackSectionType)//加壳,失败返回0,成功返回pack数据大小
{
if (m_packpe.getPeBuf() == NULL) return 0;
initDpackTmpbuf(); // 初始化pack buf
DWORD packsize = packSection(dpackSectionType); // pack各区段
DWORD shellsize = loadShellDll(dllpath); // 载入dll shellcode
DWORD packpeImgSize = m_packpe.getOptionalHeader()->SizeOfImage;
DWORD shellStartRva = m_shellpe.getSectionHeader()[0].VirtualAddress;
DWORD shellEndtRva = m_shellpe.getSectionHeader()[3].VirtualAddress; // rsrc
adjustShellReloc(packpeImgSize); // reloc调整后全局变量g_dpackShellIndex的oep也变成之后
adjustShellIat(packpeImgSize);
initShellIndex(shellEndtRva); // 初始化dpack shell index,一定要在reloc之后, 因为reloc后这里的地址也变了
makeAppendBuf(shellStartRva, shellEndtRva, packpeImgSize);
adjustPackpeHeaders(0); // 调整要pack的pe头
return packsize + shellEndtRva - shellStartRva;
}
1、shellcode的处理
DWORD CPEedit::shiftReloc(LPBYTE pPeBuf, size_t oldImageBase, size_t newImageBase, DWORD offset, bool bMemAlign)
{
//修复重定位,其实此处pShellBuf为hShell副本
DWORD all_num = 0;
DWORD sumsize = 0;
auto pRelocEntry = &getImageDataDirectory(pPeBuf)[IMAGE_DIRECTORY_ENTRY_BASERELOC];
while (sumsize < pRelocEntry->Size)
{
auto pBaseRelocation = (PIMAGE_BASE_RELOCATION)(pPeBuf + sumsize +
(bMemAlign ? pRelocEntry->VirtualAddress :
rva2faddr(pPeBuf, pRelocEntry->VirtualAddress)));
auto pRelocOffset = (PRELOCOFFSET)
((LPBYTE)pBaseRelocation + sizeof(IMAGE_BASE_RELOCATION));
DWORD item_num = (pBaseRelocation->SizeOfBlock -
sizeof(IMAGE_BASE_RELOCATION)) / sizeof(RELOCOFFSET);
for (int i = 0; i < item_num; i++)
{
if (pRelocOffset[i].offset == 0) continue;
DWORD toffset = pRelocOffset[i].offset + pBaseRelocation->VirtualAddress;
if (!bMemAlign) toffset = rva2faddr(pPeBuf, toffset);
// 新的重定位地址 = 重定位后的地址(VA)-加载时的镜像基址(hModule VA) + 新的镜像基址(VA) + 新代码基址RVA(前面用于存放压缩的代码)
// 由于讲dll附加在后面,需要在dll shell中的重定位加上偏移修正
*(PULONGLONG)(pPeBuf + toffset) += newImageBase - oldImageBase + offset; //重定向每一项地址
//printf("%08lX -> ", *(PDWORD)(pPeBuf + toffset));
*(PDWORD)(pPeBuf + toffset) += newImageBase - oldImageBase + offset; //重定向每一项地址
//printf("%08lX ", *(PDWORD)(pPeBuf + toffset));
}
pBaseRelocation->VirtualAddress += offset; //重定向页表基址
sumsize += sizeof(RELOCOFFSET) * item_num + sizeof(IMAGE_BASE_RELOCATION);
all_num += item_num;
}
return all_num;
}
DWORD CPEedit::shiftOft(LPBYTE pPeBuf, DWORD offset, bool bMemAlign, bool bResetFt)
{
auto pImportEntry = &getImageDataDirectory(pPeBuf)[IMAGE_DIRECTORY_ENTRY_IMPORT];
DWORD dll_num = pImportEntry->Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);//导入dll的个数,含最后全为空的一项
DWORD func_num = 0;//所有导入函数个数,不包括全0的项
auto pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) (pPeBuf +
(bMemAlign ? pImportEntry->VirtualAddress :
rva2faddr(pPeBuf, pImportEntry->VirtualAddress)));//指向第一个dll
for (int i = 0; i < dll_num; i++)
{
if (pImportDescriptor[i].OriginalFirstThunk == 0) continue;
auto pOFT = (PIMAGE_THUNK_DATA)(pPeBuf + (bMemAlign ?
pImportDescriptor[i].OriginalFirstThunk:
rva2faddr(pPeBuf, pImportDescriptor[i].OriginalFirstThunk)));
auto pFT = (PIMAGE_THUNK_DATA)(pPeBuf + (bMemAlign ?
pImportDescriptor[i].FirstThunk :
rva2faddr(pPeBuf, pImportDescriptor[i].FirstThunk)));
DWORD item_num = 0;
for (int j = 0; pOFT[j].u1.AddressOfData != 0; j++)
{
item_num++; //一个dll中导入函数的个数,不包括全0的项
if ((pOFT[j].u1.Ordinal >> 31) != 0x1) //不是用序号
{
pOFT[j].u1.AddressOfData += offset;
if (bResetFt) pFT[j].u1.AddressOfData = pOFT[j].u1.AddressOfData;
}
}
pImportDescriptor[i].OriginalFirstThunk += offset;
pImportDescriptor[i].FirstThunk += offset;
pImportDescriptr[i].Name += offset;
func_num += item_num;
}
return func_num;
}
2、调整exe的PE头
void CSimpleDpack::adjustPackpeHeaders(DWORD offset)
{
// 设置被加壳程序的信息, oep, reloc, iat
if (m_pShellIndex == NULL) return;
auto packpeImageSize = m_packpe.getOptionalHeader()->SizeOfImage;
// m_pShellIndex->DpackOepFunc 之前已经reloc过了,变成了正确的va了(shelldll是release版)
m_packpe.setOepRva((size_t)m_pShellIndex->DpackOepFunc -
m_packpe.getOptionalHeader()->ImageBase + offset);
m_packpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT] = {
m_shellpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + packpeImageSize + offset,
m_shellpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT].Size };
m_packpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IAT] = {
m_shellpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + packpeImageSize + offset,
m_shellpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_IMPORT].Size};
m_packpe.getImageDataDirectory()[IMAGE_DIRECTORY_ENTRY_BASERELOC] = { 0,0 };
// pe 属性设置
m_packpe.getFileHeader()->Characteristics |= IMAGE_FILE_RELOCS_STRIPPED; //禁止基址随机化
}
3、保存PE文件
DWORD CSimpleDpack::savePe(const char* path)//失败返回0,成功返回文件大小
{
/*
pack区域放到后面,由于内存有对齐问题,只允许pack一整个区段
先改pe头,再分配空间,支持若原来pe fileHeader段不够,添加段
将区段头与区段分开考虑
*/
// dpack头初始化
IMAGE_SECTION_HEADER dpackSect = {0};
strcpy((char*)dpackSect.Name, ".dpack");
dpackSect.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_EXECUTE;
dpackSect.VirtualAddress = m_dpackTmpbuf[m_dpackSectNum - 1].OrgRva;
// 准备dpack buf
DWORD dpackBufSize = 0;
for (int i = 0; i < m_dpackSectNum; i++) dpackBufSize += m_dpackTmpbuf[i].DpackSize;
LPBYTE pdpackBuf = new BYTE[dpackBufSize];
LPBYTE pCurBuf = pdpackBuf;
memcpy(pdpackBuf, m_dpackTmpbuf[m_dpackSectNum - 1].PackedBuf,
m_dpackTmpbuf[m_dpackSectNum - 1].DpackSize); // 壳代码
pCurBuf += m_dpackTmpbuf[m_dpackSectNum - 1].DpackSize;
for (int i = 0; i < m_dpackSectNum -1 ; i++)
{
memcpy(pCurBuf, m_dpackTmpbuf[i].PackedBuf,
m_dpackTmpbuf[i].DpackSize);
pCurBuf += m_dpackTmpbuf[i].DpackSize;
}
// 删除被压缩区段和写入pe
int remvoeSectIdx[MAX_DPACKSECTNUM] = {0};
int removeSectNum = 0;
for (int i = 0; i < m_packpe.getFileHeader()->NumberOfSections; i++)
{
if (m_packSectMap[i] == true) remvoeSectIdx[removeSectNum++] = i;
}
m_packpe.removeSectionDatas(removeSectNum, remvoeSectIdx);
m_packpe.appendSection(dpackSect, pdpackBuf, dpackBufSize);
delete[] pdpackBuf;
return m_packpe.savePeFile(path);
}
五、x64适配
*(PULONGLONG)(pPeBuf + toffset) += newImageBase - oldImageBase + offset;
//printf("%08lX -> ", *(PDWORD)(pPeBuf + toffset));
*(PDWORD)(pPeBuf + toffset) += newImageBase - oldImageBase + offset;
//printf("%08lX ", *(PDWORD)(pPeBuf + toffset));
extern g_orgOep:QWORD;
AfterUnpack proto c;
.code
JmpOrgOep PROC
push g_orgOep;
ret;
JmpOrgOep ENDP
end
看雪ID:devseed
https://bbs.pediy.com/user-home-838741.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!
以上是关于SimpleDpack_C++编写shellcode压缩壳的主要内容,如果未能解决你的问题,请参考以下文章