mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Merge pull request #1432 from pchaigno/cycript
Support for Cycript language
This commit is contained in:
		@@ -479,6 +479,12 @@ Cuda:
 | 
				
			|||||||
  - .cu
 | 
					  - .cu
 | 
				
			||||||
  - .cuh
 | 
					  - .cuh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Cycript:
 | 
				
			||||||
 | 
					  type: programming
 | 
				
			||||||
 | 
					  lexer: JavaScript
 | 
				
			||||||
 | 
					  extensions:
 | 
				
			||||||
 | 
					  - .cy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Cython:
 | 
					Cython:
 | 
				
			||||||
  type: programming
 | 
					  type: programming
 | 
				
			||||||
  group: Python
 | 
					  group: Python
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,580 @@
 | 
				
			|||||||
 | 
					(function(utils) {
 | 
				
			||||||
 | 
						// Load C functions declared in utils.loadFuncs
 | 
				
			||||||
 | 
						var shouldLoadCFuncs = true;
 | 
				
			||||||
 | 
						// Expose the C functions to cycript's global scope
 | 
				
			||||||
 | 
						var shouldExposeCFuncs = true;
 | 
				
			||||||
 | 
						// Expose C constants to cycript's global scope
 | 
				
			||||||
 | 
						var shouldExposeConsts = true;
 | 
				
			||||||
 | 
						// Expose functions defined here to cycript's global scope
 | 
				
			||||||
 | 
						var shouldExposeFuncs = true;
 | 
				
			||||||
 | 
						// Which functions to expose
 | 
				
			||||||
 | 
						var funcsToExpose = ["exec", "include", "sizeof", "logify", "apply", "str2voidPtr", "voidPtr2str", "double2voidPtr", "voidPtr2double", "isMemoryReadable", "isObject", "makeStruct"];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// C functions that utils.loadFuncs loads
 | 
				
			||||||
 | 
						var CFuncsDeclarations = [
 | 
				
			||||||
 | 
							// <stdlib.h>
 | 
				
			||||||
 | 
							"void *calloc(size_t num, size_t size)",
 | 
				
			||||||
 | 
							// <string.h>
 | 
				
			||||||
 | 
							"char *strcpy(char *restrict dst, const char *restrict src)",
 | 
				
			||||||
 | 
							"char *strdup(const char *s1)",
 | 
				
			||||||
 | 
							"void* memset(void* dest, int ch, size_t count)",
 | 
				
			||||||
 | 
							// <stdio.h>
 | 
				
			||||||
 | 
							"FILE *fopen(const char *, const char *)",
 | 
				
			||||||
 | 
							"int fclose(FILE *)",
 | 
				
			||||||
 | 
							"size_t fread(void *restrict, size_t, size_t, FILE *restrict)",
 | 
				
			||||||
 | 
							"size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict)",
 | 
				
			||||||
 | 
							// <mach.h>
 | 
				
			||||||
 | 
							"mach_port_t mach_task_self()",
 | 
				
			||||||
 | 
							"kern_return_t task_for_pid(mach_port_name_t target_tport, int pid, mach_port_name_t *tn)",
 | 
				
			||||||
 | 
							"kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection)",
 | 
				
			||||||
 | 
							"kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt)",
 | 
				
			||||||
 | 
							"kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt)",
 | 
				
			||||||
 | 
						];
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Replacement for eval that can handle @encode etc.
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.exec("@encode(void *(int, char))")
 | 
				
			||||||
 | 
								@encode(void*(int,char))
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.exec = function(str) {
 | 
				
			||||||
 | 
							var mkdir = @encode(int (const char *, int))(dlsym(RTLD_DEFAULT, "mkdir"));
 | 
				
			||||||
 | 
							var tempnam = @encode(char *(const char *, const char *))(dlsym(RTLD_DEFAULT, "tempnam"));
 | 
				
			||||||
 | 
							var fopen = @encode(void *(const char *, const char *))(dlsym(RTLD_DEFAULT, "fopen"));
 | 
				
			||||||
 | 
							var fclose = @encode(int (void *))(dlsym(RTLD_DEFAULT, "fclose"));
 | 
				
			||||||
 | 
							var fwrite = @encode(int (const char *, int, int, void *))(dlsym(RTLD_DEFAULT, "fwrite"));
 | 
				
			||||||
 | 
							var symlink = @encode(int (const char *, const char *))(dlsym(RTLD_DEFAULT, "symlink"));
 | 
				
			||||||
 | 
							var unlink = @encode(int (const char *))(dlsym(RTLD_DEFAULT, "unlink"));
 | 
				
			||||||
 | 
							var getenv = @encode(const char *(const char *))(dlsym(RTLD_DEFAULT, "getenv"));
 | 
				
			||||||
 | 
							var setenv = @encode(int (const char *, const char *, int))(dlsym(RTLD_DEFAULT, "setenv"));
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var libdir = "/usr/lib/cycript0.9";
 | 
				
			||||||
 | 
							var dir = libdir + "/tmp";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mkdir(dir, 0777);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// This is needed because tempnam seems to ignore the first argument on i386
 | 
				
			||||||
 | 
							var old_tmpdir = getenv("TMPDIR");
 | 
				
			||||||
 | 
							setenv("TMPDIR", dir, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// No freeing :(
 | 
				
			||||||
 | 
							var f = tempnam(dir, "exec-");
 | 
				
			||||||
 | 
							setenv("TMPDIR", old_tmpdir, 1);
 | 
				
			||||||
 | 
							if(!f) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							symlink(f, f + ".cy");
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							str = "exports.result = " + str;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var handle = fopen(f, "w");
 | 
				
			||||||
 | 
							fwrite(str, str.length, 1, handle);
 | 
				
			||||||
 | 
							fclose(handle);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var r;
 | 
				
			||||||
 | 
							var except = null;
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								r = require(f.replace(libdir + "/", ""));
 | 
				
			||||||
 | 
							} catch(e) {
 | 
				
			||||||
 | 
								except = e;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							unlink(f + ".cy");
 | 
				
			||||||
 | 
							unlink(f);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(except !== null) {
 | 
				
			||||||
 | 
								throw except;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return r.result;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Applies known typedefs
 | 
				
			||||||
 | 
							Used in utils.include and utils.makeStruct
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.applyTypedefs("mach_vm_address_t")
 | 
				
			||||||
 | 
								"uint64_t"
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.applyTypedefs = function(str) {
 | 
				
			||||||
 | 
							var typedefs = {
 | 
				
			||||||
 | 
								"struct": "",
 | 
				
			||||||
 | 
								"restrict": "",
 | 
				
			||||||
 | 
								"FILE": "void",
 | 
				
			||||||
 | 
								"size_t": "uint64_t",
 | 
				
			||||||
 | 
								"uintptr_t": "unsigned long",
 | 
				
			||||||
 | 
								"kern_return_t": "int",
 | 
				
			||||||
 | 
								"mach_port_t": "unsigned int",
 | 
				
			||||||
 | 
								"mach_port_name_t": "unsigned int",
 | 
				
			||||||
 | 
								"vm_offset_t": "unsigned long",
 | 
				
			||||||
 | 
								"vm_size_t": "unsigned long",
 | 
				
			||||||
 | 
								"mach_vm_address_t": "uint64_t",
 | 
				
			||||||
 | 
								"mach_vm_offset_t": "uint64_t",
 | 
				
			||||||
 | 
								"mach_vm_size_t": "uint64_t",
 | 
				
			||||||
 | 
								"vm_map_offset_t": "uint64_t",
 | 
				
			||||||
 | 
								"vm_map_address_t": "uint64_t",
 | 
				
			||||||
 | 
								"vm_map_size_t": "uint64_t",
 | 
				
			||||||
 | 
								"mach_port_context_t": "uint64_t",
 | 
				
			||||||
 | 
								"vm_map_t": "unsigned int",
 | 
				
			||||||
 | 
								"boolean_t": "unsigned int",
 | 
				
			||||||
 | 
								"vm_prot_t": "int",
 | 
				
			||||||
 | 
								"mach_msg_type_number_t": "unsigned int",
 | 
				
			||||||
 | 
								"cpu_type_t": "int",
 | 
				
			||||||
 | 
								"cpu_subtype_t": "int",
 | 
				
			||||||
 | 
								"cpu_threadtype_t": "int",
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							for(var k in typedefs) {
 | 
				
			||||||
 | 
								str = str.replace(new RegExp("(\\s|\\*|,|\\(|^)" + k + "(\\s|\\*|,|\\)|$)", "g"), "$1" + typedefs[k] + "$2");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return str;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Parses a C function declaration and returns the function name and cycript type
 | 
				
			||||||
 | 
							If load is true, tries to load it into cycript using utils.exec
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# var str = "void *calloc(size_t num, size_t size)";
 | 
				
			||||||
 | 
								"void *calloc(size_t num, size_t size)"
 | 
				
			||||||
 | 
								cy# utils.include(str)
 | 
				
			||||||
 | 
								["calloc","@encode(void *(uint64_t num,  uint64_t size))(140735674376857)"]
 | 
				
			||||||
 | 
								cy# var ret = utils.include(str, true)
 | 
				
			||||||
 | 
								["calloc",0x7fff93e0e299]
 | 
				
			||||||
 | 
								cy# ret[1].type
 | 
				
			||||||
 | 
								@encode(void*(unsigned long long int,unsigned long long int))
 | 
				
			||||||
 | 
								cy# ret[1](100, 1)
 | 
				
			||||||
 | 
								0x100444100
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.include = function(str, load) {
 | 
				
			||||||
 | 
							var re = /^\s*([^(]*(?:\s+|\*))(\w*)\s*\(([^)]*)\)\s*;?\s*$/;
 | 
				
			||||||
 | 
							var match = re.exec(str);
 | 
				
			||||||
 | 
							if(!match) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var rType = utils.applyTypedefs(match[1]);
 | 
				
			||||||
 | 
							var name = match[2];
 | 
				
			||||||
 | 
							var args = match[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var argsRe = /([^,]+)(?:,|$)/g;
 | 
				
			||||||
 | 
							var argsTypes = [];
 | 
				
			||||||
 | 
							while((match = argsRe.exec(args)) !== null) {
 | 
				
			||||||
 | 
								var type = utils.applyTypedefs(match[1]);
 | 
				
			||||||
 | 
								argsTypes.push(type);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var encodeString = "@encode(";
 | 
				
			||||||
 | 
							encodeString += rType + "(";
 | 
				
			||||||
 | 
							encodeString += argsTypes.join(", ") + "))";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var fun = dlsym(RTLD_DEFAULT, name);
 | 
				
			||||||
 | 
							if(fun !== null) {
 | 
				
			||||||
 | 
								encodeString += "(" + fun + ")";
 | 
				
			||||||
 | 
								if(load) {
 | 
				
			||||||
 | 
									return [name, utils.exec(encodeString)];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if(load) {
 | 
				
			||||||
 | 
								throw "Function couldn't be found with dlsym!";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return [name, encodeString];
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Loads the function declaration in the defs array using utils.exec and exposes to cycript's global scope
 | 
				
			||||||
 | 
							Is automatically called if shouldLoadCFuncs is true
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.funcs = {};
 | 
				
			||||||
 | 
						utils.loadfuncs = function(expose) {
 | 
				
			||||||
 | 
							for(var i = 0; i < CFuncsDeclarations.length; i++) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									var o = utils.include(CFuncsDeclarations[i], true);
 | 
				
			||||||
 | 
									utils.funcs[o[0]] = o[1];
 | 
				
			||||||
 | 
									if(expose) {
 | 
				
			||||||
 | 
										Cycript.all[o[0]] = o[1];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} catch(e) {
 | 
				
			||||||
 | 
									system.print("Failed to load function: " + i);
 | 
				
			||||||
 | 
									try {
 | 
				
			||||||
 | 
										system.print(utils.include(CFuncsDeclarations[i]));
 | 
				
			||||||
 | 
									} catch(e2) {
 | 
				
			||||||
 | 
										
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Calculates the size of a type like the C operator sizeof
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.sizeof(int)
 | 
				
			||||||
 | 
								4
 | 
				
			||||||
 | 
								cy# utils.sizeof(@encode(void *))
 | 
				
			||||||
 | 
								8
 | 
				
			||||||
 | 
								cy# utils.sizeof("mach_vm_address_t")
 | 
				
			||||||
 | 
								8
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.sizeof = function(type) {
 | 
				
			||||||
 | 
							if(typeof type === "string") {
 | 
				
			||||||
 | 
								type = utils.applyTypedefs(type);
 | 
				
			||||||
 | 
								type = utils.exec("@encode(" + type + ")");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// (const) char * has "infinite" preceision
 | 
				
			||||||
 | 
							if(type.toString().slice(-1) === "*") {
 | 
				
			||||||
 | 
								return utils.sizeof(@encode(void *));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							// float and double
 | 
				
			||||||
 | 
							if(type.toString() === @encode(float).toString()) {
 | 
				
			||||||
 | 
								return 4;
 | 
				
			||||||
 | 
							} else if (type.toString() === @encode(double).toString()) {
 | 
				
			||||||
 | 
								return 8;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var typeInstance = type(0);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(typeInstance instanceof Object) {
 | 
				
			||||||
 | 
								// Arrays
 | 
				
			||||||
 | 
								if("length" in typeInstance) {
 | 
				
			||||||
 | 
									return typeInstance.length * utils.sizeof(typeInstance.type);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// Structs
 | 
				
			||||||
 | 
								if(typeInstance.toString() === "[object Struct]") {
 | 
				
			||||||
 | 
									var typeStr = type.toString();
 | 
				
			||||||
 | 
									var arrayTypeStr = "[2" + typeStr + "]";
 | 
				
			||||||
 | 
									var arrayType = new Type(arrayTypeStr);
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									var arrayInstance = new arrayType;
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									return @encode(void *)(&(arrayInstance[1])) - @encode(void *)(&(arrayInstance[0]));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							for(var i = 0; i < 5; i++) {
 | 
				
			||||||
 | 
								var maxSigned = Math.pow(2, 8 * Math.pow(2, i) - 1) - 1;
 | 
				
			||||||
 | 
								if(i === 3) {
 | 
				
			||||||
 | 
									// Floating point fix ;^)
 | 
				
			||||||
 | 
									maxSigned /= 1000;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// can't use !== or sizeof(void *) === 0.5
 | 
				
			||||||
 | 
								if(type(maxSigned) != maxSigned) {
 | 
				
			||||||
 | 
									return Math.pow(2, i - 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Logs a specific message sent to an instance of a class like logify.pl in theos
 | 
				
			||||||
 | 
							Requires Cydia Substrate (com.saurik.substrate.MS) and NSLog (org.cycript.NSLog) modules
 | 
				
			||||||
 | 
							Returns the old message returned by MS.hookMessage (Note: this is not just the old message!)
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# var oldm = utils.logify(objc_getMetaClass(NSNumber), @selector(numberWithDouble:))
 | 
				
			||||||
 | 
								...
 | 
				
			||||||
 | 
								cy# var n = [NSNumber numberWithDouble:1.5]
 | 
				
			||||||
 | 
								2014-07-28 02:26:39.805 cycript[71213:507] +[<NSNumber: 0x10032d0c4> numberWithDouble:1.5]
 | 
				
			||||||
 | 
								2014-07-28 02:26:39.806 cycript[71213:507]  = 1.5
 | 
				
			||||||
 | 
								@1.5
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.logify = function(cls, sel) {
 | 
				
			||||||
 | 
							@import com.saurik.substrate.MS;
 | 
				
			||||||
 | 
							@import org.cycript.NSLog;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var oldm = {};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							MS.hookMessage(cls, sel, function() {
 | 
				
			||||||
 | 
								var args = [].slice.call(arguments);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var selFormat = sel.toString().replace(/:/g, ":%@ ").trim();
 | 
				
			||||||
 | 
								var logFormat = "%@[<%@: 0x%@> " + selFormat + "]";
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var standardArgs = [logFormat, class_isMetaClass(cls)? "+": "-", cls.toString(), (&this).valueOf().toString(16)];
 | 
				
			||||||
 | 
								var logArgs = standardArgs.concat(args);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								NSLog.apply(null, logArgs);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var r = oldm->apply(this, arguments);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if(r !== undefined) {
 | 
				
			||||||
 | 
									NSLog(" = %@", r);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								return r;
 | 
				
			||||||
 | 
							}, oldm);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return oldm;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Calls a C function by providing its name and arguments
 | 
				
			||||||
 | 
							Doesn't support structs
 | 
				
			||||||
 | 
							Return value is always a void pointer
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.apply("printf", ["%s %.3s, %d -> %c, float: %f\n", "foo", "barrrr", 97, 97, 1.5])
 | 
				
			||||||
 | 
								foo bar, 97 -> a, float: 1.500000
 | 
				
			||||||
 | 
								0x22
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.apply = function(fun, args) {
 | 
				
			||||||
 | 
							if(!(args instanceof Array)) {
 | 
				
			||||||
 | 
								throw "Args needs to be an array!";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var argc = args.length;
 | 
				
			||||||
 | 
							var voidPtr = @encode(void *);
 | 
				
			||||||
 | 
							var argTypes = [];
 | 
				
			||||||
 | 
							for(var i = 0; i < argc; i++) {
 | 
				
			||||||
 | 
								var argType = voidPtr;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								var arg = args[i];
 | 
				
			||||||
 | 
								if(typeof arg === "string") {
 | 
				
			||||||
 | 
									argType = @encode(char *);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if(typeof arg === "number" && arg % 1 !== 0) {
 | 
				
			||||||
 | 
									argType = @encode(double);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								argTypes.push(argType);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var type = voidPtr.functionWith.apply(voidPtr, argTypes);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(typeof fun === "string") {
 | 
				
			||||||
 | 
								fun = dlsym(RTLD_DEFAULT, fun);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(!fun) {
 | 
				
			||||||
 | 
								throw "Function not found!";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return type(fun).apply(null, args);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Converts a string (char *) to a void pointer (void *)
 | 
				
			||||||
 | 
							You can't cast to strings to void pointers and vice versa in cycript. Blame saurik.
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# var voidPtr = utils.str2voidPtr("foobar")
 | 
				
			||||||
 | 
								0x100331590
 | 
				
			||||||
 | 
								cy# utils.voidPtr2str(voidPtr)
 | 
				
			||||||
 | 
								"foobar"
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.str2voidPtr = function(str) {
 | 
				
			||||||
 | 
							var strdup = @encode(void *(char *))(dlsym(RTLD_DEFAULT, "strdup"));
 | 
				
			||||||
 | 
							return strdup(str);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							The inverse function of str2voidPtr
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.voidPtr2str = function(voidPtr) {
 | 
				
			||||||
 | 
							var strdup = @encode(char *(void *))(dlsym(RTLD_DEFAULT, "strdup"));
 | 
				
			||||||
 | 
							return strdup(voidPtr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Converts a double into a void pointer
 | 
				
			||||||
 | 
							This can be used to view the binary representation of a floating point number
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# var n = utils.double2voidPtr(-1.5)
 | 
				
			||||||
 | 
								0xbff8000000000000
 | 
				
			||||||
 | 
								cy# utils.voidPtr2double(n)
 | 
				
			||||||
 | 
								-1.5
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.double2voidPtr = function(n) {
 | 
				
			||||||
 | 
							var doublePtr = new double;
 | 
				
			||||||
 | 
							*doublePtr = n;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var voidPtrPtr = @encode(void **)(doublePtr);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return *voidPtrPtr;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							The inverse function of double2voidPtr
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.voidPtr2double = function(voidPtr) {
 | 
				
			||||||
 | 
							var voidPtrPtr = new @encode(void **);
 | 
				
			||||||
 | 
							*voidPtrPtr = voidPtr;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var doublePtr = @encode(double *)(voidPtrPtr);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return *doublePtr;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Determines in a safe way if a memory location is readable
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.isMemoryReadable(0)
 | 
				
			||||||
 | 
								false
 | 
				
			||||||
 | 
								cy# utils.isMemoryReadable(0x1337)
 | 
				
			||||||
 | 
								false
 | 
				
			||||||
 | 
								cy# utils.isMemoryReadable(NSObject)
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
								cy# var a = malloc(100); utils.isMemoryReadable(a)
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.isMemoryReadable = function(ptr) {
 | 
				
			||||||
 | 
							if(typeof ptr === "string") {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var fds = new @encode(int [2]);
 | 
				
			||||||
 | 
							utils.apply("pipe", [fds]);
 | 
				
			||||||
 | 
							var result = utils.apply("write", [fds[1], ptr, 1]) == 1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							utils.apply("close", [fds[0]]);
 | 
				
			||||||
 | 
							utils.apply("close", [fds[1]]);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Determines in a safe way if the memory location contains an Objective-C object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# utils.isObject(0)
 | 
				
			||||||
 | 
								false
 | 
				
			||||||
 | 
								cy# utils.isObject(0x1337)
 | 
				
			||||||
 | 
								false
 | 
				
			||||||
 | 
								cy# utils.isObject(NSObject)
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
								cy# utils.isObject(objc_getMetaClass(NSObject))
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
								cy# utils.isObject([new NSObject init])
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
								cy# var a = malloc(100); utils.isObject(a)
 | 
				
			||||||
 | 
								false
 | 
				
			||||||
 | 
								cy# *@encode(void **)(a) = NSObject; utils.isObject(a)
 | 
				
			||||||
 | 
								true
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.isObject = function(obj) {
 | 
				
			||||||
 | 
							obj = @encode(void *)(obj);
 | 
				
			||||||
 | 
							var lastObj = -1;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							function objc_isa_ptr(obj) {
 | 
				
			||||||
 | 
								// See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
 | 
				
			||||||
 | 
								var objc_debug_isa_class_mask = 0x00000001fffffffa;
 | 
				
			||||||
 | 
								obj = (obj & 1)? (obj & objc_debug_isa_class_mask): obj;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if((obj & (utils.sizeof(@encode(void *)) - 1)) != 0) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									return obj;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							function ptrValue(obj) {
 | 
				
			||||||
 | 
								return obj? obj.valueOf(): null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var foundMetaClass = false;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							for(obj = objc_isa_ptr(obj); utils.isMemoryReadable(obj); ) {
 | 
				
			||||||
 | 
								obj = *@encode(void **)(obj);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								if(ptrValue(obj) == ptrValue(lastObj)) {
 | 
				
			||||||
 | 
									foundMetaClass = true;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								lastObj = obj;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(!foundMetaClass) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(lastObj === -1 || lastObj === null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var obj_class = objc_isa_ptr(@encode(void **)(obj)[1]);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(!utils.isMemoryReadable(obj_class)) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							var metaclass = objc_isa_ptr(@encode(void **)(obj_class)[0]);
 | 
				
			||||||
 | 
							var superclass = objc_isa_ptr(@encode(void **)(obj_class)[1]);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return ptrValue(obj) == ptrValue(metaclass) && superclass == null;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
							Creates a cycript struct type from a C struct definition
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							Usage:
 | 
				
			||||||
 | 
								cy# var foo = makeStruct("int a; short b; char c; uint64_t d; double e;", "foo");
 | 
				
			||||||
 | 
								@encode(foo)
 | 
				
			||||||
 | 
								cy# var f = new foo
 | 
				
			||||||
 | 
								&{a:0,b:0,c:0,d:0,e:0}
 | 
				
			||||||
 | 
								cy# f->a = 100; f
 | 
				
			||||||
 | 
								&{a:100,b:0,c:0,d:0,e:0}
 | 
				
			||||||
 | 
								cy# *@encode(int *)(f)
 | 
				
			||||||
 | 
								100
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						utils.makeStruct = function(str, name) {		
 | 
				
			||||||
 | 
							var fieldRe = /(?:\s|\n)*([^;]+\s*(?:\s|\*))([^;]+)\s*;/g;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							if(!name) {
 | 
				
			||||||
 | 
								name = "struct" + Math.floor(Math.random() * 100000);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var typeStr = "{" + name + "=";
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							while((match = fieldRe.exec(str)) !== null) {
 | 
				
			||||||
 | 
								var fieldType = utils.applyTypedefs(match[1]);
 | 
				
			||||||
 | 
								var fieldName = match[2];
 | 
				
			||||||
 | 
								var encodedType = utils.exec("@encode(" + fieldType + ")").toString();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								typeStr += '"' + fieldName + '"' + encodedType;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							typeStr += "}";
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return new Type(typeStr);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Various constants
 | 
				
			||||||
 | 
						utils.constants = {
 | 
				
			||||||
 | 
							VM_PROT_NONE:       0x0,
 | 
				
			||||||
 | 
							VM_PROT_READ:       0x1,
 | 
				
			||||||
 | 
							VM_PROT_WRITE:      0x2,
 | 
				
			||||||
 | 
							VM_PROT_EXECUTE:    0x4,
 | 
				
			||||||
 | 
							VM_PROT_NO_CHANGE:  0x8,
 | 
				
			||||||
 | 
							VM_PROT_COPY:       0x10,
 | 
				
			||||||
 | 
							VM_PROT_WANTS_COPY: 0x10,
 | 
				
			||||||
 | 
							VM_PROT_IS_MASK:    0x40,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						var c = utils.constants;
 | 
				
			||||||
 | 
						c.VM_PROT_DEFAULT = c.VM_PROT_READ | c.VM_PROT_WRITE;
 | 
				
			||||||
 | 
						c.VM_PROT_ALL =     c.VM_PROT_READ | c.VM_PROT_WRITE | c.VM_PROT_EXECUTE;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(shouldExposeConsts) {
 | 
				
			||||||
 | 
							for(var k in c) {
 | 
				
			||||||
 | 
								Cycript.all[k] = c[k];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(shouldExposeFuncs) {
 | 
				
			||||||
 | 
							for(var i = 0; i < funcsToExpose.length; i++) {
 | 
				
			||||||
 | 
								var name = funcsToExpose[i];
 | 
				
			||||||
 | 
								Cycript.all[name] = utils[name];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						if(shouldLoadCFuncs) {
 | 
				
			||||||
 | 
							utils.loadfuncs(shouldExposeCFuncs);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					})(exports);
 | 
				
			||||||
		Reference in New Issue
	
	Block a user