Created
April 19, 2018 08:10
-
-
Save rainyx/8cad2de594767d1be1c8884603ecc72f to your computer and use it in GitHub Desktop.
Dylib Remote Injection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.c | |
// swinjector | |
// | |
// Created by rainyx on 13-7-24. | |
// Copyright (c) 2013年 __MyCompanyName__. All rights reserved. | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <dlfcn.h> | |
#include <mach/mach.h> | |
#include <mach/machine/thread_status.h> | |
#include <pthread.h> | |
#define CPSR_T_MASK (1u<<5) | |
struct INJECT_CONTEXT | |
{ | |
unsigned int _pthreadStruct; | |
void (*__pthread_set_self)(pthread_t); | |
int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); | |
int (*pthread_join)(pthread_t, void **); | |
mach_port_t (*mach_thread_self)(); | |
kern_return_t (*thread_terminate)(thread_act_t); | |
const char *library; | |
void *(*dlopen)(const char *, int); | |
} INJECT_CONTEXT; | |
int main (int argc, const char * argv[]) | |
{ | |
if(argc!=3) | |
{ | |
printf("Usage: <PID> <Dynamic library path>\n"); | |
return 0; | |
} | |
const char *library = argv[2]; | |
mach_port_t self = mach_task_self(); | |
mach_port_t remoteTask; | |
pid_t pid = (pid_t)strtoul(argv[1], NULL, 10); | |
task_for_pid(mach_task_self(), pid, &remoteTask); | |
if(!remoteTask) | |
{ | |
printf("Failed: task_for_pid, pid: %d(0x%X).\n", pid, pid); | |
return 0; | |
} | |
// 分配栈空间 | |
vm_address_t remoteStack; | |
vm_size_t stackSize = 16*1024; | |
vm_allocate(remoteTask, &remoteStack, stackSize, TRUE); | |
// 写入library字符串 | |
vm_size_t libraryLen = strlen(library); | |
vm_address_t remoteLibrary; | |
vm_allocate(remoteTask, &remoteLibrary, libraryLen, TRUE); | |
vm_write(remoteTask, remoteLibrary, library, (mach_msg_type_number_t)libraryLen); | |
// 分配_pthread struct空间 | |
vm_address_t remotePthreadStruct; | |
vm_size_t pthreadStructSize = 1024; | |
vm_allocate(remoteTask, &remotePthreadStruct, pthreadStructSize, TRUE); | |
// 写入Context | |
struct INJECT_CONTEXT context; | |
extern void __pthread_set_self(pthread_t); | |
context.library = remoteLibrary; | |
context._pthreadStruct = (unsigned int)remotePthreadStruct; | |
context.__pthread_set_self = &__pthread_set_self; | |
context.thread_terminate = &thread_terminate; | |
context.mach_thread_self = &mach_thread_self; | |
context.pthread_create = &pthread_create; | |
context.pthread_join = &pthread_join; | |
context.dlopen = &dlopen; | |
vm_size_t contextSize = sizeof(INJECT_CONTEXT); | |
vm_address_t remoteContext; | |
vm_allocate(remoteTask, &remoteContext, contextSize, TRUE); | |
vm_write(remoteTask, remoteContext, &context, (mach_msg_type_number_t)contextSize); | |
// 写入Code | |
unsigned char code[124] = { | |
0x80, 0x40, 0x2D, 0xE9, 0x08, 0xD0, 0x4D, 0xE2, 0x00, 0x70, 0xA0, 0xE1, 0x00, 0x00, 0x97, 0xE5, | |
0x00, 0x00, 0x80, 0xE5, 0x04, 0x10, 0x97, 0xE5, 0x31, 0xFF, 0x2F, 0xE1, 0x0D, 0x00, 0xA0, 0xE1, | |
0x00, 0x10, 0xA0, 0xE3, 0x30, 0x20, 0x8F, 0xE2, 0x07, 0x30, 0xA0, 0xE1, 0x08, 0x40, 0x97, 0xE5, | |
0x34, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0x9D, 0xE5, 0x04, 0x10, 0x8D, 0xE2, 0x0C, 0x20, 0x97, 0xE5, | |
0x32, 0xFF, 0x2F, 0xE1, 0x10, 0x10, 0x97, 0xE5, 0x31, 0xFF, 0x2F, 0xE1, 0x14, 0x10, 0x97, 0xE5, | |
0x31, 0xFF, 0x2F, 0xE1, 0x08, 0xD0, 0x8D, 0xE2, 0x80, 0x80, 0xBD, 0xE8, 0x80, 0x40, 0x2D, 0xE9, | |
0x00, 0x70, 0xA0, 0xE1, 0x18, 0x00, 0x97, 0xE5, 0x02, 0x10, 0xA0, 0xE3, 0x1C, 0x20, 0x97, 0xE5, | |
0x32, 0xFF, 0x2F, 0xE1, 0x00, 0x00, 0xA0, 0xE3, 0x80, 0x80, 0xBD, 0xE8 | |
}; | |
vm_size_t codeSize = 124; | |
vm_address_t remoteCode; | |
vm_allocate(remoteTask, &remoteCode, codeSize, TRUE); | |
vm_write(remoteTask, remoteCode, &code, (mach_msg_type_number_t)codeSize); | |
vm_protect(remoteTask, remoteCode, codeSize, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); | |
// 创建远程线程 | |
arm_thread_state_t state; | |
memset(&state, 0, sizeof(state)); | |
state.__r[0] = (__uint32_t)remoteContext; | |
state.__pc = (__uint32_t)remoteCode; | |
state.__sp = (__uint32_t)(remoteStack + stackSize/2); | |
if (state.__pc & 0x1) | |
{ | |
state.__pc &= ~0x1; | |
state.__cpsr |= CPSR_T_MASK; | |
} | |
else | |
{ | |
state.__cpsr &= ~CPSR_T_MASK; | |
} | |
// 启动线程 | |
thread_act_t remoteThread; | |
thread_create_running(remoteTask, ARM_THREAD_STATE, (thread_state_t) &state, ARM_THREAD_STATE_COUNT, &remoteThread); | |
//printf("Remote thread is running.\n"); | |
// 等待线程结束,释放资源 | |
thread_state_flavor_t flavor; | |
mach_msg_type_number_t count; | |
flavor = ARM_THREAD_STATE; | |
count = ARM_THREAD_STATE_COUNT; | |
mach_msg_type_number_t read; | |
kern_return_t status; | |
while (true) | |
{ | |
read = count; | |
status = thread_get_state(remoteThread, flavor, (thread_state_t)&state, &read); | |
if(status == KERN_SUCCESS) | |
{ | |
usleep(10000); | |
continue; | |
} | |
else if(status == KERN_TERMINATED || status == MACH_SEND_INVALID_DEST) | |
{ | |
break; | |
} | |
else | |
{ | |
// TODO on error. | |
} | |
} | |
if(remoteThread) | |
mach_port_deallocate(self, remoteThread); | |
if(remoteCode) | |
vm_deallocate(remoteTask, remoteCode, codeSize); | |
if(remotePthreadStruct) | |
vm_deallocate(remoteTask, remotePthreadStruct, pthreadStructSize); | |
if(remoteLibrary) | |
vm_deallocate(remoteTask, remoteLibrary, libraryLen); | |
if(remoteContext) | |
vm_deallocate(remoteTask, remoteContext, contextSize); | |
if(remoteStack) | |
vm_deallocate(remoteTask, remoteStack, stackSize); | |
printf("Injected successfully!\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment