首页 > 编程语言 >perlapp BFS格式分析

perlapp BFS格式分析

时间:2023-08-22 22:22:42浏览次数:36  
标签:__ bfs perlapp res unsigned BFS fname offset 格式

perlapp BFS格式分析

1、加载资源中加密的BFS

LoadResource_BFS_406670

LPVOID *__fastcall LoadResource_BFS_406670(char *Source)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  v2 = (BFS **)malloc(0x28ui64);
  v3 = v2;
  if ( !v2 )
    return 0i64;

  v2[1] = (BFS *)Source;
  *((_DWORD *)v2 + 4) = 1;
  *((_DWORD *)v2 + 5) = 0;
  if ( Source )
    v2[1] = (BFS *)strdup(Source);

  v4 = (const CHAR *)v3[1];
  if ( !v4 )
  {
    free(v3);
    return 0i64;
  }

  ModuleHandleA = GetModuleHandleA((LPCSTR)v3[1]);
  if ( !ModuleHandleA )
  {
    ModuleHandleA = LoadLibraryExA(v4, 0i64, 2u);
    if ( !ModuleHandleA )
      goto LABEL_23;
  }

  ResourceA = FindResourceA(ModuleHandleA, "#1", "BFS");
  if ( ResourceA )
  {
    Resource = LoadResource(ModuleHandleA, ResourceA);
    if ( Resource )
      *v3 = (BFS *)LockResource(Resource);
  }

  if ( (unsigned int)load_bfs(v3) )
  {
    v9 = *v3;
    if ( *v3 )
    {
      if ( v9->magic == 'SFB\xFF' )
      {
        endian = v9->endian;
        if ( endian == 2 || endian == 0x2000000 )
          return (LPVOID *)v3;
      }
    }
  }

LABEL_23:
  if ( *((_DWORD *)v3 + 5) )
    free(*v3);

  free(v3[1]);
  free(v3);
  return 0i64;
}

load_bfs

__int64 __fastcall load_bfs(BFS **buf)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  data = *buf;
  if ( !*buf || data->magic != 0xAA5B3A7F )
    return 1i64;

  endian = data->endian;                        // +4
  if ( endian == 0x2000000 )
    totalsize = ((data->totalsize & 0xFF00 | (data->totalsize << 16)) << 8) | ((HIWORD(data->totalsize) | data->totalsize & 0xFF0000) >> 8);
  else
    totalsize = data->totalsize;                // +8

  if ( endian == 0x2000000 )
    filecount_c_low = (unsigned __int16)__ROL2__(data->filecount_c, 8);
  else
    filecount_c_low = LOWORD(data->filecount_c);// +c

  v6 = totalsize - filecount_c_low;
  out = (__int64)malloc(v6);
  *buf = (BFS *)out;
  if ( out )
  {
    // xordata ^ totalsize
    index = 0i64;
    for ( *((_DWORD *)buf + 5) = 1; index < v6; *(_DWORD *)(index + out - 4) = data->totalsize ^ v9 )
    {
      v9 = *(DWORD *)((char *)&data->magic + filecount_c_low + index);
      index += 4i64;
    }

    return 1i64;
  }

  return out;
}

示例:

7F 3A 5B AA-->magic

02 00 00 00-->0x02小端标志 (0x2000000-->大端标志)

D8 71 9F 00-->0x9f71d8 后面数据大小&xor value,

54 00 00 00-->0x54 xor_data_offset

script_size=0x9f71d8-0x54

image-20230820183637609

2、BFS格式解析

dec_script_40CBB0

​ v56 = (BFS )dec_script_40CBB0(v10, v54, "script");

