手撸一个安装包制作工具(4) --解压

在开写解压代码之前,我们要先知道尾部数据的位置:

我本来是准备直接写入尾部一个区段,

然后在区段中设置大小或Flags来确定是否自己添加的.(和NSIS一样)

 

但是在这里, 为了方便, 我选择直接写入文件尾部数据,

并且假设这个文件并没有任何的没有头信息的已添加区段

 

但是为了兼容之后的代码,仍然选择通过PE格式来获取最后区段所在的位置来确定尾部数据位置

 

先定义几个尾部数据的结构 (写入时也要按此结构写入):

struct addedSector
{
    DWORD verifycode;                  // 0

    char compressType[10];             // 压缩方式
    char programName[20];              // 安装包的程序名
    char autorun[150];                 // 自动运行程序的相对路径

    int nfiles;                        // 总文件数量
                                       //
                                       // +sizeof(addedSector) 之后就是每个文件块 fileblock
};

struct fileblock
{
    char relativepath[150];            // 临时文件=".tmp" or 相对路径 : aa/bb/
    char filename[50];                 // 文件名   : a.dll   >> 那么这个文件的路径: setuppath/aa/bb/a.dll
    DWORD filesize;                    // 大小
                                       //
                                       // +sizeof(fileblock) 之后就是文件内容 byte* filebuf
};

设置的数据很少,但是够用了.

addedSector结构就是刚开始时说到的'安装包信息'的结构体

这个结构的后面紧接着就是连续的每个文件块.

文件块遍历的话 直接使用  filesize+sizeof(fileblock) 即可

模板EXE就可以按照上面的结构, 找到尾部结构:

// 简单的初始化PE信息的封装类
ctPEFile::PEFile selfpe;

// 获取被添加的内存所在位置
addedSector* getAddedSector()
{
    char tmp[260];
    GetModuleFileNameA( NULL, tmp, 260 );
    if(selfpe.loadfile( tmp ))
    {
        // 越过最后一个区段,就是添加数据的位置
        PIMAGE_SECTION_HEADER lastsec = selfpe.secheader + selfpe.seccount - 1;
        return (addedSector*)(selfpe.filebuf + lastsec->PointerToRawData + lastsec->SizeOfRawData);
    }
    return nullptr;
}

获取尾部并且初始化结构中的信息后, 下一步就是解压了,

而解压最重要的是遍历文件块(fileblock):

// 获取指定的文件块位置
fileblock* getFileBlock( int ifile )
{
    if(ifile < addedsec->nfiles)
    {
        // 先到第一个
        fileblock* fb = (fileblock*)((DWORD)addedsec + sizeof( addedSector ));
        // 一直遍历到指定的位置
        for(int i = 0; i < ifile; i++)
            fb = (fileblock*)((DWORD)fb + fb->filesize + sizeof( fileblock ));
        return fb;
    }
    return nullptr;
}

拿到文件块之后就很简单了,直接写入文件内容(filebuf)到文件中即可:

//
// if relativepath exist, create folders
//
char dir[260];
wsprintfA( dir, "%s\\%s", setuppath.c_str(), fb->relativepath );
SHCreateDirectoryExA( NULL, dir, NULL );
wsprintfA( extractPath, "%s\\%s\\%s", setuppath.c_str(), fb->relativepath, fb->filename );
// 
writetoexfile ( filebuf , fb-> filesize );

 

再给这个解压函数加上一些额外的功能, 比如界面显示,临时文件释放等.

解压函数就可以正常运作了

//
// 释放文件到指定位置
//
void extractFile( int ifile )
{
    fileblock* fb = getFileBlock( ifile );
    if(fb)
    {
        // 创建要释放的目录/确定文件全路径
        char extractPath[260] = {0};
        if(strcmp( fb->relativepath, ".tmp" ) == 0)
        {
            // 临时文件,直接释放到临时目录
            GetTempPathA( 260, extractPath );
            strcat( extractPath, fb->filename );
        }
        else
        {
            if(fb->relativepath[0])
            {
                //if relativepath exist, create folders
                char dir[260];
                wsprintfA( dir, "%s\\%s", setuppath.c_str(), fb->relativepath );
                SHCreateDirectoryExA( NULL, dir, NULL );
                wsprintfA( extractPath, "%s\\%s\\%s", setuppath.c_str(), fb->relativepath, fb->filename );
            }
            else
            {
                wsprintfA( extractPath, "%s\\%s", setuppath.c_str(), fb->filename );
            }
        }

        // 界面上显示当前解压文件的名称
        ctd.setText( "showpath", extractPath );

        // 这里直接写入文件, 并没有解压相关 , 请去完整代码中查看
        byte* filebuf = (byte*)((DWORD)fb + sizeof( fileblock ));
        // 
        FILE *f = fopen(extractPath,"wb");
        if(f)
        {
            fwrite( filebuf, 1, fb->filesize, f );
            fclose( f );
        }
    }
}

 

 

下一篇: 手撸一个安装包制作工具(5) --生成器/项目链接

转载于:https://my.oschina.net/tasker/blog/724653

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值