]> git.saurik.com Git - cycript.git/commitdiff
Completely reworked how process attach works: now the console is a server for the...
authorJay Freeman (saurik) <saurik@saurik.com>
Sat, 31 Oct 2009 20:05:46 +0000 (20:05 +0000)
committerJay Freeman (saurik) <saurik@saurik.com>
Sat, 31 Oct 2009 20:05:46 +0000 (20:05 +0000)
Baton.hpp
Connector.cpp [deleted file]
Console.cpp
Darwin-arm.mk
Darwin.mk
Library.cpp
Mach/Inject.cpp
Trampoline.t.cpp

index 45f0ec92c2366d1f76864af558c6d20bd49c6df5..7aa7673f1195b38b696794220d7255ff3e318347 100644 (file)
--- a/Baton.hpp
+++ b/Baton.hpp
@@ -1,12 +1,19 @@
 #include <dlfcn.h>
 #include <mach/mach.h>
+#include <sys/types.h>
 
 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 (file)
index 9d49a05..0000000
+++ /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 <substrate.h>
-
-#include "cycript.hpp"
-#include "Pooling.hpp"
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/un.h>
-
-#include <apr_thread_proc.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#import <CoreFoundation/CFLogUtilities.h>
-
-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<void *>(data));
-    dlclose(handle); */
-    return APR_SUCCESS;
-}
-
-static void * APR_THREAD_FUNC Cyrver(apr_thread_t *thread, void *data) {
-    CYServer *server(reinterpret_cast<CYServer *>(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<void (*)(apr_pool_t *, int)>(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<sockaddr *>(&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"));
-    }
-}
index 569157a6dcc65bbfd49f46b8b238a0a0ac730dc0..49952e461b694ee04f076eaf7388ef63e84334fd 100644 (file)
@@ -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<sockaddr *>(&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<sockaddr *>(&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 ?: "<stdin>");
         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);
             }
     }
 
index 10e4289ff4a25ea999810af81e8d15b31c85c375..cd3fcfb119981d406bcb932de6c88e80abc7ae09 100644 (file)
@@ -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
-
index bbb669113dc095cb35eae6d3018b78db761eb986..a1773fd3a84325ac527cf1ce67b1b7c74d4b82da 100644 (file)
--- 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
index a981b2bcb8281322f68e62c41d591641a13cb9d3..4cccc06a6e401d54ebfdddb172c71aa33ac8843a 100644 (file)
 #include <sstream>
 #include <cmath>
 
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+
 #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<sockaddr *>(&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();
 
index ca1f07cfab097935bc6849c0ff81ae4970b4ae4f..a2c5f045c3abee148259ec3d255c43596f1c38cb 100644 (file)
@@ -7,6 +7,7 @@ extern "C" {
 
 #include <cstdio>
 #include <pthread.h>
+#include <unistd.h>
 
 #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<uint8_t *>(apr_palloc(pool, depth)));
-
     Baton *baton(reinterpret_cast<Baton *>(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<thread_state_t>(&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<thread_state_t>(&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<thread_state_t>(&state), count));
 #else
     #error XXX: implement
 #endif
 
+    _krncall(thread_set_state(thread, flavor, reinterpret_cast<thread_state_t>(&state), count));
     _krncall(thread_resume(thread));
 
-    //_krncall(thread_create_running(task, flavor, reinterpret_cast<thread_state_t>(&state), count, &thread));
-
-    //_krncall(mach_port_deallocate(self, task));
+    _krncall(mach_port_deallocate(self, task));
 }
index 8689df34bf74bbddc71375e95968a1d251aaf83c..e56f350cbc72749c34abb35bfb4e4fbf7e486703 100644 (file)
@@ -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<Baton *>(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<void (*)(pid_t)>(baton->dlsym(handle, "CYHandleServer"));
+    HandleServer(baton->pid);
     return arg;
 }