ZNDS智能电视网 推荐当贝市场

TV应用下载 / 资源分享区

软件下载 | 游戏 | 讨论 | 社区App下载

综合交流 / 评测 / 活动区

交流区 | 测硬件 | 网站活动 | Z币中心

新手入门 / 进阶 / 社区互助

新手 | 你问我答 | 免费刷机救砖 | ROM固件

查看: 1959|回复: 2
[新手提问]

MTK PKG固件包解包怎么弄?

[复制链接]
发表于 2021-5-6 16:20 | 显示全部楼层 |阅读模式
MTK PKG固件包解包怎么弄?有没有人知道

上一篇:九联UNT401芯片是HI3798MV30100000H破解
下一篇:如何将极米New Z6X刷机系统到当贝OS?
发表于 2021-5-6 16:46 | 显示全部楼层
https://www.znds.com/tv-1195385-1-1.html 可以用这个解包工具
回复 支持 1 反对 0

使用道具 举报

发表于 2021-5-6 16:21 | 显示全部楼层
以下是pkg固件包的解包代码:
/**
* Mediatek PKG Handling
* Copyright 2016 Smx <smxdev4@gmail.com>
* All right reserved
*/
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <pthread.h>
#include "main.h" //for handle_file
#include "mfile.h"
#include "mediatek_pkg.h"
#include "lzhs/lzhs.h"
#include "util.h"
#include "util_crypto.h"
#include "thpool.h"

enum mtkpkg_variant {
        OLD = 1 << 0,
        NEW = 1 << 1,
        THOMPSON = 1 << 2,
        PHILIPS = 1 << 3,
        SHARP = 1 << 4
};

#define SIZEOF_THOMPSON_HEADER 0x170
#define SIZEOF_OLD_HEADER 0x98

static int mtkpkg_variant_flags = NEW;

static struct mtkupg_header packageHeader;
static bool was_decrypted = false;

int compare_pkg_header(uint8_t *header, size_t headerSize){
        struct mtkupg_header *hdr = (struct mtkupg_header *)header;

        if( !strncmp(hdr->vendor_magic, HISENSE_PKG_MAGIC, strlen(HISENSE_PKG_MAGIC)) ){
                printf("[+] Found HISENSE Package\n");
                return 1;
        }
        if( !strncmp(hdr->vendor_magic, SHARP_PKG_MAGIC, strlen(SHARP_PKG_MAGIC)) ){
                printf("[+] Found SHARP Package\n");
                mtkpkg_variant_flags |= SHARP;
                return 1;
        }
        if( !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC, strlen(TPV_PKG_MAGIC)) ||
                !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC2,strlen(TPV_PKG_MAGIC2))
        ){
                printf("[+] Found PHILIPS(TPV) Package\n");
                return 1;
        }
        
        if( !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC, strlen(PHILIPS_PKG_MAGIC))
         || !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC2, strlen(PHILIPS_PKG_MAGIC2))
        ){
                printf("[+] Found PHILIPS Package\n");
                return 1;
        }

        if( !strncmp(hdr->mtk_magic, MTK_FIRMWARE_MAGIC, strlen(MTK_FIRMWARE_MAGIC)) ){
                printf("[+] Found UNKNOWN Package (Magic: '%.*s')\n",
                        member_size(struct mtkupg_header, vendor_magic),
                        hdr->vendor_magic
                );
                return 1;
        }

        return 0;
}

int compare_content_header(uint8_t *header, size_t headerSize){
        struct mtkpkg_data *data = (struct mtkpkg_data *)header;
        if ( !strncmp(data->header.mtk_reserved, MTK_RESERVED_MAGIC, strlen(MTK_RESERVED_MAGIC)) ){
                return 1;
        }
        return 0;
}

bool is_known_partition(struct mtkpkg *pak){
        const char *likelyPartitionNames[] = {
                "cfig",
                "ixml",
                "tzbp",
                NULL
        };
        
        char **curPartName = likelyPartitionNames;
        for(int nameIndex=0; *curPartName != NULL; nameIndex++){
                if(!strncmp(pak->header.pakName, *curPartName, sizeof(pak->header.pakName))){
                        return true;
                }
                curPartName++;
        }
        return false;
}

