iOS 安全论坛 - 专注于研究 iOS 安全

标题: APP内如何调用命令安装下载的ipa包 [打印本页]

作者: 向着标杆直跑    时间: 2019-7-15 20:15
标题: APP内如何调用命令安装下载的ipa包
APP代码如何调用命令行安装APP内下载的ipa、我现在是APP内下载一个ipa包,下载完了后自动安装和启动应用,请问您有什么好的方法
现在需要实现这样一个功能:一个APP内从服务端下载完ipa后自动安装和打开该ipa应用,越狱机上已安装相关ipa插件,需要APP内代码实现调用命令行自动进行ipa安装、卸载等操作。Mac开发中有NStask,但是iOS开发中如何实现?跪求解答!急!

作者: exchen    时间: 2019-7-15 21:44
1.你说到的 NSTask 在 iOS 上也是有的,也可以使用.
2.ipa包在越狱环境上用的话,你可以直接弄成deb包,安装deb包的命令是 dpkg -i xxx.deb,卸载的命令是 dpkg -r xxx.deb。
作者: 向着标杆直跑    时间: 2019-7-16 15:40
exchen 发表于 2019-7-15 21:44
1.你说到的 NSTask 在 iOS 上也是有的,也可以使用.
2.ipa包在越狱环境上用的话,你可以直接弄成deb包,安 ...

ios上没有NStask
我现在是APP程序内下载的ipa,不弄成deb包,而是需要下载完直接APP内自动安装ipa,我的问题是想问iOS代码如何调用命令,只要我能调用命令,安装都不是问题。非常感谢你的回答
作者: exchen    时间: 2019-7-16 16:08
向着标杆直跑 发表于 2019-7-16 15:40
ios上没有NStask
我现在是APP程序内下载的ipa,不弄成deb包,而是需要下载完直接APP内自动安装ipa,我的 ...

posix_spawn 执行命令的示例代码如下:
  1. pid_t pid;
  2. char *argv[] = {
  3.   "/bin/ls",  //path
  4.   "-al",     //parameter1
  5.   "/",       //parameter2
  6.   NULL
  7. };

  8. posix_spawn(&pid, argv[0], NULL, NULL, argv, NULL);

  9. printf("pid=%d,child pid = %d\n",getpid(),pid);

  10. int stat;
  11. waitpid(pid,&stat,0);
  12. printf("stat is %d\n",stat);
复制代码


NSTask 执行命令的代码如下:
  1. NSTask *task = [[NSTask alloc] init];
  2. task.launchPath = @"/bin/ls";
  3. task.arguments = [NSArray arrayWithObjects:
  4.                   @"-al",
  5.                   @"/",
  6.                   nil];
  7. [task launch];
  8. [task waitUntilExit];
复制代码

作者: exchen    时间: 2019-7-16 16:08
NSTask.h 头文件信息如下:
  1. #import <Foundation/NSObject.h>

  2. @class NSString, NSArray, NSDictionary;

  3. @interface NSTask : NSObject

  4. // Create an NSTask which can be run at a later time
  5. // An NSTask can only be run once. Subsequent attempts to
  6. // run an NSTask will raise.
  7. // Upon task death a notification will be sent
  8. //   { Name = NSTaskDidTerminateNotification; object = task; }
  9. //

  10. - (instancetype)init;

  11. // set parameters
  12. // these methods can only be done before a launch
  13. // if not set, use current
  14. // if not set, use current

  15. // set standard I/O channels; may be either an NSFileHandle or an NSPipe
  16. - (void)setStandardInput:(id)input;
  17. - (void)setStandardOutput:(id)output;
  18. - (void)setStandardError:(id)error;

  19. // get parameters
  20. @property (NS_NONATOMIC_IOSONLY, copy) NSString *launchPath;
  21. @property (NS_NONATOMIC_IOSONLY, copy) NSArray *arguments;
  22. @property (NS_NONATOMIC_IOSONLY, copy) NSDictionary *environment;
  23. @property (NS_NONATOMIC_IOSONLY, copy) NSString *currentDirectoryPath;

  24. // get standard I/O channels; could be either an NSFileHandle or an NSPipe
  25. - (id)standardInput;
  26. - (id)standardOutput;
  27. - (id)standardError;

  28. // actions
  29. - (void)launch;

  30. - (void)interrupt; // Not always possible. Sends SIGINT.
  31. - (void)terminate; // Not always possible. Sends SIGTERM.

  32. @property (NS_NONATOMIC_IOSONLY, readonly) BOOL suspend;
  33. @property (NS_NONATOMIC_IOSONLY, readonly) BOOL resume;

  34. // status
  35. @property (NS_NONATOMIC_IOSONLY, readonly) int processIdentifier;
  36. @property (NS_NONATOMIC_IOSONLY, getter=isRunning, readonly) BOOL running;

  37. @property (NS_NONATOMIC_IOSONLY, readonly) int terminationStatus;

  38. @end

  39. @interface NSTask (NSTaskConveniences)

  40. + (NSTask *)launchedTaskWithLaunchPath:(NSString *)path arguments:(NSArray *)arguments;
  41. // convenience; create and launch

  42. - (void)waitUntilExit;
  43. // poll the runLoop in defaultMode until task completes

  44. @end

  45. FOUNDATION_EXPORT NSString * const NSTaskDidTerminateNotification;
