首页
社区
课程
招聘
[原创] UPX源码学习和简单修改
发表于: 2023-1-7 11:52 54829

[原创] UPX源码学习和简单修改

2023-1-7 11:52
54829

之前一直学习如何脱壳,接触到的第一种壳就是UPX。经过一段脱壳训练后,逐渐对UPX的压缩流程有了兴趣。本文是笔者对UPX源码的学习记录,包括代码学习过程和源码简单修改,希望对大家有所帮助。

分析环境:
UPX版本: 3.96 (https://github.com/upx/upx/releases/download/v3.96/upx-3.96-src.tar.xz)
linux系统: centOS 7 - Linux localhost.localdomain 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
kali: Linux kali 5.9.0-kali1-amd64 #1 SMP Debian 5.9.1-1kali2 (2020-10-29) x86_64 GNU/Linux
010 Editor版本: v10.0 (64 bit)

为了方便调试,笔者只分析了x86-64位ELF文件的加壳流程代码,本文所用程序见结尾文件 demo。代码跟踪过程主要参考文章UPX源码分析——加壳篇,大家有兴趣可详细阅读。这里只介绍大体流程。

UPX的核心加壳代码是 upx-3.96/src/p_unix.cpp 文件的 pack 函数。

该函数调用了4个关键函数,分别为pack1、pack2、pack3和pack4,代表了加壳的四个步骤。

pack1 函数功能是,写入新文件的elf头,写入程序头表,写入1个初始化的l_info结构。

pack2 函数功能是,对所有类型为PT_LOAD的段进行压缩存储。

其中,在对第一个类型为PT_LOAD的段(该块一般包含原文件的文件头和程序头表)进行压缩时,会将该段分为两个部分分别压缩写入。这两部分为:一、原文件的elf头和程序头表;二、该段数据的其他部分。
例如,demo文件中第一个PT_LOAD段如下

第一段文件偏移为0,大小为0x5F0。从图中可以看到文件头+程序头表的大小为0x270,这就是需要压缩的第一块数据。第二块数据就是文件偏移为0x270,大小为0x380。

pack3 函数的功能是,写入loader,压缩原文件中除PT_LOAD段之外的其余数据并写入,修正程序头表内容

pack4 函数的功能是,写入PackHeader和overlay_offset。这里overlay_offset值为p_info字段的文件偏移。本demo中为0xf4。

经过UPX处理后,压缩后的文件格式如下。

new eheader(64 bytes) (文件头)
+ new pheader(56 bytes) * 3 (程序头表)
+ l_info(12 bytes)
+ p_info(12 bytes)
+ b_info(12 bytes) + compressed block (原程序文件头和程序头表)
+ b_info(12 bytes) + compressed block (第一个类型为PT_LOAD的段中除原程序文件头和程序头表的部分)
+ b_info(12 bytes) + compressed block (第二个类型为PT_LOAD的段)
+ ......
+ fpad8 (8字节对齐)
+ int(4 bytes) (第一个b_info的文件偏移)
+ int(4 bytes) (当前位置的文件偏移,也就是之前所有数据总长度)
+ loader (加载器,也就是脱壳代码)
+ b_info(12 bytes) + compressed block (第一个PT_LOAD和第二个PT_LOAD中间的数据)
+ b_info(12 bytes) + compressed block (第二个PT_LOAD和第三个PT_LOAD中间的数据)
+ ......
+ b_info(12 bytes) + compressed block (最后一个PT_LOAD到文件末尾之间的数据)
+ 00 00 00 00 55 50 58 21 00 00 00 00 (b_info)
+ fpad4 (4字节对齐)
+ PackHeader(32 bytes)
+ int(4 bytes) (p_info的文件偏移)

其中,b_info、l_info和p_info是三个结构体。

针对demo文件的loader生成代码在 upx-3.96/src/p_lx_elf.cpp 文件的PackLinuxElf64::buildLinuxLoader()函数中,loader中各section的相应顺序由函数PackLinuxElf::addStubEntrySections()确定。

除了"FOLDEXEC",其余section的汇编代码在upx-3.96/src/stub/src/amd64-linux.elf-entry.S文件中,编译后的二进制数据在文件upx-3.96/src/stub/amd64-linux.elf-entry.h中。loader直接使用*.h文件中的二进制数据。

最终,demo文件压缩后loader的结构如下

FOLDEXEC节存放的是压缩后的数据,源数据是编译后的二进制数据,存放在upx-3.96/src/stub/amd64-linux.elf-fold.h文件中。
编译前的代码分为两部分,一部分是upx-3.96/src/stub/src/amd64-linux.elf-fold.S文件中的汇编代码,一部分是upx-3.96/src/stub/src/amd64-linux.elf-main.c文件中的C代码。该文件核心是upx_main()函数,此函数返回值为解压后程序(原程序)的入口点.

在阅读UPX源码过程中,经常需要对压缩后的文件格式进行分析,以验证自己的猜想。因为笔者经常使用010作为二进制分析工具,遂决定自己写一个010模板。这里是对标准的 ELF.bt(V2.5.5)进行了修改。

首先,将上节所述的三个关键结构体加入到模板中,为了增加可读性,在个别字段添加属性值。添加的结构体代码如下:

然后,将原来模板中file结构体中对section的解析代码去掉,因为UPX压缩后的文件没有相关字段。

最后,在file结构体中program_header_table结构体生成之后,添加l_info结构之后的数据解析代码。

最终效果如下,红框中是我们添加的新结构。

修改完成的模板见结尾文件 upx.bt。因为文件格式问题,该模板只适用于 demo 文件压缩后的文件。大家有其他需求可以在此基础上自己修改。

之前做病毒分析时,碰到了一个无法使用标准UPX程序解压的程序。后来通过搜寻资料和学习,了解到有多种方式可实现该效果。基本思路是修改替换程序中的特征字符,常见的修改方法如下:

据此,笔者萌生直接对源码进行修改的想法,所以有以下两个简单尝试。

本次尝试主要是修改源程序的入口点位置,使常规的UPX解压程序后无法快速找到正确的入口点位置。

存储入口点之前,处理该值,这里异或一个常量0xdeafdeaf。文件upx-3.96/src/p_unix.cpp添加如下代码

解压得到入口点之后,处理该值,也是异或常量0xdeafdeaf。这里有两种方式,实现的功能一样。

xor eax, 3736067759 -> 35 AF DE AF DE -> 53,175,222,175,222

上面对于入口点的修改虽然成功了,但是压缩后的程序仍然可被解压。而且从原理来看,解压后是可以看到原程序代码执行逻辑的。所以笔者有了第二次代码修改。主要修改思路是,对压缩之前的数据进行处理,然后再进行压缩。这样标准UPX就无法解压我们自己压缩的程序,比只对入口点的修改效果更好。

压缩前修改数据,我们做一个简单的异或处理,这里对所有的数据异或0xe9(十进制为233)
文件:upx-3.96/src/compress.cpp
upx_compress函数修改,核心部分

upx_decompress函数修改,此处修改主要是因为在文件upx-3.96/src/packer.cpp的Packer::compress函数中,会对压缩后的数据进行解压验证,需要保持压缩和解压函数逻辑对称。

upx在加载loader是会对其进行压缩处理,而解压算法已写成汇编代码,修改起来比较麻烦。这里我就对loader数据多进行一次处理,以抵消upx-3.96/src/compress.cpp文件upx_compress函数中添加的异或处理。
文件:upx-3.96/src/p_lx_elf.cpp

因为原数据压缩前进行了处理,为保证执行时程序逻辑不变,需要对解压后的数据进行逆处理。下面就是对loader的源码进行修改。
文件:upx-3.96/src/stub/src/amd64-linux.elf-main.c

本文主要介绍了三个部分的内容:

文章较短,如有不足,恳请指正,不胜感激。

https://www.cnblogs.com/ichunqiu/p/7245329.html
https://bbs.kanxue.com/thread-257797.htmtmnxue.com/thread-257797.htm

void PackUnix::pack(OutputFile *fo)
{
    Filter ft(ph.level);
    ft.addvalue = 0;
    b_len = 0;
    progid = 0;
 
    // set options
    blocksize = opt->o_unix.blocksize;
    if (blocksize <= 0)
        blocksize = BLOCKSIZE;
    if ((off_t)blocksize > file_size)
        blocksize = file_size;
 
    // init compression buffers
    ibuf.alloc(blocksize);
    obuf.allocForCompression(blocksize);
 
    fi->seek(0, SEEK_SET);
    pack1(fo, ft);  // generate Elf header, etc.
 
    p_info hbuf;
    set_te32(&hbuf.p_progid, progid);
    set_te32(&hbuf.p_filesize, file_size);
    set_te32(&hbuf.p_blocksize, blocksize);
    fo->write(&hbuf, sizeof(hbuf));
 
    // append the compressed body
    if (pack2(fo, ft)) {
        // write block end marker (uncompressed size 0)
        b_info hdr; memset(&hdr, 0, sizeof(hdr));
        set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
        fo->write(&hdr, sizeof(hdr));
    }
 
    pack3(fo, ft);  // append loader
 
    pack4(fo, ft);  // append PackHeader and overlay_offset; update Elf header
 
    // finally check the compression ratio
    if (!checkFinalCompressionRatio(fo))
        throwNotCompressible();
}
void PackUnix::pack(OutputFile *fo)
{
    Filter ft(ph.level);
    ft.addvalue = 0;
    b_len = 0;
    progid = 0;
 
    // set options
    blocksize = opt->o_unix.blocksize;
    if (blocksize <= 0)
        blocksize = BLOCKSIZE;
    if ((off_t)blocksize > file_size)
        blocksize = file_size;
 
    // init compression buffers
    ibuf.alloc(blocksize);
    obuf.allocForCompression(blocksize);
 
    fi->seek(0, SEEK_SET);
    pack1(fo, ft);  // generate Elf header, etc.
 
    p_info hbuf;
    set_te32(&hbuf.p_progid, progid);
    set_te32(&hbuf.p_filesize, file_size);
    set_te32(&hbuf.p_blocksize, blocksize);
    fo->write(&hbuf, sizeof(hbuf));
 
    // append the compressed body
    if (pack2(fo, ft)) {
        // write block end marker (uncompressed size 0)
        b_info hdr; memset(&hdr, 0, sizeof(hdr));
        set_le32(&hdr.sz_cpr, UPX_MAGIC_LE32);
        fo->write(&hdr, sizeof(hdr));
    }
 
    pack3(fo, ft);  // append loader
 
    pack4(fo, ft);  // append PackHeader and overlay_offset; update Elf header
 
    // finally check the compression ratio
    if (!checkFinalCompressionRatio(fo))
        throwNotCompressible();
}
 
 
 
 
 
 
 
 
 
 
// 在每个压缩块之前,存放压缩前和压缩后的数据大小
struct b_info {     // 12-byte header before each compressed block
    uint32_t sz_unc;            // uncompressed_size
    uint32_t sz_cpr;            // compressed_size
    unsigned char b_method;     // compression algorithm
    unsigned char b_ftid;       // filter id
    unsigned char b_cto8;       // filter parameter
    unsigned char b_unused;
};
// 存放校验数据和"UPX!"魔数
struct l_info       // 12-byte trailer in header for loader (offset 116)
{
    uint32_t l_checksum;
    uint32_t l_magic;
    uint16_t l_lsize;
    uint8_t  l_version;
    uint8_t  l_format;
};
// 全文只有一个该结构体,存储的是原文件的大小
struct p_info       // 12-byte packed program header follows stub loader
{
    uint32_t p_progid;
    uint32_t p_filesize;
    uint32_t p_blocksize;  
};
// 在每个压缩块之前,存放压缩前和压缩后的数据大小
struct b_info {     // 12-byte header before each compressed block
    uint32_t sz_unc;            // uncompressed_size
    uint32_t sz_cpr;            // compressed_size
    unsigned char b_method;     // compression algorithm
    unsigned char b_ftid;       // filter id
    unsigned char b_cto8;       // filter parameter
    unsigned char b_unused;
};
// 存放校验数据和"UPX!"魔数
struct l_info       // 12-byte trailer in header for loader (offset 116)
{
    uint32_t l_checksum;
    uint32_t l_magic;
    uint16_t l_lsize;
    uint8_t  l_version;
    uint8_t  l_format;
};
// 全文只有一个该结构体,存储的是原文件的大小
struct p_info       // 12-byte packed program header follows stub loader
{
    uint32_t p_progid;
    uint32_t p_filesize;
    uint32_t p_blocksize;  
};
void
PackLinuxElf::addStubEntrySections(Filter const *)
{
    addLoader("ELFMAINX", NULL);
    if (hasLoaderSection("ELFMAINXu")) {
            // brk() trouble if static
        addLoader("ELFMAINXu", NULL);
    }
   //addLoader(getDecompressorSections(), NULL);
    addLoader(
        ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
        : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
        : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
        : M_IS_LZMA(ph.method)  ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
        : NULL), NULL);
    if (hasLoaderSection("CFLUSH"))
        addLoader("CFLUSH");
    addLoader("ELFMAINY,IDENTSTR", NULL);
    if (hasLoaderSection("ELFMAINZe")) { // ppc64 big-endian only
        addLoader("ELFMAINZe", NULL);
    }
    addLoader("+40,ELFMAINZ", NULL);
    if (hasLoaderSection("ANDMAJNZ")) { // Android trouble with args to DT_INIT
        if (opt->o_unix.android_shlib) {
            addLoader("ANDMAJNZ", NULL);  // constant PAGE_SIZE
        }
        else {
            addLoader("ELFMAJNZ", NULL);  // PAGE_SIZE from AT_PAGESZ
        }
        addLoader("ELFMAKNZ", NULL);
    }
    if (hasLoaderSection("ELFMAINZu")) {
        addLoader("ELFMAINZu", NULL);
    }
    addLoader("FOLDEXEC", NULL);
}
void
PackLinuxElf::addStubEntrySections(Filter const *)
{
    addLoader("ELFMAINX", NULL);
    if (hasLoaderSection("ELFMAINXu")) {
            // brk() trouble if static
        addLoader("ELFMAINXu", NULL);
    }
   //addLoader(getDecompressorSections(), NULL);
    addLoader(
        ( M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E,NRV_TAIL"
        : M_IS_NRV2D(ph.method) ? "NRV_HEAD,NRV2D,NRV_TAIL"
        : M_IS_NRV2B(ph.method) ? "NRV_HEAD,NRV2B,NRV_TAIL"
        : M_IS_LZMA(ph.method)  ? "LZMA_ELF00,LZMA_DEC20,LZMA_DEC30"
        : NULL), NULL);
    if (hasLoaderSection("CFLUSH"))
        addLoader("CFLUSH");
    addLoader("ELFMAINY,IDENTSTR", NULL);
    if (hasLoaderSection("ELFMAINZe")) { // ppc64 big-endian only
        addLoader("ELFMAINZe", NULL);
    }
    addLoader("+40,ELFMAINZ", NULL);
    if (hasLoaderSection("ANDMAJNZ")) { // Android trouble with args to DT_INIT
        if (opt->o_unix.android_shlib) {
            addLoader("ANDMAJNZ", NULL);  // constant PAGE_SIZE
        }
        else {
            addLoader("ELFMAJNZ", NULL);  // PAGE_SIZE from AT_PAGESZ
        }
        addLoader("ELFMAKNZ", NULL);
    }
    if (hasLoaderSection("ELFMAINZu")) {
        addLoader("ELFMAINZu", NULL);
    }
    addLoader("FOLDEXEC", NULL);
}
 