MFILE *is_mtk_pkg(const char *pkgfile){
        setKeyFile_MTK();
        
        MFILE *mf = mopen(pkgfile, O_RDONLY);
        if(!mf){
                err_exit("Cannot open file %s\n", pkgfile);
        }
        
        uint8_t *data = mdata(mf, uint8_t);
        void *decryptedHeader = NULL;
        KeyPair *headerKey = NULL;

        do {
                if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){
                        break;
                }

                /* It failed, but we want to check for Philips.
                 * Philips has an additional 0x80 header before the normal PKG one
                 */
                if((headerKey = find_AES_key(data + PHILIPS_HEADER_SIZE, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){
                        mtkpkg_variant_flags |= PHILIPS;
                }
        } while(0);

        if(headerKey != NULL){
                was_decrypted = true;
                memcpy(&packageHeader, decryptedHeader, sizeof(packageHeader));
                free(headerKey);
                return mf;
        }

        /* No AES key found to decrypt the header. Try to check if it's a MTK PKG anyways
         * This method can return false for valid packages as the order of partitions isn't fixed
         */

        /* First pak doesn't have extended fields */
        struct mtkpkg *firstPak = (struct mtkpkg *)(data + sizeof(struct mtkupg_header));
        if(is_known_partition(firstPak))
                return mf;
        
        firstPak = (struct mtkpkg *)(data + SIZEOF_OLD_HEADER);
        if(is_known_partition(firstPak)){
                mtkpkg_variant_flags = OLD;
                return mf;
        }

        firstPak = (struct mtkpkg *)(data + SIZEOF_OLD_HEADER + PHILIPS_HEADER_SIZE);
        if(is_known_partition(firstPak)){
                mtkpkg_variant_flags = OLD | PHILIPS;
                return mf;
        }

        firstPak = (struct mtkpkg *)(data + SIZEOF_THOMPSON_HEADER);
        if(is_known_partition(firstPak)){
                mtkpkg_variant_flags = NEW | THOMPSON;
                return mf;
        }

        mclose(mf);
        return NULL;
}

#define SIZEOF_FIRM_HEADERS 0x90

MFILE *is_firm_image(const char *pkg){
        MFILE *mf = mopen(pkg, O_RDONLY);
        if(!mf){
                err_exit("Cannot open file %s\n", pkg);
        }

        if(msize(mf) < (SIZEOF_FIRM_HEADERS + 16)){
                mclose(mf);
                return NULL;
        }

        if(is_lzhs_mem(mf, SIZEOF_FIRM_HEADERS)){
                return mf;
        }
        mclose(mf);
        return NULL;
}

int extract_firm_image(MFILE *mf){
        return process_segment(mf, SIZEOF_FIRM_HEADERS, "firm");
}

MFILE *is_lzhs_fs(const char *pkg){
        MFILE *mf = mopen(pkg, O_RDONLY);
        if(!mf){
                err_exit("Cannot open file %s\n", pkg);
        }

        uint8_t *data = mdata(mf, uint8_t);

        off_t start = MTK_EXT_LZHS_OFFSET;
        if(is_nfsb_mem(mf, SHARP_PKG_HEADER_SIZE)){
                start += SHARP_PKG_HEADER_SIZE;
        }

        if(msize(mf) < (start + sizeof(struct lzhs_header))){
                goto fail;
        }

        if(
                is_lzhs_mem(mf, start) &&
                is_lzhs_mem(mf, start + sizeof(struct lzhs_header)) &&
                // First LZHS header contains number of segment in checksum. Make sure that it is the first segment
                ((struct lzhs_header *)&data[start])->checksum == 1
        ){
                return mf;
        }

        fail:
                mclose(mf);
                return NULL;
}

/* Arguments passed to the thread function */
struct thread_arg {
        MFILE *mf;
        off_t offset;
        char *filename;
        uint blockNo;
};

void process_block(struct thread_arg *arg){
        printf("[+] Extracting %u...\n", arg->blockNo);
        uint8_t out_checksum = 0x00;
        cursor_t *out_cur = lzhs_decode(arg->mf, arg->offset, NULL, &out_checksum);
        if(out_cur == NULL || (intptr_t)out_cur < 0){
                err_exit("LZHS decode failed\n");
        }

        MFILE *out = mfopen(arg->filename, "w+");
        if(!out){
                err_exit("mfopen failed for file '%s'\n", arg->filename);
        }
        mfile_map(out, out_cur->size);
        memcpy(
                mdata(out, void),
                out_cur->ptr,
                out_cur->size
        );
        mclose(out);
        free(out_cur);

        free(arg->filename);
        free(arg);
}

/*
* Hisense (or Mediatek?) uses an ext4 filesystem splitted in chunks, compressed with LZHS
* They use 2 LZHS header for each chunk
* The first header contains the chunk number, and the compressed size includes the outer lzhs header (+16)
* The second header contains the actual data
*/
void extract_lzhs_fs(MFILE *mf, const char *dest_file, config_opts_t *config_opts){
        int is_sharp = 0;
        uint8_t *data = mdata(mf, uint8_t);
        if(is_nfsb_mem(mf, SHARP_PKG_HEADER_SIZE)){
                data += SHARP_PKG_HEADER_SIZE;
                is_sharp = 1;
        }

        FILE *out_file = fopen(dest_file, "w+");
        if(!out_file){
                err_exit("Cannot open %s for writing\n", dest_file);
        }

        char *dir = my_dirname(dest_file);
        char *file = my_basename(dest_file);
        char *base = remove_ext(file);

        char *tmpdir;
        asprintf(&tmpdir, "%s/tmp", dir);
        createFolder(tmpdir);

        printf("Copying 0x%08X bytes\n", MTK_EXT_LZHS_OFFSET);

        /* Copy first MB as-is (uncompressed) */
        fwrite (
                data,
                MTK_EXT_LZHS_OFFSET,
                1,
                out_file
        );

        data += MTK_EXT_LZHS_OFFSET;

        int nThreads = sysconf(_SC_NPROCESSORS_ONLN);
        printf("[+] Max threads: %d\n", nThreads);
        threadpool thpool = thpool_init(nThreads);

        uint segNo = 0;
        while(moff(mf, data) < msize(mf)){
                struct lzhs_header *main_hdr = (struct lzhs_header *)data;
                struct lzhs_header *seg_hdr = (struct lzhs_header *)(data + sizeof(*main_hdr));

                printf("\n[0x%08X] segment #%u (compressed='%u bytes', uncompressed='%u bytes')\n",
                        moff(mf, main_hdr),
                        main_hdr->checksum,
                        seg_hdr->compressedSize, seg_hdr->uncompressedSize);

                char *outSeg;
                asprintf(&outSeg, "%s/%s.%d", tmpdir, base, (segNo++) + 1);
                struct thread_arg *arg = calloc(1, sizeof(struct thread_arg));
                arg->mf = mf;
                arg->offset = moff(mf, seg_hdr);
                arg->filename = outSeg;
                arg->blockNo = main_hdr->checksum;
               
                thpool_add_work(thpool, (void *)process_block, arg);

                uint pad;
                pad = (pad = (seg_hdr->compressedSize % 16)) == 0 ? 0 : (16 - pad);

                data += (
                        sizeof(*main_hdr) + sizeof(*seg_hdr) +
                        seg_hdr->compressedSize +
                        pad
                );
        }
        
        thpool_wait(thpool);
        thpool_destroy(thpool);

        int i;
        for(i=1; i<=segNo; i++){
                printf("[+] Joining Segment %d\n", i);
                char *outSeg;
                asprintf(&outSeg, "%s/%s.%d", tmpdir, base, i);
               
                MFILE *seg = mopen(outSeg, O_RDONLY);
                fwrite(mdata(seg, void), msize(seg), 1, out_file);
                mclose(seg);
               
                unlink(outSeg);
                free(outSeg);
        }

        rmrf(tmpdir);
        free(tmpdir);

        fclose(out_file);

        free(dir);
        free(file);
        free(base);

        if(is_sharp){
                handle_file(dest_file, config_opts);
        }
}

void print_pkg_header(struct mtkupg_header *hdr){
        hexdump(hdr, sizeof(*hdr));

        printf("======== Firmware Info ========\n");
        printf("| Product Name: %s\n", hdr->product_name);
        printf("| Firmware ID : %.*s\n",
                member_size(struct mtkupg_header, vendor_magic) +
                member_size(struct mtkupg_header, mtk_magic) +
                member_size(struct mtkupg_header, vendor_info),
                hdr->vendor_magic
        );
        printf("| File Size: %u bytes\n", hdr->fileSize);
        printf("| Platform Type: 0x%02X\n", hdr->platform);
        printf("======== Firmware Info ========\n");
}

static off_t get_mtkpkg_offset(){
        if((mtkpkg_variant_flags & THOMPSON) == THOMPSON){
                return SIZEOF_THOMPSON_HEADER;
        }

        off_t offset = 0;
        if((mtkpkg_variant_flags & NEW) == NEW){
                offset += sizeof(struct mtkupg_header);
        } else if((mtkpkg_variant_flags & OLD) == OLD){
                offset += SIZEOF_OLD_HEADER;
        }
        
        if((mtkpkg_variant_flags & PHILIPS) == PHILIPS){
                offset += PHILIPS_HEADER_SIZE;
        }

        return offset;
}

void extract_mtk_pkg(const char *pkgFile, config_opts_t *config_opts){
        MFILE *mf = mopen_private(pkgFile, O_RDONLY);
        mprotect(mf->pMem, msize(mf), PROT_READ | PROT_WRITE);

        off_t offset = get_mtkpkg_offset();
        uint8_t *data = mdata(mf, uint8_t) + offset;

        char *file_name = my_basename(mf->path);
        char *file_base = remove_ext(file_name);

        struct mtkupg_header *hdr = (was_decrypted) ? &packageHeader : NULL;
        if(hdr != NULL)
                print_pkg_header(hdr);
        
        if(hdr != NULL){
                // Use product name for now (version would be better)
                sprintf(config_opts->dest_dir, "%s/%s", config_opts->dest_dir, hdr->product_name);
        } else {
                sprintf(config_opts->dest_dir, "%s/%s", config_opts->dest_dir, file_base);
        }
        createFolder(config_opts->dest_dir);
        
        KeyPair *dataKey = NULL;
        
        int pakNo;
        for(pakNo=0; moff(mf, data) < msize(mf); pakNo++){
                struct mtkpkg *pak = (struct mtkpkg *)data;
                if((mtkpkg_variant_flags & PHILIPS) == PHILIPS && moff(mf, data) + PHILIPS_SIGNATURE_SIZE == msize(mf)){
                        printf("-- RSA 2048 Signature --\n");
                        hexdump(data, PHILIPS_SIGNATURE_SIZE);
                        //Philips RSA-2048 signature
                        break;
                }

                size_t cryptedHeaderSize = ((mtkpkg_variant_flags & NEW) == NEW) ? sizeof(pak->content.header) : 0;
               
                /* Skip pak header and crypted header */
                data += sizeof(pak->header) + cryptedHeaderSize;

                uint8_t *pkgData = (uint8_t *)&(pak->content.header);
                size_t dataSize = sizeof(pak->content.header);
                size_t pkgSize = pak->header.pakSize;
                if(pkgSize == 0){
                        goto save_file;
                }
               
                if((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED){
                        dataSize += pak->header.pakSize;
                }

#pragma region FindAesKey
                uint8_t *decryptedPkgData = NULL;
               
                if(was_decrypted){
                        if(dataKey == NULL){
                                dataKey = find_AES_key(
                                        pkgData,
                                        dataSize,
                                        compare_content_header,
                                        KEY_CBC,
                                        (void **)&decryptedPkgData,
                                        1
                                );
                                int success = dataKey != NULL;
                                if(success){
                                        /* Copy decrypted data */
                                        memcpy(pkgData, decryptedPkgData, dataSize);
                                        free(decryptedPkgData);
                                } else if(was_decrypted) {
                                        /* Try to decrypt by using vendorMagic repeated 4 times, ivec 0 */
                                        do {
                                                AES_KEY aesKey;
                                                uint8_t keybuf[16];                                
                                                uint i;
                                                for(i=0; i<4; i++){
                                                        memcpy(&keybuf[4 * i], hdr->vendor_magic, sizeof(uint32_t));
                                                }

                                                AES_set_decrypt_key((uint8_t *)&keybuf, 128, &aesKey);

                                                dataKey = calloc(1, sizeof(KeyPair)); //also fills ivec with zeros
                                                memcpy(&(dataKey->key), &aesKey, sizeof(aesKey));

                                                uint8_t iv_tmp[16];
                                                memcpy(&iv_tmp, &(dataKey->ivec), sizeof(iv_tmp));
                                                AES_cbc_encrypt(
                                                        pkgData, pkgData,
                                                        dataSize, &(dataKey->key),
                                                        (void *)&iv_tmp, AES_DECRYPT
                                                );

                                                success = compare_content_header(pkgData, sizeof(struct mtkpkg_data));
                                        } while(0);
                                }
                                if(!success){
                                        if((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED){
                                                printf("[-] Couldn't decrypt data!\n");
                                        } else {
                                                printf("[-] Couldn't decrypt header!\n");
                                        }
                                }
                        } else {
        #pragma endregion
                                uint8_t iv_tmp[16];
                                memcpy(&iv_tmp, &(dataKey->ivec), sizeof(iv_tmp));
                                AES_cbc_encrypt(
                                        pkgData, pkgData,
                                        dataSize, &(dataKey->key),
                                        (void *)&iv_tmp, AES_DECRYPT
                                );
                                int success = compare_content_header(pkgData, sizeof(struct mtkpkg_data));
                                if(!success){
                                        fprintf(stderr, "[!] WARNING: MTK Crypted header not found, continuing anyways...\n");
                                }
                        }
                }
               
                if((mtkpkg_variant_flags & NEW) == NEW){
                        // Skip the mtk header (reserved inc)
                        pkgData += sizeof(struct mtkpkg_crypted_header);
                }
               
                printf("\nPAK #%u %s (name='%s', offset='0x%lx', size='%u bytes'",
                        pakNo + 1,
                        ((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED) ? "[ENCRYPTED]" : "",
                        pak->header.pakName,
                        moff(mf, data),
                        pak->header.pakSize
                );

                struct mtkpkg_plat *ext = (struct mtkpkg_plat *)pkgData;

                /* Parse the fields at the start of pkgData, and skip them */
                if(!strncmp(ext->platform, MTK_PAK_MAGIC, strlen(MTK_PAK_MAGIC))){
                        uint8_t *extData = (uint8_t *)&(ext->otaID_len);
                        /* otaID is optional. if we have it, it's preceded by its length. If we don't have it, we have the iPAD magic instead */
                        int has_otaID = strncmp(extData, MTK_PAD_MAGIC, strlen(MTK_PAD_MAGIC)) != 0;
                        if(has_otaID){
                                printf(", platform='%s', otaid='%s'", ext->platform, ext->otaID);
                                if(pakNo == 1 && hdr == NULL){
                                        sprintf(config_opts->dest_dir, "%s/%s", config_opts->dest_dir, ext->otaID);
                                        createFolder(config_opts->dest_dir);
                                }
                        } else if(pakNo == 1 && hdr == NULL){
                                sprintf(config_opts->dest_dir, "%s/%s", config_opts->dest_dir, file_base);
                                createFolder(config_opts->dest_dir);
                        }

                        /* Skip the headers to get to the data */
                        uint skip = sizeof(*ext);
                        if(has_otaID){
                                skip += ext->otaID_len;
                        }
                        if(skip < MTK_EXTHDR_SIZE){
                                skip += (MTK_EXTHDR_SIZE - skip);
                        }

                        pkgData += skip;
                        pkgSize -= skip;
                }

                save_file:
                printf(")\n");
               
                char *dest_path = NULL;
                asprintf(&dest_path, "%s/%.*s.pak",
                        config_opts->dest_dir,
                        member_size(struct mtkpkg_header, pakName), pak->header.pakName
                );

                MFILE *out = mfopen(dest_path, "w+");
                if(!out){
                        err_exit("Cannot open %s for writing\n", dest_path);
                }

                printf("Saving partition (%s) to file %s\n\n", pak->header.pakName, dest_path);

                if(pkgSize == 0)
                        goto saved_file;

                mfile_map(out, pkgSize);
                mwrite(pkgData, pkgSize, 1, out);

                saved_file:
                mclose(out);

                if(dest_path != NULL && pkgSize != 0){
                        handle_file(dest_path, config_opts);
                }
                if(dest_path != NULL){
                        free(dest_path);
                }

                data += pak->header.pakSize;
        }

        if(dataKey != NULL){
                free(dataKey);
        }

        free(file_name);
        free(file_base);
        mclose(mf);
}



这是之前看到的一个大神分享的
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐 上一条 /3 下一条

Archiver|新帖|标签|软件|Sitemap|ZNDS智能电视网 ( 浙ICP备14000780号 )

网络信息服务信用承诺书 | 增值电信业务经营许可证:浙B2-20150411 丨 浙公网安备 33010802006145号

浙网文(2016)6491-366号 | GMT+8, 2021-6-24 01:29 , Processed in 0.062736 second(s), 25 queries .

Powered by Discuz!

监督举报:report#znds.com (请将#替换为@)

© 2007-2021 ZNDS.Com

快速回复 返回顶部 返回列表