布支盗 发表于 2021-5-6 16:20

MTK PKG固件包解包怎么弄?

MTK PKG固件包解包怎么弄?有没有人知道

啵咯波咯哒 发表于 2021-5-6 16:46

https://www.znds.com/tv-1195385-1-1.html 可以用这个解包工具

所长小弟 发表于 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)->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 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;                              
                                                uint i;
                                                for(i=0; i<4; i++){
                                                      memcpy(&keybuf, 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;
                                                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;
                              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) ? "" : "",
                        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);
}



这是之前看到的一个大神分享的

15006917135 发表于 2024-2-14 11:41

光有代码也没有用啊

markdryxixi 发表于 2024-11-21 13:57

所长小弟 发表于 2021-5-6 16:21
以下是pkg固件包的解包代码:
/**
* Mediatek PKG Handling


代码怎么用教教 谢谢
页: [1]
查看完整版本: MTK PKG固件包解包怎么弄?