iOS静态方式绕过svc反动态调试

2023-11-14

在iOS反动态调试中,常用到”svc #0x80”,通过svc汇编实现对ptrace、syscall的调用,实现反动态调试,使得lldb无法附加到app进程,不易定位到代码位置,增加反调试绕过难度。

如何绕过这种反调试手段呢?

本文通过搜索app的可执行文件,查找svc相关汇编指令的位置,并修改”svc #0x80” 为 “nop” 从而绕过反动态调试。

本文通过搜索汇编代码块的方式,连续匹配多条汇编指令,从而确定最后一条指令的地址。

一、svc反动态调试代码

举例说明,新创建一个测试APP,在main函数中增加svc汇编,调用svc实现ptrace:

这个测试app编译生成可执行文件,找到svc所在位置:

此时,APP在手机运行,尝试附加app就会提示失败:

debugserver-@(#)PROGRAM:LLDB  PROJECT:lldb-900.3.106
 for arm64.
Attaching to process TestSpace...
Segmentation fault: 11

二、查找svc汇编指令流程

大体思路是读取APP的二进制文件,解析macho格式,找到对应的代码段,把代码段内的二进制转换成汇编指令,遍历找到svc指定对应的地址:

三、主要代码解析

(1)使用capstone库做二进制转汇编。

intmain(int argc, constchar * argv[]){
    //原文件路径
    string sFilePath = "/path/to/TestSpace";
    //存储路径
    string sFilePath_save = "/path/to/TestSpace_2";
    //将要搜索的汇编指令
    vector<string> svc_asm_vec = {"movz x0,#0x1f", "movz x1,#0", "movz x2,#0", "movz x3,#0", "movz w16,#0x1a", "svc #0x80"};

    uint64_t file_size = FileGetSize((char*)sFilePath.c_str());//计算文件大小void *file_buf = gain_fileBuf(sFilePath.c_str());//加载文件到内存//搜索到的"svc #0x80"的地址
    vector<uint64_t> addr_arry = search_svc_from_asm(file_buf, svc_asm_vec);

    if(addr_arry.size()>0){
        void * file_buf_save = alter_svc_to_nop(file_buf, addr_arry[0]);//修改第一个svc为nopsave_buf_to_file(file_buf_save, file_size, sFilePath_save);//存储修改后的二进制到本地文件
    }

    return0;
}

(2)gain_text_sections函数是从二进制文件中找到对应的代码段:

//获取二进制文件中的代码段vector<struct section_64 const *> gain_text_sections(void * file_buf){
    // 判断是否为胖文件
    mach_header * mhHeader = (mach_header*)file_buf;
    vector<struct section_64 const *> sectionArray;
    // 查找代码段structsection_64const * sectionTxt_DB = findSection64ByName(mhHeader, "__text", "__BD_TEXT");//if(sectionTxt_DB==NULL){
        NSLog(@"找不到代码段--1");
    }
    else{
        sectionArray.push_back(sectionTxt_DB);
    }

    structsection_64const * sectionTxt = findSection64ByName(mhHeader, "__text", "__TEXT");//if(sectionTxt==NULL){
        NSLog(@"找不到代码段--2");
    }
    else{
        sectionArray.push_back(sectionTxt);
    }

    return sectionArray;
}

因为大部分APP的代码段是在Section64(TEXT,text)中,有的代码段在Section64(BD_TEXT,text)中,因此代码中需要判断代码段的位置。

(3)从app的二进制文件中,搜索指定的汇编数组,如果完全符合则返回最后一条汇编指令的地址,search_svc_from_asm函数会返回一个数组:

