第14章
RAWファイル回復のためのプログラミング
RAWファイルの回復
ファイルの先頭と末尾に特定の文字のシーケンスまたは組み合わせが書き込まれた特定のファイル タイプが多数あります。これらの組み合わせは、任意のディスク編集プログラムを使用して簡単に分析できます。 EDIT DOS コマンドを使用して ASCII ファイルの構造を調べることもできます。
ファイルの先頭にある特定の文字のシーケンスまたは組み合わせは通常、ヘッダーと呼ばれ、ファイルの末尾に格納されている文字のシーケンスまたは組み合わせは、ファイルのフッターと呼ばれます。
データを回復するための FAT またはルート ディレクトリ情報がないようなディスク障害でデータを失った場合は、ヘッダーとフッターを使用してこれらの特定の種類のファイルを見つけることができます。ヘッダーは特定のファイル タイプのファイルの始まりを示し、フッターは特定のファイル タイプのファイルの終わりを示します。
ここでは、特定のファイル タイプの生の構造を使用してデータを回復するため、回復方法は Raw File Recovery と呼ばれます。ディスク表面をセクターごとにスキャンして、ヘッダーとフッターの情報を検索します。
Raw File Recovery には幅広い用途がありますが、非常に役立つ特殊な回復ケースがいくつかあります。たとえば、誤って、重要なファイルが含まれているディスク上でデータ消去プログラムを実行した場合、プログラムを停止するまで、オペレーティング システム ファイルを含むすべての MBR、DBR、FAT、およびルート ディレクトリ情報が消去されます。
この場合、フォーマット回復プログラムでもデータの回復に役立たない可能性があります。ここでは、Raw ファイルの回復を使用して、ヘッダーとフッターを検索することで、これらの特定のファイル タイプのファイルを回復できます。
それだけでなく、ハード ドライブのすべての論理パーティションを削除し、以前とは異なるサイズのパーティションを再作成し、オペレーティング システムをインストールした場合でも、データを回復できます。
これで、パーティション分割およびフォーマットされる前にディスク上に重要なデータがあったことが思い出されます。オペレーティング システムをインストールしたばかりであれば、ファイルが回復される可能性が高くなります。
生のファイルの回復パフォーマンスに影響を与える要因は、断片化されたデータと他のデータによって上書きされたデータの量です。ただし、RAW ファイルを自分で回復するためのアプリケーションはますます多く見つかります。
RAW ファイル回復ソフトウェアを使用してファイルを検索するための手順またはほとんどのルールでは、次の条件が考慮されます。
- ディスク セクター内でファイル ヘッダーまたは複数のファイル タイプを同時に検索します。
- ファイル タイプ ヘッダーが見つかった場合は、ファイル内のデータを保存し、次の 4 つの条件を確認してファイルを閉じて保存します。
- このファイルタイプのフッターが見つかりました
- 同じファイルタイプの別のヘッダーが見つかりました。
- 異なるファイルタイプのヘッダーが見つかりました
- プログラム内の特定のファイル タイプに対して他のヘッダーまたはフッターが見つからず、データを保存するファイル サイズがプログラムでファイル サイズに定義した最大サイズ制限に達しています。
ファイル タイプ ヘッダーとフッターが見つかったセクター データを含む情報がファイルに保存されるはずです。
いくつかの重要なファイルタイプのヘッダーとフッター
いくつかの重要なファイル タイプのヘッダーとフッターを以下の表に示します。表にリストされているフッターは、指定されたファイル タイプのファイルの末尾またはファイルの終了オフセットにあるため、データ回復のフッターとして使用できます。
DOS EDIT コマンドまたは任意のディスク編集ツールを使用して、これらのファイル タイプ以外のヘッダーとフッターを自分で検索することもできます。情報をより理解しやすくするために、16進数を使用して表現しました。
拡大 |
ヘッダー (16進数) |
フッター (16 進数) |
ドキュメント |
D0 CF 11 E0 A1 B1 1A E1 |
57 6F 72 64 2E 44 6F 63 75 6G 65 6E 74 2E |
XLSX |
D0 CF 11 E0 A1 B1 1A E1 |
FE FF FF FF 00 00 00 00 00 00 00 00 57 00 6F 00 72 00 6B 00 62 00 6F 00 6F 00 6B 00 |
パワーポイント |
D0 CF 11 E0 A1 B1 1A E1 |
50 00 6F 00 77 00 65 00 72 00 50 00 6F 00 69 00 6E 00 74 00 20 00 44 00 6F 00 63 00 75 00 6D 00 65 00 6E 00 74 |
郵便番号 |
50 4B 03 04 14 |
50 4B 05 06 00 |
画像 |
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 |
D9 (「ファイルサイズチェックを使用する方が良い」) |
画像 |
47 49 46 38 39 61 4E 01 53 00 C4 |
21 00 00 3B 00 |
PDF |
25 50 44 46 2D 31 2E |
25 25 45 4F 46 |
RAWファイルを復元するプログラムの作成
以下は、Microsoft Word ファイル (拡張子 .DOC) の Raw ファイル回復プログラムのエンコードです。プログラムはディスク セクター内のファイルを検索し、復元されたファイルを自動的に保存し、ファイル名を自動的に作成します。
ユーザーがファイルを保存するために指定したパスは、復元されたデータを保存するための保存先パスとして使用されます。宛先ディレクトリが存在しない場合は、プログラムは 1 ディレクトリ レベルまで作成できます。
ここで提供されるリカバリ ソフトウェアは、大容量のディスクでもデータの検索とリカバリをサポートします。このプログラムは、2 番目の物理ハード ドライブ上のデータを検索するために作成されました。
/* Microsoft Word RAW ファイル回復ソフトウェア*/
#include<stdio.h>
#include<dos.h>
/* INT 13H 拡張、関数番号 0x48 を使用して getdrivegeometry 関数によって使用される構造体。 */
構造幾何学
{
符号なし整数サイズ; /* (呼び出し) バッファサイズ */
符号なし整数フラグ; /* 情報フラグ */
符号なしロングシリンダー; /* 物理数
ドライブのシリンダー */
符号なしロングヘッダー ;/* 物理数
ドライブのヘッド */
符号なしロング spt ; /* 物理数
トラックあたりのセクター数 */
符号なしロングセクター[2] ; /* 合計数量
ディスク上のセクター */
符号なし整数 bps ; /* セクターあたりのバイト数 */
} ;
/* readabsolutesectors で使用されるディスク アドレス パケット形式の構造 */
ディスクアドレスパケット構造
{
char パケットサイズ ; /* パケットサイズ、通常は 10H */
シンボルは予約済みです。 /* 予約済み (0) */
int ブロック数; /* 転送するブロック数 */
char far *バッファアドレス; /* 送信用アドレス
バッファ */
符号なしlongブロック番号[2] ; /* 初期絶対値
ブロック番号 */
} ;
///// ドライブパラメータを取得する関数 \\\\\
符号なしロング getdrivegeometry(intdrive)
{
労働組合REGS i、o;
構造 SREGS;
構造形状 g = { 26, 0, 0, 0, 0, 0, 0, 0 } ;
ihah = 0x48 ; /* 関数番号 0x48 */
ihdl = ドライブ; /* ディスク番号 */
ixsi = FP_OFF ( (void far*)&g ) ;
s.ds = FP_SEG ( (void far*)&g ) ;
/* 指定されたINT 13H拡張関数番号をセグメントレジスタ値で呼び出します */
int86x ( 0x13, &i, &o, &s ) ;
printf("\n ヘッド = %lu、トラックあたりのセクター数 = %lu、シリンダー = %lu\n",
g.head、g.spc、g.cyl);
/* ディスクジオメトリを取得する関数が失敗した場合は、エラーメッセージを出力して終了します */
g.spt==0の場合
{
printf("\n ドライブジオメトリを取得する関数は実行されませんでした...");
printf("\n 拡張機能はサポートされていません。任意のキーを押してください
出口...");
getch();
終了(1);
}
return *g.sectors; /* セクター数を返す
ドライブ上のセクター */
}
符号なしロングファイルサイズ=0、i=0;
符号なしlong start_file=0、end_file=0;
符号なしlong Sectors_in_HDD2=0、ループ=0;
char バッファ[512]、ファイル名[80]、一時[8];
charパス[80];
符号なし整数の結果、数値=0;
/* Microsoft Word ファイルのヘッダー*/
文字ヘッダー[10] = {0xD0,0xCF,0x11,0xE0, 0xA1,0xB1,0x1A,0xE1};
/* Microsoft Word ファイルのフッター */
char DOC_footer[14] =
{0x57,0x6F,0x72,0x64, 0x2E,0x44,0x6F,0x63,
0x75,0x6D,0x65,0x6E,0x74};
/// メインの開始 \\\
void main()
{
clrscr();
/* 接続されているハードディスクの合計数が
2 番目はエラー メッセージを表示して終了します。 */
if(((char)peekb(0x0040, 0x0075))<2)
{
printf("\n\n 少なくとも2台のハードディスクが必要です
これを実行するにはコンピュータに接続してください");
printf("\n プログラム。このプログラムは開発されました
2台目のハードディスクのデータを回復します。");
printf("\n 終了するには任意のキーを押してください... ");
getch();
終了(1);
}
Sectors_in_HDD2=getdrivegeometry (0x81);
printf("\n 2番目のハードディスクの合計セクター数 = %lu",
HDD2のセクター数);
printf("\n\n \"回復したファイルは
同じディスクではなく、別のハードディスクです。");
printf("\n 失われたものを探している
データ。\"");
printf("\n\n 保存先のパスを入力してください
回復されたファイル...\n ");
パスを取得します。
/* 宛先ディレクトリが存在するかどうかを確認します */
アクセスパスが 0 の場合 != 0
{
/* 宛先ディレクトリが存在しない場合は作成する
ディレクトリを1レベルまで上げる */
if(mkdir(パス)!=0)
{
printf("\n ディレクトリ \"%s\" を作成できませんでした",
パス);
printf("\n パスを確認...、任意のキーを押して
出口...");
getch();
終了(1);
}
}
strcat(パス,"\\Ptt");
/*画面上のカーソルを非表示(および表示)する関数*/
カーソルを表示しない ( 32,
gotoxy(15,18);cprintf("[ %d ] ファイルが回復されました...",
で);
/* ディスクの終了セクタまでデータを検索します */
while(loop<Sectors_in_HDD2)
{
/* 1セクターを読み取ります (セクター番号 = ループ) */
絶対セクターを読み取ります ( 0x81, ループ, 1, バッファ );
gotoxy(19,16);cprintf("スキャンセクター番号 = % ld",
ループ);
if(kbhit())
{
show_hide_cursor ( 6, 7 ); /* カーソルを非表示にする
カーソルの前
プログラムを終了する
*/
終了(0);
}
/* 指定されたヘッダーが見つかった場合 */
if((memcmp ( バッファ、ヘッダー、7))==0)
{
/* ファイル名を自動的に提供するロジック
復元したデータを保存するためのファイルを作成する */
strcpy(ファイル名, パス);
itoa(数値、温度、10);
strcat(ファイル名, temp);
strcat(ファイル名,".DOC");
start_file=loop; /* ファイルの開始セクター */
gotoxy(5,19);cprintf("ファイルが見つかりました...、%s として保存しています",
ファイル名);
数値++;
////////////// ファイルのクローズ条件 \\\\\\\\\\\\\\\\\
ファイルサイズ=0;
(ファイルサイズ<5000000)
{
ループ++;
ファイルサイズ+=512;
絶対セクターを読み取ります ( 0x81, ループ, 1, バッファ );
gotoxy(19,16);cprintf("スキャンセクター番号 = % ld" ,
ループ);
/* ファイルサイズが最大サイズの 5MB に達した場合 */
ファイルサイズ>=5000000の場合
{
end_file=loop; /* ファイルの終了セクター */
Recover_the_file();/* データをファイルに書き込む */
壊す;
}
/* DOC ファイルのフッターが見つかった場合 */
(i=0;i<512;i++) の場合
{
if( memcmp(バッファ+i,DOC_footer,12)==0 )
{
end_file=loop; /* ファイルの終了セクター */
Recover_the_file();/* データをファイルに書き込む */
壊す;
}
}
/* 別のヘッダーが見つかった場合 */
memcmp(バッファ、ヘッダー、7)==0の場合
{
ループ=ループ-1;
end_file=loop; /* ファイルの終了セクター */
Recover_the_file();/* データをファイルに書き込む */
壊す;
}
if(kbhit())
{
カーソルを表示/非表示 ( 6, 7 );
終了(0);
}
}
}
ループ++;
}
////////Whileループはここで終了します
/* 検索と回復の完了メッセージを表示する */ if(loop>=Sectors_in_HDD2 )
{
gotoxy(17,23);cprintf("ディスクへのファイルの保存は
完了しました!!");
gotoxy(17,24);cprintf("終了するには任意のキーを押してください...");
カーソルを表示/非表示 ( 6, 7 );
getch();
}
}
構造体ジオメトリは、INT 13H 拡張機能、関数番号 0x48 を使用して getdrivegeometry 関数によって使用され、ディスクのさまざまなパラメータを取得します。
構造体 diskaddrpacket は、readabsolutesectors 関数で使用されるディスク アドレス パケット形式です。
関数 getdrivegeometry (int drive) は、指定された物理ドライブ番号のディスクのドライブ パラメータを取得します。
(char) peekb(0x0040, 0x0075) は、セグメント 0040H:オフセット 0075H で表されるメモリ位置に格納されている、コンピュータに接続されているハード ディスクの数を検索するために使用されます。接続されているハード ディスクの合計数が 2 未満の場合は、エラー メッセージを表示して終了します。
Sectors_in_HDD2=getdrivegeometry (0x81); は、2 番目の物理ハード ディスク (0x81) のさまざまなパラメーターを検出し、ディスクのセクターの合計数を返します。
ステートメント if(access(path, 0) != 0) は、ユーザーが指定したパスのアクセス可能性をチェックします。宛先ディレクトリが存在しない場合は、宛先が 1 レベルまで作成され、条件 if(mkdir(path)!=0) によってチェックされた指定されたパスが不正な場合は、エラー メッセージが表示されます。
復元されたデータを保存するために自動的に作成されるファイルのファイル名は、strcat(path,"\\Ptt"); 関数によってファイルの最初の 3 文字に PTT が付与されるように作成されます。これは、宛先ディレクトリでファイル名が重複するのを避けるためです。したがって、復元されたファイルのファイル名は「PTTxxxxx.DOC」の形式で付与されます。
関数 show_hide_cursor ( 32, 0 ); は、カーソルを画面から非表示にするために使用されます。show_hide_cursor ( 6, 7 ); は、カーソルを画面に戻します。
関数 readabsolutesectors (0x81, loop, 1, buffer); は、セクター番号 loop で指定された 2 番目の物理ハード ディスクの 1 つのセクターを読み取ります。
ファイルのヘッダーが見つかった場合、start_file = loop; は、回復するファイルの開始セクター番号に start_file を設定します。プログラムは、次の 3 つの条件に従って、ファイルの終了セクターを検索します。
- ファイルサイズが最大5MBに達した場合
- DOCファイルのフッターが見つかった場合
- 別のヘッダーが見つかった場合
3 つの条件のうち 1 つが満たされた場合、end_file=loop; によって、long 整数 end_file がファイルの終了セクター番号に設定されます。これで、セクター番号 start_file からセクター番号 end_file までのセクターのデータが、関数 Recover_the_file( ) を使用してファイルに保存されます。
関数 Recover_the_file() のコーディングは次のとおりです。
/*セクタ番号 start_file からセクタ番号 end_file までのセクタのデータを保存する関数*/
ファイルの回復()
{
ファイル *fp;
if((fp=fopen(ファイル名, "wb"))==NULL)
{
gotoxy(10,23);printf("ファイル %s を開くときにエラーが発生しました",
ファイル名);
getch();
終了(1);
}
(i=開始ファイル;i<=終了ファイル;i++)
{
gotoxy(19,16);cprintf("スキャンセクター番号 =
%ld", i);
絶対セクタを読み取ります ( 0x81, i, 1, バッファ );
fwrite(バッファ,512,1,fp);
}
fp を閉じる
gotoxy(15,18);cprintf("[ %d ] ファイルが回復されました...",num);
gotoxy(5,19);cprintf(" ");
戻る;
}
関数 readabsolutesectors のコーディングを次に示します。この関数は、セクターを読み取り、INT 13H 拡張機能と関数番号 42H を使用します。
関数の詳細な説明については、この本の前半で説明した「バックアップの作成」の章を参照してください。関数のコーディングは次のとおりです。
//// 絶対セクターを読み取る関数 \\\\
int readabsolutesectors ( int ドライブ、
符号なし長整数セクター番号、
int セクター数、
void *バッファ)
{
ユニオン REGS i、o ;
構造体SREGs;
構造体ディスクアドレスパケットpp;
pp.packetsize = 16 ; /* パケットサイズ = 10H */
pp.reserved = 0 ; /* 予約済み = 0 */
pp.blockcount = numofsectors ; /* セクター数
読む */
/* データバッファ用 */
pp.bufferaddress = (char far*) MK_FP ( FP_SEG((void far*)buffer), FP_OFF((void far*)buffer));
pp.blocknumber[0] = sectornumber ; /* セクター番号
読む */
pp.blocknumber[1] = 0 ; /* ブロック番号 */
ihah = 0x42 ; /* 関数番号*/
ihdl = drive ; /* 物理ドライブ番号 */
/* バッファパラメータのds:si */
ixsi = FP_OFF ( (void far*)&pp ) ;
/* バッファパラメータのds:si */
s.ds = FP_SEG ( (void far*)&pp ) ;
/* INT 13Hの指定された関数を呼び出す
セグメントレジスタ値 */
int86x ( 0x13, &i, &o, &s ) ;
(oxcflag==1の場合)
0を返す; //失敗
それ以外
1を返す; // 成功
}
画面上のカーソルを非表示または表示するには、次の関数を使用します。この関数は、割り込み 10H、関数 01H を使用してカーソル タイプを設定します。エンコードは次のとおりです。
カーソルを表示しない(ssl, esl)
整数 ssl、esl ;
{
労働組合REGS i、o;
増加 = 1 ;
SSL を有効にするには、SSL を有効にする必要があります。
ihcl = esl;
0 ;
int86 ( 16, &i, &o ) ;
戻ってくる;
}
show_hide_cursor( 32, 0 ) はカーソルを非表示にし、show_hide_cursor( 6, 7 ) はカーソルを戻します。 ssl はカーソルの開始行であり、 esl はカーソルの終了行です。
01H INT 10H 機能の簡単な説明は次のとおりです。
INT 10H (16 または 0x10)
関数 01H (または 0x01) --> カーソルの種類を設定する
発信元: AH = 01H
ビット 0-4 CH = カーソルの開始行
CL ビット 0-4 = カーソルの終了行
戻り値: なし。
コメント:
この関数は、テキスト表示モードで点滅するハードウェア カーソルの開始行と終了行を選択して、カーソルの種類を設定するために使用されます。ハードウェア カーソルはグラフィック モードでは使用できません。