源码地址点击此处
第一次在此版发帖,更多的是涉及内存加载执行。
该方案比较简单,只适用于测试和简单情景下的应用,测试中能够运行大多数体积和功能比较简单的32位/64位程序,兼容性和稳定性有待测试和提高。
源码包含两个工程,加壳程序PeShell和脱壳程序PeUnshell。
加壳程序:PeShell工程。该工程根据命令行参数,将需要加壳的程序和文件先用zip压缩,后用xor加密,生成一段新的数据,接着在PEUnshell.exe程序中创建一个新的段区,名称默认为"ldata",最后将这段数据写入在PEUnshell.exe文件的新的"ldata"段中。这块加密数据的内存影像(从低地址到高地址)为:
文件个数(int型),密钥(char型,16字节,用的当前时间的md5值),文件大小1(int),文件名1(char型,64字节),文件大小2(int),文件名2(char型,64字节),。。。,,文件大小n(int),文件名n(char型,64字节)。
代码实现:
加壳命令行的写法:
参数的解释:
-be:b代表bind,绑定的意思;e代表executable,可执行的。
-bd:b代表bind,绑定的意思;d代表dll,即动态重定位文件。
-o: 输出文件,即加壳后的程序。
-c: 参数。
加壳程序比较复杂的代码是添加区段。pe文件的区段结构如下:
其中,VirtualSize是区段大小,VirtualAddress是对齐后的虚拟地址,SizeOfRawData是文件对齐后的大小,PointerToRawData是区段在文件中相对于文件头的偏移地址。这里采用的思路是,一般情况下,段表结构PIMAGE_SECTION_HEADER中有空余的项,找到后空项后,计算和重新修改该段表项即可。其中,
VirtualAddress字段=上一个段表的值+上一个段表内存页面对齐后的大小,
PointerToRawData = 上一个段表的值+上一个段表扇区对齐后的大小,
SizeOfRawData是段文件对齐后大小,
VirtualSize是段实际大小,
Characteristics必须是代码或者数据段,否则不会被装入内存,
IMAGE_FILE_HEADER中NumberOfSections字段加1,
IMAGE_OPTIONAL_HEADER32中SizeOfImage字段要加上该段对齐后的大小。
上述功能中使用的结构体如下:
至此,加壳程序工作基本完成。
解壳和内存加载执行:即PEUnshell工程。该工程支持编译为PEUnshell.exe和PEUnshell.dll,可以根据命令行参数,将程序隐藏在exe或者dll中,并且都可以正确的释放和加载运行。在程序运行时(PEUnshell.exe是在WinMain函数入口处,PEUnshell.dll是在DllEntry入口处)在自己的内存加载映像中查找"ldata"区段,然后按照加壳中定义的数据结构,将这段压缩加密内存数据解密解压后,写入当前目录,并将其中后缀名为exe的程序启动起来。启动方法是内存加载执行。内存加载执行主要分为三个部分,段加载,导入表填充,重定位。
其中,程序释放程序跟加壳程序压缩加密和内存布局是相反的。
内存加载执行代码如下:
pe文件中的OptionalHeader.ImageBase字段可以修改,故程序编译时指定的加载地址并不是必须的。
通过内存分配,MapFile函数映射区段,RelocationTable重定位,导入表ImportTable,VirtualProtect修改程序内存属性可读写可执行,SetImageBase设置OptionalHeader.ImageBase字段后,程序内存映射基本完毕。接下来,如果是exe程序,那么直接跳转地址:加载地址 + OptionalHeader.AddressOfEntryPoint,如果是dll程序,直接带参数DLL_PROCESS_ATTACH执行DllMainEntry函数,如果是console程序,则带参数执行main函数。
本文写的比较粗糙,实际上,本文的核心内容在此处的三个函数上:MapFile,RelocationTable,ImportTable。通过此三个函数,完成了PE文件的内存加载和执行。由于windows平台开发兼容性做的比较好,32位和64位的数据结构基本相同,开发时未作适配,32位即可兼容64位程序。
本程序具体细节不在表述(因为我也是一个初学者,只是照着葫芦画瓢),有兴趣的同学自己看代码体会吧。
测试时,保证peshell.exe,peunshell.exe或者peunshell.dll,加壳运行的exe或者dll在同一个目录,通过命令运行peshell.exe即可。测试中,大部分体积比较小的32位和64位windows PE程序都可以加载执行,但是稍微大一些的程序无法正确运行。原因百思不得其解,望各位赐教。
unsigned
char
* Crypto::makeDataBlock(
int
flag,
const
char
filename[MAX_FILE_COUNT][256],
int
cnt,
int
& dstdatasize) {
int
ret = 0;
int
filesize = 0;
for
(
int
i = 0; i < cnt; i++)
{
int
fz = FileHelper::getfilesize(filename[i]);
filesize += fz;
printf
(
"file name:%s size:%d\r\n"
, filename[i], fz);
}
int
dstbufsize = filesize + 0x1000;
unsigned
char
* dstblock =
new
unsigned
char
[dstbufsize];
*(
int
*)dstblock = flag;
unsigned
char
* key = dstblock + 4;
getkey(key);
*(
int
*)(dstblock + 4 + CRYPT_KEY_SIZE) = cnt;
unsigned
char
* dstbuf = dstblock + 4 + CRYPT_KEY_SIZE + 4;
int
dstbuflimit = dstbufsize - 4 - CRYPT_KEY_SIZE - 4;
for
(
int
i = 0; i < cnt; i++)
{
lstrcpyA((
char
*)dstbuf, filename[i]);
PathStripPathA((
char
*)dstbuf);
dstbuf += FILENAME_LEN;
dstbuflimit -= FILENAME_LEN;
char
* lpdata = 0;
ret = FileHelper::fileReader(filename[i], &lpdata, &filesize);
if
(ret > 0)
{
unsigned
long
cmpresssize = dstbuflimit - 4;
ret = Compress::compressdata((unsigned
char
*)lpdata, filesize, dstbuf + 4, &cmpresssize);
delete
[] lpdata;
if
(ret != 0)
{
delete
dstblock;
printf
(
"compress file:%s error:%u\r\n"
, filename[i], GetLastError());
return
0;
}
*(
int
*)(dstbuf) = cmpresssize;
dstbuf += 4;
dstbuf += cmpresssize;
dstbuflimit -= 4;
dstbuflimit -= cmpresssize;
}
else
{
delete
dstblock;
printf
(
"read file:%s error\r\n"
, filename[i]);
return
0;
}
}
dstdatasize = dstbuf - dstblock;
CryptData(dstblock + 4 + CRYPT_KEY_SIZE, dstdatasize - 4 - CRYPT_KEY_SIZE, key, CRYPT_KEY_SIZE);
return
dstblock;
}
unsigned
char
* Crypto::makeDataBlock(
int
flag,
const
char
filename[MAX_FILE_COUNT][256],
int
cnt,
int
& dstdatasize) {
int
ret = 0;
int
filesize = 0;
for
(
int
i = 0; i < cnt; i++)
{
int
fz = FileHelper::getfilesize(filename[i]);
filesize += fz;
printf
(
"file name:%s size:%d\r\n"
, filename[i], fz);
}
int
dstbufsize = filesize + 0x1000;
unsigned
char
* dstblock =
new
unsigned
char
[dstbufsize];
*(
int
*)dstblock = flag;
unsigned
char
* key = dstblock + 4;
getkey(key);
*(
int
*)(dstblock + 4 + CRYPT_KEY_SIZE) = cnt;
unsigned
char
* dstbuf = dstblock + 4 + CRYPT_KEY_SIZE + 4;
int
dstbuflimit = dstbufsize - 4 - CRYPT_KEY_SIZE - 4;
for
(
int
i = 0; i < cnt; i++)
{
lstrcpyA((
char
*)dstbuf, filename[i]);
PathStripPathA((
char
*)dstbuf);
dstbuf += FILENAME_LEN;
dstbuflimit -= FILENAME_LEN;
char
* lpdata = 0;
ret = FileHelper::fileReader(filename[i], &lpdata, &filesize);
if
(ret > 0)
{
unsigned
long
cmpresssize = dstbuflimit - 4;
ret = Compress::compressdata((unsigned
char
*)lpdata, filesize, dstbuf + 4, &cmpresssize);
delete
[] lpdata;
if
(ret != 0)
{
delete
dstblock;
printf
(
"compress file:%s error:%u\r\n"
, filename[i], GetLastError());
return
0;
}
*(
int
*)(dstbuf) = cmpresssize;
dstbuf += 4;
dstbuf += cmpresssize;
dstbuflimit -= 4;
dstbuflimit -= cmpresssize;
}
else
{
delete
dstblock;
printf
(
"read file:%s error\r\n"
, filename[i]);
return
0;
}
}
dstdatasize = dstbuf - dstblock;
CryptData(dstblock + 4 + CRYPT_KEY_SIZE, dstdatasize - 4 - CRYPT_KEY_SIZE, key, CRYPT_KEY_SIZE);
return
dstblock;
}
PeShell
-
be sogou.exe sbiedll.dll
-
c params.dat
-
o out.exe
PeShell
-
bd sogou.exe sbiedll.dll
-
c params.dat
-
o out.dll
PeShell
-
e sogou.exe
-
c params.dat
-
o out.exe
PeShell
-
d sogou.exe
-
c params.dat
-
o out.dll
PeShell
-
be sogou.exe sbiedll.dll
-
c params.dat
-
o out.exe
PeShell
-
bd sogou.exe sbiedll.dll
-
c params.dat
-
o out.dll
PeShell
-
e sogou.exe
-
c params.dat
-
o out.exe
PeShell
-
d sogou.exe
-
c params.dat
-
o out.dll
typedef
struct
_IMAGE_SECTION_HEADER {
BYTE
Name[IMAGE_SIZEOF_SHORT_NAME];
union
{
DWORD
PhysicalAddress;
DWORD
VirtualSize;
} Misc;
DWORD
VirtualAddress;
DWORD
SizeOfRawData;
DWORD
PointerToRawData;
DWORD
PointerToRelocations;
DWORD
PointerToLinenumbers;
WORD
NumberOfRelocations;
WORD
NumberOfLinenumbers;
DWORD
Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef
struct
_IMAGE_SECTION_HEADER {
BYTE
Name[IMAGE_SIZEOF_SHORT_NAME];
union
{
DWORD
PhysicalAddress;
DWORD
VirtualSize;
} Misc;
DWORD
VirtualAddress;
DWORD
SizeOfRawData;
DWORD
PointerToRawData;
DWORD
PointerToRelocations;
DWORD
PointerToLinenumbers;
WORD
NumberOfRelocations;
WORD
NumberOfLinenumbers;
DWORD
Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef
struct
_IMAGE_FILE_HEADER {
WORD
Machine;
WORD
NumberOfSections;
DWORD
TimeDateStamp;
DWORD
PointerToSymbolTable;
DWORD
NumberOfSymbols;
WORD
SizeOfOptionalHeader;
WORD
Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef
struct
_IMAGE_OPTIONAL_HEADER {
WORD
Magic;
BYTE
MajorLinkerVersion;
BYTE
MinorLinkerVersion;
DWORD
SizeOfCode;
DWORD
SizeOfInitializedData;
DWORD
SizeOfUninitializedData;
DWORD
AddressOfEntryPoint;
DWORD
BaseOfCode;
DWORD
BaseOfData;
DWORD
ImageBase;
DWORD
SectionAlignment;
DWORD
FileAlignment;
WORD
MajorOperatingSystemVersion;
WORD
MinorOperatingSystemVersion;
WORD
MajorImageVersion;
WORD
MinorImageVersion;
WORD
MajorSubsystemVersion;
WORD
MinorSubsystemVersion;
DWORD
Win32VersionValue;
DWORD
SizeOfImage;
DWORD
SizeOfHeaders;
DWORD
CheckSum;
WORD
Subsystem;
WORD
DllCharacteristics;
DWORD
SizeOfStackReserve;
DWORD
SizeOfStackCommit;
DWORD
SizeOfHeapReserve;
DWORD
SizeOfHeapCommit;
DWORD
LoaderFlags;
DWORD
NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
typedef
struct
_IMAGE_FILE_HEADER {
WORD
Machine;
WORD
NumberOfSections;
DWORD
TimeDateStamp;
DWORD
PointerToSymbolTable;
DWORD
NumberOfSymbols;
WORD
SizeOfOptionalHeader;
WORD
Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
[招生]系统0day安全-IOT设备漏洞挖掘(第6期)!
最后于 2024-2-3 10:47
被satadrover编辑
,原因: