最近弄了一个iphone5,看到网上的越狱教程,就顺便越狱了,并且下载了一套开发环境【注1】由于可以ssh登录,并且直接在手机上进行开发,这激起了我的兴趣——这不就是将手机变成一台linux服务器,然后在上面耍吗!{:lol:}
由于我只会c/c++,完全没有object-c基础和苹果其他开发软件基础,参考/var/mobile/Projects/StandardCLibrary/(详情见注1)项目,所以我先试着用c++写了一个helloword
嗯,效果还不错,可以直接运行。这让我一下找到了感觉,这和linux程序开发也没有太大的区别嘛
好了,既然这样那就进一步试一试,写个进程信息分析工具试一试!
注意到iphone系统根本没有/proc目录,所以很多以前linux下面的套路完全用不上了
只能使用sysctl接口来模拟,先拿到所有进程的列表再说【注2】好了,拿到列表了但是怎么获取进程内存信息呢?
这倒是个麻烦。首先参考了http://iosre.com/forum.php?mod=viewthread&tid=105&extra=page%3D1 英文的
大意讲了这么一件事情:我们一般使用的是虚拟地址(比如0x12345678 这个是所谓内存地址)虚拟地址会被系统映射到物理内存地址。物理内存是有分块的,每一个进程都有一个region,而每一个region又分为若干个page。
获取进程内存信息就落在region上了。
由于每个进程都有一个region,相互都是一对一的关系(不知道我的理解是不是错误的),所以只要拿到region信息就能够得到进程使用内存的详细信息。
OK下一步就是如何获取region信息了
当你包含了mach/mach.h头文件之后,就可以使用一个函数vm_region
说明一下,刚才提到的英文资料,里面给出的示例使用的是mach_vm_region函数。我试了一下,^&@#!的根本编译不过去,我#$%!
然后各种资料查询无果,翻墙无果。最后看头文件,找到了vm_region和上面的很像,再查这个函数,发现功能描述和上面一样,我只能呵呵了。
然后将mach_vm_read、mach_vm_write替换成了vm_read、vm_write。注意参数类型有点小小的变动,对应的修改一下,就可以用了。
makefile、签名文件和代码见【注3】
这里特别提一下签名文件ent.xml
ldid -Sent.xml obj/$(TOOL_NAME)
如果没有这个对文件进行签名,则程序只能打开wheel用户开启的进程(这个是普通用户)。任何其他进程,包括mobile用户的进程,都无法访问。vm_region会返回-1 errno显示错误5 kern error
好了,到这里,所有进程以及其内存使用详情现在都有了,下面我要开始分析这些内存数据,看看他们到底都是一些啥,以后会补充我的发现,待续……
你可以参考英文资料继续写一个游戏修改器,也可以利用这些信息进行更多的操作
【注1】:开发环境镜像:
http://yunpan.cn/cKF4nvseXsiWB 访问密码
d03e
安装参考命令:(注意安装前不要有任何gcc gdb等东东,如果有请先卸载,否则可能导致未知的问题)
- cd /var/root/
- tar xzvf iiphonedev_v5.1_ios81.tgz
- cd /var/root/iphonedev/DEBS
- dpkg -i *.deb
- cd /var/root/iphonedev/
- mv Projects /var/mobile/
- rm -fr /var/theos
-
mv theos /var/
参考资料:在
iPhone 或 iPad 安装 llvm-clang, THEOS 编译程序或插件, 更新支持 iOS SDK 8.1 arm64
【注2】
获取所有正在运行的进程列表信息,参考如下:
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL ,0};//调用CTL_KERN接口下的KERN_PROC功能,获取所有的进程信息(其实只有pid groupid uid session ruid lcid tty这七种信息) size_t len,count; PROCINF *kp = 0; int ret = 0; printf("%s(%d):%s uid %d\n",__FILE__,__LINE__,__FUNCTION__,getuid()); ret = sysctl(mib, 4, 0, &len, NULL, 0);//获取信息长度 mib最后一个为0表明获取所有进程信息 printf("%s(%d):%s %d %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,len); if(ret<0){ return; } count = (len+sizeof(PROCINF)-1)/sizeof(PROCINF);//按照结构体大小,进行对齐,得到真正的个数 kp = new PROCINF[count]; if(kp==0){ printf("%s(%d):%s no more memory\n",__FILE__,__LINE__,__FUNCTION__); return; } memset(kp,0,len); ret = sysctl(mib, 4, kp, &len, NULL, 0);//获取全部的进程信息 printf("%s(%d):%s %d %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,len); count = len/sizeof(PROCINF);//这里有个坑,前后两次调用获取到的len可能并不一定相同,所以要重新计算count数量,方便后面遍历。否则count可能大于实际数量
【注3】
Makefile
TARGET := iphone:clang THEOS_PLATFORM_SDK_ROOT_armv6 = /var/theos/sdks/iPhoneOS5.1.sdk THEOS_PLATFORM_SDK_ROOT_armv7 = /var/theos/sdks/iPhoneOS6.1.sdk THEOS_PLATFORM_SDK_ROOT_arm64 = /var/theos/sdks/iPhoneOS7.1.sdk SDKVERSION_armv6 = 5.1 SDKVERSION_armv7 = 6.1 SDKVERSION_arm64 = 7.1 TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv6 = 5.1 TARGET_IPHONEOS_DEPLOYMENT_VERSION_armv7 = 6.1 TARGET_IPHONEOS_DEPLOYMENT_VERSION_arm64 = 7.1 IPHONE_ARCHS = armv7 #armv6 arm64 #iphone 5使用7 iphone4使用 6 LOCAL_OBJ_PATH = obj export THEOS=/var/theos include $(THEOS)/makefiles/common.mk TOOL_NAME = test test_FILES = main.cpp include $(THEOS_MAKE_PATH)/tool.mk cmd: stage echo $(THEOS_STAGING_DIR) @pwd @if [ -d obj ];then echo "already has obj directory";else mkdir obj;fi @if [ -f .theos/obj/armv7/$(TOOL_NAME) ];then cp .theos/obj/armv7/$(TOOL_NAME) ./obj/;fi @if [ -f .theos/obj/armv7/$(TOOL_NAME) ];then ldid -Sent.xml obj/$(TOOL_NAME);fi
mian.cpp
#include <stdio.h> #include <memory.h> #include <map> #include <list> #include <sys/sysctl.h> #include <sys/types.h> #include <sys/mount.h> #include <mach/mach.h> #include <string> typedef struct _tag_Process_Info_{ _tag_Process_Info_(){ nUid = -1; nPid = -1; nPpid = -1; nPgid = -1; nSessionID = -1; nJobc = -1; *(int*)strStatus = 0; memset(strTT,0,sizeof(strTT)); memset(strTime,0,sizeof(strTime)); } int nUid;//user id pid_t nPid;//Process ID pid_t nPpid;//Parent Process ID pid_t nPgid;//Process Group Number int nSessionID; int nJobc;//job control count char strStatus[4]; char strTT[8];//control terminal name (two letter abbreviation) char strTime[16];//accumulated CPU time, user + system (alias cputime) ProArgs clsArgs;//command and arguments }PINF; void getprocinf(pid_t pid,PINF* pinf) { <span style="white-space:pre"> </span>int mib[3]; <span style="white-space:pre"> </span>mib[0] = CTL_KERN; <span style="white-space:pre"> </span>mib[1] = KERN_ARGMAX; <span style="white-space:pre"> </span>size_t size = 0; <span style="white-space:pre"> </span>size_t len = 4; <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>int ret = sysctl(mib, 2, &size, &len, NULL, 0); <span style="white-space:pre"> </span>printf("%s(%d):%s ret = %d size %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,size); <span style="white-space:pre"> </span>mib[0] = CTL_KERN; <span style="white-space:pre"> </span>mib[1] = KERN_PROCARGS2; <span style="white-space:pre"> </span>mib[2] = pid; <span style="white-space:pre"> </span>char* buf = new char[size]; <span style="white-space:pre"> </span>memset(buf,0,size); <span style="white-space:pre"> </span>if(buf){ <span style="white-space:pre"> </span>ret = sysctl(mib, 3, buf, &size, NULL, 0); <span style="white-space:pre"> </span>printf("%s(%d):%s ret = %d size %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,size); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>pinf->clsArgs.nArgc = *(int*)buf; <span style="white-space:pre"> </span>char* pcmd = buf+sizeof(int); <span style="white-space:pre"> </span>pinf->clsArgs.strProcPathName = pcmd; <span style="white-space:pre"> </span>len = strlen(pcmd); <span style="white-space:pre"> </span>len += (4-(len%4)); <span style="white-space:pre"> </span>pcmd += len; <span style="white-space:pre"> </span>if(pinf->clsArgs.nArgc>0){ <span style="white-space:pre"> </span>pinf->clsArgs.lstArgv.resize(*(int*)buf); <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>for(int i=0;i<pinf->clsArgs.nArgc;i++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>printf("%s(%d):%s argv[%d]=%s\n",__FILE__,__LINE__,__FUNCTION__,i,pcmd); <span style="white-space:pre"> </span>pinf->clsArgs.lstArgv[i] = pcmd; <span style="white-space:pre"> </span>pcmd += strlen(pcmd); <span style="white-space:pre"> </span>while(*pcmd == 0 && (pcmd<buf+size)) <span style="white-space:pre"> </span>pcmd++; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>while(*pcmd != 0) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>printf("%s(%d):%s env[%d]=%s\n",__FILE__,__LINE__,__FUNCTION__, <span style="white-space:pre"> </span>pinf->clsArgs.nEnvc,pcmd); <span style="white-space:pre"> </span>pinf->clsArgs.lstEnv.push_back(string(pcmd)); <span style="white-space:pre"> </span>pinf->clsArgs.nEnvc++; <span style="white-space:pre"> </span>pcmd += strlen(pcmd); <span style="white-space:pre"> </span>while(*pcmd == 0 && (pcmd<buf+size)) <span style="white-space:pre"> </span>pcmd++; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>delete[]buf; } int main(int argc,char*argv[]) { size_t i; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL ,0}; size_t len,count; PROCINF *kp = 0; int ret = 0; printf("%s(%d):%s uid %d\n",__FILE__,__LINE__,__FUNCTION__,getuid()); ret = sysctl(mib, 4, 0, &len, NULL, 0);//获取信息长度 mib最后一个为0表明获取所有进程信息 printf("%s(%d):%s %d %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,len); if(ret<0){ return; } count = (len+sizeof(PROCINF)-1)/sizeof(PROCINF); kp = new PROCINF[count]; if(kp==0){ printf("%s(%d):%s no more memory\n",__FILE__,__LINE__,__FUNCTION__); return; } memset(kp,0,len); ret = sysctl(mib, 4, kp, &len, NULL, 0);//获取全部的进程信息 printf("%s(%d):%s %d %lu\n",__FILE__,__LINE__,__FUNCTION__,ret,len); count = len/sizeof(PROCINF); if(ret == 0){ for(i=0;i<count;i++) { PINF info; info.nPid = kp[i].kp_proc.p_pid; getprocinf(kp[i].kp_proc.p_pid,&info); mach_port_t task; kern_return_t kret = task_for_pid(mach_task_self(),kp[i].kp_proc.p_pid,&task); printf("%d %s %02X %u\n",kp[i].kp_proc.p_pid,kp[i].kp_proc.p_comm, kp[i].kp_proc.p_stat&0xFF,task); if(kret == KERN_SUCCESS){ mach_port_name_array_t name = 0; mach_msg_type_number_t namelen = 0; mach_port_type_array_t types = 0; mach_msg_type_number_t typelen = 0; kret = mach_port_names(task,&name,&namelen,&types,&typelen); if(kret == KERN_SUCCESS) { printf("%s(%d):%s %p %u %p %u\n",__FILE__,__LINE__,__FUNCTION__, name,namelen,types,typelen); } vm_address_t address = 0; vm_size_t size = 0; vm_region_basic_info_64 info; mach_msg_type_number_t ct = VM_REGION_BASIC_INFO_COUNT_64; mach_port_t object_name; while (vm_region(task, &address, &size, VM_REGION_BASIC_INFO, (vm_region_info_t)&info, &ct, &object_name) == KERN_SUCCESS) { vm_prot_t protection = info.protection; if(memcmp(kp[i].kp_proc.p_comm,"sftp-server",4)==0){ printf("%s(%d):%s address %08X %d size %u\n",__FILE__,__LINE__,__FUNCTION__, address,protection,size); char* data=0; mach_msg_type_number_t datalen = size; { //kret = vm_read(task,address,size,(vm_offset_t*)&data,&datalen); if(kret == KERN_SUCCESS){ printf("%s(%d):%s address %08X %d size %u\n",__FILE__,__LINE__,__FUNCTION__, address,protection,size); }else{ printf("%s(%d):%s address %08X size %u\n",__FILE__,__LINE__,__FUNCTION__, (unsigned int)data,datalen); } } } address += size; } }else{ printf("%s(%d):%s error(%d):%s %d\n",__FILE__,__LINE__,__FUNCTION__, kret, mach_error_string(kret),mach_host_self()); } } } if(kp){ delete[]kp; } printf("%s(%d):%s\n",__FILE__,__LINE__,__FUNCTION__); }
ent.xml
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.springboard.debugapplications</key> <true/> <key>get-task-allow</key> <true/> <key>proc_info-allow</key> <true/> <key>task_for_pid-allow</key> <true/> <key>run-unsigned-code</key> <true/> </dict> </plist>