复制代码

作者: 向着标杆直跑    时间: 2019-7-16 21:20
exchen 发表于 2019-7-16 16:08
posix_spawn 执行命令的示例代码如下:

非常非常感谢你提供的答案,现在我还有两个疑问想问下:
1、我在代码中使用posix_spawn会报错:Declaration of 'posix_spawn' must be imported from module 'Darwin.POSIX.spawn' before it is required 和 Implicit declaration of function 'posix_spawn' is invalid in C99,添加头文件#import <sys/time.h>也无济于事,请问该怎么解决?
2、使用NSTask还不太会,比如说我在/var/mobile/Downloads/目录下有一个xxxx.ipa文件,需要调用命令:ipainstaller /var/mobile/Downloads/xxxx.ipa来安装,那么这个task.arguments该如何写,其实是刚入门的小白,求指导!期待您的解答
作者: exchen    时间: 2019-7-16 21:43
posix_spawn 的头文件是在 #import <spawn.h>

作者: exchen    时间: 2019-7-16 21:44
你想要执行的命令,用 NSTask 的方式写法如下:
  1. NSTask *task = [[NSTask alloc] init];
  2. task.launchPath = @"ipainstaller";   //这里要写 ipainstaller 的绝对路径       
  3. task.arguments = [NSArray arrayWithObjects:
  4.                         @"/var/mobile/Downloads/xxxx.ipa",
  5.                   nil];
  6. [task launch];
  7. [task waitUntilExit];
复制代码

作者: 向着标杆直跑    时间: 2019-7-17 00:01
exchen 发表于 2019-7-16 21:44
你想要执行的命令,用 NSTask 的方式写法如下:

您好,在我的APP测试助手程序内下载IPA,完了后自动安装该IPA,我使用Cydia中安装的IPA Installer Console插件进行IPA安装,此时需要调命令,而您说的task.launchPath那写ipainstaller 的绝对路径是指的什么?不太明白,  非常感谢您的耐心解答!
如方便的话加下QQ1020386527
作者: exchen    时间: 2019-7-17 00:10
ipainstaller,你先直接这样写看行不行。不行的话就得写绝对路径了,find / -name ipainstaller,这个命令可以查找文件的位置。
作者: exchen    时间: 2019-7-17 02:32
我想到一个可能是比较适合你用的办法,动态调用 system 函数,这个应该不用关心环境变量和绝对路径的问题了。

  1. #import <dlfcn.h>
  2. typedef int (*my_system) (const char *str);
  3. int call_system(const char *str){
  4.    
  5.     //动态库路径
  6.     char *dylib_path = "/usr/lib/libSystem.dylib";
  7.     //打开动态库
  8.     void *handle = dlopen(dylib_path, RTLD_GLOBAL | RTLD_NOW);
  9.     if (handle == NULL) {
  10.         //打开动态库出错
  11.         fprintf(stderr, "%s\n", dlerror());
  12.     } else {
  13.         //获取 system 地址
  14.         my_system system = dlsym(handle, "system");
  15.         
  16.         //地址获取成功则调用
  17.         if (system) {
  18.             
  19.             int ret = system(str);
  20.             return ret;
  21.         }
  22.         dlclose(handle); //关闭句柄
  23.     }
  24.    
  25.     return -1;
  26. }

  27. call_system("ipainstaller /var/mobile/Downloads/xxxx.ipa");
复制代码

作者: 向着标杆直跑    时间: 2019-7-17 09:53
exchen 发表于 2019-7-17 02:32
我想到一个可能是比较适合你用的办法,动态调用 system 函数,这个应该不用关心环境变量和绝对路径的问题了 ...

