From b166b11b8612a2428d7b86bd3dd27207a3f60dab Mon Sep 17 00:00:00 2001 From: "Jay Freeman (saurik)" Date: Sat, 31 Oct 2009 20:05:46 +0000 Subject: [PATCH] Completely reworked how process attach works: now the console is a server for the client, and it directly injects a payload into the attachee. --- Baton.hpp | 9 ++- Connector.cpp | 141 ----------------------------------------------- Console.cpp | 76 ++++++++++++++----------- Darwin-arm.mk | 20 +------ Darwin.mk | 10 +++- Library.cpp | 26 +++++++++ Mach/Inject.cpp | 43 +++++++++------ Trampoline.t.cpp | 6 +- 8 files changed, 118 insertions(+), 213 deletions(-) delete mode 100644 Connector.cpp diff --git a/Baton.hpp b/Baton.hpp index 45f0ec9..7aa7673 100644 --- a/Baton.hpp +++ b/Baton.hpp @@ -1,12 +1,19 @@ #include #include +#include struct Baton { void (*_pthread_set_self)(pthread_t); + int (*pthread_create)(pthread_t *, const pthread_attr_t *, void *(*)(void *), void *); - int (*pthread_detach)(pthread_t); + int (*pthread_join)(pthread_t, void **); + void *(*dlopen)(const char *, int); + void *(*dlsym)(void *, const char *); + mach_port_t (*mach_thread_self)(); kern_return_t (*thread_terminate)(thread_act_t); + + pid_t pid; char library[]; }; diff --git a/Connector.cpp b/Connector.cpp deleted file mode 100644 index 9d49a05..0000000 --- a/Connector.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* Cycript - Remove Execution Server and Disassembler - * Copyright (C) 2009 Jay Freeman (saurik) -*/ - -/* Modified BSD License {{{ */ -/* - * Redistribution and use in source and binary - * forms, with or without modification, are permitted - * provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the - * above copyright notice, this list of conditions - * and the following disclaimer. - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions - * and the following disclaimer in the documentation - * and/or other materials provided with the - * distribution. - * 3. The name of the author may not be used to endorse - * or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/* }}} */ - -#include - -#include "cycript.hpp" -#include "Pooling.hpp" - -#include -#include -#include -#include - -#include - -#include -#include - -#import - -void CYThrow(const char *format, ...) { - CYPool pool; - - va_list args; - va_start (args, format); - const char *message(apr_pvsprintf(pool, format, args)); - va_end (args); - - fprintf(stderr, "%s\n", message); - throw std::string(message); -} - -struct CYServer : - CYData -{ - int socket_; -}; - -apr_status_t CYPoolDLClose_(void *data) { - // XXX: this is an interesting idea - /* void *handle(reinterpret_cast(data)); - dlclose(handle); */ - return APR_SUCCESS; -} - -static void * APR_THREAD_FUNC Cyrver(apr_thread_t *thread, void *data) { - CYServer *server(reinterpret_cast(data)); - - for (;;) { - int socket(_syscall(accept(server->socket_, NULL, NULL))); - - if (void *handle = dlopen("/usr/lib/libcycript.dylib", RTLD_LAZY | RTLD_LOCAL)) { - apr_pool_t *pool; - _aprcall(apr_pool_create(&pool, NULL)); - - apr_pool_cleanup_register(pool, handle, &CYPoolDLClose_, &apr_pool_cleanup_null); - - if (void (*CYHandleClient_)(apr_pool_t *, int) = reinterpret_cast(dlsym(handle, "CYHandleClient"))) - (*CYHandleClient_)(pool, socket); - else - apr_pool_destroy(pool); - } else - CFLog(kCFLogLevelError, CFSTR("CY:Error: cannot load: %s"), dlerror()); - } - - delete server; - return NULL; -} - -static void Unlink() { - pid_t pid(getpid()); - char path[104]; - sprintf(path, "/tmp/.s.cy.%u", pid); - unlink(path); -} - -MSInitialize { - CFLog(kCFLogLevelError, CFSTR("CY:Notice: library loaded")); - - _aprcall(apr_initialize()); - - CYServer *server(new CYServer()); - server->socket_ = _syscall(socket(PF_UNIX, SOCK_STREAM, 0)); - - struct sockaddr_un address; - memset(&address, 0, sizeof(address)); - address.sun_family = AF_UNIX; - - pid_t pid(getpid()); - sprintf(address.sun_path, "/tmp/.s.cy.%u", pid); - - try { - _syscall(bind(server->socket_, reinterpret_cast(&address), SUN_LEN(&address))); - atexit(&Unlink); - _syscall(listen(server->socket_, 0)); - - apr_threadattr_t *attr; - _aprcall(apr_threadattr_create(&attr, server->pool_)); - - apr_thread_t *thread; - _aprcall(apr_thread_create(&thread, attr, &Cyrver, server, server->pool_)); - } catch (...) { - CFLog(kCFLogLevelError, CFSTR("CY:Error: cannot bind unix domain socket")); - } -} diff --git a/Console.cpp b/Console.cpp index 569157a..49952e4 100644 --- a/Console.cpp +++ b/Console.cpp @@ -113,11 +113,11 @@ void Setup(CYOutput &out, CYDriver &driver) { driver.program_->Replace(context); } -void Run(int socket, const char *data, size_t size, FILE *fout = NULL, bool expand = false) { +void Run(int client, const char *data, size_t size, FILE *fout = NULL, bool expand = false) { CYPool pool; const char *json; - if (socket == -1) { + if (client == -1) { mode_ = Running; #ifdef CY_EXECUTE json = CYExecute(pool, data); @@ -129,15 +129,15 @@ void Run(int socket, const char *data, size_t size, FILE *fout = NULL, bool expa size = strlen(json); } else { mode_ = Sending; - CYSendAll(socket, &size, sizeof(size)); - CYSendAll(socket, data, size); + CYSendAll(client, &size, sizeof(size)); + CYSendAll(client, data, size); mode_ = Waiting; - CYRecvAll(socket, &size, sizeof(size)); + CYRecvAll(client, &size, sizeof(size)); if (size == _not(size_t)) json = NULL; else { char *temp(new(pool) char[size + 1]); - CYRecvAll(socket, temp, size); + CYRecvAll(client, temp, size); temp[size] = '\0'; json = temp; } @@ -170,11 +170,11 @@ void Run(int socket, const char *data, size_t size, FILE *fout = NULL, bool expa } } -void Run(int socket, std::string &code, FILE *fout = NULL, bool expand = false) { - Run(socket, code.c_str(), code.size(), fout, expand); +void Run(int client, std::string &code, FILE *fout = NULL, bool expand = false) { + Run(client, code.c_str(), code.size(), fout, expand); } -static void Console(apr_pool_t *pool, int socket) { +static void Console(apr_pool_t *pool, int client) { passwd *passwd; if (const char *username = getenv("LOGNAME")) passwd = getpwnam(username); @@ -310,7 +310,7 @@ static void Console(apr_pool_t *pool, int socket) { if (driver.program_ == NULL) goto restart; - if (socket != -1) + if (client != -1) code = command; else { std::ostringstream str; @@ -327,7 +327,7 @@ static void Console(apr_pool_t *pool, int socket) { if (debug) std::cout << code << std::endl; - Run(socket, code, fout, expand); + Run(client, code, fout, expand); } _syscall(close(_syscall(open(histfile, O_CREAT | O_WRONLY, 0600)))); @@ -446,14 +446,14 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { size += read; if (size == sizeof(value)) { pid = _not(pid_t); - goto pclose; + goto fail; } } } size: if (size == 0) - goto pclose; + goto fail; if (value[size - 1] == '\n') { --size; goto size; @@ -462,10 +462,8 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { value[size] = '\0'; size = strlen(value); pid = strtoul(value, &end, 0); - if (value + size != end) + if (value + size != end) fail: pid = _not(pid_t); - - pclose: _syscall(pclose(pids)); } @@ -517,29 +515,41 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { } #endif - int socket; + int client; #ifdef CY_ATTACH if (pid == _not(pid_t)) - socket = -1; + client = -1; else { - InjectLibrary(pid); - - socket = _syscall(::socket(PF_UNIX, SOCK_STREAM, 0)); - - struct sockaddr_un address; - memset(&address, 0, sizeof(address)); - address.sun_family = AF_UNIX; - sprintf(address.sun_path, "/tmp/.s.cy.%u", pid); - - _syscall(connect(socket, reinterpret_cast(&address), SUN_LEN(&address))); + int server(_syscall(socket(PF_UNIX, SOCK_STREAM, 0))); try { + struct sockaddr_un address; + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + + sprintf(address.sun_path, "/tmp/.s.cy.%u", getpid()); + + _syscall(bind(server, reinterpret_cast(&address), SUN_LEN(&address))); + _syscall(chmod(address.sun_path, 0777)); + + try { + _syscall(listen(server, 1)); + InjectLibrary(pid); + client = _syscall(accept(server, NULL, NULL)); + } catch (...) { + // XXX: exception? + unlink(address.sun_path); + throw; + } + } catch (...) { + _syscall(close(server)); + } } #else - socket = -1; + client = -1; #endif if (script == NULL && tty) - Console(pool, socket); + Console(pool, client); else { CYDriver driver(script ?: ""); cy::parser parser(driver); @@ -574,8 +584,8 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { for (CYDriver::Errors::const_iterator i(driver.errors_.begin()); i != driver.errors_.end(); ++i) std::cerr << i->location_.begin << ": " << i->message_ << std::endl; } else if (driver.program_ != NULL) - if (socket != -1) - Run(socket, start, end - start, stdout); + if (client != -1) + Run(client, start, end - start, stdout); else { std::ostringstream str; CYOutput out(str); @@ -585,7 +595,7 @@ int Main(int argc, char const * const argv[], char const * const envp[]) { if (compile) std::cout << code; else - Run(socket, code, stdout); + Run(client, code, stdout); } } diff --git a/Darwin-arm.mk b/Darwin-arm.mk index 10e4289..cd3fcfb 100644 --- a/Darwin-arm.mk +++ b/Darwin-arm.mk @@ -1,35 +1,19 @@ flags += -F${PKG_ROOT}/System/Library/PrivateFrameworks -all += Cycript.$(dll) #cyrver +all += #cyrver arch := iphoneos-arm console += -framework UIKit depends += readline libffi mobilesubstrate sqlite3-lib -code += Handler.o -inject += Mach/Inject.o - -Mach/Inject.o: Trampoline.t.hpp Baton.hpp - -%.t.hpp: %.t.cpp - $(target)gcc -c -o $*.t.o $< && $(target)otool -s __TEXT __text $*.t.o | tail -n +3 | sed -e 's/^[^ ]* //;s/ $$//;s/ /\n/g' | sed -e 's/\(..\)\(..\)\(..\)\(..\)/0\x\4,0\x\3,0\x\2,0\x\1/' | tr '\n' ',' | sed -e '$$ s/,$$//; s/^/static const char $*_[] = {/;s/$$/};\n/' >$@ && rm -f $*.t.o ldid := ldid -S entitle := ldid -Scycript.xml -Cycript.$(dll): Connector.o - $(target)g++ $(flags) -dynamiclib -o $@ $(filter %.o,$^) \ - -lobjc -lapr-1 -lsubstrate \ - -framework CoreFoundation - ldid -S $@ - cyrver: Server.o $(target)g++ $(flags) -o $@ $(filter %.o,$^) \ -lapr-1 -lsubstrate -framework CFNetwork $(ldid) $@ extra: - mkdir -p package/System/Library/LaunchDaemons + #mkdir -p package/System/Library/LaunchDaemons #cp -a com.saurik.Cyrver.plist package/System/Library/LaunchDaemons - mkdir -p package/Library/MobileSubstrate/DynamicLibraries - cp -a Cycript.$(dll) package/Library/MobileSubstrate/DynamicLibraries - diff --git a/Darwin.mk b/Darwin.mk index bbb6691..a1773fd 100644 --- a/Darwin.mk +++ b/Darwin.mk @@ -1,7 +1,7 @@ # XXX: objective-c exists on non-Darwin dll := dylib -flags += -DCY_ATTACH -DCY_EXECUTE +flags += -DCY_EXECUTE link += -lobjc -framework CoreFoundation console += -framework Foundation library += -install_name /usr/lib/libcycript.$(dll) @@ -9,4 +9,12 @@ library += -framework Foundation -framework CFNetwork library += -framework JavaScriptCore -framework WebCore library += -lsubstrate -liconv +flags += -DCY_ATTACH +code += Handler.o +inject += Mach/Inject.o +Mach/Inject.o: Trampoline.t.hpp Baton.hpp + +%.t.hpp: %.t.cpp + $(target)gcc -c -o $*.t.o $< && { $(target)otool -l $*.t.o | sed -e '/^ *segname __TEXT$$/ { x; s/^ *sectname //; p; }; /^ *sectname / x; d;' | while read -r sect; do otool -s __TEXT "$$sect" Trampoline.t.o; done | sed -e '/:$$/ d; / section$$/ d; s/^[^ \t]*[ \t]*//;s/ $$//;s/ /\n/g' | sed -e 's/\(..\)\(..\)\(..\)\(..\)/0\x\4,0\x\3,0\x\2,0\x\1/' | tr '\n' ',' | sed -e '$$ s/,$$//; s/^/static const char $*_[] = {/;s/$$/};\n/' && echo && echo "/*" && $(target)otool -vVt $*.t.o && echo "*/"; } >$@ && rm -f $*.t.o + include ObjectiveC.mk diff --git a/Library.cpp b/Library.cpp index a981b2b..4cccc06 100644 --- a/Library.cpp +++ b/Library.cpp @@ -61,6 +61,11 @@ #include #include +#include +#include +#include +#include + #include "Parser.hpp" #include "Cycript.tab.hh" @@ -1449,6 +1454,27 @@ CYJSError::CYJSError(JSContextRef context, const char *format, ...) { CYThrow(context, exception); } +extern "C" void CYHandleServer(pid_t pid) { + CYInitialize(); + + int socket(_syscall(::socket(PF_UNIX, SOCK_STREAM, 0))); try { + struct sockaddr_un address; + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + sprintf(address.sun_path, "/tmp/.s.cy.%u", pid); + + _syscall(connect(socket, reinterpret_cast(&address), SUN_LEN(&address))); + + apr_pool_t *pool; + apr_pool_create(&pool, NULL); + + CYHandleClient(pool, socket); + } catch (const CYException &error) { + CYPool pool; + fprintf(stderr, "%s\n", error.PoolCString(pool)); + } +} + JSGlobalContextRef CYGetJSContext() { CYInitialize(); diff --git a/Mach/Inject.cpp b/Mach/Inject.cpp index ca1f07c..a2c5f04 100644 --- a/Mach/Inject.cpp +++ b/Mach/Inject.cpp @@ -7,6 +7,7 @@ extern "C" { #include #include +#include #include "Baton.hpp" #include "Exception.hpp" @@ -25,7 +26,8 @@ static void nlset(Type_ &function, struct nlist *nl, size_t index) { } void InjectLibrary(pid_t pid) { - const char *library("/Library/MobileSubstrate/DynamicLibraries/Cycript.dylib"); + // XXX: break this into the build environment + const char *library("/usr/lib/libcycript.dylib"); static const size_t Stack_(8 * 1024); size_t length(strlen(library) + 1), depth(sizeof(Baton) + length); @@ -33,14 +35,7 @@ void InjectLibrary(pid_t pid) { CYPool pool; uint8_t *local(reinterpret_cast(apr_palloc(pool, depth))); - Baton *baton(reinterpret_cast(local)); - baton->pthread_create = &pthread_create; - baton->pthread_detach = &pthread_detach; - baton->dlopen = &dlopen; - baton->mach_thread_self = &mach_thread_self; - baton->thread_terminate = &thread_terminate; - memcpy(baton->library, library, length); struct nlist nl[2]; memset(nl, 0, sizeof(nl)); @@ -48,6 +43,18 @@ void InjectLibrary(pid_t pid) { nlist("/usr/lib/libSystem.B.dylib", nl); nlset(baton->_pthread_set_self, nl, 0); + baton->pthread_create = &pthread_create; + baton->pthread_join = &pthread_join; + + baton->dlopen = &dlopen; + baton->dlsym = &dlsym; + + baton->mach_thread_self = &mach_thread_self; + baton->thread_terminate = &thread_terminate; + + baton->pid = getpid(); + memcpy(baton->library, library, length); + vm_size_t size(depth + Stack_); mach_port_t self(mach_task_self()), task; @@ -71,14 +78,19 @@ void InjectLibrary(pid_t pid) { #if defined(__arm__) arm_thread_state_t state; - memset(&state, 0, sizeof(state)); - flavor = ARM_THREAD_STATE; count = ARM_THREAD_STATE_COUNT; +#else + #error XXX: implement +#endif - _krncall(thread_get_state(thread, flavor, reinterpret_cast(&state), &count)); - _assert(count == ARM_THREAD_STATE_COUNT); + memset(&state, 0, sizeof(state)); + mach_msg_type_number_t read(count); + _krncall(thread_get_state(thread, flavor, reinterpret_cast(&state), &read)); + _assert(count == count); + +#if defined(__arm__) state.r[0] = data; state.r[1] = RTLD_LAZY | RTLD_GLOBAL; state.sp = stack + Stack_; @@ -88,15 +100,12 @@ void InjectLibrary(pid_t pid) { state.pc &= ~0x1; state.cpsr |= 0x20; } - - _krncall(thread_set_state(thread, flavor, reinterpret_cast(&state), count)); #else #error XXX: implement #endif + _krncall(thread_set_state(thread, flavor, reinterpret_cast(&state), count)); _krncall(thread_resume(thread)); - //_krncall(thread_create_running(task, flavor, reinterpret_cast(&state), count, &thread)); - - //_krncall(mach_port_deallocate(self, task)); + _krncall(mach_port_deallocate(self, task)); } diff --git a/Trampoline.t.cpp b/Trampoline.t.cpp index 8689df3..e56f350 100644 --- a/Trampoline.t.cpp +++ b/Trampoline.t.cpp @@ -13,13 +13,15 @@ extern "C" void Start(Baton *baton) { baton->pthread_create(&thread, NULL, &Routine, baton); void *result; - baton->pthread_detach(thread); + baton->pthread_join(thread, &result); baton->thread_terminate(baton->mach_thread_self()); } void *Routine(void *arg) { Baton *baton(reinterpret_cast(arg)); - baton->dlopen(baton->library, RTLD_LAZY | RTLD_GLOBAL); + void *handle(baton->dlopen(baton->library, RTLD_LAZY | RTLD_LOCAL)); + void (*HandleServer)(pid_t) = reinterpret_cast(baton->dlsym(handle, "CYHandleServer")); + HandleServer(baton->pid); return arg; } -- 2.45.2