From afa9a5373df35cd37f4b635c4a4213e54b317344 Mon Sep 17 00:00:00 2001 From: n1481 Date: Mon, 16 May 2011 06:40:47 +0000 Subject: [PATCH] =?UTF-8?q?FNT=20=E3=81=8C=20FNT=E3=81=A8=E9=96=A2?= =?UTF-8?q?=E4=BF=82=E3=81=AE=E7=84=A1=E3=81=84=E3=83=87=E3=83=BC=E3=82=BF?= =?UTF-8?q?=E3=81=A7=E5=9F=8B=E3=82=81=E3=82=89=E3=82=8C=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F=E5=A0=B4=E5=90=88=E3=81=AB=E3=80=81FNT=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E3=82=92=E6=89=93=E3=81=A1=E5=88=87=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlToolsRED@559 7061adef-622a-194b-ae81-725974e89856 --- build/tools/TamperDetectorForSrl/checker.cpp | 33 ++++++++++++++---- build/tools/TamperDetectorForSrl/checker.h | 4 +-- build/tools/TamperDetectorForSrl/main.cpp | 12 +++---- .../TamperDetectorForSrl/tamperdetector.exe | Bin 157273 -> 157785 bytes 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/build/tools/TamperDetectorForSrl/checker.cpp b/build/tools/TamperDetectorForSrl/checker.cpp index c8facc5..f610366 100644 --- a/build/tools/TamperDetectorForSrl/checker.cpp +++ b/build/tools/TamperDetectorForSrl/checker.cpp @@ -202,7 +202,7 @@ void Checker::AnalyzeBanner( RomHeader* gHeaderBuf, RomHeader* mHeaderBuf) } -void Checker::AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable) +bool Checker::AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable) { int i; ROM_FNTDir currentDir; @@ -213,6 +213,12 @@ void Checker::AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLev fseek( fp, (u32)(headerBuf->fnt_offset), SEEK_SET); fread( ¤tDir, sizeof(ROM_FNTDir), 1, fp); + if( (currentDir.parent_id) >= 4096) + { + printf( "invalid FNT! directory count over 4096.\n"); + return false; + } + // ディレクトリテーブル全体を読む fseek( fp, (u32)(headerBuf->fnt_offset), SEEK_SET); fread( &fntBuf, sizeof(ROM_FNTDir) * currentDir.parent_id, 1, fp); @@ -235,6 +241,11 @@ void Checker::AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLev } tmpDirEntry.self_id = (0xF000 + i); tmpDirEntry.parent_id = fntBuf[i].parent_id; + if( fntBuf[i].parent_id < 0xF000) + { + printf( "invalid FNT! illegal parent-directory-id.\n"); + return false; + } } if( !entry->FindDirEntry( tmpDirEntry.self_id)) { // 見つからなかったら追加 @@ -243,14 +254,18 @@ void Checker::AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLev entry->addDirEntry( pDirEntry); } - FindEntry( fntBuf[i].entry_start, - fntBuf[i].entry_file_id, - headerBuf, fp, entry, tmpDirEntry.self_id, - print_enable); + if( !FindEntry( fntBuf[i].entry_start, + fntBuf[i].entry_file_id, + headerBuf, fp, entry, tmpDirEntry.self_id, + print_enable)) + { + return false; + } } + return true; } -void Checker::FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, u16 parent_id, PrintLevel print_enable) +bool Checker::FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, u16 parent_id, PrintLevel print_enable) { EntryInfo entryInfo; char entryNames[FILE_NAME_LENGTH]; @@ -273,6 +288,11 @@ void Checker::FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FIL if( print_enable) { printf( "- %s(file_id:0x%d)\n", entryNames, entry_id); } + if( entry_id >= 61440) + { + printf( "invalid FNT! file count over 61440.\n"); + return false; + } /* パス解析用 */ fileEntry = (MyFileEntry*)malloc( sizeof(MyFileEntry)); entry->InitializeEntry( fileEntry); @@ -303,6 +323,7 @@ void Checker::FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FIL entry->SetName( dirEntry, entryNames, entryInfo.entry_name_length); } } + return true; } void Checker::FindAllocation( u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable) diff --git a/build/tools/TamperDetectorForSrl/checker.h b/build/tools/TamperDetectorForSrl/checker.h index 307fa41..5947d1c 100644 --- a/build/tools/TamperDetectorForSrl/checker.h +++ b/build/tools/TamperDetectorForSrl/checker.h @@ -51,8 +51,8 @@ class Checker void AnalyzeBanner( RomHeader* gHeaderBuf, RomHeader* mHeaderBuf); /* FNT と FAT を解析して、各ファイルに対して Diff をかける */ - void AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable); - void FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, u16 parent_id, PrintLevel print_enable); + bool AnalyzeFNT( RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable); + bool FindEntry( u32 fnt_offset, u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, u16 parent_id, PrintLevel print_enable); void FindAllocation( u16 entry_id, RomHeader* headerBuf, FILE* fp, Entry* entry, PrintLevel print_enable); void CheckAllEntries( Entry* gEntry, Entry* mEntry); diff --git a/build/tools/TamperDetectorForSrl/main.cpp b/build/tools/TamperDetectorForSrl/main.cpp index 5df253a..7bff090 100644 --- a/build/tools/TamperDetectorForSrl/main.cpp +++ b/build/tools/TamperDetectorForSrl/main.cpp @@ -140,12 +140,12 @@ int main (int argc, char *argv[]) gEntry.FollowParent(); gEntry.AutoSetFullPath(); - checker.AnalyzeFNT( &mHeaderBuf, mfp, &mEntry, PRINT_LEVEL_0); - mEntry.FollowParent(); - mEntry.AutoSetFullPath(); - - checker.CheckAllEntries( &gEntry, &mEntry); - + if( checker.AnalyzeFNT( &mHeaderBuf, mfp, &mEntry, PRINT_LEVEL_0)) + { + mEntry.FollowParent(); + mEntry.AutoSetFullPath(); + checker.CheckAllEntries( &gEntry, &mEntry); + } checker.ExportGenuineBmpFiles( &gEntry, PRINT_LEVEL_0); /* gEntry.PrintAllDirEntry(); diff --git a/build/tools/TamperDetectorForSrl/tamperdetector.exe b/build/tools/TamperDetectorForSrl/tamperdetector.exe index 8a83d1694f10e532debb16324b3ecdcb84e7e40c..eb6dd2dda2f5a82fd4204eec0496ec98b8c9be07 100755 GIT binary patch delta 21785 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 Dd@h*? delta 21355 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