vector<uint64_t> search_svc_from_asm(void * file_buf, vector<string> asmStrArray){
    vector<uint64_t> resultVec;//声明一个int型向量
    vector<struct section_64 const *> sectionArray = gain_sections(file_buf);

    if(sectionArray.size()<1){
        NSLog(@"找不到代码段--3");
        return resultVec;
    }

    for(int i=0; i<sectionArray.size(); i++){
        structsection_64const * sectionTxt = sectionArray[i];

        // 展示 Section64_Header中的 offset 和 sizeuint64_t offset = sectionTxt->offset;
        uint64_t text_size = sectionTxt->size;

        int tmp_length = 4;//单条汇编所占内存//反汇编
        Disasm * disasm = [[Disasm alloc] init];

        uint32_t my_offset = (uint32_t)0;
        uint64_t my_addr = (uint64_t)offset;
        uint32_t my_size = 0x640;//400条int asmStrCount = (int)asmStrArray.size();

        while(1){

            my_size = 0x640;

            if(my_offset==0){
                my_offset = (uint32_t)offset;
            }
            else{
                my_offset = my_offset + my_size - (asmStrCount-1)*tmp_length;
            }

            if(my_offset < text_size+offset && my_offset+my_size > text_size+offset)
            {
                my_size = (uint32_t)(text_size+offset-my_offset);
            }
            elseif(my_offset>text_size+offset){
                break;
            }

            NSArray * asmArrayTmp = [disasm disAsmWithBuff:file_buf offset:my_offset size:my_size addr:(uint64_t)my_addr];

            int count = (int)[asmArrayTmp count];

            uint64_t first_addr = (uint32_t)my_offset;

            int samecount = 0;

            for(int i = 0; i<count; i++){
                NSString * curAsm = [asmArrayTmp objectAtIndex:i];

                for(int j=0; j<asmStrCount; j++){
                    if(j==samecount){
                        NSString * strTmp = [NSString stringWithCString:(asmStrArray[j]).c_str()  encoding:NSUTF8StringEncoding];

                        if([strTmp isEqualToString:curAsm])
                        {
                            samecount = samecount+1;
                            break;
                        }
                        else
                        {
                            samecount = 0;
                            break;
                        }
                    }
                }

                if(samecount==asmStrCount){

                    uint64_t target_addr = (uint64_t)(first_addr+i*4);
                    NSLog(@"查找到svc调用反动态调试:0x%lx    %@", target_addr, curAsm);

                    resultVec.push_back(target_addr);

                    break;
                }

            }

        }
    }

    return resultVec;
}

search_svc_from_asm函数第二个参数是汇编指令数组,可以搜索任意汇编指令。

(4)可根据得到的汇编指令地址,修改”svc #0x80”为”nop”:

void * alter_svc_to_nop(void * file_buf, uint64_t target_addr){
    uint8_t *pBegin = (uint8_t*)file_buf;


    uint64_t target = 0xD4001001;//svc 0x80uint64_t textAddr_base = (uint64_t)pBegin+target_addr;

    structSingleAss * sAss = (struct SingleAss *)(textAddr_base);


    if(sAss->singleAss == target)
    {
        sAss->singleAss = 0xD503201F;// nop
    }

    return file_buf;

}

(5)将修改后的二进制存储到指定文件:

//存储二进制到文件voidsave_buf_to_file(void * file_buf, uint64_t file_size, string filePath_save){
        FILE *fp = fopen(filePath_save.c_str(), "w");
        uint8_t *pBegin = (uint8_t*)file_buf;

        fwrite((void*)pBegin, 1, file_size, fp);

        fclose(fp);

        free(file_buf);

        printf("rBuff=写入完成\n");

        printf("**********************************\n");
}

测试效果如下:

可对新生成的app做重签名,就可以做动态调试了。

五、注意事项

(1)search_svc_from_asm 函数可以搜索任意汇编指令,第二个参数是汇编指令数组,就是要搜索的内容;

(2)如果查不到如下arm汇编:

{“mov x0,#0x1f”, “mov x1,#0”, “mov x2,#0”, “mov x3,#0”, “mov w16,#0x1a”, “svc #0x80”}

可以尝试查一下:

{“movz x0,#0x1f”, “movz x1,#0”, “movz x2,#0”, “movz x3,#0”, “movz w16,#0x1a”, “svc #0x80”}

只有完全匹配才判断为找到对应的汇编指令,如果这也找不到.

可尽量减少汇编指令的数量,例如只搜索最后两条指令{“mov w16,#0x1a”, “svc #0x80”},或者只搜索最后一条指令{“svc #0x80”}

(3)有的app中会存在很多”svc #0x80”指令,只用search_svc_from_asm函数搜索”svc #0x80”指令可能会得到很多结果:

2022-12-1500:19:37.636260+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x7736b94svc#0x802022-12-1500:19:37.642945+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x77383b4svc#0x802022-12-1500:19:37.651847+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x773a824svc#0x802022-12-1500:19:37.654735+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x773b570svc#0x802022-12-1500:19:37.658423+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x773c5d0svc#0x802022-12-1500:19:37.660096+0800MachConfuse[4456:36033721] 查找到svc调用反动态调试:0x773c66csvc#0x80
......

全部改成”nop”也不能正常运行,尽量不要全部改为nop,可尝试逐个修改为nop后签名并测试效果。

一般情况下svc会在main函数中,可尝试找到APP二进制文件中的main函数,看其中如果有svc,可尝试修改为nop。

(4)本工程可用于搜索macho中的任意汇编指令

源码地址:

https://github.com/luoyanbei/MachConfuse

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS静态方式绕过svc反动态调试 的相关文章

  • 设置 Form.KeyPreview = true 的缺点?

    我想知道 Form KeyPreview 属性实际上有什么用处 它为什么存在以及将其设置为 true 会带来什么 风险 我想它一定有some负面影响 否则它根本不应该存在 或者至少默认情况下是正确的 EDIT 我很清楚what确实如此 我问
  • Kerberos 双跳

    我们遇到了臭名昭著的 Kerberos 双跳问题 这是一个全新的域 是从以前使用模拟和委派的另一个提供商迁移而来的 我们已将操作系统升级到最新的 SQL 服务器 2017 WPF 应用程序 使用域凭据 gt Web 服务 IIS 10 上的
  • 如何使用命令行压缩文件?

    我想使用批处理文件命令 Windows XP 批处理文件 压缩目录 例如 如果我想解压缩一个文件意味着我可以使用jar xf file zip java bat 文件命令 就像我想要一个命令行批处理来压缩目录一样 如果您使用的是 Ubunt
  • 不在焦点时响应键盘? (C#、Vista)

    我正在尝试编写一个应用程序 只要按下 Shift 键 无论当前哪个应用程序具有焦点 它都会做出响应 我尝试过这个SetWindowsHookEx 与GetKeyboardState 但这两种方法仅在应用程序窗口具有焦点时才有效 我需要它在全
  • 在哪里可以获得 PHP 5.3+ 的 runkit DLL 扩展?

    这是一个简单的问题 我在哪里可以获得 PHP 5 3 版本的 runkit 扩展 它的手册 http php net manual en book runkit php http php net manual en book runkit
  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • SetCurrentDirectoryW 中的错误 206

    在我之后之前不清楚的问题 https stackoverflow com questions 44389617 long path name in setcurrentdirectoryw 我以某种方式能够创建一个具有长路径名的目录 但是
  • 非托管 C++ 中的默认打印机

    我正在寻找一种使用非托管 C 查找 Windows 默认打印机名称的方法 找到了大量 NET 示例 但非托管没有成功 谢谢 以下是如何获取当前打印机和默认打印机的列表 如果有一台设置为默认打印机 另请注意 如果用户没有打印机或未将打印机名称
  • Tensorflow 导入错误:没有名为“tensorflow”的模块

    我在 Windows Python 3 5 Anaconda 环境中安装了 TensorFlow 验证成功 有警告 tensorflow C gt python Python 3 5 3 英特尔公司 默认 2017 年 4 月 27 日 1
  • 如何向未知用户目录读取/写入文件?

    我正在尝试从用户目录 C Users USERNAME Test Source 读取和写入文件 但我未能成功找到任何有关如何自动检测用户名的资源 其中的 USERNAME上面的例子 或者无论如何 我可以让它读取和写入目录 而不需要知道用户名
  • 所见即所得与 Unicode

    我在 Delphi 中编写了一个 Windows 程序 该程序使用 GetCharWidth 和 Em Square 将文本非常精确地放置并换行到屏幕和打印机 这对于 ANSI 文本效果很好 您只需要检索和计算 255 个字符的宽度 但当您
  • 尽管 if 语句,Visual Studio 仍尝试包含 Linux 标头

    我正在尝试创建一个强大的头文件 无需更改即可在 Windows 和 Linux 上进行编译 为此 我的包含内容中有一个 if 语句 如下所示 if defined WINDOWS include
  • 用于创建计划任务的 VBScript

    我正在尝试创建一个 VBScript 它创建一个批处理文件 然后创建一个计划任务来运行该批处理文件 到目前为止 我尝试过的所有操作都创建了批处理文件 但没有创建计划任务 并且我没有收到任何错误 这是我到目前为止所拥有的 Option Exp
  • 当我启动 Windows 命令提示符时,我做了什么导致环境变量发生更改?

    我使用的是 Windows 10 x64 我安装了 Anaconda3 如果我启动 C Windows system32 cmd exe 时没有运行任何其他内容 并且在我可以看到的后台中没有任何有趣的内容 则以下内容将添加到控制面板 UI
  • 将所有文件与指定目录(和子目录)中的所有文件进行二进制比较

    我需要将目录及其子目录中包含的所有文件与同一目录及其子目录中包含的所有其他文件进行比较 并将匹配文件的路径记录到文本文件或 CSV 我意识到有一些软件工具可以做到这一点 但除非它可以在 Windows 中开箱即用 否则我将不被允许在我的网络
  • 在 Windows 中使用 PHP 创建受密码保护的 Zip 文件

    我正在 PHP 中创建给定文件的 zip 文件 下面是函数 function create zip file file name zip new ZipArchive zip name file name zip Zip name zip
  • 为什么 Windows 命令 DIR 在搜索 *.tif 文件时也会输出 *.tiff 文件?

    我想使用 Windows 命令DIR为了找到唯一TIF文件 即具有扩展名的文件 tif 因此我使用以下小批处理文件 for f delims a IN dir b a d s C wolter testversion input tif d
  • npm package.json bin 无法在 Windows 上运行

    我正在尝试通过 package json 启动我的 cli 工具bin财产 我有以下内容 name mycli bin bin mycli 当我在包路径中打开 cmd 并输入 mycli 时 它表示该命令无法识别 我应该运行 npm 命令吗
  • 从 Powershell 脚本安装 Python

    当以管理员身份从 PowerShell 命令行运行以下命令时 可以在 Windows 11 上成功安装 Python c temp python 3 11 4 amd64 exe quiet InstallAllUsers 0 Instal
  • 如果我使用客户端计算机上未安装的字体,会发生什么情况?

    有人可以告诉我 如果我在 WinForms 应用程序中使用目标计算机上不可用的字体 会发生什么情况 它是否使用同一系列的字体 只是 Sans Serif 还是其他字体 您的应用程序将回退到 Segoe UI Tahoma 然后是 MS Sa

随机推荐

  • 分数混合运算简便方法_《分数乘法》中的简便运算指导

    六年级上册 分数乘法 是在学生学习了运用乘法运算定律和整数 小数乘法简便计算以及分数加 减 乘法计算的基础上进行教学的 这一节课学生进一步理解整数乘法的运算定律不仅适用于小数 整数乘法 而且也适用于分数乘法 使计算更简便 是让学生在经历探索
  • java.lang.NoClassDefFoundError: org/springframework/context/event/EventListenerFactory

    集成rabbitmq的时候报错 只要看到NoClassDefFoundError基本都是jira包冲突了 1 首先找到相关类 spring tx有2个版本 2 利用IDEAL插件mavenhelper看一下 把高版本排除掉就可以了 java
  • 统计学习系列之参数估计

    参数估计 1 什么是参数估计 简单来说是 参数估计是指使用样本统计量估计总体的参数的 百度百科的解释如下 参数估计 parameter estimation 统计推断的一种 根据从总体中抽取的随机样本来估计总体分布中未知参数的过程 从估计形
  • 使用cmake配置aws-cpp-sdk以及在cmake项目中使用

    目录 环境 配置cmake 编译aws cpp sdk 1 使用git bash下载aws cpp sdk项目到指定目录 2 使用clion打开项目 3 设置cmake编译选项 4 BUILD INSTALL 项目 在cmake项目中使用a
  • 【服务器】ASUS ESC4000-E11 安装系统

    ASUS ESC4000 E11说明书 没找到 ASUS ESC4000 E11的说明书 下面是ESC4000A E11的说明书 https manualzz com doc 65032674 asus esc4000a e11 serve
  • E: 仓库 “http://mirrors.aliyun.com/ubuntu eoan Release” 没有 Release 文件 —— 解决方案

    Ubuntu 20 04 更新的时候 遇到如下问题 可以通过修改源 来进行修复 1 登录如下网址 LUG s repo file generator 2 选择对应的 Ubuntu 版本 这里我是 Ubuntu 20 04 点击 Downlo
  • vue实现excel文件上传并解析数据

    vue实现excel文件上传并解析数据 1 安装xlsx并引入 2 页面使用上传组件 3 补充完善 不使用action实现自定义上传 1 安装xlsx并引入 npm install xlsx 0 17 0 save import XLSX
  • 如何将已加好的脚注或尾注转换成中括号“[]”格式

    下面让流程更加清晰 1 正常插入所有尾注 2 点击word文档上方 编辑 选项按钮 3 点击 查找 4 点击 替换 选项 5 在 查找内容 框中输入 e 这是尾注的象征符 在 替换为 框中输入 6 点击下方的 全部替换
  • 9.调试技巧与调试工具

    9
  • Unix网络编程5种IO模型

    IO模型 用一幅图表示所支持的I O模型 纵向维度是 阻塞 Blocking 非阻塞 Non blocking 横向维度是 同步 异步 总结起来是四种模型 同步阻塞 同步非阻塞 异步阻塞 异步非阻塞 Unix网络编程 中划分出了 第五种 模
  • mysql数据库入门教程

    Markdown database notebook Markdown database notebook 1 1 Mysql知识 基础 1 1 1 Msyql的基本知识 1 2 Mysql知识 深入 1 2 1 Mysql的储存引擎 1
  • DIV与Table布局在大型网站的可用性比较

    DIV与TABLE本身并不存在什么优缺点 所谓web标准只是推荐的是正确的使用标签 好比说 DIV用于布局 而TABLE则本来就是转二维数据的 让TABLE做该做的事 并不是说页面里不出现TABLE就是多么多么牛 用DIV进行排版的优势就是
  • jQuery-migrate 插件---各类版本下载

    步骤 1 CDN jquery migrate 2 找到所需版本打开 3 全选复制到自己创建的记事本 4 复制 5 粘贴到IntelliJ IDEA 模块下的 webapp js 没有自己手动创建目录 jquery migrate 1 4
  • Oracal的Lpad函数

    lpad函数是Oracle数据库函数 lpad函数从左边对字符串使用指定的字符进行填充 从其字面意思也可以理解 l是left的简写 pad是填充的意思 所以lpad就是从左边填充的意思 语法格式如下 lpad string padded l
  • unity笔记-20161109

    1 Animator CullingMode 动画器剔除模式 AlwaysAnimate Always animate the entire character Object is animated even when offscreen
  • 在Python中如何优雅地处理PDF文件

    1 引言 PDF文档是我们在日常工作中经常会遇到的文件格式 有时我们需要编辑并从中提取一些有用的数据 在本文中 我将向大家介绍如何使用Python中的PDF库从PDF文档中提取文本 表格和图像以及其他类型的数据 闲话少说 我们直接开始吧 2
  • JS实现请假时长计算(计算小时数差)

    给公司做了一套系统 涉及到请假单功能开发 在计算请假时长这块总结一下 按天计算的就不总结了比较简单 这里总结一下按小时数计算的 话不多说 直接上代码 获取两个日期相差的工作小时 不包括节假日 function getHour StartTi
  • Python 中的异常种类

    常用异常 AttributeError 试图访问一个对象没有的树形 比如foo x 但是foo没有属性x IOError 输入 输出异常 基本上是无法打开文件 ImportError 无法引入模块或包 基本上是路径问题或名称错误 Inden
  • Matlab quiver函数用法 - 画矢量箭头图

    提要 quiver x y u v 在点 x y 处画 u v 所定义的向量箭头 x y u v必须是维度和元素数都一样的矩阵 如果是一维数组的话 x y u v的元素数必须一致 quiver函数会自动调整箭头的长度以适应显示 quiver
  • iOS静态方式绕过svc反动态调试

    在iOS反动态调试中 常用到 svc 0x80 通过svc汇编实现对ptrace syscall的调用 实现反动态调试 使得lldb无法附加到app进程 不易定位到代码位置 增加反调试绕过难度 如何绕过这种反调试手段呢 本文通过搜索app的