#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[];
};
+++ /dev/null
-/* 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"));
- }
-}
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);
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;
}
}
}
-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);
if (driver.program_ == NULL)
goto restart;
- if (socket != -1)
+ if (client != -1)
code = command;
else {
std::ostringstream str;
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))));
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;
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));
}
}
#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);
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);
if (compile)
std::cout << code;
else
- Run(socket, code, stdout);
+ Run(client, code, stdout);
}
}
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
-
# 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)
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
#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"
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();
#include <cstdio>
#include <pthread.h>
+#include <unistd.h>
#include "Baton.hpp"
#include "Exception.hpp"
}
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);
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));
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;
#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_;
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));
}
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;
}