看来 简单的事情 比最麻烦的事情 还麻烦
一些重定位 输入表处理的东西
还有getmodulehandle函数模拟反而比较简单
倒是1个代码解压到内存运行的过程总是出问题?why?
以下代码参考linuxer的虚拟机
BOOL PELoader(char *lpStaticPEBuff, long lStaticPELen)
{
long lSectionNum;
IMAGE_SECTION_HEADER *pISH;
long lFileAlignMask;
long lSectionAlignMask;
int nIndex;
PIMAGE_FILE_HEADER pfh;
PIMAGE_OPTIONAL_HEADER poh;
PIMAGE_SECTION_HEADER psh;
long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c);
IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset);
//取加载到内存中大小
long lImageSize = pINH->OptionalHeader.SizeOfImage;
char *lpDynPEBuff = ExAllocatePool(NonPagedPool,lImageSize);
dprintf("[dvupx] peoep is %8X\n",lpDynPEBuff);
// pepool=ExAllocatePool(NonPagedPool, poh->SizeOfImage);
memset(lpDynPEBuff, 0, lImageSize);
//取PE文件的节数量
lSectionNum = pINH->FileHeader.NumberOfSections;
pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS));
//加载PE文件第一个节前的信息
memcpy(lpDynPEBuff, lpStaticPEBuff, pISH->VirtualAddress);
//加载各个节
lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1; //各节在磁盘中的对齐掩码
lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1; //各节在load后内存中的对齐掩码
for( nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++)
{
/***************************************************
在对FSG1.33加壳程序进行loader的时候,其节对齐属性
比较怪异,对PE文件接触时间不长,不过地方不知道为什么,
请各位大虾指点迷津,故注掉节属性验证代码
***************************************************/
//判定各节的对齐属性,合法不
/*if((pISH->VirtualAddress & lSectionAlignMask) || (pISH->SizeOfRawData & lFileAlignMask))
{
//出现非法节
delete lpDynPEBuff;
return false;
}*/
//加载改节
memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData);
}
ProcessImports((ULONG)lpDynPEBuff);
ProcessRelocs((ULONG)lpDynPEBuff,(ULONG)lpDynPEBuff);
GetHeaders(lpDynPEBuff,&pfh,&poh,&psh);
dprintf("[dvupx] peoep is %8X\n",poh->AddressOfEntryPoint+lpDynPEBuff);
peoep=(poh->AddressOfEntryPoint+(DWORD)lpDynPEBuff);
dprintf("[dvupx] peoep is %8X\n",peoep);
return 1;
}
加载结果
00000000 0.00000000 [dvupx] Loaded
00000001 0.00029277 [dvupx] peloadaddr is 81644C48
00000002 0.00158456 [dvupx] peoep is 81644E48
使用windbg查看 代码正确
lkd> dd 81644e48
81644e48 b8ec8b55 c0000182 0008c2c9 00000000
81644e58 00000000 00000000 00000000 00000000
81644e68 00000000 00000008 00000000 00000000
81644e78 00000000 00000000 00000000 00000000
81644e88 0a040049 74726f50 00050005 00000000
81644e98 81644e98 81644e98 7fffffff e182d7e8
81644ea8 0a060004 ee657645 00000001 00000001
81644eb8 817babf8 00000000 80561580 00000000
lkd> u 81644e48
81644e48 55 push ebp
81644e49 8bec mov ebp,esp
81644e4b b8820100c0 mov eax,0C0000182h
81644e50 c9 leave
81644e51 c20800 ret 8
81644e54 0000 add byte ptr [eax],al
81644e56 0000 add byte ptr [eax],al
81644e58 0000 add byte ptr [eax],al
但是1运行,
pehex为被加壳文件的解开的文件镜像
执行 PELoader(pehex,sizeof(pehex));
然后
push pRegistryString
push pDriverObj
call peoep
继续在这里写好了
两边的接口问题都解决了
下面应该是考虑压缩算法了
不过这个偶真的没有发言权 还是大牛们来评论吧
aPLib 和LZMA 应该是最常用的2个选择了
由 dwing 发布
论压缩率大致是这样的:
zip < RAR16 < aPLib < RAR32 < LZMA < PPM
TeLeMan:
aPlib只是属于传统LZ方式,一般不会比LZH的高,所以aPlib在上面几种里压缩率是最低的。
dwing:
aPlib压缩率不是最低的,因为使用的字典比zip大,匹配算法比zip完善(但比较慢).
LZH压缩率与zip差不多.
TeLeMan:
aPlib之所以比LZH和zip压缩率要小,是因为没有用到Huffman编码。这一点不需要有什么质疑的,举个现实的例子就可以了。ASPack就是用LZH算法,要比UPX和只用到aPlib库的Packer压缩率大。
dwing
你说的也有道理,经过测试发现压缩较小的文件aPLib有优势,较大的文件使用Huffman算法的有优势,前者的优势只是较大的字典和更好的匹配算法.
LZMA则发挥了LZ算法最大的潜能,使用最完善的匹配算法+算术编码(比Huffman更好)
理论偶就不仔细说了 因为偶也不懂
aplib
压缩函数
size_t aP_pack( const void *source,
void *destination,
size_t length,
void *workmem,
int (*callback)(size_t, size_t, size_t, void *),
void *cbparam );
Parameters:
source - pointer to the data to be compressed.
destination - pointer to where the compressed data should be stored.
length - the length of the uncompressed data in bytes.
workmem - pointer to the work memory which is used during compression.
callback - pointer to the callback function (or NULL).
cbparam - callback argument.
size_t aPsafe_pack( const void *source,
void *destination,
size_t length,
void *workmem,
int (*callback)(size_t, size_t, size_t, void *),
void *cbparam );
Wrapper function for aP_pack, which adds a header to the compressed data containing the length of the original data, and CRC32 checksums of the original and compressed data.
Parameters:
source - pointer to the data to be compressed.
destination - pointer to where the compressed data should be stored.
length - the length of the uncompressed data in bytes.
workmem - pointer to the work memory which is used during compression.
callback - pointer to the callback function (or NULL).
cbparam - callback argument
与之对应的解压缩函数
size_t aP_depack( const void *source,
void *destination );
Decompresses the compressed data from source[] into destination[].
The destination[] buffer must be large enough to hold the decompressed data.
Parameters:
source - pointer to the compressed data.
destination - pointer to where the decompressed data should be stored.
Returns:
the length of the decompressed data, or APLIB_ERROR on error.
size_t aPsafe_depack( const void *source,
size_t srclen,
void *destination,
size_t dstlen );
Wrapper function for aP_depack_asm_safe, which checks the CRC32 of the compressed data, decompresses, and checks the CRC32 of the decompressed data.
Parameters:
source - pointer to the compressed data.
srclen - the size of the source buffer in bytes.
destination - pointer to where the decompressed data should be stored.
dstlen - the size of the destination buffer in bytes.
Returns:
the length of the decompressed data, or APLIB_ERROR on error.
其实这个过程一点也不复杂
如下代码data为原始数据
compressed 为压缩后的数据
/* allocate workmem and destination memory */
char *workmem = malloc(aP_workmem_size(length));
char *compressed = malloc(aP_max_packed_size(length));
/* compress data[] to compressed[] */
size_t outlength = aPsafe_pack(data, compressed, length, workmem, NULL, NULL);
/* if APLIB_ERROR is returned, and error occured */
if (outlength == APLIB_ERROR)
{
printf("An error occured!\n");
} else {
printf("Compressed %u bytes to %u bytes\n", length, outlength);
}
//---------------------------
/* get original size */
size_t orig_size = aPsafe_get_orig_size(compressed);
/* allocate memory for decompressed data */
char *data = malloc(orig_size);
/* decompress compressed[] to data[] */
size_t outlength = aPsafe_depack(compressed, compressed_size, data, orig_size);
/* check decompressed length */
if (outlength != orig_size)
{
printf("An error occured!\n");
} else {
printf("Decompressed %u bytes\n", outlength);
}
//----------------------------------------------------------------------------
压缩过程没有什么好说的 选择1个算法处理处理就ok了
另外 前面有几个小问题 的专门处理1下才行
驱动退出的时候 如果注册了DriverUnload函数 那么就会去调用
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
我们需要将这个函数设置成壳的处理函数,先执行完被加壳程序的DriverUnload
然后再ExFreePool
这里驱动有2种 1种的正常驱动 注册了DriverUnload函数的 我们照上面处理即可
另外1种是流氓驱动 没有注册DriverUnload函数 我们此时不能注册壳的DriverUnload处理函数,不然 也许一些代码还在运行,你就ExFreePool了,那么你只能得到蓝屏
我们需要1个函数 MmIsAddressValid来验证DriverUnload处理函数是否被注册了
在DriverEntry里面加入
if (MmIsAddressValid(pDriverObj->DriverUnload))
{
OldDriverUnload=pDriverObj->DriverUnload;
pDriverObj->DriverUnload = DriverUnload;
}
相应的
我们先判断OldDriverUnload是否有效,如果是正常驱动,那么去执行他
完成以后ExFreePool掉空间
如果OldDriverUnload函数无效,那么我们只好什么也不做了
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
if (MmIsAddressValid(OldDriverUnload))
{
_asm
{
push pDriverObj
call OldDriverUnload
}
ExFreePool(lpDynPEBuff);
}
dprintf("[dvupx] Unloaded\n");
}
基本上到这里 1个半成品(偶只写完了解压部分)就应该差不多了,
其实这个东西娱乐意义远远大于实用意义