IOS通过备份,得到的目录里面是一片乱码(严格来说是sha1编码)。解析出具体的文件列表的分析有很多了,整理了一下,写出来。
大概介绍下,这个文件的开头是“mbdb”,前六个字节一般是固定的“mbdb\05\00”,然后就是一个个结构体。结构体大概是这样子的:
struct fileinfo{ char *domain; char *filename; char *linktarget; char *datahash; char *unknown1; unsigned short mode; unsigned int unknown2; unsigned int inode; unsigned int userid; unsigned int groupid; unsigned int mtime; unsigned int atime; unsigned int ctime; unsigned long long filelen; unsigned int flag; unsigned int numprops; };
domain就是包名,每个应用都不同。filename就是path。datahash发现现在都是空的了,无用。最后就是那个numprops是附加数据,这个必须处理。flag为0是文件夹或者link,也可以通过filelen来判断是否为文件。
备份目录里面的文件名 = sha1(domain+filename)。
直接贴个代码(引用自p0sixspwn的越狱工具中的代码,改为windows下的代码,VS可直接编译):
mbdb.cpp
/** * mbdb.cpp * Copyright (C) 2010 Joshua Hill * Copyright (C) 2012 Hanéne Samara * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mbdb.h" mbdb_t *mbdb_create() { mbdb_t *mbdb = NULL; mbdb = (mbdb_t *) malloc(sizeof(mbdb_t)); if (mbdb == NULL) { return NULL; } memset(mbdb, '\0', sizeof(mbdb_t)); return mbdb; } mbdb_t *mbdb_parse(unsigned char *data, unsigned int size) { int i = 0; unsigned int count = 0; unsigned int offset = 0; mbdb_t *mbdb = NULL; mbdb_header_t *header = NULL; mbdb_record_t *record = NULL; mbdb = mbdb_create(); if (mbdb == NULL) { printf("Unable to create mbdb\n"); return NULL; } header = (mbdb_header_t *) data; if (strncmp((const char *)header->magic, MBDB_MAGIC, 6) != 0) { printf("Unable to identify this filetype\n"); return NULL; } // Copy in our header data mbdb->header = (mbdb_header_t *) malloc(sizeof(mbdb_header_t)); if (mbdb->header == NULL) { printf("Allocation error\n"); return NULL; } memset(mbdb->header, '\0', sizeof(mbdb_header_t)); memcpy(mbdb->header, &data[offset], sizeof(mbdb_header_t)); offset += sizeof(mbdb_header_t); mbdb->data = (unsigned char *)malloc(size); if (mbdb->data == NULL) { printf("Allocation Error!!\n"); return NULL; } memcpy(mbdb->data, data, size); mbdb->size = size; mbdb->records = (mbdb_record_t **) malloc((mbdb->size / 64) * sizeof(mbdb_record_t)); // should be enough mbdb->num_records = 0; while (offset < mbdb->size) { mbdb_record_t *rec = mbdb_record_parse(&(mbdb->data)[offset]); if (!rec) { printf("Unable to parse record at offset 0x%x!\n", offset); break; } mbdb->records[mbdb->num_records++] = rec; offset += rec->this_size; } return mbdb; } mbdb_t *mbdb_open(unsigned char *file) { int err = 0; unsigned int size = 0; unsigned char *data = NULL; mbdb_t *mbdb = NULL; FILE *pf = fopen((const char *)file, "rb"); if(pf == NULL) return NULL; fseek(pf, 0, SEEK_END); size = ftell(pf); rewind(pf); if (size == 0) { fclose(pf); return NULL; } data = (unsigned char*)malloc(size + 1); fread(data, 1, size, pf); fclose(pf); mbdb = mbdb_parse(data, size); if (mbdb == NULL) { printf("Unable to parse mbdb file\n"); return NULL; } free(data); return mbdb; } mbdb_record_t *mbdb_get_record(mbdb_t * mbdb, unsigned int index) { return NULL; } void mbdb_free(mbdb_t * mbdb) { if (mbdb) { if (mbdb->header) { free(mbdb->header); mbdb->header = NULL; } if (mbdb->records) { int i; for (i = 0; i < mbdb->num_records; i++) { mbdb_record_free(mbdb->records[i]); } free(mbdb->records); } if (mbdb->data) { free(mbdb->data); } free(mbdb); } }
mbdb_record.cpp
/** * mbdb_record.cpp * Copyright (C) 2010 Joshua Hill * Copyright (C) 2012 Hanéne Samara * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include "mbdb.h" mbdb_record_t *mbdb_record_create() { mbdb_record_t *record = (mbdb_record_t *) malloc(sizeof(mbdb_record_t)); if (record == NULL) { printf("Allocation Error!\n"); return NULL; } memset(record, '\0', sizeof(mbdb_record_t)); return record; } mbdb_record_t *mbdb_record_parse(unsigned char *data) { unsigned int offset = 0; mbdb_record_t *record = mbdb_record_create(); if (record == NULL) { printf("Unable to parse mbdb record\n"); return NULL; } // Parse Domain unsigned short strsize = be16toh(*((unsigned short *)&data[offset])); if (strsize > 0 && strsize < 0xFFFF) { record->domain = (char *)malloc(strsize + 1); if (record->domain == NULL) { printf("Allocation Error!\n"); return NULL; } offset += 2; memcpy(record->domain, &data[offset], strsize); record->domain[strsize] = 0; offset += strsize; } else { record->domain = NULL; offset += 2; } record->domain_size = strsize; // Parse Path strsize = be16toh(*((unsigned short *)&data[offset])); if (strsize > 0 && strsize < 0xFFFF) { record->path = (char *)malloc(strsize + 1); if (record->path == NULL) { printf("Allocation Error!\n"); return NULL; } offset += 2; memcpy(record->path, &data[offset], strsize); record->path[strsize] = 0; offset += strsize; } else { record->path = NULL; offset += 2; } record->path_size = strsize; // Parse Target strsize = be16toh(*((unsigned short *)&data[offset])); if (strsize > 0 && strsize < 0xFFFF) { record->target = (char *)malloc(strsize + 1); if (record->target == NULL) { printf("Allocation Error!\n"); return NULL; } offset += 2; memcpy(record->target, &data[offset], strsize); record->target[strsize] = 0; offset += strsize; } else { record->target = NULL; offset += 2; } record->target_size = strsize; // parse DataHash strsize = be16toh(*((unsigned short *)&data[offset])); if (strsize > 0 && strsize < 0xFFFF) { record->datahash = (char *)malloc(strsize); if (record->datahash == NULL) { printf("Allocation Error!\n"); return NULL; } offset += 2; memcpy(record->datahash, &data[offset], strsize); offset += strsize; } else { record->datahash = NULL; offset += 2; } record->datahash_size = strsize; // parse unknown1 strsize = be16toh(*((unsigned short *)&data[offset])); if (strsize > 0 && strsize < 0xFFFF) { record->unknown1 = (char *)malloc(strsize + 1); if (record->unknown1 == NULL) { printf("Allocation Error!\n"); return NULL; } offset += 2; memcpy(record->unknown1, &data[offset], strsize); record->unknown1[strsize] = 0; offset += strsize; } else { record->unknown1 = NULL; offset += 2; } record->unknown1_size = strsize; record->mode = be16toh(*((unsigned short *)&data[offset])); offset += 2; record->unknown2 = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->inode = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->uid = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->gid = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->time1 = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->time2 = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->time3 = be32toh(*((unsigned int *)&data[offset])); offset += 4; record->length = be64toh(*((unsigned long long *)&data[offset])); offset += 8; record->flag = *((unsigned char *)&data[offset]); offset += 1; record->property_count = *((unsigned char *)&data[offset]); offset += 1; if (record->property_count > 0) { record->properties = (mbdb_record_property_t **) malloc(sizeof(mbdb_record_property_t *) * record->property_count); int i; for (i = 0; i < record->property_count; i++) { mbdb_record_property_t *prop = (mbdb_record_property_t *)malloc(sizeof(mbdb_record_property_t)); prop->name_size = be16toh(*((unsigned short *)&data[offset])); prop->name = (char *)malloc(prop->name_size + 1); offset += 2; memcpy(prop->name, &data[offset], prop->name_size); prop->name[prop->name_size] = 0; offset += prop->name_size; prop->value_size = be16toh(*((unsigned short *)&data[offset])); prop->value = (char *)malloc(prop->value_size + 1); offset += 2; memcpy(prop->value, &data[offset], prop->value_size); prop->value[prop->value_size] = 0; offset += prop->value_size; record->properties[i] = prop; } } record->this_size = offset; //mbdb_record_debug(record); return record; } /* struct mbdb_record_t { char* domain; char* path; char* target; // absolute path char* datahash; // SHA1 hash char* unknown1; unsigned short mode; // Axxx = symlink, 4xxx = dir, 8xxx = file unsigned int unknown2; unsigned int inode; unsigned int uid; unsigned int gid; unsigned int time1; unsigned int time2; unsigned int time3; unsigned long long length; // 0 if link or dir unsigned char flag; // 0 if link or dir unsigned char properties; // number of properties } __attribute__((__packed__)); */ void mbdb_record_free(mbdb_record_t * record) { if (record) { if (record->domain) { free(record->domain); } if (record->path) { free(record->path); } if (record->target) { free(record->target); } if (record->datahash) { free(record->datahash); } if (record->unknown1) { free(record->unknown1); } if (record->property_count > 0) { int i; for (i = 0; i < record->property_count; i++) { if (record->properties[i]->name) { free(record->properties[i]->name); } if (record->properties[i]->value) { free(record->properties[i]->value); } free(record->properties[i]); } free(record->properties); } free(record); } } void mbdb_record_debug(mbdb_record_t * record) { DEBUG("mbdb record\n"); DEBUG("\tdomain = %s\n", record->domain); DEBUG("\tpath = %s\n", record->path); DEBUG("\ttarget = %s\n", record->target); DEBUG("\tdatahash = %p\n", record->datahash); DEBUG("\tunknown1 = %s\n", record->unknown1); DEBUG("\tmode = 0%o (0x%x)\n", record->mode, record->mode); DEBUG("\tunknown2 = 0x%x\n", record->unknown2); DEBUG("\tinode = 0x%x\n", record->inode); DEBUG("\tuid = %d\n", record->uid); DEBUG("\tgid = %d\n", record->gid); DEBUG("\ttime1 = 0x%x\n", record->time1); DEBUG("\ttime2 = 0x%x\n", record->time2); DEBUG("\ttime3 = 0x%x\n", record->time3); DEBUG("\tlength = %llu\n", record->length); DEBUG("\tflag = 0x%x\n", record->flag); DEBUG("\tproperty_count = %d\n", record->property_count); } void mbdb_record_init(mbdb_record_t * record) { if (!record) { return; } memset(record, '\0', sizeof(mbdb_record_t)); record->target_size = 0xFFFF; record->datahash_size = 0xFFFF; record->unknown1_size = 0xFFFF; record->this_size = 2 + 2 + 2 + 2 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + 8 + 1 + 1; } void mbdb_record_set_domain(mbdb_record_t * record, const char *domain) { if (!record) return; unsigned short old_size = record->domain_size; if (record->domain) { free(record->domain); record->domain = NULL; } if (record->domain_size > 0 && record->domain_size < 0xFFFF) { record->this_size -= record->domain_size; } if (domain && (strlen(domain) > 0)) { record->domain_size = strlen(domain); record->domain = strdup(domain); record->this_size += record->domain_size; } else { record->domain_size = 0; } } void mbdb_record_set_path(mbdb_record_t * record, const char *path) { if (!record) return; unsigned short old_size = record->path_size; if (record->path) { free(record->path); record->path = NULL; } if (record->path_size > 0 && record->path_size < 0xFFFF) { record->this_size -= record->path_size; } if (path && (strlen(path) > 0)) { record->path_size = strlen(path); record->path = strdup(path); record->this_size += record->path_size; } else { record->path_size = 0; } } void mbdb_record_set_target(mbdb_record_t * record, const char *target) { if (!record) return; unsigned short old_size = record->target_size; if (record->target) { free(record->target); record->target = NULL; } if (record->target_size > 0 && record->target_size < 0xFFFF) { record->this_size -= record->target_size; } if (target && (strlen(target) > 0)) { record->target_size = strlen(target); record->target = strdup(target); record->this_size += record->target_size; } else { record->target_size = 0xFFFF; } } void mbdb_record_set_datahash(mbdb_record_t * record, const char *hash, unsigned short hash_size) { if (!record) return; unsigned short old_size = record->datahash_size; if (record->datahash) { free(record->datahash); record->datahash = NULL; } if (record->datahash_size > 0 && record->datahash_size < 0xFFFF) { record->this_size -= record->datahash_size; } if (hash && (hash_size > 0)) { record->datahash_size = hash_size; record->datahash = (char *)malloc(hash_size); memcpy(record->datahash, hash, hash_size); record->this_size += record->datahash_size; } else { record->datahash_size = 0xFFFF; } } void mbdb_record_set_unknown1(mbdb_record_t * record, const char *data, unsigned short size) { if (!record) return; unsigned short old_size = record->unknown1_size; if (record->unknown1) { free(record->unknown1); record->unknown1 = NULL; } if (record->unknown1_size > 0 && record->unknown1_size < 0xFFFF) { record->this_size -= record->unknown1_size; } if (data && (size > 0)) { record->unknown1_size = size; record->unknown1 = (char *)malloc(size); memcpy(record->unknown1, data, size); record->this_size += record->unknown1_size; } else { record->unknown1_size = 0xFFFF; } } void mbdb_record_set_mode(mbdb_record_t * record, unsigned short mode) { if (!record) return; record->mode = mode; } void mbdb_record_set_unknown2(mbdb_record_t * record, unsigned int unknown2) { if (!record) return; record->unknown2 = unknown2; } void mbdb_record_set_inode(mbdb_record_t * record, unsigned int inode) { if (!record) return; record->inode = inode; } void mbdb_record_set_uid(mbdb_record_t * record, unsigned int uid) { if (!record) return; record->uid = uid; } void mbdb_record_set_gid(mbdb_record_t * record, unsigned int gid) { if (!record) return; record->gid = gid; } void mbdb_record_set_time1(mbdb_record_t * record, unsigned int time1) { if (!record) return; record->time1 = time1; } void mbdb_record_set_time2(mbdb_record_t * record, unsigned int time2) { if (!record) return; record->time2 = time2; } void mbdb_record_set_time3(mbdb_record_t * record, unsigned int time3) { if (!record) return; record->time3 = time3; } void mbdb_record_set_length(mbdb_record_t * record, unsigned long long length) { if (!record) return; record->length = length; } void mbdb_record_set_flag(mbdb_record_t * record, unsigned char flag) { if (!record) return; record->flag = flag; } // // int mbdb_record_build(mbdb_record_t * record, unsigned char **data, // unsigned int *size) // { // unsigned int offset = 0; // unsigned char *data_buf = NULL; // // if (!record) { // return -1; // } // // data_buf = (unsigned char *)malloc(record->this_size); // if (!data_buf) { // printf("Allocation Error!\n"); // return -1; // } // // unsigned short strsize; // // // append Domain // strsize = htobe16(record->domain_size); // memcpy(&data_buf[offset], &strsize, 2); // offset += 2; // if (record->domain != NULL) { // memcpy(&data_buf[offset], record->domain, record->domain_size); // offset += record->domain_size; // } // // append Path // strsize = htobe16(record->path_size); // memcpy(&data_buf[offset], &strsize, 2); // offset += 2; // if (record->path != NULL) { // memcpy(&data_buf[offset], record->path, record->path_size); // offset += record->path_size; // } // // append Target // strsize = htobe16(record->target_size); // memcpy(&data_buf[offset], &strsize, 2); // offset += 2; // if (record->target != NULL) { // memcpy(&data_buf[offset], record->target, record->target_size); // offset += record->target_size; // } // // append DataHash // strsize = htobe16(record->datahash_size); // memcpy(&data_buf[offset], &strsize, 2); // offset += 2; // if (record->datahash != NULL) { // memcpy(&data_buf[offset], record->datahash, record->datahash_size); // offset += record->datahash_size; // } // // append unknown1 // strsize = htobe16(record->unknown1_size); // memcpy(&data_buf[offset], &strsize, 2); // offset += 2; // if (record->unknown1 != NULL) { // memcpy(&data_buf[offset], record->unknown1, record->unknown1_size); // offset += record->unknown1_size; // } // // unsigned short mode = htobe16(record->mode); // memcpy(&data_buf[offset], &mode, 2); // offset += 2; // // int unknown2 = htobe32(record->unknown2); // memcpy(&data_buf[offset], &unknown2, 4); // offset += 4; // // int inode = htobe32(record->inode); // memcpy(&data_buf[offset], &inode, 4); // offset += 4; // // int uid = htobe32(record->uid); // memcpy(&data_buf[offset], &uid, 4); // offset += 4; // // int gid = htobe32(record->gid); // memcpy(&data_buf[offset], &gid, 4); // offset += 4; // // int time1 = htobe32(record->time1); // memcpy(&data_buf[offset], &time1, 4); // offset += 4; // // int time2 = htobe32(record->time2); // memcpy(&data_buf[offset], &time2, 4); // offset += 4; // // int time3 = htobe32(record->time3); // memcpy(&data_buf[offset], &time3, 4); // offset += 4; // // unsigned long long length = htobe64(record->length); // memcpy(&data_buf[offset], &length, 8); // offset += 8; // // unsigned char flag = record->flag; // memcpy(&data_buf[offset], &flag, 1); // offset++; // // unsigned char prop = record->property_count; // memcpy(&data_buf[offset], &prop, 1); // offset++; // // // add properties // int i; // for (i = 0; i < (int)prop; i++) { // mbdb_record_property_t *property = record->properties[i]; // // unsigned short pnsize = htobe16(property->name_size); // memcpy(&data_buf[offset], &pnsize, 2); // offset += 2; // memcpy(&data_buf[offset], property->name, property->name_size); // offset += property->name_size; // // unsigned short pvsize = htobe16(property->value_size); // memcpy(&data_buf[offset], &pvsize, 2); // offset += 2; // memcpy(&data_buf[offset], property->value, property->value_size); // offset += property->value_size; // } // // if (record->this_size != offset) { // *data = NULL; // *size = 0; // ERROR // ("%s: ERROR: inconsistent record size (present %d != created %d)\n", // __func__, record->this_size, offset); // return -1; // } // // *data = data_buf; // *size = offset; // // return 0; // }
mbdb.h
/** * GreenPois0n * Copyright (C) 2010 Chronic-Dev Team * Copyright (C) 2010 Joshua Hill * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ #ifndef _MBDB_H_ #define _MBDB_H_ struct mbdb_t; #pragma pack(1) struct mbdb_record_property_t { unsigned short name_size; char *name; unsigned short value_size; char *value; }; typedef struct mbdb_record_property_t mbdb_record_property_t; struct mbdb_record_t { unsigned short domain_size; char *domain; unsigned short path_size; char *path; unsigned short target_size; char *target; // absolute path unsigned short datahash_size; char *datahash; // SHA1 hash unsigned short unknown1_size; char *unknown1; unsigned short mode; // Axxx = symlink, 4xxx = dir, 8xxx = file unsigned int unknown2; unsigned int inode; unsigned int uid; unsigned int gid; unsigned int time1; unsigned int time2; unsigned int time3; unsigned long long length; // 0 if link or dir unsigned char flag; // 0 if link or dir unsigned char property_count; // number of properties mbdb_record_property_t **properties; // properties unsigned int this_size; // size of this record in bytes }; #pragma pack() #define be16toh(x) ((((x) & 0xFF00) >> 8) | (((x) & 0x00FF) << 8)) #define be32toh(x) ((((x) & 0xFF000000) >> 24) \ | (((x) & 0x00FF0000) >> 8) \ | (((x) & 0x0000FF00) << 8) \ | (((x) & 0x000000FF) << 24)) #define be64toh(x) ((((x) & 0xFF00000000000000ull) >> 56) \ | (((x) & 0x00FF000000000000ull) >> 40) \ | (((x) & 0x0000FF0000000000ull) >> 24) \ | (((x) & 0x000000FF00000000ull) >> 8) \ | (((x) & 0x00000000FF000000ull) << 8) \ | (((x) & 0x0000000000FF0000ull) << 24) \ | (((x) & 0x000000000000FF00ull) << 40) \ | (((x) & 0x00000000000000FFull) << 56)) typedef struct mbdb_record_t mbdb_record_t; mbdb_record_t *mbdb_record_create(); mbdb_record_t *mbdb_record_parse(unsigned char *data); void mbdb_record_debug(mbdb_record_t * record); void mbdb_record_free(mbdb_record_t * record); void mbdb_record_init(mbdb_record_t * record); void mbdb_record_set_domain(mbdb_record_t * record, const char *domain); void mbdb_record_set_path(mbdb_record_t * record, const char *path); void mbdb_record_set_target(mbdb_record_t * record, const char *target); void mbdb_record_set_datahash(mbdb_record_t * record, const char *hash, unsigned short hash_size); void mbdb_record_set_unknown1(mbdb_record_t * record, const char *data, unsigned short size); void mbdb_record_set_mode(mbdb_record_t * record, unsigned short mode); void mbdb_record_set_unknown2(mbdb_record_t * record, unsigned int unknown2); void mbdb_record_set_inode(mbdb_record_t * record, unsigned int inode); void mbdb_record_set_uid(mbdb_record_t * record, unsigned int uid); void mbdb_record_set_gid(mbdb_record_t * record, unsigned int gid); void mbdb_record_set_time1(mbdb_record_t * record, unsigned int time1); void mbdb_record_set_time2(mbdb_record_t * record, unsigned int time2); void mbdb_record_set_time3(mbdb_record_t * record, unsigned int time3); void mbdb_record_set_length(mbdb_record_t * record, unsigned long long length); void mbdb_record_set_flag(mbdb_record_t * record, unsigned char flag); // TODO sth like mbdb_record_add_property() //int mbdb_record_build(mbdb_record_t * record, unsigned char **data, // unsigned int *size); #define MBDB_MAGIC "\x6d\x62\x64\x62\x05\x00" typedef struct mbdb_header { unsigned char magic[6]; // 'mbdb\5\0' } mbdb_header_t; typedef struct mbdb_t { unsigned int size; unsigned char *data; mbdb_header_t *header; int num_records; mbdb_record_t **records; } mbdb_t; extern mbdb_t *apparition_mbdb; mbdb_t *mbdb_create(); mbdb_t *mbdb_open(unsigned char *file); mbdb_t *mbdb_parse(unsigned char *data, unsigned int size); mbdb_record_t *mbdb_get_record(mbdb_t * mbdb, unsigned int offset); void mbdb_free(mbdb_t * mbdb); #endif
用法:
将mbdb.cpp、mbdb_record.cpp、mbdb.h添加到工程中,包含.h。
mbdb_t * pList = mbdb_open((unsigned char *)"Manifest.mbdb"); //遍历 for (int i = 0; i < pList->num_records; i++) { printf("%s - %s\n", pList->records[i]->domain, pList->records[i]->path); } mbdb_free(pList);