void *__fastcall dec_script_40CBB0(BFS *res_bfs, const char *fname, const char *a3)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  StackCookie = qword_4162E8;
  buffer = 0i64;
  if ( (unsigned int)getFile_inbfs_406D10(res_bfs, (char *)fname, strlen(fname), &fileinfo) )
  {
    if ( fileinfo.compressdata_offset20 )
    {
      if ( fileinfo.res_bfs_0->endian == 0x2000000 )
        uncompsize = ((fileinfo.compressdata_offset20->uncompsize & 0xFF00 | (fileinfo.compressdata_offset20->uncompsize << 16)) << 8) | ((HIWORD(fileinfo.compressdata_offset20->uncompsize) | fileinfo.compressdata_offset20->uncompsize & 0xFF0000) >> 8);
      else
        uncompsize = fileinfo.compressdata_offset20->uncompsize;
    }
    else
    {
      uncompsize = 0;
    }

    v6 = uncompsize + 1;
    buffer = malloc(v6);
    if ( !buffer )
    {
      sprintf(Buffer, "Panic: Can't alloc %lu bytes for %s", (unsigned int)v6, a3);
      debug_409930(Buffer);
    }

    if ( !buffer )
      return 0i64;

    EnterCriticalSection(&CriticalSection);
    if ( !extract_4067C0(&fileinfo, buffer) )   // buffer--> perl 脚本内容
    {
      LeaveCriticalSection(&CriticalSection);
      debug_409930("Panic: Can't extract %s", a3);
      free(buffer);
      return 0i64;
    }

    LeaveCriticalSection(&CriticalSection);
    *((_BYTE *)buffer + uncompsize) = 0;
  }

  return buffer;
}

getFile_inbfs_406D10

通过BFS 的fnames_data 匹配文件名

