Bootstrap

MacOS如何读取磁盘原始的扇区内容,恢复误删除的数据

MacOS 也是把磁盘当成一个文件,也是可以使用 dd来读取,命行令行如下:

sudo dd if=/dev/disk2 bs=512 count=1 skip=100 of=sector_100.bin

这个就是读取 /dev/disk2这个磁盘每100这个sector, bs表示扇区大小是512.

但是你直接用读,应该是会出错的,如下:

dd: /dev/disk2: Resource busy

你需要把这个磁盘umount下来。

先使用diskutil list找到这磁盘的挂载

$ diskutil list


/dev/disk2 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +1.0 TB     disk2
                                 Physical Store disk1s2
   1:                APFS Volume ⁨p1t2⁩                    86.0 KB    disk2s1

然后umount它的挂载

$ diskutil umount disk2s1

Volume p1t2 on disk2s1 unmounted

再执行就ok了。

$ sudo dd if=/dev/disk2 bs=512 count=1 skip=100 of=sector_100.bin
1+0 records in
1+0 records out
512 bytes transferred in 0.000225 secs (2274877 bytes/sec)

也可以使用grep命令去查找一个字符串出现的位置。

$ sudo grep -a -o -b 'EFI PART' /dev/nvme0n1
512:EFI PART
41661792:EFI PART
412075976:EFI PART
412207048:EFI PART
587940832:EFI PART
512110190080:EFI PART

按上面的原理,我们可以使用代码来一个一个扇区的查找我们丢失数据。我丢了一个android的签名keystore, 用遍了网上的工具都没有找到。我自己写了一个搜索扇区程序,尝试去恢复这个文件。代码如下:

//
//  main.cpp
//  recoverssd

#include <unistd.h>
#include <stdio.h>
#include <string>
#include <fcntl.h>

#include <iostream>
//00000000: feed feed 0000 0002 0000 0001 0000 0001  ................
//00000010: 0010 616e 6472 6f69 642e 6b65 7973 746f  ..android.keysto
//00000020: 7265 0000 0192 d2fb 4242 0000 0502 3082  re......BB....0.
//00000030: 04fe 300e 060a 2b06 0104 012a 0211 0101  ..0...+....*....
//00000040: 0500 0482 04ea 0170 fa35 f5c6 96d6 3cd9  .......p.5....<.
//00000050: c181 8fb9 129c 64ab bfb2 357f a8db 7b36  ......d...5...{6
//00000060: cab8 d8d2 bd83 74a0 1310 b5f5 0c35 e78d  ......t......5..

 char keystoreHeader[] = "\xfe\xed\xfe\xed\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\x00\x10\x61\x6e\x64\x72\x6f\x69\x64\x2e\x6b\x65\x79\x73\x74\x6f\x72\x65";

#define needlesize 0x22
void BytesToStringA(char *&pBinStr, const  unsigned char * pbin, int len,char seperator)
{
    pBinStr = new char[len*3+2];
    pBinStr[0]=0;
    if(len==0 || pbin == NULL)
    {
        return;
    }
    int ncLen = 0;
    for(int i=0;i<len;i++)
    {
        if(seperator!=0)
            ncLen += sprintf(pBinStr+ncLen,"%02X%c",pbin[i],seperator);
        else
            ncLen += sprintf(pBinStr+ncLen,"%02X",pbin[i]);
    }
}


const char* strnstr(const char *dst,  int dlen, const char * src, int slen)
{
    const char *s = NULL;

    while (dlen >= slen) {
        if (memcmp(src, dst, slen) == 0) {
            s = dst;
            break;
        }
        dst++;
        dlen--;
    }
    return s;
}



int main(int argc, const char * argv[]) {
    // insert code here...
    std::string diskdev="/dev/disk2";
    int fdes = open(diskdev.c_str(), O_RDONLY);
    if (fdes < 0)
    {
        std::cout << "open dev failed " << diskdev << "\n";
        return -1;
    }
#define SECTOR_SIZE 1024*1024
    char szSector[SECTOR_SIZE];
    size_t numberdone=0;
    while(true)
    {
        ssize_t nr = read(fdes, szSector, SECTOR_SIZE);
        if(nr>0)
        {
            if(strnstr(szSector,SECTOR_SIZE,  keystoreHeader,needlesize )!=NULL)
            {
                char *pBinStr = NULL;
                BytesToStringA(pBinStr,(const  unsigned char *)szSector,SECTOR_SIZE,' ');
                
                if(pBinStr!=NULL)
                {
                    printf("\n\n%s\n",pBinStr);
                    delete pBinStr;
                }
                return 0;
            }
            
            printf("\r read %ld",++numberdone);
        }
        else{
            printf("read all \n");
        }
    }
    
    std::cout  << "open ok \n";
    close(fdes);
    return 0;
}

;