--- squashfs-tools/unsquashfs.c
+++ squashfs-tools/unsquashfs.c
@@ -77,6 +77,8 @@
 int inode_number = 1;
 int no_xattrs = XATTR_DEF;
 int user_xattrs = FALSE;
+int scan_for_superblock = FALSE;
+off_t superblock_offset = 0;
 
 int exit_on_error = FALSE;
 
@@ -626,10 +628,89 @@
 	return -1;
 }
 
+typedef struct sblk_buf {
+	unsigned int magic;
+	char b[256 - sizeof(unsigned int)];
+} sblk_buf;
+
+int is_squashfs4_superblock(const sblk_buf* buf) {
+	struct squashfs_super_block sBlk_4;
+
+	memcpy(&sBlk_4, buf, sizeof(struct squashfs_super_block));
+	SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4);
+
+	if (sBlk_4.s_major == 4)
+		return TRUE;
+
+	return FALSE;
+}
+
+#ifdef LEGACY_FORMATS_SUPPORT
+int is_squashfs123_superblock(const sblk_buf* buf) {
+	struct squashfs_super_block_3 sBlk_3;
+
+	memcpy(&sBlk_3, buf, sizeof(squashfs_super_block_3));
+
+	if (sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) {
+		squashfs_super_block_3 sblk_3;
+		SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk_3, &sBlk_3);
+		memcpy(&sBlk_3, &sblk_3, sizeof(squashfs_super_block_3));
+	}
+
+	{
+		int is_valid_major = (1 <= sBlk_3.s_major) && (sBlk_3.s_major <= 3);
+		int is_valid_minor = (sBlk_3.s_minor <= 1) || (sBlk_3.s_minor == 76);
+		if (is_valid_major && is_valid_minor)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+#endif
+
+off_t find_superblock(int fd) {
+	off_t offset;
+	sblk_buf buf;
+
+	for (offset = 0; /* forever */; offset += 256) {
+		if (lseek(fd, offset, SEEK_SET) == -1) {
+			ERROR("Lseek failed because %s\n", strerror(errno));
+			break;
+		}
+
+		if (read(fd, &buf, sizeof(sblk_buf)) != sizeof(sblk_buf)) {
+			break;
+		}
+
+		if (buf.magic != SQUASHFS_MAGIC && buf.magic != SQUASHFS_MAGIC_SWAP) {
+			continue;
+		}
+
+		TRACE("find_superblock:%s magic 0x%08X found at 0x%08X\n", (buf.magic == SQUASHFS_MAGIC_SWAP ? " swapped" : ""), buf.magic, (unsigned int)offset);
+
+		// do not rely on MAGIC only, check a little bit more
+		if (is_squashfs4_superblock(&buf)) {
+			TRACE("found valid SquashFS-4 superblock\n");
+			return offset;
+		}
+
+#ifdef LEGACY_FORMATS_SUPPORT
+		if (is_squashfs123_superblock(&buf)) {
+			TRACE("found valid SquashFS-1/2/3 superblock\n");
+			return offset;
+		}
+#endif
+
+		// do not look for any further MAGICs, abort after the 1st match
+		break;
+	}
+
+	return (off_t) -1;
+}
 
 int read_fs_bytes(int fd, long long byte, int bytes, void *buff)
 {
-	off_t off = byte;
+	off_t off = byte + superblock_offset;
 	int res, count;
 
 	TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n", byte,
@@ -2644,6 +2725,8 @@
 			use_regex = TRUE;
 		else if(strcmp(argv[i], "-exit-on-error") == 0)
 			exit_on_error = TRUE;
+		else if(strcmp(argv[i], "-scan") == 0 || strcmp(argv[i], "-k") == 0)
+			scan_for_superblock = TRUE;
 		else
 			goto options;
 	}
@@ -2708,6 +2791,8 @@
 			ERROR("\t\t\t\trather than use the default shell "
 				"wildcard\n\t\t\t\texpansion (globbing)\n");
 			ERROR("\t-exit-on-error\t\ttreat normally ignored errors as fatal\n");
+			ERROR("\t-scan or -k\t\ttreat filesystem as a combined image\n");
+			ERROR("\t\t\t\t(kernel+SquashFS) and scan it to locate the superblock\n");
 			ERROR("\nDecompressors available:\n");
 			display_compressors("", "");
 		}
@@ -2723,6 +2808,16 @@
 		exit(1);
 	}
 
+	if(scan_for_superblock == TRUE) {
+		superblock_offset = find_superblock(fd);
+		if (superblock_offset == (off_t) -1) {
+			ERROR("Unable to find something looking like a SquashFS superblock in %s.\n", argv[i]);
+			exit(2);
+		}
+
+		ERROR("Found a valid superblock at offset 0x%08X while scanning %s.\n", (unsigned int) superblock_offset, argv[i]);
+	}
+
 	if(read_super(argv[i]) == FALSE)
 		exit(1);
 
