C/C++知识点之MachOView源码(AppController.mm)
小标 2019-04-22 来源 : 阅读 1841 评论 0

摘要:本文主要向大家介绍了C/C++知识点之MachOView源码(AppController.mm),通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。

本文主要向大家介绍了C/C++知识点之MachOView源码(AppController.mm),通过具体的内容向大家展示,希望对大家学习C/C++知识点有所帮助。


//AppController.h

/*
 *  AppController.h
 *  MachOView
 *
 *  Created by psaghelyi on 15/06/2010.
 *
 */#import @class MVPreferenceController;@interface MVAppController : NSObject {
  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*)""!\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

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标编程语言C/C+频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved