perlapp BFS格式分析
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
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;
};
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)
解析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)