1.静态注入
https://cloud.tencent.com/developer/article/1193647
insert_dylib 将dylib注入到二进制文件中生成新的二进制。
2.DYLD_INSERT_LIBRARIES动态注入
https://blog.nswebfrog.com/2018/02/09/make-injection-app-for-mac/
- xcode创建一个dynamic的的项目
主要注入的代码如下:
#import "libwechatInject.h"
@implementation libwechatInject
__attribute__((constructor)) void myentry() {
NSLog(@"AAAAAAAAAAAAAAAAAAAAAAA!!!");
}
@end
- 新建要重启动的项目app
放置我们要注入的动态链接库,新建一个文件夹,命名为 WeChatInject.app,并创建一个子文件夹,名字叫 Contents 在 WeChatInject.app/Contents 下创建一个名为 Frameworks 的文件夹,将动态链接库 libQQInject.dylib 拷贝到这个文件夹中。
编写好启动脚本
在 WeChat.app/Contents 下新建文件夹 MacOS,然后在这个文件夹下新建一个 shell 脚本文件,名字为 WeChatInject 并赋予执行权限
#!/bin/sh
CurrentAppPath=$(cd $(dirname $0) && cd .. && pwd)
DYLD_INSERT_LIBRARIES=${CurrentAppPath}/Frameworks/liblibwechatInject.dylib /Applications/WeChat.app/Contents/MacOS/WeChat
3.运行App
双击WeChatInject运行即可。最后可以在系统控制台打印的日志中看到我们的自定义的hook消息。注意有时消息出现在控制台。
4.修改系统 Dock 图标
首先发现的一个问题就是,App 运行后,系统 Dock 图标不是 WeChat 的图标,而是一个默认的应用图标。解决这个问题办法就是在 WeChatInject.app/Contents 下新建一个 Info.plist 文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LSUIElement</key>
<true/>
</dict>
</plist>
再次运行 WeChatInject.app 后,系统 Dock 上已经是 WeChat 的图标了。
3.使用动态库注入
osx dylib injection 向进程中注入dylib 不动原二进制,高权限无修改的注入。
https://github.com/scen/osxinj
用法:Usage: ./osxinj [proc_name] [lib]
一种hook方案
计算新旧函数之间的距离 进行跳转
http://thomasfinch.me/blog/2015/07/24/Hooking-C-Functions-At-Runtime.html
#include <stdio.h>
#include <dlfcn.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
//Set this to 0 if you don't want to see log messages
const int PRINT_INFO = 1;
int hookReplacementFunction() {
printf("Calling replacement function!\n");
return 3;
}
//Print the first 16 bytes after the given address
static void printBytes(int64_t *address) {
int i;
for (i = 0; i < 4; i++) {
printf("*(address+%d):\t%08x\n", i * 4, htonl((int)*(address+i)));
}
}
__attribute__((constructor))
static void ctor(void) {
if (PRINT_INFO)
printf("Injection dylib constructor called.\n");
//"If filename is NULL, then the returned handle is for the main program."
void *mainProgramHandle = dlopen(NULL, RTLD_NOW);
//Get a pointer to the original function using dlsym
int64_t *origFunc = dlsym(mainProgramHandle , "hookTargetFunction");
if (PRINT_INFO)
printf("Original function address: 0x%llx\n", (int64_t)origFunc);
//Get a pointer to the replacement function
int64_t *newFunc = (int64_t*)&hookReplacementFunction;
if (PRINT_INFO)
printf("Replacement function address: 0x%llx\n", (int64_t)newFunc);
//Calculate the relative offset needed for the jump instruction
//Since relative jumps are calculated from the address of the next instruction,
// 5 bytes must be added to the original address (jump instruction is 5 bytes)
int32_t offset = (int64_t)newFunc - ((int64_t)origFunc + 5 * sizeof(char));
if (PRINT_INFO)
printf("Offset: 0x%x\n", offset);
//Make the memory containing the original funcion writable
//Code from http://stackoverflow.com/questions/20381812/mprotect-always-returns-invalid-arguments
size_t pageSize = sysconf(_SC_PAGESIZE);
uintptr_t start = (uintptr_t)origFunc;
uintptr_t end = start + 1;
uintptr_t pageStart = start & -pageSize;
mprotect((void *)pageStart, end - pageStart, PROT_READ | PROT_WRITE | PROT_EXEC);
if (PRINT_INFO) {
printf("Before replacement: \n");
printBytes(origFunc);
}
//Set the first instruction of the original function to be a jump
// to the replacement function.
//E9 is the x86 opcode for an unconditional relative jump
int64_t instruction = 0xe9 | offset << 8;
*origFunc = instruction;
if (PRINT_INFO) {
printf("After replacement: \n");
printBytes(origFunc);
}
}
参考:
https://www.exchen.net/ios-hacker-动态库-dylib-注入.html
https://wooyun.js.org/drops/OS X平台的Dylib劫持技术(下).html
hook:
https://theevilbit.github.io/posts/dyld_insert_libraries_dylib_injection_in_macos_osx_deep_dive/