• 【iOS逆向与安全】越狱检测与过检测附ida伪代码


    首先在网上查找一些检测代码

    放入项目运行,用 ida 打开后 F5 得到下面的

    1. __int64 __usercall sub_10001B3F0@(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, __int64 a9, __int64 a10, __int64 a11, __int64 a12, ...)
    2. {
    3. __int64 v12; // x0
    4. __int64 v13; // x21
    5. int v14; // w20
    6. __int64 v15; // x0
    7. __int64 v16; // x21
    8. int v17; // w22
    9. BOOL v18; // w23
    10. BOOL v19; // w24
    11. BOOL v20; // w25
    12. int v21; // w22
    13. char *v22; // x21
    14. __int64 v23; // x0
    15. __int64 v24; // x20
    16. __int64 result; // x0
    17. __int64 v26; // x0
    18. __int64 v27; // x21
    19. __int64 v28; // x0
    20. __int64 v29; // x22
    21. __int64 v30; // x0
    22. __int64 v31; // x20
    23. __int64 v32; // x0
    24. __int64 v33; // x20
    25. const char *v34; // [xsp+1C0h] [xbp+70h]
    26. va_list va; // [xsp+1C0h] [xbp+70h]
    27. __int64 v36; // [xsp+1C8h] [xbp+78h]
    28. __int64 v37; // [xsp+1D0h] [xbp+80h]
    29. __int64 v38; // [xsp+1D8h] [xbp+88h]
    30. va_list va1; // [xsp+1E0h] [xbp+90h]
    31. va_start(va1, a12);
    32. va_start(va, a12);
    33. v34 = va_arg(va1, const char *);
    34. v36 = va_arg(va1, _QWORD);
    35. v37 = va_arg(va1, _QWORD);
    36. v38 = va_arg(va1, _QWORD);
    37. v12 = ((__int64 (__fastcall *)(void *))sub_104BFCC20)(&OBJC_CLASS___NSFileManager);
    38. v13 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v12);
    39. v14 = sub_104C07D60();
    40. ((void (__fastcall *)(__int64))objc_release)(v13);
    41. v15 = ((__int64 (__fastcall *)(void *))sub_104BFCC20)(&OBJC_CLASS___NSFileManager);
    42. v16 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v15);
    43. v17 = sub_104C07D60();
    44. ((void (__fastcall *)(__int64))objc_release)(v16);
    45. v18 = stat("/Library/MobileSubstrate/MobileSubstrate.dylib", (struct stat *)va1) == 0;
    46. v19 = stat("/Applications/Cydia.app", (struct stat *)va1) == 0;
    47. v20 = stat("/var/lib/cydia/", (struct stat *)va1) == 0;
    48. v21 = (stat("/var/cache/apt", (struct stat *)va1) == 0 || v20 || v19 || v18) | v17 | v14;
    49. if ( dladdr(&_stat, (Dl_info *)va) )
    50. v21 |= strcmp(v34, "/usr/lib/system/libsystem_kernel.dylib") != 0;
    51. v22 = getenv("DYLD_INSERT_LIBRARIES");
    52. v23 = ((__int64 (__fastcall *)(void *))sub_104C831E0)(&unk_1063357B0);
    53. v24 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v23);
    54. if ( v22 || v21 )
    55. {
    56. sub_104C65B80();
    57. ((void (__fastcall *)(__int64))objc_release)(v24);
    58. v26 = ((__int64 (__fastcall *)(void *))sub_104C2B780)(&unk_1063457C8);
    59. v27 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v26);
    60. v28 = sub_104C031E0();
    61. v29 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v28);
    62. v30 = ((__int64 (__fastcall *)(void *))sub_104C8B4A0)(&OBJC_CLASS___NSString);
    63. v31 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v30);
    64. ((void (__fastcall *)(void *))sub_104C96DA0)(&unk_106361810);
    65. ((void (__fastcall *)(__int64))objc_release)(v31);
    66. ((void (__fastcall *)(__int64))objc_release)(v29);
    67. ((void (__fastcall *)(__int64))objc_release)(v27);
    68. v32 = ((__int64 (__fastcall *)(void *))sub_104BDFEA0)(&unk_10633F200);
    69. v33 = ((__int64 (__fastcall *)(__int64))objc_retainAutoreleasedReturnValue)(v32);
    70. ((void (__fastcall *)(void *))sub_104C86300)(&unk_10633F250);
    71. result = ((__int64 (__fastcall *)(__int64))objc_release)(v33);
    72. }
    73. else
    74. {
    75. sub_104C05A80();
    76. ((void (__fastcall *)(__int64))objc_release)(v24);
    77. result = ((__int64 (__fastcall *)(void *))sub_104BE4C00)(&OBJC_CLASS___UIView);
    78. }
    79. return result;
    80. }

    frida hook

    1. frida-trace -UF -i "stat" -f xxx
    2. frida-trace -UF -i "dladdr" -f xxxx
    3. log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');

    hook stat

    1. /*
    2. * Auto-generated by Frida. Please modify to match the signature of stat.
    3. * This stub is currently auto-generated from manpages when available.
    4. *
    5. * For full API reference, see: https://frida.re/docs/javascript-api/
    6. */
    7. {
    8. /**
    9. * Called synchronously when about to call stat.
    10. *
    11. * @this {object} - Object allowing you to store state for use in onLeave.
    12. * @param {function} log - Call this function with a string to be presented to the user.
    13. * @param {array} args - Function arguments represented as an array of NativePointer objects.
    14. * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
    15. * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
    16. * @param {object} state - Object allowing you to keep state across function calls.
    17. * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
    18. * However, do not use this to store function arguments across onEnter/onLeave, but instead
    19. * use "this" which is an object for keeping state local to an invocation.
    20. */
    21. onEnter(log, args, state) {
    22. log(`stat(fildes=${args[0]}, buf=${args[1]})`);
    23. log(`stat(fildes=${(args[0].readUtf8String())}]`);
    24. this.args0 = args[0]; // 入参
    25. this.args2 = args[1]; // 返回值指针
    26. },
    27. /**
    28. * Called synchronously when about to return from stat.
    29. *
    30. * See onEnter for details.
    31. *
    32. * @this {object} - Object allowing you to access state stored in onEnter.
    33. * @param {function} log - Call this function with a string to be presented to the user.
    34. * @param {NativePointer} retval - Return value represented as a NativePointer object.
    35. * @param {object} state - Object allowing you to keep state across function calls.
    36. */
    37. onLeave(log, retval, state) {
    38. log(`before:=${retval}`);
    39. var newstr = this.args0 .readUtf8String();//oldNSStr.toString();
    40. if(newstr.search("Cydia")>0
    41. || newstr.search("MobileSubstrate")>0
    42. || newstr.search("private---")>0
    43. || newstr.search("cydia")>0
    44. || newstr.search("Applications")>0
    45. || newstr.search("apt")>0
    46. ){
    47. log("=========checkJB=hook===========" );
    48. //var str = ObjC.classes.NSString.stringWithString_('{"ret":0,"msg":null,"data":{"c":3,"t":6,"w":60,"fc":1}}'); // 对应的oc语法:NSString *str = [NSString stringWithString:@"hi with!"];
    49. //args[2] = str;
    50. retval.replace(0xf1) // 修改返回值 0xffffffffffffffff
    51. log(`before:=${retval}`);
    52. log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
    53. }
    54. }
    55. }

    hook md5

    frida-trace -UF -i "CC_MD5" -f xxxxxxx.xxx.xxxx

    1. /*
    2. * Auto-generated by Frida. Please modify to match the signature of CC_MD5.
    3. * This stub is currently auto-generated from manpages when available.
    4. *
    5. * For full API reference, see: https://frida.re/docs/javascript-api/
    6. */
    7. {
    8. /**
    9. * Called synchronously when about to call CC_MD5.
    10. *
    11. * @this {object} - Object allowing you to store state for use in onLeave.
    12. * @param {function} log - Call this function with a string to be presented to the user.
    13. * @param {array} args - Function arguments represented as an array of NativePointer objects.
    14. * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.
    15. * It is also possible to modify arguments by assigning a NativePointer object to an element of this array.
    16. * @param {object} state - Object allowing you to keep state across function calls.
    17. * Only one JavaScript function will execute at a time, so do not worry about race-conditions.
    18. * However, do not use this to store function arguments across onEnter/onLeave, but instead
    19. * use "this" which is an object for keeping state local to an invocation.
    20. */
    21. onEnter(log, args, state) {
    22. log('CC_MD5()');
    23. this.args0 = args[0]; // 入参
    24. this.args2 = args[2]; // 返回值指针
    25. },
    26. /**
    27. * Called synchronously when about to return from CC_MD5.
    28. *
    29. * See onEnter for details.
    30. *
    31. * @this {object} - Object allowing you to access state stored in onEnter.
    32. * @param {function} log - Call this function with a string to be presented to the user.
    33. * @param {NativePointer} retval - Return value represented as a NativePointer object.
    34. * @param {object} state - Object allowing you to keep state across function calls.
    35. */
    36. onLeave(log, retval, state) {
    37. var ByteArray = Memory.readByteArray(this.args2, 16);
    38. var uint8Array = new Uint8Array(ByteArray);
    39. var str = "";
    40. for(var i = 0; i < uint8Array.length; i++) {
    41. var hextemp = (uint8Array[i].toString(16))
    42. if(hextemp.length == 1){
    43. hextemp = "0" + hextemp
    44. }
    45. str += hextemp;
    46. }
    47. log(`CC_MD5(${this.args0.readUtf8String()})`); // 入参
    48. log(`CC_MD5()=${str}=`);
    49. }
    50. }

    fishhook

    1. rebind_symbols((struct rebinding[1]){{"stat", my_stat, (void *)&orig_stat}}, 1);
    2. rebind_symbols((struct rebinding[1]){{"strcmp", my_strcmp, (void *)&orig_strcmp}}, 1);
    1. //***********************abort********************************
    2. //void abort(void) __dead2;
    3. void abort_hook(void) {
    4. }
    5. static void (*abort_old)(void);
    6. //int stat(const char *, struct stat *) __DARWIN_INODE64(stat);
    7. static int (*orig_stat)(const char *age1, struct stat * age2) ;
    8. static int my_stat(const char *age1, struct stat *age2){
    9. //NSLog(@"[orig_stat =================]");
    10. printf("[orig_stat =hook================]\n my_stat age1=%s ,Cydia=%s\n ",age1,strstr(age1, "Cydia"));
    11. int isfind = 0;
    12. if(strstr(age1, "Cydia") != NULL){
    13. isfind = 1;
    14. }else if (strstr(age1, "cydia") != NULL){
    15. isfind = 1;
    16. }else if (strstr(age1, "MobileSubstrate") != NULL){
    17. isfind = 1;
    18. }else if (strstr(age1, "Applications") != NULL){
    19. isfind = 1;
    20. }else if (strstr(age1, "apt") != NULL){
    21. isfind = 1;
    22. }
    23. if(isfind == 1){
    24. NSLog(@" ========hook=stat===%s\n ",age1);
    25. return 1;//返回不存在
    26. }
    27. return orig_stat(age1,age2);
    28. }
    29. //strcmp
    30. //如果返回值 < 0,则表示 str1 小于 str2。
    31. //如果返回值 > 0,则表示 str2 小于 str1。
    32. //如果返回值 = 0,则表示 str1 等于 str2。
    33. //int strcmp(const char *__s1, const char *__s2);
    34. static int (*orig_strcmp)(const char *__s1, const char *__s2);
    35. static int my_strcmp(const char *__s1, const char *__s2){
    36. if(strstr(__s2, "libsystem_kernel") != NULL){
    37. NSLog(@" ========hook=strcmp===%s %s\n ",__s1,__s2);
    38. return 0;//返回相等
    39. }
    40. return orig_strcmp(__s1,__s2);
    41. }

    下面是网上找的源码

    1. //这里都是一些越狱后的手机带的一些框架和工具,未越狱的手机是装不上的。
    2. - (void)isOk0 {
    3. NSString *cydiaPath = @"/Applications/Cydia.app";
    4. NSString *aptPath = @"/private/var/lib/apt/";
    5. NSString *applications = @"/User/Applications/";
    6. NSString *Mobile = @"/Library/MobileSubstrate/MobileSubstrate.dylib";
    7. NSString *bash = @"/bin/bash";
    8. NSString *sshd =@"/usr/sbin/sshd";
    9. NSString *sd = @"/etc/apt";
    10. if ([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
    11. exit(0);
    12. }
    13. if ([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
    14. exit(0);
    15. }
    16. if([[NSFileManager defaultManager] fileExistsAtPath:cydiaPath]) {
    17. exit(0);
    18. }
    19. if([[NSFileManager defaultManager] fileExistsAtPath:aptPath]) {
    20. exit(0);
    21. }
    22. if ([[NSFileManager defaultManager] fileExistsAtPath:applications]){
    23. exit(0);
    24. }
    25. if ([[NSFileManager defaultManager] fileExistsAtPath:Mobile]){
    26. exit(0);
    27. }
    28. if ([[NSFileManager defaultManager] fileExistsAtPath:bash]){
    29. exit(0);
    30. }
    31. if ([[NSFileManager defaultManager] fileExistsAtPath:sshd]){
    32. exit(0);
    33. }
    34. if ([[NSFileManager defaultManager] fileExistsAtPath:sd]){
    35. exit(0);
    36. }
    37. }
    1. - (void)isOK1 {
    2. //可能存在hook了NSFileManager方法,此处用底层C stat去检测
    3. // /Library/MobileSubstrate/MobileSubstrate.dylib 最重要的越狱文件,几乎所有的越狱机都会安装MobileSubstrate
    4. // /Applications/Cydia.app/ /var/lib/cydia/绝大多数越狱机都会安装
    5. struct stat stat_info;
    6. if (0 == stat("/Library/MobileSubstrate/MobileSubstrate.dylib", &stat_info)) {
    7. exit(0);
    8. }
    9. if (0 == stat("/Applications/Cydia.app", &stat_info)) {
    10. exit(0);
    11. }
    12. if (0 == stat("/var/lib/cydia/", &stat_info)) {
    13. exit(0);
    14. }
    15. if (0 == stat("/var/cache/apt", &stat_info)) {
    16. exit(0);
    17. }
    18. if (0 == stat("/var/lib/apt", &stat_info)) {
    19. exit(0);
    20. }
    21. if (0 == stat("/etc/apt", &stat_info)) {
    22. exit(0);
    23. }
    24. if (0 == stat("/bin/bash", &stat_info)) {
    25. exit(0);
    26. }
    27. if (0 == stat("/bin/sh", &stat_info)) {
    28. exit(0);
    29. }
    30. if (0 == stat("/usr/sbin/sshd", &stat_info)) {
    31. exit(0);
    32. }
    33. if (0 == stat("/usr/libexec/ssh-keysign", &stat_info)) {
    34. exit(0);
    35. }
    36. if (0 == stat("/etc/ssh/sshd_config", &stat_info)) {
    37. exit(0);
    38. }
    39. }
    1. //strcmp
    2. //如果返回值 < 0,则表示 str1 小于 str2。
    3. //如果返回值 > 0,则表示 str2 小于 str1。
    4. //如果返回值 = 0,则表示 str1 等于 str2。
    5. - (void)isOK2 {
    6. //可能存在stat也被hook了,可以看stat是不是出自系统库,有没有被攻击者换掉
    7. //这种情况出现的可能性很小
    8. int ret;
    9. Dl_info dylib_info;
    10. int (*func_stat)(const char *,struct stat *) = stat;
    11. if ((ret = dladdr(&func_stat, &dylib_info))) {
    12. NSLog(@"lib:%s",dylib_info.dli_fname); //如果不是系统库,肯定被攻击了
    13. if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) { //不相等,肯定被攻击了,相等为0
    14. exit(0);
    15. }
    16. }
    17. }
    1. - (void)isOK3 {
    2. //列出所有已链接的动态库:
    3. //通常情况下,会包含越狱机的输出结果会包含字符串: Library/MobileSubstrate/MobileSubstrate.dylib 。
    4. uint32_t count = _dyld_image_count();
    5. for (uint32_t i = 0 ; i < count; ++i) {
    6. NSString *name = [[NSString alloc]initWithUTF8String:_dyld_get_image_name(i)];
    7. if ([name containsString:@"Library/MobileSubstrate/MobileSubstrate.dylib"]) {
    8. exit(0);
    9. }
    10. }
    11. }
    1. - (void)isOK4 {
    2. //如果攻击者给MobileSubstrate改名,但是原理都是通过DYLD_INSERT_LIBRARIES注入动态库
    3. //那么可以,检测当前程序运行的环境变量
    4. char *env = getenv("DYLD_INSERT_LIBRARIES");
    5. if (env != NULL) {
    6. exit(0);
    7. }
    8. }
    9. //对于这些函数,不建议单独写方法,容易被hook掉,所以最好是写在不能被hook的函数里,比如application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions。。。
    10. //谁TM会hook程序的初始化函数。。

  • 相关阅读:
    Redis的数据类型以及应用场景
    kubesphere安装harbor
    学习c#的第十五天
    如何成功将 API 客户的 transformer 模型推理速度加快 100 倍
    java众筹网计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
    2022年陕西水利水电施工安全员模拟试题及答案
    mysql中的锁
    【机器学习】TF-IDF以及TfidfVectorizer
    自动化测试框架pytest命令参数
    数据分析三剑客之Pandas
  • 原文地址:https://blog.csdn.net/qq_21051503/article/details/133779055