我使用您提供的动态调用 system 函数后越狱真机调试,并没有任何反应,不知道是什么原因,我在想 电脑敲命令驱动手机安装IPA是要连ssh的,那这个是否需要?另外我IDA反编译某助手代码是这样的:
  1. else
  2.   {
  3.     objc_msgSend(CFSTR("echo 'szpt2014'|sudo -S ipainstaller "), "stringByAppendingString:", v4);
  4.     objc_release(v4);
  5.     objc_retainAutoreleasedReturnValue();
  6.     v11 = (void *)objc_retainAutorelease();
  7.     v6 = v11;
  8.     v12 = (const char *)objc_msgSend(v11, "cStringUsingEncoding:", 1LL);
  9.     v13 = system(v12);
  10.     NSLog(CFSTR("%s[Line %d] ->i===========%d,"));
  11.     if ( v13 == 256 )
  12.     {
  13.       v23 = _NSConcreteStackBlock;
  14.       v24 = -1040187392;
  15.       v25 = 0;
  16.       v26 = __41__HomeViewController_installdebWithPath___block_invoke;
  17.       v27 = &__block_descriptor_tmp_237_0;
  18.       v28 = objc_retain(v3, v14);
  19.       dispatch_async(&_dispatch_main_q, &v23);
  20.       v15 = v28;
  21.     }
  22.     else
  23.     {
  24.       NSLog(CFSTR("%s[Line %d] ->安装失败"));
  25.       v17 = _NSConcreteStackBlock;
  26.       v18 = -1040187392;
  27.       v19 = 0;
  28.       v20 = __41__HomeViewController_installdebWithPath___block_invoke_240;
  29.       v21 = &__block_descriptor_tmp_249_0;
  30.       v22 = objc_retain(v3, v16);
  31.       dispatch_async(&_dispatch_main_q, &v17);
  32.       v15 = v22;
  33.     }
  34.     objc_release(v15);
  35.   }
  36.   objc_release(v6);
  37. }
复制代码


小白表示看不太懂反编译的代码,还求您再次指导该如何做
作者: exchen    时间: 2019-7-17 10:50
你直接在 Xcode 上真机调试运行的程序是没有 root 权限的,有可能 mobile 用户的权限不能操作 ipainstaller,SSH 上运行命令是 root 用户。这些就需要你自己自行测试了,了解一下基本知识吧。我给你发的那段代码,命令按正常来说是执行了。

作者: 向着标杆直跑    时间: 2019-7-17 16:19
exchen 发表于 2019-7-17 10:50
你直接在 Xcode 上真机调试运行的程序是没有 root 权限的,有可能 mobile 用户的权限不能操作 ipainstaller ...

您好,我进行call_system("echo 'alpine'|sudo -S ipainstaller -l");遍历bundle id操作或者ipainstaller -u卸载操作是成功的,但是使用call_system("echo 'alpine'|sudo -S ipainstaller /var/mobile/Downloads/ggfwpt.ipa");进行ipa安装就报File not found at path: /private/var/mobile/Downloads/ggfwpt.ipa. Please specify any IPA file(s) to install. 的错误了,root密码是默认的alpine,请问这是为什么?

作者: exchen    时间: 2019-7-17 22:01
确认一下,手机上真的有这个文件吗?/private/var/mobile/Downloads/ggfwpt.ipa,如果有,那可能是权限问题,访问不了。你尝试将 ipa 文件换一个目录,比如放到 /var/mobile/Library/Preferences 目录看看行不行,或者你能不能把文件放到应用的沙盒目录,这样可以确定肯定是有读写权限的。
作者: 向着标杆直跑    时间: 2019-7-19 18:01
exchen 发表于 2019-7-17 22:01
确认一下,手机上真的有这个文件吗?/private/var/mobile/Downloads/ggfwpt.ipa,如果有,那可能是权限问题 ...

您好,按照您的指示吧ipa放到沙盒了,然后执行ipainstaller命令安装要第二次才安装的上,而且安装上去的APP打不开,点击APP应用图标就闪退了,是不是还需要remove iTunesMetadata.plist呢?
还有一个问题:我执行ipainstaller -u 卸载某APP后手机桌面上图标还在,请问如何更新移除残留图标,system()调用uicache并没有用
作者: exchen    时间: 2019-7-19 21:38
你的应用包是从哪里得到的?如果是 App Store 的话,要脱壳之后才能运行。一般从 App Store 下载的会有 iTunesMetadata.plist。
作者: 向着标杆直跑    时间: 2019-7-20 11:19
exchen 发表于 2019-7-19 21:38
你的应用包是从哪里得到的?如果是 App Store 的话,要脱壳之后才能运行。一般从 App Store 下载的会有 iTu ...

我的应用包是用户上传进行安全审计的,一般是客户他们公司iOS开发打的ipa包,按理来说一般不会是App Store下载的。我在想会不会是安装了ipa还要进行重签名啥的,求解!
作者: exchen    时间: 2019-7-20 22:41
安装 AppSync 这个插件可以绕过签名安装应用了。
作者: wwpp3399    时间: 2020-7-11 03:23
首先感谢版主的回答,还有楼主的提问,出现的闪退打不开的问题,解决方案是在安装之前卸载一次。




欢迎光临 iOS 安全论坛 - 专注于研究 iOS 安全 (https://www.ioshacker.net/) Powered by Discuz! X3.4