ELFMAINX
NRV_HEAD
NRV2E   
NRV_TAIL
ELFMAINY
IDENTSTR
+40 (4字节对齐)
ELFMAINZ
FOLDEXEC
ELFMAINX
NRV_HEAD
NRV2E   
NRV_TAIL
ELFMAINY
IDENTSTR
+40 (4字节对齐)
ELFMAINZ
FOLDEXEC
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
 
void *
upx_main(  // returns entry address
    struct b_info const *const bi,  // 1st block header
    size_t const sz_compressed,  // total length
    Elf64_Ehdr *const ehdr,  // temp char[sz_ehdr] for decompressing
    Elf64_auxv_t *const av,
    f_expand *const f_exp,
    f_unfilter *const f_unf
#if defined(__x86_64)  //{
    , Elf64_Addr elfaddr  // In: &Elf64_Ehdr for stub
#elif defined(__powerpc64__)  //}{
    , Elf64_Addr *p_reloc  // In: &Elf64_Ehdr for stub; Out: 'slide' for PT_INTERP
    , size_t const PAGE_MASK
#elif defined(__aarch64__) //}{
    , Elf64_Addr elfaddr
    , size_t const PAGE_MASK
#endif  //}
)
{
    ......
}
/*************************************************************************
// upx_main - called by our entry code
//
// This function is optimized for size.
**************************************************************************/
 
void *
upx_main(  // returns entry address
    struct b_info const *const bi,  // 1st block header
    size_t const sz_compressed,  // total length
    Elf64_Ehdr *const ehdr,  // temp char[sz_ehdr] for decompressing
    Elf64_auxv_t *const av,
    f_expand *const f_exp,
    f_unfilter *const f_unf
#if defined(__x86_64)  //{
    , Elf64_Addr elfaddr  // In: &Elf64_Ehdr for stub
#elif defined(__powerpc64__)  //}{
    , Elf64_Addr *p_reloc  // In: &Elf64_Ehdr for stub; Out: 'slide' for PT_INTERP
    , size_t const PAGE_MASK
#elif defined(__aarch64__) //}{
    , Elf64_Addr elfaddr
    , size_t const PAGE_MASK
#endif  //}
)
{
    ......
}
 
typedef uint uint32_t;
typedef ushort uint16_t;
typedef uchar uint8_t;
 
struct b_info  // 12-byte header before each compressed block
{                          
    uint32_t sz_unc<format = hex, comment = "Uncompressed size">; // uncompressed_size
    uint32_t sz_cpr<format = hex, comment = "Compressed size">;     // compressed_size
    unsigned char b_method<comment = "Compression algorithm">; // compression algorithm
    unsigned char b_ftid;   // filter id
    unsigned char b_cto8;   // filter parameter
    unsigned char b_unused;
};
 
struct l_info // 12-byte trailer in header for loader (offset 116)
{
    uint32_t l_checksum;
    uint32_t l_magic<format = hex, comment = "UPX!">;
    uint16_t l_lsize;
    uint8_t l_version;
    uint8_t l_format;
};
 
struct p_info // 12-byte packed program header follows stub loader
{
    uint32_t p_progid;
    uint32_t p_filesize;
    uint32_t p_blocksize;
};
 
typedef struct
{
    b_info bheader;
    char data[bheader.sz_cpr];
}cblock;
 
typedef struct
{
    uint32 offset_b_info;
    uint32 data_size;
}endheader;
typedef uint uint32_t;
typedef ushort uint16_t;
typedef uchar uint8_t;
 
struct b_info  // 12-byte header before each compressed block
{                          
    uint32_t sz_unc<format = hex, comment = "Uncompressed size">; // uncompressed_size
    uint32_t sz_cpr<format = hex, comment = "Compressed size">;     // compressed_size
    unsigned char b_method<comment = "Compression algorithm">; // compression algorithm
    unsigned char b_ftid;   // filter id
    unsigned char b_cto8;   // filter parameter
    unsigned char b_unused;
};
 
struct l_info // 12-byte trailer in header for loader (offset 116)
{
    uint32_t l_checksum;
    uint32_t l_magic<format = hex, comment = "UPX!">;
    uint16_t l_lsize;
    uint8_t l_version;
    uint8_t l_format;
};
 
struct p_info // 12-byte packed program header follows stub loader
{
    uint32_t p_progid;
    uint32_t p_filesize;
    uint32_t p_blocksize;
};
 
typedef struct
{
    b_info bheader;
    char data[bheader.sz_cpr];
}cblock;
 
typedef struct
{
    uint32 offset_b_info;
    uint32 data_size;
}endheader;
// 需要删除的代码
// Find the header name location 869
local quad section_name_off =
    file.elf_header.e_shoff_SECTION_HEADER_OFFSET_IN_FILE +
    (file.elf_header.e_shentsize_SECTION_HEADER_ENTRY_SIZE *
      file.elf_header.e_shtrndx_STRING_TABLE_INDEX);
 
// Find the header name block
if (file.elf_header.e_ident.ei_class_2 == ELFCLASS32) {
    ......
} else {
    ......
}
 
local int sec_tbl_cur_elem;
// Find the section headers
if(file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES > 0) {
    ......
}
 
local int sym_sect;
local int sym_name_sect;
 
// Find the symbol section
sym_sect = FindNamedSection(".symtab");
if(sym_sect >= 0) {
    ......
}
 
// Find the dynamic symbol section
sym_sect = FindNamedSection(".dynsym");
if(sym_sect >= 0) {
    ......
}
// 需要删除的代码
// Find the header name location 869
local quad section_name_off =
    file.elf_header.e_shoff_SECTION_HEADER_OFFSET_IN_FILE +
    (file.elf_header.e_shentsize_SECTION_HEADER_ENTRY_SIZE *
      file.elf_header.e_shtrndx_STRING_TABLE_INDEX);
 

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