__int64 __fastcall getFile_inbfs_406D10(BFS *res_bfs, char *fname, unsigned int fname_sz, FileInfo *outBFS)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  endianFlag = res_bfs->endian;
  fname_sz1 = fname_sz;
  fname1 = fname;
  if ( endianFlag == 0x2000000 )
  {
    flag_10h = res_bfs->flag_10h;
    v10 = ((unsigned int)flag_10h >> 16) | flag_10h & 0xFF0000;
    v11 = flag_10h & 0xFF00 | (flag_10h << 16);
    fname_sz1 = fname_sz;
    flag = (v11 << 8) | (v10 >> 8);
  }
  else
  {
    flag = res_bfs->flag_10h;
  }

  if ( (flag & FNmae_Hash_Flag) == 0 )          // 4h 0100b   第3位未置1
  {
    if ( endianFlag == 0x2000000 )
      filecount = ((res_bfs->filecount_c & 0xFF00 | (res_bfs->filecount_c << 16)) << 8) | ((HIWORD(res_bfs->filecount_c) | res_bfs->filecount_c & 0xFF0000) >> 8);
    else
      filecount = res_bfs->filecount_c;

    if ( endianFlag == 0x2000000 )
      filenames_offset14 = (unsigned __int16)__ROL2__(res_bfs->filenames_offset14, 8);
    else
      filenames_offset14 = res_bfs->filenames_offset14;

    fileinfo.filenames_offset_C = filenames_offset14;
    fileinfo.filecount_10 = filecount;
    fileinfo.res_bfs_0 = res_bfs;
    v43 = 0;
    fileinfo.current_index_8 = 0;
    if ( filecount )
    {
      if ( endianFlag == 0x2000000 )
      {
        v44 = (unsigned int)filenames_offset14;
        v45 = (unsigned __int16)__ROL2__(*(_WORD *)((char *)&res_bfs->magic + filenames_offset14), 8);
      }
      else
      {
        v45 = *(unsigned __int16 *)((char *)&res_bfs->magic + filenames_offset14);
        v44 = (unsigned int)filenames_offset14;
      }

      fileinfo.file_namesize_14 = v45;
      v46 = v45 + 2;
      if ( endianFlag == 0x2000000 )
        name_align_16h = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
      else
        name_align_16h = res_bfs->name_align_16h;

      if ( (name_align_16h & v46) != 0 )
      {
        if ( endianFlag == 0x2000000 )
          v48 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
        else
          v48 = res_bfs->name_align_16h;

        v49 = v46 + v48 + 1;
        if ( endianFlag == 0x2000000 )
          name_align_16h1 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
        else
          name_align_16h1 = res_bfs->name_align_16h;

        v46 = ~name_align_16h1 & v49;
      }

      if ( endianFlag == 0x2000000 )
        v51 = ((*(DWORD *)((_BYTE *)&res_bfs->magic + v44 + v46) & 0xFF00 | (*(DWORD *)((char *)&res_bfs->magic
                                                                                      + v44
                                                                                      + v46) << 16)) << 8) | ((HIWORD(*(DWORD *)((char *)&res_bfs->magic + v44 + v46)) | *(DWORD *)((_BYTE *)&res_bfs->magic + v44 + v46) & 0xFF0000) >> 8);
      else
        v51 = *(DWORD *)((char *)&res_bfs->magic + v44 + v46);

      next = v46 + 4;
      fileinfo.stub_sz_18 = next;
      fileinfo.compressdata_offset20 = (CompressData *)((char *)res_bfs + v51);
    }
    else
    {
      fileinfo.file_namesize_14 = 0;
      next = 0;
      fileinfo.stub_sz_18 = 0;
      fileinfo.compressdata_offset20 = 0i64;
    }

    if ( filecount )
    {
      while ( !find_filename_in_bfs(&fileinfo, fname1, fname_sz1) )
      {
        ++v43;
        filenames_offset14 = (unsigned int)(next + filenames_offset14);
        fileinfo.filenames_offset_C = filenames_offset14;
        fileinfo.current_index_8 = v43;
        if ( v43 >= filecount )
        {
          fileinfo.file_namesize_14 = 0;
          next = 0;
          fileinfo.stub_sz_18 = 0;
          fileinfo.compressdata_offset20 = 0i64;
        }
        else
        {
          if ( endianFlag == 0x2000000 )
          {
            v53 = (unsigned int)filenames_offset14;
            v54 = (unsigned __int16)__ROL2__(*(_WORD *)((char *)&res_bfs->magic + filenames_offset14), 8);
          }
          else
          {
            v54 = *(unsigned __int16 *)((char *)&res_bfs->magic + filenames_offset14);
            v53 = (unsigned int)filenames_offset14;
          }

          fileinfo.file_namesize_14 = v54;
          v55 = v54 + 2;
          if ( endianFlag == 0x2000000 )
            v56 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
          else
            v56 = res_bfs->name_align_16h;

          if ( (v56 & v55) != 0 )
          {
            if ( endianFlag == 0x2000000 )
              v57 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
            else
              v57 = res_bfs->name_align_16h;

            v58 = v55 + v57 + 1;
            if ( endianFlag == 0x2000000 )
              v59 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
            else
              v59 = res_bfs->name_align_16h;

            v55 = ~v59 & v58;
          }

          if ( endianFlag == 0x2000000 )
            v60 = ((*(DWORD *)((_BYTE *)&res_bfs->magic + v53 + v55) & 0xFF00 | (*(DWORD *)((char *)&res_bfs->magic
                                                                                          + v53
                                                                                          + v55) << 16)) << 8) | ((HIWORD(*(DWORD *)((char *)&res_bfs->magic + v53 + v55)) | *(DWORD *)((_BYTE *)&res_bfs->magic + v53 + v55) & 0xFF0000) >> 8);
          else
            v60 = *(DWORD *)((char *)&res_bfs->magic + v53 + v55);

          next = v55 + 4;
          fileinfo.stub_sz_18 = v55 + 4;
          fileinfo.compressdata_offset20 = (CompressData *)((char *)res_bfs + v60);
        }

        fname_sz1 = fname_sz;
        fname1 = fname;
        if ( v43 >= filecount )
          return 0i64;
      }

      goto LABEL_111;
    }

    return 0i64;
  }

  // 4h 0100b   第3位置1时,通过namehash查找文件
  if ( endianFlag == 0x2000000 )
    namehashs_offset = ((res_bfs->namehashs_offset_18 & 0xFF00 | (res_bfs->namehashs_offset_18 << 16)) << 8) | ((HIWORD(res_bfs->namehashs_offset_18) | res_bfs->namehashs_offset_18 & 0xFF0000) >> 8);
  else
    namehashs_offset = res_bfs->namehashs_offset_18;// C0 B1 00 00

  fname_sz11 = fname_sz1;
  namehashs = (NameHashData *)((char *)res_bfs + namehashs_offset);
  fname11 = fname1;
  for ( fname_hash = 0; fname_sz11; --fname_sz11 )
  {
    v18 = *fname11++;
    fname_hash = v18 + 0x21 * fname_hash;
  }

  if ( endianFlag == 0x2000000 )
    namehashs_count = ((res_bfs->namehashs_count_1c & 0xFF00 | (res_bfs->namehashs_count_1c << 16)) << 8) | ((HIWORD(res_bfs->namehashs_count_1c) | res_bfs->namehashs_count_1c & 0xFF0000) >> 8);
  else
    namehashs_count = res_bfs->namehashs_count_1c;

  namehashs_index = (fname_hash + (fname_hash >> 5)) & namehashs_count;
  if ( endianFlag == 0x2000000 )
    filecount_4 = (((namehashs[namehashs_index].filecount_4 << 16) | namehashs[namehashs_index].filecount_4 & 0xFF00) << 8) | ((HIWORD(namehashs[namehashs_index].filecount_4) | namehashs[namehashs_index].filecount_4 & 0xFF0000) >> 8);
  else
    filecount_4 = namehashs[namehashs_index].filecount_4;

  if ( !filecount_4 )
    return 0i64;

  if ( endianFlag == 0x2000000 )
    LODWORD(fnames_data_offset) = ((namehashs[namehashs_index].subfile_offset_0 & 0xFF00 | (namehashs[namehashs_index].subfile_offset_0 << 16)) << 8) | ((HIWORD(namehashs[namehashs_index].subfile_offset_0) | namehashs[namehashs_index].subfile_offset_0 & 0xFF0000) >> 8);
  else
    LODWORD(fnames_data_offset) = namehashs[namehashs_index].subfile_offset_0;

  i = 0;
  fileinfo.current_index_8 = 0;
  fileinfo.filenames_offset_C = fnames_data_offset;
  fileinfo.filecount_10 = filecount_4;
  fileinfo.res_bfs_0 = res_bfs;
  if ( endianFlag == 0x2000000 )
    fnamesz = (unsigned __int16)__ROL2__(*(_WORD *)((char *)&res_bfs->magic + (unsigned int)fnames_data_offset), 8);
  else
    // struct fnames_data{
    // WORD fname_sz;
    // CHAR fname[fname_sz];
    // CHAR pad[1];
    // DWORD offset
    // }
    fnamesz = *(unsigned __int16 *)((char *)&res_bfs->magic + (unsigned int)fnames_data_offset);

  fileinfo.file_namesize_14 = fnamesz;
  fnamesz_end = fnamesz + 2;
  if ( endianFlag == 0x2000000 )
    namepad_sz = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
  else
    namepad_sz = res_bfs->name_align_16h;

  if ( (namepad_sz & fnamesz_end) != 0 )
  {
    if ( endianFlag == 0x2000000 )
      v27 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
    else
      v27 = res_bfs->name_align_16h;

    v28 = fnamesz_end + v27 + 1;                // namepad_sz + 3
    if ( endianFlag == 0x2000000 )
      v29 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
    else
      v29 = res_bfs->name_align_16h;

    fnamesz_end = ~v29 & v28;
  }

  if ( endianFlag == 0x2000000 )
    v30 = ((*(DWORD *)((_BYTE *)&res_bfs->magic + (unsigned int)fnames_data_offset + (unsigned __int64)fnamesz_end) & 0xFF00 | (*(DWORD *)((char *)&res_bfs->magic + (unsigned int)fnames_data_offset + (unsigned __int64)fnamesz_end) << 16)) << 8) | ((HIWORD(*(DWORD *)((char *)&res_bfs->magic + (unsigned int)fnames_data_offset + (unsigned __int64)fnamesz_end)) | *(DWORD *)((_BYTE *)&res_bfs->magic + (unsigned int)fnames_data_offset + (unsigned __int64)fnamesz_end) & 0xFF0000) >> 8);
  else
    v30 = *(DWORD *)((char *)&res_bfs->magic + (unsigned int)fnames_data_offset + (unsigned __int64)fnamesz_end);

  stub_sz = fnamesz_end + 4;
  fileinfo.stub_sz_18 = stub_sz;
  fileinfo.compressdata_offset20 = (CompressData *)((char *)res_bfs + v30);
  while ( !find_filename_in_bfs(&fileinfo, fname1, fname_sz1) )
  {
    ++i;
    fnames_data_offset = (unsigned int)(stub_sz + fnames_data_offset);
    fileinfo.filenames_offset_C = fnames_data_offset;
    fileinfo.current_index_8 = i;
    if ( i >= filecount_4 )
    {
      fileinfo.file_namesize_14 = 0;
      stub_sz = 0;
      fileinfo.stub_sz_18 = 0;
      fileinfo.compressdata_offset20 = 0i64;
    }
    else
    {
      if ( endianFlag == 0x2000000 )
      {
        v32 = (unsigned int)fnames_data_offset;
        subfile_namesize = (unsigned __int16)__ROL2__(*(_WORD *)((char *)&res_bfs->magic + fnames_data_offset), 8);
      }
      else
      {
        subfile_namesize = *(unsigned __int16 *)((char *)&res_bfs->magic + fnames_data_offset);
        v32 = (unsigned int)fnames_data_offset;
      }

      fileinfo.file_namesize_14 = subfile_namesize;
      v34 = subfile_namesize + 2;
      if ( endianFlag == 0x2000000 )
        v35 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
      else
        v35 = res_bfs->name_align_16h;

      if ( (v35 & v34) != 0 )
      {
        if ( endianFlag == 0x2000000 )
          v36 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
        else
          v36 = res_bfs->name_align_16h;

        v37 = v34 + v36 + 1;
        if ( endianFlag == 0x2000000 )
          v38 = (unsigned __int16)__ROL2__(res_bfs->name_align_16h, 8);
        else
          v38 = res_bfs->name_align_16h;

        v34 = ~v38 & v37;
      }

      if ( endianFlag == 0x2000000 )
        subfile_data_offset = ((*(DWORD *)((_BYTE *)&res_bfs->magic + v32 + v34) & 0xFF00 | (*(DWORD *)((char *)&res_bfs->magic + v32 + v34) << 16)) << 8) | ((HIWORD(*(DWORD *)((char *)&res_bfs->magic + v32 + v34)) | *(DWORD *)((_BYTE *)&res_bfs->magic + v32 + v34) & 0xFF0000) >> 8);
      else
        subfile_data_offset = *(DWORD *)((char *)&res_bfs->magic + v32 + v34);

      stub_sz = v34 + 4;
      fileinfo.stub_sz_18 = v34 + 4;
      fileinfo.compressdata_offset20 = (CompressData *)((char *)res_bfs + subfile_data_offset);
    }

    fname_sz1 = fname_sz;
    fname1 = fname;
    if ( i >= filecount_4 )
      return 0i64;
  }

LABEL_111:
  if ( outBFS )
    *outBFS = fileinfo;

  return 1i64;
}

find_filename_in_bfs

_BOOL8 __fastcall find_filename_in_bfs(FileInfo *a1, char *fname, unsigned int fnamesz)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  if ( a1->file_namesize_14 != fnamesz )
    return 0i64;

  res_bfs_0 = a1->res_bfs_0;
  // struct fnames_data{
  // WORD fname_sz;
  // CHAR fname[fname_sz];
  // CHAR pad[1];
  // DWORD offset
  // }
  fname_ = (unsigned __int8 *)&res_bfs_0->magic + (unsigned int)a1->filenames_offset_C + 2;
  if ( res_bfs_0->endian == 0x2000000 )
    flag_10h = ((res_bfs_0->flag_10h & 0xFF00 | (res_bfs_0->flag_10h << 16)) << 8) | ((((unsigned int)res_bfs_0->flag_10h >> 16) | res_bfs_0->flag_10h & 0xFF0000) >> 8);
  else
    flag_10h = res_bfs_0->flag_10h;

  // 2h--010b 第2位置1时 xor fname
  if ( (flag_10h & FName_Xor_Flag) != 0 )
  {
    if ( !fnamesz )
      return 1i64;

    while ( 1 )
    {
      --fnamesz;
      if ( (*fname_ ^ 0xEA) != *fname )
        break;

      ++fname_;
      ++fname;
      if ( !fnamesz )
        return 1i64;
    }

    return 0i64;
  }

  return memcmp(fname, fname_, fnamesz) == 0;
}

extract_4067C0

数据经过zlib压缩或xor加密

void *__fastcall extract_4067C0(FileInfo *fileinfo, void *buffer)
{
  // [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]

  res_bfs_0 = fileinfo->res_bfs_0;
  endian = fileinfo->res_bfs_0->endian;
  p_endian = &res_bfs_0->endian;
  CompressData = fileinfo->compressdata_offset20;
  if ( endian == 0x2000000 )
    type = ((CompressData->type & 0xFF00 | (CompressData->type << 16)) << 8) | ((((unsigned int)CompressData->type >> 16) | CompressData->type & 0xFF0000) >> 8);
  else
    type = CompressData->type;

  if ( (type & BFS_CompressData) != 0 )         // 1
  {
    if ( endian == 0x2000000 )
      uncompsize = ((CompressData->uncompsize & 0xFF00 | (CompressData->uncompsize << 16)) << 8) | ((HIWORD(CompressData->uncompsize) | CompressData->uncompsize & 0xFF0000) >> 8);
    else
      uncompsize = CompressData->uncompsize;

    if ( *p_endian == 0x2000000 )
      compsize = ((CompressData->compsize & 0xFF00 | (CompressData->compsize << 16)) << 8) | ((HIWORD(CompressData->compsize) | CompressData->compsize & 0xFF0000) >> 8);
    else
      compsize = CompressData->compsize;

    if ( (unsigned int)uncompress_403970(
                         (__int64)buffer,
                         (int *)&uncompsize,
                         (unsigned __int8 *)CompressData->data,
                         compsize) )
      return 0i64;

    p_endian = &fileinfo->res_bfs_0->endian;
    CompressData = fileinfo->compressdata_offset20;
    v10 = *p_endian == 0x2000000 ? ((CompressData->uncompsize & 0xFF00 | (CompressData->uncompsize << 16)) << 8) | ((HIWORD(CompressData->uncompsize) | CompressData->uncompsize & 0xFF0000) >> 8) : CompressData->uncompsize;
    if ( uncompsize != v10 )
      return 0i64;
  }
  else
  {
    if ( endian == 0x2000000 )
      v12 = ((CompressData->uncompsize & 0xFF00 | (CompressData->uncompsize << 16)) << 8) | ((HIWORD(CompressData->uncompsize) | CompressData->uncompsize & 0xFF0000) >> 8);
    else
      v12 = CompressData->uncompsize;

    memcpy(buffer, CompressData->data, v12);
  }

  if ( *p_endian == 0x2000000 )
    type_1 = ((CompressData->type & 0xFF00 | (CompressData->type << 16)) << 8) | ((((unsigned int)CompressData->type >> 16) | CompressData->type & 0xFF0000) >> 8);
  else
    type_1 = CompressData->type;

  if ( (type_1 & BFS_XorData) != 0 )            // 2
  {
    v14 = buffer;
    if ( *p_endian == 0x2000000 )
      v15 = ((CompressData->uncompsize & 0xFF00 | (CompressData->uncompsize << 16)) << 8) | ((HIWORD(CompressData->uncompsize) | CompressData->uncompsize & 0xFF0000) >> 8);
    else
      v15 = CompressData->uncompsize;

    for ( ; v15; --v15 )
      *v14++ ^= 0xEAu;
  }

  return buffer;
}

