MachOView源碼(AppController.mm)

來源:互聯網
上載者:User

標籤:自身   odi   orm   apple   bundle   hpa   fat   布爾   oid   

//AppController.h

/* *  AppController.h *  MachOView * *  Created by psaghelyi on 15/06/2010. * */#import <Cocoa/Cocoa.h>@class MVPreferenceController;@interface MVAppController : NSObject <NSApplicationDelegate,NSOpenSavePanelDelegate>{  MVPreferenceController * preferenceController;}//喜好設定- (IBAction)showPreferencePanel:(id)sender;//附加- (IBAction)attach:(id)sender;@end

//AppController.mm

 /* *  AppController.mm *  MachOView * *  Created by psaghelyi on 15/06/2010. * */#import "Common.h"#import "AppController.h"#import "DataController.h"#import "Document.h"#import "PreferenceController.h"#import "Attach.h"// counters for statisticsint64_t nrow_total;  // number of rows (loaded and empty)int64_t nrow_loaded; // number of loaded rows//============================================================================@implementation MVAppController//----------------------------------------------------------------------------- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender{  return NO;}//----------------------------------------------------------------------------- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender{  return NO;}//----------------------------------------------------------------------------//new 方式 沒寫- (IBAction)newDocument:(id)sender{  NSLog(@"Not yet possible");}//----------------------------------------------------------------------------//是否在運行- (BOOL)isOnlyRunningMachOView{    //擷取進程的相關資訊  NSProcessInfo * procInfo = [NSProcessInfo processInfo];    //擷取程式程式包(app包就是一個mainBundle)  NSBundle * mainBundle = [NSBundle mainBundle];    //擷取當前進程的CFBundleShortVersionString    //返回指定鍵關聯的接收器中的屬性資訊列表  NSString * versionString = [mainBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];  NSUInteger numberOfInstance = 0;    //返回一個工作空間    //提供服務    //1)開啟,操作檔案/裝置,擷取檔案/裝置資訊    //2)追蹤檔案,裝置以及資料庫的變動    //3)設定或擷取檔案的 Finder 資訊    //4)操作應用程式  NSWorkspace * workspace = [NSWorkspace sharedWorkspace];    //擷取當前啟動並執行 apps  for (NSRunningApplication * runningApplication in [workspace runningApplications])  {    //檢查進程名稱是否匹配    //executableURL擷取bundle 類執行個體的 可執行檔URL    //lastPathComponent擷取路徑中的最後一個檔案名稱    NSString * fileName = [[runningApplication executableURL] lastPathComponent];      //判斷名稱是否相等    if ([fileName isEqualToString: [procInfo processName]] == NO)    {      continue;    }    //檢查版本字串是否匹配    //通過 url 擷取bundle    NSBundle * bundle = [NSBundle bundleWithURL:[runningApplication bundleURL]];      //判斷是否與當前進程的相等    if ([versionString isEqualToString:[bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]] == YES && ++numberOfInstance > 1)    {      return NO;    }  }  return YES;}//----------------------------------------------------------------------------//附加方式開啟同時解析 mach-o header- (IBAction)attach:(id)sender{    //alert  NSAlert *alert = [NSAlert alertWithMessageText:@"Insert PID to attach to:"                                   defaultButton:@"Attach"                                 alternateButton:@"Cancel"                                     otherButton:nil                       informativeTextWithFormat:@""];   //初始化一個文字框  NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];    //設定預設字串  [input setStringValue:@""];    //設定彈框的 view為input  [alert setAccessoryView:input];    //返回按鈕值  NSInteger button = [alert runModal];  if (button == NSAlertDefaultReturn)  {      //設定為不可編輯    [input validateEditing];      //擷取 pid    pid_t targetPid = [input intValue];    NSLog(@"Attach to process %d", targetPid);      //入口地址    mach_vm_address_t mainAddress = 0;      //找到入口地址    if (find_main_binary(targetPid, &mainAddress))    {      NSLog(@"Failed to find main binary address!");      return;    }    uint64_t aslr_slide = 0;    uint64_t imagesize = 0;      //擷取鏡像大小    if ( (imagesize = get_image_size(mainAddress, targetPid, &aslr_slide)) == 0 )    {      NSLog(@"[ERROR] Got image file size equal to 0!");      return;    }    //分配macho所需要的緩衝區大小(檔案)    uint8_t *readbuffer = (uint8_t*)malloc(imagesize);    if (readbuffer == NULL)    {      NSLog(@"Can‘t allocate mem for dumping target!");      return;    }    //最後讀取這些部分並將它們的內容轉儲到緩衝區中    if (dump_binary(mainAddress, targetPid, readbuffer, aslr_slide))    {      NSLog(@"Main binary memory dump failed!");      free(readbuffer);      return;    }    //將緩衝區內容轉儲到臨時檔案以使用NSDocument model      //拼接臨時檔案名稱+進程名 如:"/var/folders/l8/3kn0r51s3qdbbnxb9ng2gvb40000gn/T/MachOView_2.4.XXXXXXXXXXX"    const char *tmp = [[MVDocument temporaryDirectory] UTF8String];      //用於儲存數資料的臨時檔案絕對路徑名的緩衝區    char *dumpFilePath = (char*)malloc(strlen(tmp)+1);    if (dumpFilePath == NULL)    {      NSLog(@"Can‘t allocate mem for temp filename path!");      free(readbuffer);      return;    }      //拷貝    strcpy(dumpFilePath, tmp);    int outputFile = 0;      //在系統中以唯一的檔案名稱建立一個檔案並開啟    if ( (outputFile = mkstemp(dumpFilePath)) == -1 )    {      NSLog(@"mkstemp failed!");      free(dumpFilePath);      free(readbuffer);      return;    }    //寫入    if (write(outputFile, readbuffer, imagesize) == -1)    {      NSLog(@"[ERROR] Write error at %s occurred!\n", dumpFilePath);      free(dumpFilePath);      free(readbuffer);      return;    }    NSLog(@"\n[OK] Full binary dumped to %s!\n\n", dumpFilePath);    close(outputFile);    //開啟檔案    [self application:NSApp openFile:[NSString stringWithCString:dumpFilePath encoding:NSUTF8StringEncoding]];    //刪除臨時轉儲檔案    NSFileManager * fileManager = [NSFileManager defaultManager];    [fileManager removeItemAtPath:[NSString stringWithCString:dumpFilePath encoding:NSUTF8StringEncoding] error:NULL];    free(dumpFilePath);    free(readbuffer);  }  else if (button == NSAlertAlternateReturn)  {   //  }  else  {    NSAssert1(NO, @"Invalid input dialog button %ld", button);  }}//----------------------------------------------------------------------------//open方式開啟- (IBAction)openDocument:(id)sender{    //開啟檔案查看  NSOpenPanel *openPanel = [NSOpenPanel openPanel];    //是否顯示面板封裝的檔案的目錄  [openPanel setTreatsFilePackagesAsDirectories:YES];    //設定為多選模式  [openPanel setAllowsMultipleSelection:YES];    //不可選擇檔案夾  [openPanel setCanChooseDirectories:NO];    //設定可以選擇檔案  [openPanel setCanChooseFiles:YES];    //設定代理為自身 調用 shouldShowFilename過濾開啟面板中的檔案  [openPanel setDelegate:self];    //警示風格視窗    //completionHandler參數為事件響應  [openPanel beginSheetModalForWindow:nil    completionHandler:^(NSInteger result)    {       //判斷點擊 ok     if (result != NSOKButton)      {       return;     }       //關閉面板之前,可能會出現錯誤       //移除視窗     [openPanel orderOut:self];       //遍曆所選的檔案路徑     for (NSURL * url in [openPanel URLs])     {         //全部開啟(通過多文檔模式)       [self application:NSApp openFile:[url path]];     }   }];}//----------------------------------------------------------------------------//協議-----過濾檔案- (BOOL)panel:(id)sender shouldShowFilename:(NSString*)filename{    //檔案 url  NSURL * url = [NSURL fileURLWithPath:filename];  // 判斷是否為檔案夾  NSNumber * isDirectory = nil;  [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL];  if ([isDirectory boolValue] == YES)   {    return YES;  }  // 跳過符號連結等    //判斷是否為一些符號連結  NSNumber * isRegularFile = nil;  [url getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:NULL];  if ([isRegularFile boolValue] == NO)   {    return NO;  }  // 檢查檔案的magic    //檔案控制代碼  NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:filename];   // NSLog(@"fileHandleForReadingAtPath----- %@!\n\n", filename);  //讀取指定的字元數  NSData * magicData = [fileHandle readDataOfLength:8];    // NSLog(@"magicData----- %@!\n\n", magicData);    //關閉控制代碼  [fileHandle closeFile];  //判斷長度  if ([magicData length] < sizeof(uint32_t))  {    return NO;  }  //比較  uint32_t magic = *(uint32_t*)[magicData bytes];    //NSLog(@"magic----- %8x!\n\n", magic);  if (magic == MH_MAGIC || magic == MH_MAGIC_64 ||       magic == FAT_CIGAM || magic == FAT_MAGIC)  {    return YES;  }  if ([magicData length] < sizeof(uint64_t))  {    return NO;  }  if (*(uint64_t*)[magicData bytes] == *(uint64_t*)"!<arch>\n")  {    return YES;  }  return NO;}//----------------------------------------------------------------------------//程式將啟動- (void)applicationWillFinishLaunching:(NSNotification *)aNotification{  BOOL isFirstMachOView = [self isOnlyRunningMachOView];  //禁用狀態恢複功能,這對MachOView來說不是很有用  if([[NSUserDefaults standardUserDefaults] objectForKey: @"ApplePersistenceIgnoreState"] == nil)      [[NSUserDefaults standardUserDefaults] setBool: YES forKey:@"ApplePersistenceIgnoreState"];  // load user‘s defaults for preferences//  if([[NSUserDefaults standardUserDefaults] objectForKey: @"UseLLVMDisassembler"] != nil)//    qflag = [[NSUserDefaults standardUserDefaults] boolForKey:@"UseLLVMDisassembler"];  //擷取一個檔案管理者  NSFileManager * fileManager = [NSFileManager defaultManager];  NSString * tempDir = [MVDocument temporaryDirectory];  __autoreleasing NSError * error;  //刪除以前被遺忘的臨時檔案  if (isFirstMachOView && [fileManager fileExistsAtPath:tempDir isDirectory:NULL] == YES)  {      //移除    if ([fileManager removeItemAtPath:tempDir error:&error] == NO)    {      [NSApp presentError:error];    }  }  //為臨時檔案建立預留位置    //返回一個布爾值,該值指示一個檔案或目錄是否存在於指定路徑  if ([fileManager fileExistsAtPath:tempDir isDirectory:NULL] == NO)  {      //建立一個帶有給定屬性的指定目錄路徑    if ([fileManager createDirectoryAtPath:tempDir               withIntermediateDirectories:NO                                attributes:nil                                     error:&error] == NO)    {        //調用錯誤對話方塊      [NSApp presentError:error];    }  }}//----------------------------------------------------------------------------//程式已啟動- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {#ifdef MV_STATISTICS  nrow_total = nrow_loaded = 0;    //開線程開始列印(用於調試忽視)  [NSThread detachNewThreadSelector:@selector(printStat) toTarget:self withObject:nil];#endif   //預設一開始就開啟檔案對話方塊  if ([[NSUserDefaults standardUserDefaults] objectForKey:@"OpenAtLaunch"] != nil)  {    if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OpenAtLaunch"] == YES)    {      if ([[[NSDocumentController sharedDocumentController] documents] count] == 0)      {        [self openDocument:nil];      }    }  }}//----------------------------------------------------------------------------//程式將結束- (void)applicationWillTerminate:(NSNotification *)aNotification{  BOOL isLastMachOView = [self isOnlyRunningMachOView];  if (isLastMachOView == YES)  {    //刪除臨時檔案    NSFileManager * fileManager = [NSFileManager defaultManager];      //返回目前使用者的臨時目錄    NSString * tempDir = [MVDocument temporaryDirectory];      //NSLog(@"Can‘t allocate mem for temp filename path! %@",tempDir);      //刪除    [fileManager removeItemAtPath:tempDir error:NULL];  }}//----------------------------------------------------------------------------//回呼函數 開啟檔案- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename{  NSLog (@"open file: %@", filename);  __autoreleasing NSError *error;    //擷取一個多文檔控制器  NSDocumentController * documentController = [NSDocumentController sharedDocumentController];    //NSDocumentController 建立管理多個MVDocument    //MVDocument 建立管理多個NSWindowController    //NSWindowController    //通過檔案路徑建立一個文檔 同時顯示(通過代理實現細節)    //MVDocument必須實現的函數有:    //視窗名稱    //- (NSString *)windowNibName;    //指定視窗控制器    //- (void)windowControllerDidLoadNib:(NSWindowController *)aController;    //必須實現建立和返回受支援類型的文檔資料,通常是將資料寫入NSData對象的檔案。    //- (NSData *)dataRepresentationOfType:(NSString *)aType;    //必須實現將NSData對象(包含特定類型的文檔資料)轉換為文檔的內部資料結構,以便文檔準備顯示其內容。NSData對象通常是從讀取文檔檔案的文檔中產生的。    //- (BOOL)loadDataRepresentation:(NSData *)data:(NSString *)aType;  MVDocument * document = [documentController openDocumentWithContentsOfURL:[NSURL fileURLWithPath:filename]                                                                     display:YES                                                                       error:&error];  //判斷是否能開啟文檔  if (!document)   {    [NSApp presentError:error];    return NO;  }  return YES;}//----------------------------------------------------------------------------//線程回調-(void) printStat{  for (;;)  {    NSLog(@"stat: %lld/%lld rows in memory\n",nrow_loaded,nrow_total);    [NSThread sleepForTimeInterval:1];  }}//----------------------------------------------------------------------------//系統喜好設定 (顯示一個nib)- (IBAction)showPreferencePanel:(id)sender{    if (!preferenceController)    {        preferenceController = [[MVPreferenceController alloc] init];    }    [preferenceController showWindow:self];}@end

MachOView源碼(AppController.mm)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.