使用cynject打造一个注入工具

Cydia Substrate框架提供了一个cynject工具,位于/usr/bin目录,使用它可以注入任意进程。
本文将这个工具封装一下:
给定一个PID及dylib,如果进程未运行则一直等待,如果运行了则直接注入dylib。

0x01 源代码

#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/param.h>
#include <mach/mach.h>
#include <mach/boolean.h>
#include <dispatch/dispatch.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <spawn.h>
#include <assert.h>

extern char ***_NSGetEnviron(void);
extern int proc_listallpids(void *, int);
extern int proc_pidpath(int, void *, uint32_t);

static const char *cynject_path = "/usr/bin/cynject";
static const char *dispatch_queue_name = NULL;
static int process_buffer_size = 4096;
static pid_t process_pid = -1;

static boolean_t find_process(const char *name, pid_t *ppid_ret) {
    pid_t *pid_buffer;
    char path_buffer[MAXPATHLEN];
    int count, i, ret;
    boolean_t res = FALSE;
    
    pid_buffer = (pid_t *)calloc(1, process_buffer_size);
    assert(pid_buffer != NULL);
    
    count = proc_listallpids(pid_buffer, process_buffer_size);
    if (count) {
        for (i = 0; i < count; i++) {
            pid_t ppid = pid_buffer[i];
            
            ret = proc_pidpath(ppid, (void *)path_buffer, sizeof(path_buffer));
            if (ret < 0) {
                printf("(%s:%d) proc_pidinfo() call failed.\n", __FILE__, __LINE__);
                continue;
            }
            
            if (strstr(path_buffer, name)) {
                res = TRUE;
                *ppid_ret = ppid;
                break;
            }
        }
    }
    
    free(pid_buffer);
    return res;
}

static void inject_dylib(const char *name, pid_t pid, const char *dylib) {
    char **argv;
    char pid_buf[32];
    int res;
    pid_t child;
    
    argv = calloc(4, sizeof(char *));
    assert(argv != NULL);
    
    snprintf(pid_buf, sizeof(pid_buf), "%d", pid);
    
    argv[0] = (char *)name;
    argv[1] = (char *)pid_buf;
    argv[2] = (char *)dylib;
    argv[3] = NULL;
    
    printf("(%s:%d) calling \"%s %s %s\"\n", __FILE__, __LINE__, argv[0], argv[1], argv[2]);
    
    res = posix_spawn(&child, argv[0], NULL, NULL, argv, (char * const *)_NSGetEnviron());
    assert(res == 0);
    
    return;
}

int main(int argc, char *argv[]) {
    printf("***** pp_inject by piaoyun ***** \n");

    if (geteuid() != 0) {
        printf("FATAL: must be run as root.\n");
        return 1;
    }
    
    if (argc < 3 ) {
        printf("FATAL: ppinject <pid> <dylib>.\n");
        return 2;
    }
    
    const char *process_name = argv[1];
    const char *dylib_path = argv[2];
    
    
    printf("Creating queue...\n");
    dispatch_queue_t queue = dispatch_queue_create(dispatch_queue_name, 0);
    
    printf("Finding %s PID...\n", process_name);
    dispatch_async(queue, ^{ while (!find_process(process_name, &process_pid)); });
    
    printf("Waiting for queue to come back...\n");
    dispatch_sync(queue, ^{});
    
    printf("%s PID is %d\n", process_name, process_pid);
    
    printf("Injecting %s into %s...\n", dylib_path, process_name);
    inject_dylib(cynject_path, process_pid, dylib_path);
    
    return 0;
}

0x02 Makefile

Makefile里面增加一些自定义配置,增加签名

THEOS_DEVICE_IP = localhost
THEOS_DEVICE_PORT = 2222
ARCHS = arm64
SDVERSION = latest
TARGET = iphone:latest:8.0

include $(THEOS)/makefiles/common.mk

TOOL_NAME = ppinject
ppinject_FILES = main.c
ppinject_CFLAGS += -fvisibility=hidden
ppinject_INSTALL_PATH = /usr/bin
ppinject_CODESIGN_FLAGS = -S./entitlements.xml

include $(THEOS_MAKE_PATH)/tool.mk

0x03 支持iOS11

签名描述里面加入platform-application支持iOS11

<?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>platform-application</key>
    <true/>
</dict>
</plist>

0x04 编译安装

# piao @ PiaodeMacBook-Pro in ~/Desktop/ppinject [14:30:10]
$ DEBUG=0 make clean && make package && make install
==> Cleaning…
> Making all for tool ppinject…
==> Compiling main.c (arm64)…
==> Linking tool ppinject (arm64)…
==> Generating debug symbols for ppinject…
==> Merging tool ppinject…
==> Signing ppinject…
> Making stage for tool ppinject…
dm.pl: building package `com.chinapyg.ppinject:iphoneos-arm' in `./packages/com.chinapyg.ppinject_0.0.1-5+debug_iphoneos-arm.deb'
==> Installing…

0x05 测试

测试ppinject

0x06 参考代码

本工具修改自asu_inject.c,对原作者表示感谢。

你可能感兴趣的文章

评论区

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。