3、结构总结

头部

struct __declspec(align(4)) BFS
{
  DWORD magic;					//FF 42 46 53   BFS
  DWORD endian;					//02 00 00 00-->小端序
  DWORD totalsize;				//文件实际大小
  DWORD filecount_c;			//包含的文件数
  BFS_FLAG flag_10h;
  WORD filenames_offset14;		//偏移,指向fnames_data结构 数组
  WORD name_align_16h;
  DWORD namehashs_offset_18;	//偏移,指向NameHashData结构 数组
  DWORD namehashs_count_1c;
};

image-20230822212158237

fnames_data 数组

struct fnames_data{
WORD fname_sz;					//+0
CHAR fname[fname_sz];			//+2
//CHAR pad[1];//fname_sz and fname[] 4字节对齐
DWORD CompressData_offset//指向CompressData
}

NameHashData 数组

struct NameHashData
{
  DWORD subfile_offset_0;//偏移指向fnames_data类型
  DWORD filecount_4;
};

CompressData 加密的文件数据

struct __declspec(align(4)) CompressData
{
  DWORD uncompsize;					//+0
  DWORD compsize;					//+4
  BFS_DataType type;				//+8
  char data[1];//data[compsize]		//+c
};

other

enum BFS_FLAG
{
  FName_Xor_Flag = 0x2,
  FNmae_Hash_Flag = 0x4,
};

enum BFS_DataType
{
  BFS_CompressData = 0x1,
  BFS_XorData = 0x2,
};

//perlapp 查找文件时使用
struct __declspec(align(8)) FileInfo
{
  BFS *res_bfs_0;
  int current_index_8;
  int filenames_offset_C;
  int filecount_10;
  int file_namesize_14;
  int stub_sz_18;
  int field_1C;
  CompressData *compressdata_offset_20;
};

py

资源解密BFS

def decRes(fpath):
    res=b''
    with open(fpath,'rb') as f:
        res=f.read()

    format_str_L='<4I'  
    magic,endianFalg,size,index=struct.unpack(format_str_L,res[:struct.calcsize(format_str_L)])
    if magic!=0xAA5B3A7F:
        print('[!]Magic error!')
        return
    if endianFalg!=0x2:
        print('[!]Not little endian byte order')
        return
    if size+0xc!=len(res):
        print('[!]size error')
        return
    if index>len(res):
        print('[!]index error')
        return 
    out=[0 for i in range(size)]   
    xor_table=size.to_bytes(4,'little')
    for i in range(size-index):
        out[i]=res[i+index]^xor_table[i%4]
    with open(fpath+'.bfs','wb') as f2:
        f2.write(bytes(out) )
    print('success!')

解析BFS、fnames_data 结构

XOR_BYTE=0xEA


import io
import struct

def xorB(buf)->bytes:
    global XOR_BYTE
    return bytes([x^XOR_BYTE for x in buf])

class BFS_Header:
    header_fmt='<5L2H2L'
    header_sz=struct.calcsize(header_fmt)
    def __init__(self,bio:io.BytesIO) -> None:
        self.bio:io.BytesIO=bio
        self._parseBFS_Header()
        
    def _parseBFS_Header(self):
        self.bio.seek(0,io.SEEK_SET)
        self.magic,self.endian,self.totalsize,self.filecount,self.flag,self.filenames_offset,self.nameAlign,self.namehashs_offset,self.namehashs_count=struct.unpack(BFS_Header.header_fmt,self.bio.read(BFS_Header.header_sz))
    
    def __str__(self) -> str:
        x='''#BFS_Header#
magic:0x%08x
endian:%d
totalsize:%d
filecount:%d
flag:0x%08x
filenames_offset:0x%04x
nameAlign:%04x
namehashs_offset:0x%08x
namehashs_count:%d'''%(self.magic,self.endian,self.totalsize,self.filecount,self.flag,self.filenames_offset,self.nameAlign,self.namehashs_offset,self.namehashs_count)
        return x

class BFS_FNameData:
    def __init__(self,fname_sz:int,fname:bytes,CompressData_offset:int) -> None:
        self.fname_sz:int=fname_sz
        self.fname:bytes=fname
        self.CompressData_offset:int=CompressData_offset
    def __str__(self) -> str:
        x='''#BFS_FNameData#
fname_sz:%d
fname:%s
CompressData_offset:0x%08x'''%(self.fname_sz,self.fname,self.CompressData_offset)
        return x

class BFS:
    def __init__(self,bio:io.BytesIO) -> None:
        self.bio:io.BytesIO=bio
        self.bfs_hd_obj:BFS_Header=BFS_Header(bio)
    def parseFNames(self):
        self.bio.seek(self.bfs_hd_obj.filenames_offset,io.SEEK_SET)
        self.current_offset=self.bfs_hd_obj.filenames_offset
        self.current_index=0
        while self.current_offset<self.bfs_hd_obj.namehashs_offset \
            and self.current_index<self.bfs_hd_obj.filecount:
            fname_sz=int.from_bytes(self.bio.read(2),'little') 
            fname=xorB(self.bio.read(fname_sz)) 

            pad=(fname_sz+2)%4
            if pad:
                self.bio.read(4-pad)
            else:
                pad=0
            CompressData_offset=int.from_bytes(self.bio.read(4),'little') 
            yield BFS_FNameData(fname_sz,fname,CompressData_offset)
            self.current_offset+=2+fname_sz+pad+4
            self.current_index+=1



def parseBFS(fpath):
    # bio.seek(0,io.SEEK_SET)
    with open(fpath,'rb') as bio:
        bfs_obj=BFS(bio)
        print(bfs_obj.bfs_hd_obj)
        i=0
        for x in bfs_obj.parseFNames():
            print('#0x%08x FNameDatas[0x%08x]'%(bfs_obj.current_offset,bfs_obj.current_index))
            print(x)
            print()
            i+=1
    print('count:0x%08x'%i)

image-20230822220328891

解析CompressData

'''
struct CompressData
{
  DWORD uncompsize;
  DWORD compsize;
  DWORD type;
};
'''
def getFile(bio:io.BytesIO,offset:int,outpath):
    CompressData_fmt='<3L'
    CompressData_fmtsz=struct.calcsize(CompressData_fmt)
    bio.seek(offset,io.SEEK_SET)
    CompressData_hd=bio.read(CompressData_fmtsz)
    uncompsize,compsize,type=struct.unpack(CompressData_fmt,CompressData_hd)
    data=bio.read(compsize)
    out=data
    if type&1:
        out=zlib.decompress(data)
    if type&2:
        out=xorB(out)
    with open(outpath,'wb') as f:
        f.write(out)

参考链接:

unpapp/unpapp at master · onitake/unpapp (github.com)

标签:__,bfs,perlapp,res,unsigned,BFS,fname,offset,格式
From: https://www.cnblogs.com/DirWang/p/17649849.html

相关文章

  • Json 格式处理
    Jackson1.maven依赖导入<!--https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>......
  • ios开发之--ZHPickView输出格式不出现 +0000
    这样写就不会输出+0000了NSDate*select=[_datePickerdate];NSDateFormatter*dateFormatter=[[NSDateFormatteralloc]init];[dateFormattersetDateFormat:@"yyyy-MM-ddHH:mm:ss"];_resultString=[dateFormatterstringFromDate:select];输出+0000的原因是_......
  • 【音视频系列】RGB24数据格式及BMP文件格式以及存储方式
    RGB24是表明图像以RGB三原色,每个像素点3个字节表示的一种图像存储格式注意:在内存中RGB各分量的排列顺序为:BGRBGRBGR 先用ffmpeg生成一个RGB24的图片,命令如下:ffmpeg-itest.jpg-pix_fmtrgb24test.rgb生成后下面用C++代码拆分RGB24的三原色并保存:1234......
  • [其他]常用序号格式及特殊字符(给你懒的)
    ⓪①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳❶❷❸❹❺❻❼❽❾❿⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴ☑☐☒✔✘★☆≃≄≅≠≤≥≦≧≨≩←↑→↓↔↕↖↗↘↙♀♂㎡㎥m²m³㎜㎟㎣㎝㎠㎤㎞㎢㎦零壹贰叁肆伍陆柒捌玖拾佰仟万亿......
  • 数据库设计规范-设计格式合理
    数据库通用面试(三)原创 Suren 婺青年 2023-08-1411:14 发表于上海收录于合集#面试14个#数据库5个#sql7个数据库范式详解数据库范式:让你的数据库更规范、更高效你知道什么是数据库范式吗?为什么要用数据库范式呢?数据库范式又有哪些呢?如果你对这些问题感到困惑......
  • bfs 双向宽搜
     1、迷宫问题,找最短路:可以同时从起点和终点进行bfs,两个方向搜索的新节点分别存在不同的队列中的,若新节点在对面的状态集合中出现过,说明相遇了。2、很多bfs问题,都可以用双向宽搜,提高效率。3、分油问题,能不能用双向宽搜呢?3个无刻度的油瓶的容量是1073,其中分别有油10,0,0......
  • pytest 多参数传递时的坑 参数数组格式 :[(参数1,参数2)(参数1,参数2)] ;一个参数传递时
    一个参数传递时结果:(参数1) 两个参数传递时:参数1参数2 ......
  • (随笔)关于java自动以unix时间戳格式接收Date数据类型导致的sql查询时间失误问题的相
    前言​ 在进行项目开发的时候,有遇到过mapper执行sql语言查询指定时间范围内或截止时间之前的数据时不查询当天时间内不同时分秒时的数据,接口实现逻辑为前端传入Date类型(精度为yyyy-MM-dd)起止时间,mapper.xml文件中通过concat_ws方法实现时间精度转换(数据库内数据精度为yyyy-MM-dd......
  • vscode 配置 python black 格式化单行长度
    配置信息vscode版本1.81.1vscode安装BlackFormatter插件问题默认Black格式化之后单行长度太短,需要通过修改配置文件解决。方法Ctrl+Shift+p,打开settings.json,添加一个black-formatter.args配置项,如下所示:"black-formatter.args":["--line-le......
  • 三维模型OSGB格式轻量化的纹理压缩和质量保持分析
    三维模型OSGB格式轻量化的纹理压缩和质量保持分析   在三维模型应用中,纹理数据是一个重要的部分,可以为模型增加更多的真实感和细节。但是,由于纹理数据通常会占用大量的存储空间和传输带宽,因此,在OSGB格式轻量化处理中,采用纹理压缩技术是一种非常有效的手段。本文将从纹理压......