做为一名Android手机用户, 拿到system.img和data.img不是件难事
有这两个image可以做什么呢? ^_^可以做很多事,比如删除一些不想用的系统应用(/system/app目录下)
这里介绍的方法是针对image为yaffs2格式,也就是说android手机的存储设备是nand flash, 如果是emmc, 请看另一篇文章
(下面示例,适用于pagesize=2048 byte的nand 芯片)
1. 把system目录压缩成system.img
$out/host/linux-x86/bin/mkyaffs2image -f -c 2048 -s 64 out/target/product/{PRODUCT}/system out/target/product/{PRODUCT}/system .img
mkyaffs2image由android源码工程编译而来,随便哪个android版本在external/yaffs2目录下都有它的源码,mm这个目录即可
2. 解压system.img
$unyaffs2 -p 2048 -s 64 system,img system
源码如下,分别拷贝到Makefile, unyaffs2.h, unyaffs2.c文件,再执行 make all编译即可生成unyaffs2可执行程序
------------------------------------makefile-----------------------------------------------------------
CROSS =
CC = $(CROSS)gcc
RM = rm -fr
CFLAGS = -I.
CFLAGS += -O2
#CFLAGS += -Wall -Wshadow -Winline -Wpointer-arith -Wnested-externs \
# -Wwrite-strings -Wstrict-prototypes -Wmissing-declarations \
# -Wmissing-prototypes -Wredundant-decls
LDFLAGS += -lm
TARGET = unyaffs2
YAFF2SRCS = unyaffs2.c
YAFF2OBJS = $(YAFF2SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(YAFF2OBJS)
$(CC) -o $@ $(YAFF2OBJS) $(LDFLAGS)
distclean:
clean:
$(RM) $(TARGET) $(YAFF2OBJS)
.PHONY: all clean distclean $(TARGET)
-------------------------------------unyaffs2.h----------------------------------------------------------
/*
* definition copied from yaffs2 project
*/
#ifndef __UNYAFFS_H__
#define __UNYAFFS_H__
#define YAFFS_MAX_NAME_LENGTH 255
#define YAFFS_MAX_ALIAS_LENGTH 159
/* Definition of types */
typedef unsigned char __u8;
typedef unsigned short __u16;
typedef unsigned __u32;
typedef struct {
unsigned sequenceNumber;
unsigned objectId;
unsigned chunkId;
unsigned byteCount;
} yaffs_PackedTags2TagsPart;
typedef struct {
unsigned char colParity;
unsigned lineParity;
unsigned lineParityPrime;
} yaffs_ECCOther;
typedef struct {
yaffs_PackedTags2TagsPart t;
yaffs_ECCOther ecc;
} yaffs_PackedTags2;
typedef enum {
YAFFS_ECC_RESULT_UNKNOWN,
YAFFS_ECC_RESULT_NO_ERROR,
YAFFS_ECC_RESULT_FIXED,
YAFFS_ECC_RESULT_UNFIXED
} yaffs_ECCResult;
typedef enum {
YAFFS_OBJECT_TYPE_UNKNOWN,
YAFFS_OBJECT_TYPE_FILE,
YAFFS_OBJECT_TYPE_SYMLINK,
YAFFS_OBJECT_TYPE_DIRECTORY,
YAFFS_OBJECT_TYPE_HARDLINK,
YAFFS_OBJECT_TYPE_SPECIAL
} yaffs_ObjectType;
typedef struct {
unsigned validMarker0;
unsigned chunkUsed; /* Status of the chunk: used or unused */
unsigned objectId; /* If 0 then this is not part of an object (unused) */
unsigned chunkId; /* If 0 then this is a header, else a data chunk */
unsigned byteCount; /* Only valid for data chunks */
/* The following stuff only has meaning when we read */
yaffs_ECCResult eccResult;
unsigned blockBad;
/* YAFFS 1 stuff */
unsigned chunkDeleted; /* The chunk is marked deleted */
unsigned serialNumber; /* Yaffs1 2-bit serial number */
/* YAFFS2 stuff */
unsigned sequenceNumber; /* The sequence number of this block */
/* Extra info if this is an object header (YAFFS2 only) */
unsigned extraHeaderInfoAvailable; /* There is extra info available if this is not zero */
unsigned extraParentObjectId; /* The parent object */
unsigned extraIsShrinkHeader; /* Is it a shrink header? */
unsigned extraShadows; /* Does this shadow another object? */
yaffs_ObjectType extraObjectType; /* What object type? */
unsigned extraFileLength; /* Length if it is a file */
unsigned extraEquivalentObjectId; /* Equivalent object Id if it is a hard link */
unsigned validMarker1;
} yaffs_ExtendedTags;
/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */
typedef struct {
yaffs_ObjectType type;
/* Apply to everything */
int parentObjectId;
__u16 sum__NoLongerUsed; /* checksum of name. No longer used */
char name[YAFFS_MAX_NAME_LENGTH + 1];
/* The following apply to directories, files, symlinks - not hard links */
__u32 yst_mode; /* protection */
#ifdef CONFIG_YAFFS_WINCE
__u32 notForWinCE[5];
#else
__u32 yst_uid;
__u32 yst_gid;
__u32 yst_atime;
__u32 yst_mtime;
__u32 yst_ctime;
#endif
/* File size applies to files only */
int fileSize;
/* Equivalent object id applies to hard links only. */
int equivalentObjectId;
/* Alias is for symlinks only. */
char alias[YAFFS_MAX_ALIAS_LENGTH + 1];
__u32 yst_rdev; /* device stuff for block and char devices (major/min) */
#ifdef CONFIG_YAFFS_WINCE
__u32 win_ctime[2];
__u32 win_atime[2];
__u32 win_mtime[2];
#else
__u32 roomToGrow[6];
#endif
__u32 inbandShadowsObject;
__u32 inbandIsShrink;
__u32 reservedSpace[2];
int shadowsObject; /* This object header shadows the specified object if > 0 */
/* isShrink applies to object headers written when we shrink the file (ie resize) */
__u32 isShrink;
} yaffs_ObjectHeader;
#endif
-------------------------------------unyaffs2.c----------------------------------------------------------
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/types.h>
#ifdef _HAVE_LUTIMES
#include <sys/time.h>
#else
#include <utime.h>
#endif
#include "unyaffs2.h"
#define UNYAFFS_PRINTF(s, args...) \
do { \
fprintf(stdout, s, ##args); \
fflush(stdout); \
} while (0)
#define VENDOR_EDIT
#define MAX_OBJECTS 10000
#define YAFFS_OBJECTID_ROOT 1
#define MAX_PAGE_SIZE 16384
#define MAX_SPARE_SIZE 512
unsigned int page_size=2048;
unsigned int spare_size=64;
unsigned char data[MAX_PAGE_SIZE + MAX_SPARE_SIZE];
unsigned char *chunk_data = NULL;
unsigned char *spare_data = NULL;
int img_file = 0;
char *obj_list[MAX_OBJECTS];
#ifdef VENDOR_EDIT
//set file attrib include access time & owner & mode, scott 2012
static int unyaffs2_obj_chattr (const char *fpath, yaffs_ObjectHeader *obj)
{
/* access time */
#ifdef _HAVE_LUTIMES
struct timeval ftime[2];
ftime[0].tv_sec = obj->yst_atime;
ftime[0].tv_usec = 0;
ftime[1].tv_sec = obj->yst_mtime;
ftime[1].tv_usec = 0;
lutimes(fpath, ftime);
#else
struct utimbuf ftime;
ftime.actime = obj->yst_atime;
ftime.modtime = obj->yst_mtime;
utime(fpath, &ftime);
#endif
/* owner */
lchown(fpath, obj->yst_uid, obj->yst_gid);
/* mode - no effect on symbolic link */
if (obj->type != YAFFS_OBJECT_TYPE_SYMLINK)
chmod(fpath, obj->yst_mode);
return 0;
}
#endif
int read_chunk()
{
ssize_t s;
int ret = -1;
memset(chunk_data, 0xff, sizeof(chunk_data));
s = read(img_file, data, page_size + spare_size);
if (s == -1) {
perror("read image file\n");
} else if (s == 0) {
printf("end of image\n");
} else if ((s == (page_size + spare_size))) {
ret = 0;
} else {
fprintf(stderr, "broken image file\n");
}
return ret;
}
int process_chunk()
{
int out_file, remain, s;
char *full_path_name;
yaffs_PackedTags2 *pt = (yaffs_PackedTags2 *)spare_data;
if (pt->t.byteCount == 0xffff) {//a new object
yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)malloc(sizeof(yaffs_ObjectHeader));
memcpy(oh, chunk_data, sizeof(yaffs_ObjectHeader));
full_path_name = (char *)malloc(strlen(oh->name) + strlen(obj_list[oh->parentObjectId]) + 2);
if (full_path_name == NULL) {
perror("malloc full path name\n");
}
strcpy(full_path_name, obj_list[oh->parentObjectId]);
strcat(full_path_name, "/");
strcat(full_path_name, oh->name);
obj_list[pt->t.objectId] = full_path_name;
switch(oh->type) {
case YAFFS_OBJECT_TYPE_FILE:
remain = oh->fileSize;
out_file = creat(full_path_name, oh->yst_mode);
while(remain > 0) {
if (read_chunk())
return -1;
s = (remain < pt->t.byteCount) ? remain : pt->t.byteCount;
if (write(out_file, chunk_data, s) == -1)
return -1;
remain -= s;
}
close(out_file);
#ifdef VENDOR_EDIT
unyaffs2_obj_chattr(full_path_name,oh);
#endif
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
symlink(oh->alias, full_path_name);
#ifdef VENDOR_EDIT
unyaffs2_obj_chattr(full_path_name,oh);
#endif
break;
case YAFFS_OBJECT_TYPE_DIRECTORY:
mkdir(full_path_name, 0777);
#ifdef VENDOR_EDIT
unyaffs2_obj_chattr(full_path_name,oh);
#endif
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
link(obj_list[oh->equivalentObjectId], full_path_name);
break;
}
}
return 0;
}
static int helper (void)
{
UNYAFFS_PRINTF("unyaffs2 - A utility to extract the yaffs2 image\n\n");
UNYAFFS_PRINTF("Usage: unyaffs2 [-h|--help] \n"
" [-p|--pagesize pagesize] [-s|--sparesize sparesize]\n"
" imgfile dirname\n\n");
UNYAFFS_PRINTF("Options :\n");
UNYAFFS_PRINTF(" -h display this help message and exit.\n");
UNYAFFS_PRINTF(" -p pagesize page size of target device.\n"
" (512|2048(default)|4096|(8192|16384) bytes)\n");
UNYAFFS_PRINTF(" -s sparesize spare size of target device.\n"
" (default: pagesize/64 bytes; max: pagesize)\n");
return -1;
}
int main(int argc, char **argv)
{
char *imagefile= NULL;
char *dirpath = NULL;
int option, option_index;
static const char *short_options = "hp:s:";
static const struct option long_options[] = {
{"pagesize", required_argument, 0, 'p'},
{"sparesize", required_argument, 0, 's'},
{"help", no_argument, 0, 'h'},
{NULL, no_argument, 0, '\0'},
};
page_size = 2048;
spare_size= 64;
while ((option = getopt_long(argc, argv, short_options,
long_options, &option_index)) != EOF)
{
switch (option) {
case 'p':
page_size = strtol(optarg, NULL, 10);
break;
case 's':
spare_size = strtol(optarg, NULL, 10);
break;
case 'h':
default:
return helper();
}
}
if (argc - optind < 2)
return helper();
imagefile = argv[optind];
dirpath = argv[optind + 1];
chunk_data = data;
spare_data = data + page_size;
img_file = open(imagefile, O_RDONLY);
if (img_file == -1) {
printf("open image file failed\n");
exit(1);
}
obj_list[YAFFS_OBJECTID_ROOT] = dirpath;//".";
while(1) {
if (read_chunk() == -1)
break;
process_chunk();
}
close(img_file);
return 0;
}