PE文件操作-简单的加壳实现

本文介绍了如何实现一个简单的PE文件加壳程序,主要使用异或运算对文件数据进行编码。在加壳过程中,保留了文件头、原始节表,并在文件末尾添加新的节以存放解码代码和数据。备份资源节、遍历所有节进行编码、构造解码程序所需的配置信息等步骤详述。最后,解码代码将控制权转交给原始代码的入口点(OEP)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

处于一些原因,需要对PE文件进行加壳。所谓加壳就是有某种编码算法对原始文件数据进行编码,并使原始文件内容成为数据部分,而嵌进文件的解密代码成为主体。在loader加载加壳文件后,会将控制权交给解码程序,解码程序在完成解码后,再把控制权交给原始代码。
这个加壳程序是学习之用,所以只实现了最简单的可逆变换-异或运算。对文件操作用了内存映射文件,所以直接操作内存即可。
先说一下思路:对原始PE文件编码,一般是保护数据部分,而文件头则不需要进行编码,所以保留文件头。至于原始文件的节表我们也会保留,而我们会在原始PE文件末尾追加几个节以供解码(见PE文件操作-在末尾添加节)。

  • PACKRES节:备份的原始PE的资源数据。这个节是原始文件中唯一需要备份的节,因为图标的显示以及一些程序配置都在这个节中,涉及到程序的加载参数,所以需要保留。
  • PACKCODE节:解码代码,负责解码所有节,填充IAT和跳回OEP。
  • PACKDATA节:解码参数,其中保存了映像信息,原始节表。由于在填充IAT过程中用到了LoadLibrary和GetProcAddress,所以这个节还包含了我们壳程序的导入表和IAT。

最终文件结构就像下面这样:
原始数据
PACKRES
  RES1
  RES2
  …….
PACKCODE
  CODE
PACKDATA
  PACK_CONFIG
  IAT
  INT

首先是备份资源节,这个操作最简单,在PE末尾后添加一个节,把原始资源节的数据拷贝至其中,然后遍历 资目录修正其中数据目录项的DataOffset,这个修正过程和重定位表的修正差不多,大致流程:

    PIMAGE_SECTION_HEADER res_sec;
    insert_section_at_eof(ctx,
        "PACKRES",
        opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size,
        IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA,
        &res_sec);

    DWORD old_res = opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
    //拷贝数据
    memcpy((PUCHAR)ctx->map_ptr + res_sec->PointerToRawData,
        (PUCHAR)ctx->map_ptr + rva_to_fo(ctx, (opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)),
        opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
    //将资源目录定位到新的节
    opt_hdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = res_sec->VirtualAddress;
    //修正dataoffset
    adjust_resource_rva(ctx, res_sec->VirtualAddress - old_res);

这一步的效果如下图:
这里写图片描述
这一步备份完后,就可以对原始数据编码了,遍历所有节进行编码,这里要小心一下,因为有些奇怪的程序VirtualSize是比SizeOfRawData大的,不要想当然的觉得VirtualSize肯定小:

    for (int i = 0;i < get_section_count(ctx)-1;i++)
    {
        PIMAGE_SECTION_HEADER sec_hdr;
        get_section_entry_by_index(ctx, i, &sec_hdr);

        for (int j = 0;j < sec_hdr->SizeOfRawData;j++)
        {
            *((PUCHAR)ctx->map_ptr + sec_hdr->PointerToRawData + j) ^= 0x1;
        }
    }

这一步后,PE文件便无法使用了,只能看到其资源数据,而双击是无法打开的。
然后开始构造供解码程序使用的配置信息,这里准备了6个数据,
OriginalImportTable用来让解码程序找到原始导入目录,
OriginalIATDirectory找到原始IAT目录,
NumberOfSections记录了需要解码的节数量,
ImageBase记录了加载机制,用于和RVA相加, <

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值