利用Mac OSX注入技术编写插件/外挂的实现

之前就有朋友在我的博客留言问我是否研究过OSX的注入技术,前不久,有幸与新浪的一位技术总监聊天又提到这个话题,这样一来,我对注入不感兴趣都不行了。

其实早在他们提及这个话题之前,我就尝试过相关的技术研究,当然我所谓的研究也不过是在学习怎样使用别人已经造好的”车轮”,对于OSX的注入已经有非常有名的开源库叫做mach_inject(GitHub跳转),但因为这个项目更新并不及时,加上作者写的代码非常有技术泛儿,所以第一次Clone下来使用并不顺畅,出现了很多错误,于是就搁置在一边了,直到这两天上班比较空闲,我又搬出来折腾了,终于把整个过程理顺了,并成功的注入了Finder。

首先解释一下何为注入,注入就是从外部把可执行的代码片段载入到目标进程的技术,大家肯定对SQL注入不陌生吧,其实这个概念就是相通的,对于桌面程序,如OSX上运行的程序,我们合理的利用注入技术就可以方便的为第三方程序编写插件/外挂。比如目前大名鼎鼎的DropBox的OSX客户端程序就是利用了注入将DropBox与Finder合理的整合在了一起,直接在Finder中就可以对本地和远程的文件进行操作,如下图:

dropbox

当然注入只是第一步,要实现像DropBox这样给文件和文件夹打上标识、在右键菜单中添加自定义的功能,还需要很长的路要走,首先要对OSX的编程非常了解,然后需要经过很多的注入测试来了解目标程序本身的逻辑,然后利用比如RunTime的特性加入这些高级功能。

下面就通过一个我今天编写的实例Demo来完整的走一遍注入的全过程(相关代码在末尾),下图是整个工程的目录:

mach_inject_1

其中mach_inject、mach_inject_bundle、mach_inject_bundle_stub是GitHub上Clone下来的mach_inject原工程的三个目录,我们的工程最终需要依赖于mach_inject_bundle,它的编译结果是一个framework,我们只需要这个framework就足以,但我们可以了解一下这三个目录的关联:mach_inject_bundle工程依赖于mach_inject_bundle_stub工程编译结果,而这两个工程中都会使用到mach_inject中的代码,本文提供的测试工程我已经在原工程中对工程配置进行了一些修改,并且修改了几处编译会出错的代码(这几处修改花费了我不少的时间)。

mach_inject_finder是我们注入Finder程序所有逻辑的工程,其中包括两个Target,第一个Target叫做mach_inject_finder_plugin,它是一个插件,目前里面就只有一个主类,该类所负责的工作就是注入到Finder之后要做的所有事情(该测试工程最终结果是改变Finder所有窗口的Title为“已经注入成功!”这句话,并在控制台打印出窗口的视图层级关系图),下面贴出该类的所有代码,非常的简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
+ ( id )enumView:( NSView *)aView
{
     NSMutableArray *array = [ NSMutableArray array];
     NSArray *subViews = [aView subviews];
     for ( NSView *subView in subViews)
     {
         id result = [ self enumView:subView];
         if (result)
         {
             [array addObject:result];
         }
     }
     return [ NSDictionary dictionaryWithObject:array forKey: NSStringFromClass (aView. class )];
}
 
+ ( void )load
{
     NSArray *windows = [ NSApp windows];
     if ([windows count] > 0)
     {
         for ( NSWindow *aWindow in windows)
         {
             [aWindow setTitle: @"已经注入成功!" ];
             //此为Finder的窗口
             if ([ NSStringFromClass (aWindow. class ) isEqualToString: @"TBrowserWindow" ])
             {
                 NSLog ( @"视图的层级关系图:%@" ,[ self enumView:aWindow.contentView]);
             }
         }
     }
}

这个工程另一个Target叫做mach_inject_finder,它所负责的就是调用mach_inject_bundle.framework中的方法,并将mach_inject_finder_plugin做为参数传递给framework,实现注入,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//获取finder的pid
NSArray *finderApps = [ NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.apple.finder" ];
if ([finderApps count] == 0) return ;
NSRunningApplication *finderApplication = [finderApps objectAtIndex:0];
pid_t process_id = [finderApplication processIdentifier];
 
//开始注入
NSString *injectedBundlePath = [[ NSBundle mainBundle] pathForResource: @"mach_inject_finder_plugin"
                                                                ofType: @"bundle" ];
assert ( injectedBundlePath );
 
mach_error_t err = mach_inject_bundle_pid( [injectedBundlePath fileSystemRepresentation],
                                           process_id );
assert (!err);

最后还有一个工程叫做mach_inject_finder_loader,并且它也是我们这个测试程序的入口,它的原理更简单,就是mach_inject_finder的一个启动器,因为要使用注入,程序就必须通过ROOT权限打开,所以这个启动器的原理就是通过STPrivilegedTask来使用ROOT权限打开mach_inject_finder程序而已。

PS:不能对同一进程多次注入,所以测试工程运行一次之后想要再次测试就需要将Finder进程重启才行。

测试工程最终结果截图(见Window的Title变化):

mach_inject_2

转自:http://www.tanhao.me/code/1005.html?replytocom=960

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值