最后于 2023-1-7 16:42 被luoye_ATL编辑 ,原因: 标题格式有问题,进行修正
上传的附件:
  • demo (2.12MB,223次下载)
  • upx.bt (38.75kb,216次下载)
收藏
免费 23
支持
分享
最新回复 (49)
雪    币: 2575
活跃值: (502)
能力值: ( LV2,RANK:85 )
在线值:
发帖
回帖
粉丝
2
不错的帖子,二次开发,加点VM进去?
2023-1-7 15:05
0
雪    币: 110
活跃值: (3325)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-1-7 16:00
0
雪    币: 1242
活跃值: (1434)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
4
wyfe 不错的帖子,二次开发,加点VM进去?
VM得下下个阶段了,下一步想着想研究下解压的汇编代码
2023-1-7 17:44
0
雪    币: 2575
活跃值: (502)
能力值: ( LV2,RANK:85 )
在线值:
发帖
回帖
粉丝
5
luoye_ATL VM得下下个阶段了,下一步想着想研究下解压的汇编代码[em_41]
看看解压算法是自已实现的,还是用了第三方的压缩引擎
2023-1-7 21:20
0
雪    币: 30050
活跃值: (2432)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
wyfe 看看解压算法是自已实现的,还是用了第三方的压缩引擎

UDX使用的是开源的UCL压缩库吧,那东西对于PE的压缩率很高,主要是解压速度快。一直在使用。http://www.oberhumer.com/opensource/ucl/

最后于 2023-1-7 21:55 被bestbird编辑 ,原因: 添加附件
上传的附件:
2023-1-7 21:53
1
雪    币: 458
活跃值: (515)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
感谢分享
2023-1-14 12:34
0
雪    币: 4228
活跃值: (3030)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
感谢大佬分享
2023-1-21 17:32
0
雪    币: 2055
活跃值: (418)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
感谢分享
2023-1-29 18:35
0
雪    币: 1671
活跃值: (215832)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
10
tql
2023-1-30 09:51
0
雪    币: 211
活跃值: (526)
能力值: ( LV9,RANK:172 )
在线值:
发帖
回帖
粉丝
11
https://github.com/upx/upx-stubtools
upx的loader是通过这个工具生成的 (也就是你上面修改的 amd64-linux.elf-fold.h )
2023-1-30 11:20
0
雪    币: 1242
活跃值: (1434)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
12
vmtest https://github.com/upx/upx-stubtools upx的loader是通过这个工具生成的 (也就是你上面修改的 amd64-linux.elf-fold.h )
是的,我后来就是用这个工具重新编译修改后的代码生成 amd64-linux.elf-fold.h 文件
2023-2-1 22:27
0
雪    币: 6472
活跃值: (4456)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
感謝分享!
2023-2-2 08:32
0
雪    币: 220
活跃值: (721)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
WIN下的,也是一样的么?
2023-2-5 11:31
0
雪    币: 1242
活跃值: (1434)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
15
dayang WIN下的,也是一样的么?

WIN的加壳流程我不太清楚,得你自己阅读源码了。loader部分的话使用的是另外的文件,在目录upx-3.96/src/stub/src/可以看到

最后于 2023-2-6 14:29 被luoye_ATL编辑 ,原因:
2023-2-6 14:07
0
雪    币: 381
活跃值: (165)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
请教下修改.s的汇编文件后, 怎么编译呢
2023-2-8 11:36
0
雪    币: 381
活跃值: (165)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
vmtest https://github.com/upx/upx-stubtools upx的loader是通过这个工具生成的 (也就是你上面修改的 amd64-linux.elf-fold.h )
请教下windows环境下怎么使用这个工具呢
2023-2-8 14:33
0
雪    币: 1242
活跃值: (1434)
能力值: ( LV5,RANK:78 )
在线值:
发帖
回帖
粉丝
18

用vmtest师傅提到的工具就可以,根据说明配置好之后,编译的时候类似amd64-linux.elf-fold.h的.h文件都会重新生成的。

最后于 2023-2-9 17:01 被luoye_ATL编辑 ,原因:
2023-2-9 16:58
0
雪    币: 102
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
修改入口点代码的部分,修改.h文件是不行的,或者说只修改那三个部分不行。那个长度常量后面还跟着两个校验值也会变,并且代码长度也不是固定增加5字节,具体取决于编译器生成的bin文件。生成h文件的逻辑在stub/scripts/下,主要是那给bin2h的py脚本。自行编译修改的话可以用一下
2023-3-23 14:44
1
雪    币: 102
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
楼主好!我在根据您的文章进行代码修改和复现过程中,发现一个问题,分享出来供参考。问题出现在修改入口点代码的loader部分。文章中loader异或key的位置在汇编码中,根据注释是将upx_main函数的返回值进行异或恢复,但我这里测试这样的操作会导致segmentation fault。我根据注释找到upx_main函数查看,可以获知入口点由前面的do_xmap函数返回,跟入该函数发现它的返回值实际上是ehdr->e_entry + reloc,而我们在加壳部分处理的代码实际上是直接对ehdr->e_entry进行处理的,由于reloc的存在导致返回值异或后会产生异常。
我重新分析了upx_main的流程,ehdr是该函数的第三个参数,推测前面的loader部分只是提取ehdr不会对其进行处理,进入upx_main后可看到ehdr被赋值给xo.buf,随后被传入unpackExtent函数处理。处理的代码我没仔细跟,因为根据函数名和其注释来看,该函数确实会对ehdr进行处理,应该是包含一些入口点相关的内容的,不能硬碰,另外我们在加壳部分的代码是位于packExtent的头部(申请内存并填充后立刻进行了入口点的异或),后续的处理逻辑应该和这个函数对应上了。所以根据前后对应的逻辑,我将异或恢复的代码放在了该函数后:
// ehdr = Uncompress Ehdr and Phdrs
    unpackExtent(&xi2, &xo, f_exp, 0); // never filtered?
    ehdr->e_entry = (ehdr->e_entry ^ 0xdeafdeaf);
然后程序就正常运行不会报错了。
因此提出一个问题,原始版本的代码实际上仅能应用于reloc为0的情况下(do_xmap函数结尾的部分),当其不为0就会导致问题,而我这里就刚刚好踩了这个坑。我这里在简单的逻辑上修复了该问题(pack前加密,unpack后解密,没有经过do_xmap的处理和影响;但这是简单的逻辑层面的,深层上仍应该严格分析packExtent和unpackExtent函数的逻辑来确定相关修改有没有影响),供各位参考
2023-3-28 17:15
1
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
压缩数据修改,修改这4处,运行不了,会报错。
2023-4-10 08:26
1
雪    币: 3059
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
感谢分享
2023-4-10 09:16
1
雪    币: 102
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
weekend~ 压缩数据修改,修改这4处,运行不了,会报错。
你这个问题我也遇到了,答案是那个p_lx_elf里有两个同名函数,分别隶属于不同的类,用于处理不同平台下的loader(一个32位的一个64位的),你改了其中一个但实际用的是另一个就会出现这个问题,得俩都改才能保证linux下的使用没有问题
2023-4-23 18:10
0
雪    币: 1
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
Vantler 你这个问题我也遇到了,答案是那个p_lx_elf里有两个同名函数,分别隶属于不同的类,用于处理不同平台下的loader(一个32位的一个64位的),你改了其中一个但实际用的是另一个就会出现这个问题,得 ...
好的,我一会试试,谢谢~
2023-4-24 11:18
0
雪    币: 424
活跃值: (699)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
25
为何没有修改任何文件,直接使用make(安装了camke)编译src得到的upx加壳的文件运行也会出现segmentation fault错误?
2023-5-12 08:46
0
游客
登录 | 注册 方可回帖
返回
//