精华内容
下载资源
问答
  • 使用Visual Studio 2015的工程源代码。 分析Linux动态库文件,进行32位,64位的文件判断,并进行elf的文件头分析。 在文件中查找特定字符串"version"。查找字符串可根据源码自行修改。 在windows下执行,有类似Linux...
  • 动态符号执行 三、动机 四、后向有界符号执行BACKWARD-BOUNDEDDSEBB-DSE 五、使用BB-DSE解决不可行性问题 A.不透明谓词 B.调用堆栈篡改 C.其他反混淆相关的不可行性问题 六、评估:对照实验 A.初步:与标准...

    目录

    一、介绍

    二、背景

    混淆

    反汇编 

    动态符号执行

    三、动机

    四、后向有界符号执行BACKWARD-BOUNDED DSE    BB-DSE

    五、使用BB-DSE解决不可行性问题

    A. 不透明谓词

    B. 调用堆栈篡改

    C. 其他反混淆相关的不可行性问题

    六、评估:对照实验

    A. 初步:与标准DSE比较

    B. 不透明谓词评估

    C. 调用堆栈篡改评估

    D. 结论

    七、使用封装程序进行大规模评估

    八、真实的恶意程序:X-TUNNEL

    九、应用:稀疏反汇编(SPARSE DISASSEMBLY)

    十、讨论:安全分析

    十一、相关工作

    十二、结论


    原文 Backward-Bounded DSE: Targeting Infeasibility Questions on Obfuscated Codes

    binsec是一个开源工具,主要的应用领域:恶意软件检测、crash分析、反混淆、漏洞分析。
    相当于IDA中的一个插件, 可以去除一些死代码. 实验性质的, 有兴趣的可以玩玩.
    反向的意思,就是从后往前收集约束条件, 做符号执行. 与一般方式相反.
    有界限的意思,就是设定一个从后往前回溯的界限.

    混淆代码的逆向过程中所产生的许多问题归结为不可行问题的求解,下面的文章中提出了后向有界的动态符号执行,可以自动识别不透明谓词,并在CFG图中对其进行裁剪,新生成的CFG图非常精简。相关研究成果发表在2016 blackhat和2017 S&P上:
    2016 blackhat Code Deobfuscation:Intertwining Dynamic, Static and Symbolic Approaches
    2017 S&P Backward-Bounded DSE: Targeting Infeasibility Questions on Obfuscated Codes

    网站 http://binsec.gforge.inria.fr/
    源代码 http://binsec.gforge.inria.fr/distrib/binsec-0.1-20170301.tgz 论文发表后就没更新了

    工程结构分5部分:

    • WP1: requirements
    • WP2: models and generic analysis for binary-level security
    • WP3: vulnerability analysis
    • WP4: malware analysis
    • WP5: experimental evaluation 

    作者上传的一个反混淆的演示视频 https://www.youtube.com/watch?v=Z14ab_rzjfA

    源代码主要由三部分组成

    1. binsec 反汇编,ocaml语言编写
    2. pinsec 跟踪生成trace,c语言编写
    3. idasec ida插件,python语言编写

    安装过程非常麻烦, 等后面有空了, 我再整理一下编译安装过程.

    把文中反混淆的实验测试了一下. 如下图所示, 左边是混淆后的代码, 右边是使用BinSec处理后的代码


    摘要

    代码混淆是安全分析中的重要内容,动态符号执行提出了一个有趣的方案,比静态分析更强大,比动态分析的更完整。但是,DSE只针对某些种类的反向问题,即可行性问题。

    Backward Bounded DSE是一个通用、精确、高效和强大的用来解决不可行问题的方法,我们证明了该方法对不透明谓词和调用堆栈篡改的优势。

    Backward Bounded DSE不是要替代现有的DSE,而是通过以可扩展和精确的方式解决不可行性问题来补充DSE。

    遵循这条线,我们提出了稀疏反汇编,反向有界DSE和静态分析的组合,能够以有保证的方式扩大动态分析,从而获得最佳的动态和静态分析。这项工作为针对严重混淆的二进制文件进行高效和精确的反汇编工具铺平了道路。

     

     

    一、介绍

    静态分析:IDA、objdump,但是容易被混淆:代码交叉覆盖、不透明谓词、不透明常量、调用堆栈覆盖、自修改

    动态分析:仅仅覆盖少量的代码

    目前,只有结合动态分析和DSE(Dynamic Symbolic Execution)才强大到足以解决严重混淆的代码。

     

    在这篇文章中,我们感兴趣的是解决(大型)混淆程序的逆向过程中发生的不可行性问题。 预期的方法必须是精确的(低误报率),并且能够在规模(效率)和保护方面(包括自我修改(稳健性))在实际代码上进行扩展,并且足够通用于处理大型不可行性问题。 同时实现所有这些目标尤其具有挑战性.

    我们结合软件形式化验证方法的一些最先进的关键功能,如推理验证,有界模型检测或DSE。特别是面向目标的、面向效率的、结合动态信息和形式推理的鲁棒性技术。

    提出了Backward-Bounded DSE方法,并做了评估,主要是隐晦谓词和调用堆栈修改方面的测试,也使用了其他的程序做了测试。

    最后,给出了两个应用:首先,我们描述了政府级恶意软件X-TUNNEL的深入案例研究,BB-DSE允许识别和删除所有混淆(不透明谓词)。 我们已经能够自动提取功能的去混淆版本 - 丢弃几乎50%的死亡和“虚假”指令,并提供对其保护方案的深入了解,为进一步深入调查奠定了良好的基础。 其次,我们提出了稀疏反汇编,这是一个BB-DSE,动态分析和标准静态反汇编的组合,允许以一种精确的方式扩大动态拆卸 - 获得了最好的动态和静态技术,以及令人鼓舞的初步实验。

    也可以应用与其他的混淆,比如虚拟化、自修改

    二、背景

    混淆

    这篇文章主要针对不透明谓词和调用堆栈篡改。

    不透明谓词是指一个表达式,他的值在执行到某处时,对程序员而言必然是已知的,但是由于某种原因,编译器或者说静态分析器无法推断出这个值,只能在运行时确定。因此,不透明谓词可以作为控制流混淆时的条件生成器。用它构造一些必真或必假的条件,改造目标程序控制流。举个例子,在执行一些语句序列,如下面这个基本块

    {

      statment1;

      statment2;

      statment3;

    }

    有个表达式,取值总是真或假bool op = true;

    那么就可以使用op来改造上面基本块的控制流1,改造成分支结构。{

      statment1;

      if (op) {

        statment2;

        statment3;

      } else {

        statment3;

        statment2;

      }

    }

    由于else分支根本不可能执行,所以,运行结果和原始程序是等价的。

    此文中以7y*y - 1 != x*x为例,这个表达式总是为真

    调用堆栈篡改

    调用堆栈修改:push X, ret

    反汇编 

    递归

    线性扫描 objdump

    动态反汇编

    动态符号执行

    优缺点:

    三、动机

    针对上面提到的反汇编中的问题,设计一个有效的方法来解决不可行性问题。

    四、后向有界符号执行BACKWARD-BOUNDED DSE    BB-DSE

    三个关键要素:

    1. 利用推理验证来反向推理,用于精确的目标推理;

    2. 与动态分析相结合的形式化方法(DSE),用于鲁棒性;

    3. 利用有界模型检验来推理边界,用于可扩展性和执行可行性论证的能力。

     

    从后往前推理,设定执行的指令条数k作为边界,收集约束条件,求解。

    k太小,FN(false negative)现象,本身是不透明谓词,被判定为不是不透明谓词

    k太大,由于较大的k意味着更多的空间来错过分支,它也产生更多的FP(false positive)。 因此,在一般情况下,较大的k导致较少的FN和更多的FP

    实现

    BINSEC/SE已开源 Pin + IDA插件

    PINSEC运行,记录运行时的变量, 

    IDASEC分析

    BB-DSE 算法集成在其中。在解析谓词可行性时,执行反向修剪过程,以消除任何无用的变量或约束。

    五、使用BB-DSE解决不可行性问题

    A. 不透明谓词

    3类不透明谓词:

    不变量:总是为真或假

    上下文关联

    动态

    动态执行过程中有路径,认为可行,否则调用BB-DSE看是否可行

    B. 调用堆栈篡改

    1. call和ret时,栈中数据是否相同

    2. call和ret时,ESP值是否相同

    3. 是否有多个不同的ret地址可满足

    使用动态执行和BB-DSE一起,有个表没看懂

    C. 其他反混淆相关的不可行性问题

    不透明常量:与不透明谓词类似,不透明常量只有一个解

    动态跳转闭包:比如switch,判断是否所有的jmp被找到了。判断是否没有其他输入了

    虚拟机&CFG扁平化:可以证明很多分支不可达,剪除

    条件自修改一撇:没太明白

    六、评估:对照实验

    A. 初步:与标准DSE比较

    DSE不适应于不可行性问题

    BB-DSE不适应于可行性问题

    B. 不透明谓词评估

    测试结果表示,BB-DSE在检测不透明谓词时非常精准,但是边界很重要。试验中10 < k < 30比较好

    C. 调用堆栈篡改评估

    BB-DSE表现很好,没有FP。该技术同时恢复真正的ret和单目标篡改后的ret。

    D. 结论

    这些不同的对照实验清晰地证明BB-DSE是一个解决不同种类不可行性问题的非常精确的方法。还表明在实践中找到一个合适的约束k不是一个问题。最后,这种方法似乎是可扩展的。最后一点将在第七章和第八节中得到明确证明。

    这些不同的对照实验清楚地表明,BB-DSE是解决不同类型的不可行性问题的一种非常精确的方法。它们还表明,找到一个合适的界限k在实践中不是一个问题。最后,这个方法似乎是可扩展的。最后一点将在第七章和第八节中得到明确证明。

    七、使用封装程序进行大规模评估

    封装程序是嵌入其他程序并在运行时解压或解密它们的程序。

    跟踪指令限制到10000000条。

     

    对一个简单的程序进行加壳,使用了很多常用的加壳软件,如ACProtect/ASPack/UPX…

    证明BB-DSE足够有效和健壮

    八、真实的恶意程序:X-TUNNEL

    APT28使用的一个加密代理组件。

    移除死代码和无意义的指令,显示的CFG比原始的要精简很多。

    九、应用:稀疏反汇编(SPARSE DISASSEMBLY

    1. 动态跟踪,记录trace及中间一个值

    2. 静态分析,在分支处调用BB-DSE,跳过死分支

    3. 使用BB-DSE找到call对应的真正的ret

    最好的动静结合的反汇编方法。但依然被递归反汇编的固有弱点所限制。

    十、讨论:安全分析

    三个对抗方法及缓解措施:

    1. 把混淆方案的计算分布在一个长的代码序列上,超过BB-DSE中的k值。对于这些“远依赖性的谓词”来说,一个很好的缓解就是依赖一个更一般的k边界的概念,例如基于def-use链长度或者一些公式复杂度标准而不是严格的指令数量。

    2. 对策是引入难以解决的谓词(例如基于混合布尔算法或密码散列函数)会造成求解器超时。但是,超时可能反而暴露了重要代码。同时这样措施会使恶意软件设计大大复杂化,可能导致非典型的代码结构,容易出现相关的恶意代码指纹。

    3. 一些反动态跟踪的技巧。本文中方法可以与其他技术协同工作,来缓解这个问题。

    十一、相关工作

    DSE和反混淆

    反向推理。反后推理在无限状态模型检查中很有名,纯粹的向后方法在二进制水平上几乎不可能实现,因为缺少计算跳跃的先验信息。而BB-DSE解决了这个问题。

    反汇编。这些方法在伸缩性和健壮性方面仍然面临着重大问题。特别是,自修改很难对付,并且在这个方向中只有很少的工作存在。几项工作试图将静态分析和动态分析相结合,以便更好地反汇编。特别是,codisasm利用动态轨迹进行自动修改程序语法的静态反汇编。

    混淆。不透明的谓词,为了检测它们,已经提出了多种方法,特别是抽象解释和最近与DSE的研究。堆栈篡改引起的问题以及最显着的不返回函数,提出了一种基于抽象解释的方法。以上解决方案都不能像BB-DSE那样以可扩展和可靠的方式解决问题。

    十二、结论

    混淆代码的逆向过程中所产生的许多问题归结为不可行的问题解决。然而,这类问题大多是标准和高级的反汇编工具的盲点。我们提出了后向有界的动态符号执行,一种精确,高效,稳健和通用的方法来解决与反混淆相关的不可行性问题。我们已经证明了这种方法对几个真实类型的混淆如不透明谓词和调用栈篡改的好处,并给出了其他保护方案的见解。后向有界的动态符号执行不取代现有的反汇编方法,而是通过解决不可行性问题来补充它们。接下来,我们展示了如何使用这些技术来解决国家资助的恶意软件(X-TUNNEL),以及如何将这一技术与标准的静态反汇编和动态分析相结合,从而以精确和有保证的方式扩大动态分析。这项工作为针对混淆二进制文件的精确高效的反汇编工具铺平了道路。

    展开全文
  • 目录 1.实验说明 1.1 DSE简介 符号执行 (Symbolic Execution)是一种程序分析技术,它可以通过分析程序来得到让特定代码区域执行的输入。顾名思义,使用符号执行分析一个程序时...动态符号执行是以具体数值作为输入来

    目录

    1.实验说明

    1.1 DSE简介

    符号执行 (Symbolic Execution)是一种程序分析技术,它可以通过分析程序来得到让特定代码区域执行的输入。顾名思义,使用符号执行分析一个程序时,该程序会使用符号值作为输入,而非一般执行程序时使用的具体值。在达到目标代码时,分析器可以得到相应的路径约束,然后通过约束求解器来得到可以触发目标代码的具体值。

    符号执行在发展过程中出现了一种叫做动态符号执行的方法(concrete and symbolic, concolic)。动态符号执行是以具体数值作为输入来模拟执行程序代码,与传统静态符号执行相比,其输入值的表示形式不同。动态符号执行使用具体值作为输入,同时启动代码模拟执行器,并从当前路径的分支语句的谓词中搜集所有符号约束。然后修改该符号约束内容构造出一条新的可行的路径约束,并用约束求解器求解出一个可行的新的具体输入,接着符号执行引擎对新输入值进行一轮新的分析。通过使用这种输入迭代产生变种输入的方法,理论上所有可行的路径都可以被计算并分析一遍。

    1.2 实验要求

    • 基于llvm和Z3求解器实现基本的动态符号执行工具
    • 设计路径搜索策略,发现测试程序中的ERROR
    • 分析不可达路径的测试用例执行情况

    2.实验环境

    2.1 软件环境

    软件/系统 版本
    Ubuntu(虚拟机) 18.01
    Clion 2020.02.1
    llvm 8.0.1
    Z3 4.8.8

    2.2 实验环境配置

    1. 本次实验原本是在MacOs上进行的,但是由于最终在运行程序时,需要加载动态库libruntime.在Ubuntu下是需要导入环境变量LD_LIBRARY_PATH,这基本等同于在MAC下配置DYLD+LIBRARY_PATH的环境路径,但是运行时的动态库加载却一时无法加载。因此,我直接选择了在Ubuntu下对环境进行重新的配置。
    2. 安装LLVM。
      本次实验推荐安装的LLVM版本为8.0.1,直接在github代码库中下载,进行源码编译即可(首次编译时间可能过长,可以开启多线程编译,缩短时间)。同时设置好LLVM的环境变量。
    3. 安装Z3。
      Z3可以选择对应系统的已编译完成的二进制源码即可,同样可以再gtthub release中下载对应4.8.8版本。(ubuntu18.04选择ubuntu16.0.4版本下载即可)。同时设置好Z3_DIR的环境变量。
    4. Clion
      作为代码的编辑器,同时管理CMakeFile文件。

    3.实验步骤

    3.1 整体流程

    ./dse ./branch0 N
    循环次数小于N
    从input.txt 中读符号变量的值
    符号执行
    测试程序是否崩溃
    程序执行结束
    应用搜索策略
    Z3求解
    产生新的input.txt
    1. 在流程图中,N决定尝试找寻有效路径的次数。
    2. input.txt没有初值时,会根据符号化的变量产生对应符号的随机值。
    3. 每次测试程序执行时,如果成功执行,会将路径约束记录下来。
    4. 根据路径约束和搜索策略可以得到另外一条可满足的约束路径(本次实验所采用的就是DFS搜索策略)

    3.2 插装函数

    我们插装的目的是为了进行符号运算。只有通过插装函数,才能跟踪程序执行过程中符号关系以及赋值的变化。

    1. 初始化
      在LLVM main函数执行之初插装
      __DSE__Init__
      __DSE_Init__插装位置

    2. LLVM-IR alloc
      __DSE_Alloc__插装位置

    3. LLVM_IR Stroe
      当Store指令的第一个操作数为常数时,需要先调用__DSE_Const__将常数压入DSE栈中。
      __DSE_Store__指令插装位置1
      当Store指令的第一个操作数为寄存器时,需要先调用__DSE_Register__将寄存器压入DSE栈中。
      __DSE_Store__指令插装位置2

    4. LLVM_IR Load

    __DSE_Load__指令插装位置

    1. LLVM_IR BinarryOperator
      BinOp插装之前需要先将BinOp的两个操作数首先压如到DSE栈中,然后插装BinOp指令。
      插装两个操作数是首先需要判断操作数的类别是寄存器还是常数,调用不同的入栈函数。

    __DSE_BinOp指令插装位置

    上图表示的第一个操作数是寄存器,第二个操作数是常数的情况。

    1. LLVM-IR Icmp
      Icmp指令插装是首先需要把两个操作数调用指令压入DSE栈中,类似于DSE_BinOp的插装.
      __DSE_Icmp__指令插装位置
      上图表示两个操作数都是寄存器。

    2. LLVM-IR Branch
      br指令在LLVM指令集中有两种形式,一种是无条件跳转,这种指令不需要进行任何插装。对于条件指令,需要在运行路径上插装,不能简单地插装在现有的任何一个代码块中。

    对于条件语句的插装位置一种简单的实现方式就是在跳转的代码块之间建立一个新的代码块,在新的代码块中插入跳转指令的插装函数。

    ; 原llvm
    br i1 %cmp, label %for.body, label %for.end
    
    for.body:      
    xxx
    
    for.end:  
    xxx
    
    
    ; 插装后llvm
    br i1 %cmp, label %for.body_temp, label %for.end_temp
    
    for.body:      
    xxx
    
    for.end:  
    xxx
    
    for.body_temp:                                    ; preds = %for.cond
    call void @__DSE_Branch__(i32 0, i32 7, i32 1)
    br label %for.body
    
    for.end_temp:                                     ; preds = %for.cond
    call void @__DSE_Branch__(i32 0, i32 7, i32 0)
    br label %for.end
    
    

    3.3 运行时函数

    插装函数是作为钩子函数嵌入在代码中,当程序运行时,会调用外部动态库中相应名称的函数方法。
    在所给的程序代码框架中已经对如下LLVM函数实现了插装函数的运行时函数:

    LLVM函数 对应插装函数 功能
    XX __DSE_Input__
    br __DSE_Branch__ 在对应需要跳转的路径上记录跳转条件
    xx __DSE_Const__ 将常量压入DSE栈中
    xx __DSE_Register__ 将寄存器压入DSE栈中
    xx __DSE_Init__ 初始化新的DSE栈和DSE内存
    xx __DSE_Exit__ 将执行路径条件打印到日志中
    1. DSE_Alloca
      在DSE内存中存储分配变量的地址。
    2. DSE_Store
      从栈中取值,赋值给传过来的寄存器(该寄存器已经在DSE内存中)。
    3. DSE_Load
      从DSE内存中将一个值赋值另一个寄存器。
    4. DSE_ICmp
      从DSE栈中取出两个操作数,并且根据操作符进行比较,将结果分配给传入的寄存器。
    5. DSE_BinOp
      从DSE栈中取出两个操作数,并且根据操作符进行运算,将结果分配给传入的寄存器。

    3.4 搜索策略

    本次实验采用的是DSE的深度优先搜索的策略。
    大致过程如下:

    1. 首先构造一个二叉树根节点,(值为空,左右节点为空)
    2. 当前一次条件过来时执行如下步骤(条件顺序就是路径顺序):
    3. 以根节点作为当前节点。
    4. 如果左节点为空,将该条件加入左节点(新建节点),左节点作为当前节点。
    5. 如果左节点条件与该条件等价,那么左节点作为当前左节点。
    6. 如果右节点为空,那么将条件加入到右节点(新建右节点)。
    7. 如果右节点与当前条件等价,那么右节点作为当前节点。
    8. 跳至第四步操作,直至条件循环。
    9. 得到最新的当前节点
    10. 如果当前节点为左节点,同时它的邻居右节点为空,那么将该节点的值取反加入到右节点,右节点成为当前节点。
    11. 如果当前节点为右节点,需要向上取其父母,直到有邻居右节点为空,执行第10步的操作。如果找不到这样的节点,说明条件搜索完毕。

    4.实验结果

    4.1 测试用例1分析(branch0)-崩溃测试

    // branch0.c
    int main() {
      int x;
      DSE_Input(x);
      int y;
      DSE_Input(y);
      int z;
      DSE_Input(z);
    
      if (x == 0) {
    	 if (y == z) {
    		x = x / (y-z);
    	 }
      }
    
      return 0;
    }
    

    该程序对x、y、z进行了符号化。

    dse程序对该程序执行的结果如下:
    结果1

    同时log.txt中的内容如下:

    === Inputs ===
    X0 : 0
    X1 : 1035168130
    X2 : 180465486
    
    === Symbolic Memory ===
    140733207362528 : X2
    140733207362532 : X1
    140733207362536 : X0
    140733207362540 : 0
    R0 : |140733207362540|
    R1 : |140733207362536|
    R2 : |140733207362532|
    R3 : |140733207362528|
    R4 : X0
    R5 : (= 0 X0)
    R6 : X1
    R7 : X2
    R8 : (= X2 X1)
    
    === Path Condition ===
    B0 : (= (= 0 X0) true)
    B1 : (= (= X2 X1) false)
    
    === New Path Condition ===
    (= (= 0 X0) true)
    (not (= (= X2 X1) false))
    
    

    对比运行结果,我们发现,即使程序设置是5次迭代,但是在第2次时,由于最新的路径条件
    (=(=0X0)true) (= (= 0 X0) true)
    (not(=(=X2X1)false)) (not (= (= X2 X1) false))
    ,使得程序崩溃。

    同时发现,搜索策略对第二条路径直接取反,成为了新的路径条件。

    4.2 测试用例2分析(branch0-1)-分支测试

    //branch0-1.c
    int main() {
      int x;
      DSE_Input(x);
      int y;
      DSE_Input(y);
      int z;
      DSE_Input(z);
    
      if (x > 0) {
    	 if (y > 0) {
    	     if (z > 0)
    		x = x;
    	 }
      }
    
      return 0;
    }
    

    观察该程序,发现该程序的路径有4条。

    运行结果如下:
    结果2

    结合上面的输出,可以画出执行路径:
    路径1
    路径2
    路径3
    路径4

    4.3 测试用例3分析(infeseable)-不可达测试

    int main() {
      int x;
      DSE_Input(x);
    
      //c is a product of two primes 
      int c = 181 * 191;
    
      int y = 1;
    
      for(int i=0; i<x; i++){
    	y *= 2;
      }
    
      if (y % c == 17) {
      	x = x / (c-c);
      }
      return 0;
    }
    

    该函数的路径数取决于x。x越大路径数越多。由于该原型设计的深度优先搜索策略,以第一次输入的路径为基础。
    当x固定输入10时:
    结果
    在for循环内执行10次,接着是一次不满足的for循环条件,接下来是一个没有被符号化的条件。
    第二次条件为:
    结果
    根据深度优先搜索,之后的条件都会与(=(<0X0)true)(= (< 0 X0) true)矛盾,因此,直接产生第三次的可满足的条件:
    结果
    此时该次DFS搜索全部结束。
    由于我在程序中加入了break语句,在搜索完毕后直接退出,但是如果继续重置搜索二叉树,生成随机的x,从而产生y,满足非符号化的条件,生成这样的随机x的概率很小。
    x=log2(17+181191r),rN,s.t.xN x=\log_2{(17+181*191*r)},r\in\N,s.t. x\in\N

    代码资源下载

    展开全文
  • 聚焦源代码安全,网罗国内外最新资讯!*声明:《缺陷周话》栏目系列文章由奇安信代码卫士团队原创出品。未经许可,禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。代码审计是使用静态分析发现源代码...

    37aa2050aa23a64e7b9b5026174a792d.gif 聚焦源代码安全,网罗国内外最新资讯!

    *声明:《缺陷周话》栏目系列文章由奇安信代码卫士团队原创出品。未经许可,禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。

    代码审计是使用静态分析发现源代码中安全缺陷的方法,辅助开发或测试人员在软件上线前较为全面地了解安全问题,防患于未然,因此一直以来都是学术界和产业界研究的热点,并已成为安全开发生命周期 SDL 和 DevSecOps 等保障体系的重要技术手段。

    奇安信代码卫士团队基于自主研发的国内首款源代码安全检测商用工具,以及十余年漏洞技术研究的积累,推出“缺陷周话”系列栏目。每周针对 CWEOWASP 等标准中的一类缺陷,结合实例和工具使用进行详细介绍,旨在为广大开发和安全人员提供代码审计的基础性标准化教程。

    缺陷周话 • 第48期

    动态解析代码     

      

    1、动态解析代码

    1474f63cd468ffd7204b7a916be69553.png

    许多编程语言都允许动态解析源代码指令。这使得程序可以执行基于用户输入的动态指令。若不经过适当的验证,程序会错误地认为由用户直接提供的指令仅会执行一些无害的操作,会正常解析并执行该指令。远程用户可以提供特定URL以将任意代码传递给eval()语句,从而导致代码执行。该种攻击会使用与目标Web服务相同的权限执行代码,包括操作系统命令。本文以JAVA语言源代码为例,分析“动态解析代码”缺陷产生的原因以及修复方法。该缺陷的详细介绍请参见CWE ID 95: Improper Neutralizationof Directives in Dynamically Evaluated Code ('Eval Injection')(http://cwe.mitre.org/data/definitions/95.html)。

    2、动态解析代码的危害

    5516b3590723c0ae230d3ac5baf76dfb.png

    攻击者可以利用该漏洞注入恶意代码访问受限的数据和文件。几乎在所有情况下,注入恶意代码都可能导致数据完整性缺失,也有可能导致执行任意代码。

    从2018年1月至2019年8月,CVE中共有1条漏洞信息与其相关。漏洞信息如下:

    CVE概述
    CVE-2018-7046DISPUTED  Kentico 版本9到11中的任意代码执行漏洞允许远程认证用户通过页面 - >编辑 - >模板 ->编辑模板属性来动态解析上下文代码以执行任意操作系统命令 。注意:供应商修复该漏洞,授权用户可以编辑和更新ascx代码布局。


    3、示例代码

    5516b3590723c0ae230d3ac5baf76dfb.png

    3.1 缺陷代码

    a7945a19c3a7040e77e7efe1628907b7.png

    上述代码是获取 JavaScript 脚本字符串并将该字符串值作为命令执行的操作。第15行获取请求参数script,第16行调用 Context 类的静态方法 enter(),该方法会返回一个与当前线程关联的对象cx。17行对象 cx 调用initStandardObjects() 方法用于初始化标准对象,执行结果将会返回一个Scriptable 实例化对象 scope。第18行调用 evaluateString () 方法执行JavaScript 脚本字符串 script。当 script 参数值合法时,程序将会正常运行。例如,当该值为 "8 + 7 * 2" 时,result 变量被赋予的值将为 22。然而攻击者指定的语言操作既有可能是有效的,又有可能是恶意的。如果底层语言提供了访问系统资源的途径或允许执行系统命令,这种攻击甚至会更加危险。例如,JavaScript 允许调用 Java 对象。如果攻击者计划将 " java.lang.Runtime.getRuntime().exec("shutdown -hnow")" 指定为script的值,则主机系统就会执行关机命令。

    使用代码卫士对上述示例代码进行检测,可以检出“动态解析代码”缺陷,显示等级为高。在代码行第18行报出缺陷,如图1所示:

    de12565699b7d7c95e5559f5756296db.png

    图1:动态解析代码检测示例

    3.2 修复代码

    cb9768380d8b8d32a1700839c0a321ca.png

    在上述修复代码中,在第18行调用 setClassShutter() 方法,该方法参数为ClassShutter 接口的子类,需要实现接口方法 visibleToScripts(),方法用于控制程序中的类是否对脚本可见,在代码行第23行中指定不允许脚本访问或使用 java.lang.Runtime 包下的所有类及方法。使用代码卫士对修复后的代码进行检测,可以看到已不存在“动态解析代码”缺陷。如图2所示:

    0bcc1776b232df3209f4918ed227952a.png

    图2:修复后检测结果

    4、如何避免动态解析代码

    5516b3590723c0ae230d3ac5baf76dfb.png

    在任何时候,都应尽可能地避免动态的解析源代码。如果程序的功能要求对代码进行动态解析,应用程序不应该直接执行和解析未验证的用户输入。建议创建一份合法操作和数据对象列表,用户可以指定其中的内容,并且只能从中进行选择。

    推荐阅读

    【缺陷周话】第47期:参数未初始化

    【缺陷周话】第46期:邮件服务器建立未加密的连接

    【缺陷周话】第45期:进程控制

    【缺陷周话】第44期:Spring Boot 配置错误:不安全的 Actuator

    【缺陷周话】第43期:不当的函数地址使用

    【缺陷周话】第42期 — Cookie:未经过SSL加密

    【缺陷周话】第41期:忽略返回值

    【缺陷周话】第40期:JSON 注入

    【缺陷周话】第 39期:解引用未初始化的指针

    【缺陷周话】第 38期——不安全的反序列化:XStream

    【缺陷周话】第 37期:未初始化值用于赋值操作

    【缺陷周话】第 36 期:弱验证

    【缺陷周话】第 35 期:除数为零

    【缺陷周话】第 34 期:重定向

    【缺陷周话】第 33期:错误的资源关闭

    【缺陷周话】第 32期:弱加密

    【缺陷周话】第 31 期:错误的内存释放方法

    【缺陷周话】第 30 期:不安全的哈希算法

    【缺陷周话】第 29 期:返回栈地址

    【缺陷周话】第 28 期:被污染的内存分配

    【缺陷周话】第 27 期:不安全的随机数

    【缺陷周话】第 26期:被污染的格式化字符串

    【缺陷周话】第 25期:硬编码密码

    【缺陷周话】第 24期:在scanf 函数中没有对 %s 格式符进行宽度限制

    【缺陷周话】第 23期:双重检查锁定

    【缺陷周话】第 22期:错误的内存释放对象

    【缺陷周话】第 21 期:数据库访问控制

    【缺陷周话】第 20 期:无符号整数回绕

    【缺陷周话】第19期:LDAP 注入

    【缺陷周话】第18 期  XPath 注入

    【缺陷周话】第17 期:有符号整数溢出

    【缺陷周话】第 16 期 — 资源未释放:流

    【缺陷周话】第 15 期 — 资源未释放:文件

    【缺陷周话】第 14 期 :HTTP 响应截断

    【缺陷周话】第 13期 :二次释放

    【缺陷周话】第 12期 :存储型 XSS

    【缺陷周话】第 11期 :释放后使用

    【缺陷周话】第 10 期 :反射型 XSS

    【缺陷周话】第 9 期 :缓冲区下溢

    【缺陷周话】第 8 期 :路径遍历

    【缺陷周话】第 7 期 :缓冲区上溢

    【缺陷周话】第 6 期 :命令注入

    【缺陷周话】第5期 :越界访问

    【缺陷周话】第4期 :XML 外部实体注入

    【缺陷周话】第3期 :内存泄漏

    【缺陷周话】第 2 期 :SQL 注入

    【缺陷周话】第1期 :空指针解引用

    *奇安信代码卫士团队原创出品。未经许可,禁止转载。转载请注明“转自奇安信代码卫士 www.codesafe.cn”。

    9abf3bf77a1f6388352c44dddcf32a12.png

    奇安信代码卫士 (codesafe)

    国内首个专注于软件开发安全的产品线。

    展开全文
  • 概述MIPS平台中动态库的装载与解析...之所以要了解mips动态符号的解析调用,是因为之前在实现mips backtrace时,对一些调整gp的指令存在疑惑,顾而深入研究一下。先上结论:MIPS动态库中的外部符号调用,是依赖.got...
    1. 概述
    MIPS平台中动态库的装载与解析原理,网上资料并不多,而且很多讲解都是错误的,甚至MIPS宝书《see mips run》中也没有提供详细的方案。因此本人只好通过代码走读和运行验证的方法来详细了解其原理。之所以要了解mips动态符号的解析调用,是因为之前在实现mips backtrace时,对一些调整gp的指令存在疑惑,顾而深入研究一下。

    先上结论:MIPS动态库中的外部符号调用,是依赖.got段和.MIPS.stubs段来共同实现的。
    .got中保存着外部符号的地址,但由于采用了延迟绑定技术,某外部符号在第一次被调用前,其地址是未知的,ld.so在装载动态库阶段并没有立刻将外部函数解析并填充到.got中,目的是为了加快启动速度,也是为了不必要的时间浪费,因为在进程运行期间,某些外部符号可能永远都不会被调用到,所以装载阶段解析所有符号是一个浪费时间的行为。
    因此,.got中的未决议符号项内,先指向了.MIPS.stubs中的一段指令(每个符号都对应一段单独的指令),这段指令的作用是跳转至符号解析函数_dl_runtime_resolve。
    .got段的第一项比较特殊,它保存的符号正是函数"_dl_runtime_resolve",用objdump查看时此项为0,但运行起来之后,会被ld.so填充进_dl_runtime_resolve的地址。

    下面简单举例说明。
    hello.c:
    #include <stdio.h>
    #include "hello.h"
    int hello(int i)
    {
    printf("hello %d \n",i);
    return 0;
    }

    main.c:
    #include <stdio.h>
    #include "hello.h"
    int main(int argc, char** argv)
    {
    int i = 0;

    hello(i);
    i++;

    hello(i);
    return 0;
    }

    mipsel-linux-gcc hello.c -g -fPIC -rdynamic -fasynchronous-unwind-tables -shared -o libhello.so
    mipsel-linux-gcc main.c -g -fPIC -rdynamic -fasynchronous-unwind-tables -L./ -lhello -o main.elf
    1. 流程图
    1. main首次调用hello
    mips_lazy_banding.png
    图1 main首次调hello
    1. main再次调用hello
    mips_after_banding.png

    图2 main再次调hello
    1. 汇编代码走读
    main函数汇编代码走读:
    00400810 <main>:
    400810: 3c1c0002 lui gp,0x2 //gp = 0x20000
    400814: 279c81b0 addiu gp,gp,-32336 //gp = gp -32336;
    400818: 0399e021 addu gp,gp,t9 //gp == &_gp,此时gp寄存器指向符号_gp(_gp_disp),也就是 &_gp = 4189c0 关于_gp的详细解释请见附录,t9存的是本函数地址
    40081c: 27bdffd8 addiu sp,sp,-40 //调整栈顶指针
    400820: afbf0024 sw ra,36(sp) //保存返回地址
    400824: afbe0020 sw s8,32(sp) //保存caller fp
    400828: 03a0f021 move s8,sp //调整fp
    40082c: afbc0010 sw gp,16(sp) //保存本函数gp
    400830: afc40028 sw a0,40(s8) //保存入参
    400834: afc5002c sw a1,44(s8) //保存入参
    400838: afc00018 sw zero,24(s8) //本地变量初始化
    40083c: 8fc40018 lw a0,24(s8) //准备将本地变量作为入参传给子函数
    400840: 8f828018 lw v0,-32744(gp) //v0 = *(&_gp - 32744) = *(4109d8) = 4008f0,也就是.got内第3项存的是.MIPS.stub的地址,稍后经过binding之后,此处会got第3项变成hello的地址
    400844: 0040c821 move t9,v0 //经计算,此处t9寄存器的值是4008f0,也即.MIPS.stubs的地址
    400848: 0320f809 jalr t9 //跳转到.MIPS.stubs处执行,返回地址已自动存入ra寄存器
    40084c: 00000000 nop
    ...

    004008f0 <.MIPS.stubs>:
    4008f0: 8f998010 lw t9,-32752(gp) //t9 = *(4109d0),为 .got的首地址
    4008f4: 03e07821 move t7,ra //将返回地址存到t7,此处的返回地址显然是main中的指令 "jalr t9"的下下条指令。_dl_runtime_resolve中会用t7寄存器来返回到main。
    4008f8: 0320f809 jalr t9 //跳转执行.got首地址的指令,也就是_dl_runtime_resolve函数地址
    4008fc: 24180015 li t8,21 //t8=21 此处是将hello的符号表(.dynsym)的索引21存入t8
    ...

    Disassembly of section .got:
    004109d0 <_GLOBAL_OFFSET_TABLE_>:
    4109d0: 00000000 nop //此处保存的是_dl_runtime_resolve,编译后值为0,但运行后会被ld.so填充上_dl_runtime_resolve的地址,已用gdb验证
    4109d4: 80000000 lb zero,0(zero)
    4109d8: 004008f0 tge v0,zero,0x23


    ld-uClibc.so中的_dl_runtime_resolve函数:
    00007f50 <_dl_runtime_resolve>:
    7f50: 03801821 move v1,gp
    7f54: 27bdffd8 addiu sp,sp,-40
    7f58: 2739000c addiu t9,t9,12
    7f5c: 3c1c0002 lui gp,0x2
    7f60: 279ca0b4 addiu gp,gp,-24396
    7f64: 0399e021 addu gp,gp,t9
    7f68: 03e01021 move v0,ra
    7f6c: afbc0020 sw gp,32(sp)
    7f70: afaf0024 sw t7,36(sp) //将.MIPS.stubs中保存的main中的返回地址保存起来
    7f74: afa40010 sw a0,16(sp)
    7f78: afa50014 sw a1,20(sp)
    7f7c: afa60018 sw a2,24(sp)
    7f80: afa7001c sw a3,28(sp)
    7f84: 03002021 move a0,t8 //将t8的值做为入参传给函数<__dl_runtime_resolve>,从其函数原型看,t8存的是hello在符号表中的index,__dl_runtime_resolve会根据这个index来更新got(通过对hello在symtab中的index进行一定的计算和转换,能得到hello在got表中的位置)
    7f88: 00602821 move a1,v1
    7f8c: 8f99814c lw t9,-32436(gp)
    7f90: 0411ec02 bal 2f9c <__dl_runtime_resolve>
    7f94: 00000000 nop
    7f98: 8fbc0020 lw gp,32(sp)
    7f9c: 8fbf0024 lw ra,36(sp) //此处将main中调用hello的返回地址加载到ra
    7fa0: 8fa40010 lw a0,16(sp)
    7fa4: 8fa50014 lw a1,20(sp)
    7fa8: 8fa60018 lw a2,24(sp)
    7fac: 8fa7001c lw a3,28(sp)
    7fb0: 27bd0028 addiu sp,sp,40
    7fb4: 0040c821 move t9,v0 //v0做为__dl_runtime_resolve的返回值,保存的是hello的实际地址
    7fb8: 03200008 jr t9 //执行hello函数,由于此时ra存的是main调hello的返回地址,因此hello函数返回时正好跳转到main中。这也是此处使用jr而不是jal的原因,因为jal会自动更新ra寄存器!
    7fbc: 00000000 nop


    uclinux-rootfs/lib/uClibc/ldso/ldso/mips/elfinterp.c:
    unsigned long __dl_runtime_resolve(unsigned long sym_index,
    unsigned long old_gpreg)
    {
    ......
    return new_addr;
    }
    1. 运行验证
    # ./gdb ./main.elf
    Reading symbols from /mnt/usb/main.elf...done.
    (gdb) b main
    Breakpoint 1 at 0x400838: file ./main.c, line 8.
    (gdb) r
    Starting program: /mnt/usb/main.elf
    [Thread debugging using libthread_db enabled]

    Breakpoint 1, main (argc=1, argv=0x7fff6e04) at ./main.c:8
    8 ./main.c: No such file or directory.
    in ./main.c
    (gdb) info address main
    Symbol "main" is a function at address 0x400810.
    (gdb) x/xw &main
    0x400810 <main>: 0x3c1c0002 //此处main的地址还是0x400810,说明main.elf虽然以fPIC编译的,但是做为主程序,依然被加载到了默认地址。
    (gdb) x/32xw &main
    0x400810 <main>: 0x3c1c0002 0x279c81b0 0x0399e021 0x27bdffd8
    0x400820 <main+16>: 0xafbf0024 0xafbe0020 0x03a0f021 0xafbc0010
    0x400830 <main+32>: 0xafc40028 0xafc5002c 0xafc00018 0x8fc40018
    0x400840 <main+48>: 0x8f828018 0x0040c821 0x0320f809 0x00000000
    0x400850 <main+64>: 0x8fdc0010 0x8fc20018 0x24420001 0xafc20018
    0x400860 <main+80>: 0x8fc40018 0x8f828018 0x0040c821 0x0320f809
    0x400870 <main+96>: 0x00000000 0x8fdc0010 0x00001021 0x03c0e821
    0x400880 <main+112>: 0x8fbf0024 0x8fbe0020 0x27bd0028 0x03e00008
    (gdb) x/32xw 0x4109d0 //既然main的地址没发生偏移,那么说明.got的地址也没变,依然是编译后的0x4109d0,打印显示.got的第一项是0x77fe6780
    0x4109d0 <_GLOBAL_OFFSET_TABLE_>: 0x77fe6780 0x77ff5028 0x004008f0 0x00000000 //.got第3项是4008f0,也即.MIPS.stubs内的地址,此时还没真正调用到hello()
    0x4109e0 <completed.5347>: 0x00000000 0x00000000 0xffffffff 0x00000000
    0x4109f0 <object.5359+8>: 0x00000000 0x0041095c 0x000007f8 0x77fba898
    0x410a00: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a10: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a20: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a30: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a40: 0x00000000 0x00000000 0x00000000 0x00000000
    (gdb) info symbol 0x77fe6780 //此地址真的是_dl_runtime_resolve!猜想得以验证!
    _dl_runtime_resolve in section .text of /lib/ld-uClibc.so.0
    (gdb) info address hello
    Symbol "hello" is a function at address 0x77faa690.
    (gdb) b main.c:11
    Breakpoint 2 at 0x400854: file ./main.c, line 11.
    (gdb) c
    Continuing.
    hello,world, i=0

    Breakpoint 2, main (argc=1, argv=0x7fff6e04) at ./main.c:11
    11 in ./main.c
    (gdb) x/32xw 0x4109d0 //此时已经调用过一次hello函数了,再次查看.got的第3项:已经变成hello的地址了!!
    0x4109d0 <_GLOBAL_OFFSET_TABLE_>: 0x77fe6780 0x77ff5028 0x77faa690 0x00000000
    0x4109e0 <completed.5347>: 0x00000000 0x00000000 0xffffffff 0x00000000
    0x4109f0 <object.5359+8>: 0x00000000 0x0041095c 0x000007f8 0x77fba898
    0x410a00: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a10: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a20: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a30: 0x00000000 0x00000000 0x00000000 0x00000000
    0x410a40: 0x00000000 0x00000000 0x00000000 0x00000000
    (gdb) info symbol 0x77faa690
    hello in section .text of /mnt/usb/libhello.so
     附录 关于寄存器gp与符号_gp
    我们知道PIC的函数入口处,首先会调整gp寄存器,很多资料上都说gp指向的是.got,实际上并不是,gp寄存器指向的是符号_gp,这个_gp绝不是got段的地址,而是一个常数区的中间位置,它是在编译阶段生成的,它的身份是做为gp相对寻址的“基准”位置。
    《see mips run》p260 9.4.1 相对于gp寻址:
    要求compiler,assembler,linker以及运行时激活代码(runtime startup code)偕同配合,把程序中的’小’变量和常数汇集到一个独立的内存区间;然后设置register $28(通常称为全局量指针global pointer或简写为gp)指向该区间的中央(linker生成一个特殊符号_gp,其地址为该区间的中央,激活代码负责将_gp的地址加载到gp寄存 器,这一动作在第一个load/store指令运行之前完成).只要这些全局变量\静态编量\常量加起来不占用超过64k大小的空间,这些资料相对该区间 的中点也就不超过正负32k(偏移量15bit+符号位1bit,参见mips机器码格式),那幺我们就可以在一条指令中完成对它们的 load/store操作:
    lw $2, addr ---> lw $2, addr-_gp(at)
    在同一个动态模块中,每个函数入口处的gp寄存器调整,都将使gp指向符号_gp的地址。

    展开全文
  • 动态符号链接的细节

    2019-12-02 11:15:28
    ELF 是 Linux 支持的一种程序文件格式,本身包含重定位、执行、共享(动态链接库)三种类型(man elf)。 代码: /* test.c */ #include <stdio.h> int global = 0; int main() { char local = 'A'; ...
  • 在mybatis执行sql编译之前,使用java代码拦截该sql并拼接入条件进去,比如xml里一条sql SELECT * FROM TABLE,在执行这条sql语句之前动态使用java代码加入 WHERE ID > 1这一个条件,并且不能不适用${}传入,也就是...
  • 本文介绍如何用IDA进行动态调试及部分ARM指令的学习。环境:已root的安卓手机一部,IDA pro 6.8,win7系统。下载样本app,并已确认可调试(debuggable = true),下文不表:http://pan.baidu.com/s/1jG22HMY一 手机...
  • Linux 动态库的符号冲突问题 最近,给同事定位了一个符号表的冲突问题,简单记录一下。 A代码作为静态链接库,被包含进了B代码,然后编译成了动态链接库B.so, A代码同时作为静态链接库,被编译进入了main的主代码。...
  • 首先声明一点:符号的值是地址,该地址上存储的值才是变量,不明白的话看另一篇文章:“静态链接与动态链接的宏观概述及微观详解”。(1)对非数组符号的访问,编译器生成访存指令,要想寻址(获得符号的值或变量的...
  • Linux动态链接(5)动态符号搜索顺序

    千次阅读 2016-08-03 21:25:32
    这里的动态搜索是指通过dlopen+dlsym来搜索动态符号的过程,而静态搜索则是指程序在运行的过程中的惰性链接实现。这里其实又是一个比较边界的问题,但是也是可能存在的,另外这些问题可以促使感兴趣的同学看一下...
  • 查看符号表 # 查看 nm *.dylib nm -C *.dylib ...-C,以原代码显示 -P,以简单格式显示每一个符号 符号表分析 符号类型 符号类型代号 说明 A Global absolute 符号 a Local absolute 符...
  • A代码作为静态链接库,被包含进了B代码,然后编译成了动态链接库,B.so A代码同时作为静态链接库,被编译进入了main的主代码。 main函数调用B.so里面的函数,同时B.so里面的函数调用了A代码,结果进程异常退出了。...
  • 什么是angr: angr是一个二进制代码分析工具,能够自动...angr是一个基于python的二进制漏洞分析框架,它将以前多种分析技术集成进来,­­­它能够进行动态符号执行分析(如,KLEE和Mayhem),也能够进行多种静态
  • 符号熵(附matlab代码)

    2020-02-27 17:46:34
    符号熵        固定时间间隔下对系统进行采样取值的方法来追踪系统动态,熵是计算系统中...符号熵将数据转化为少量的符号模式,虽然失去了大量信息,但保留了动态系统的周期性,...
  • C/C++中控制动态库的符号可见性

    千次阅读 2018-02-26 21:08:20
    解决方案优点缺点static 关键字简单语言级别支持static 关键字限定变量或函数只可以在定义它的文件范围内使用导出列表消除了 static 关键字上的限制不需要更多的代码可以关联版本信息具有不同粒度的符号可见性控...
  • 微信开发者工具中,我不能直接在wxml文件中使用换行符号,只能使用动态代码来换行,比如说我的字符串为“第一行第二行”,我怎么让分两行呢?我试了“第一行\n第二行”效果是“第一行 第二行”解析成空格了,也试了 ...
  • ABAP动态生成代码上传TXT数据

    万次阅读 2011-02-27 21:08:00
    动态程序代码生成技术 3.ABAP动态程序执行技术 4.TXT文本文件对应用Table字段编辑技术   注意事项: 文件文件编辑过程中时间日期格式为 20060201 120000 表示 2006.02.01 12:00:00...
  • ABAP动态生成代码上传EXCEL数据

    万次阅读 2011-02-27 21:04:00
    动态程序代码生成技术 3.ABAP动态程序执行技术 4.TXT文本文件对应用Table字段编辑技术   注意事项: 文件文件编辑过程中时间日期格式为 20060201 120000 表示 2006.02.01 12:00:00...
  • 首先声明一点:符号的值是地址,该地址上存储的值才是变量,不明白的话看另一篇文章:“静态链接与动态链接的宏观概述及微观详解”。(1)对非数组符号的访问,编译器生成访存指令,要想寻址(获得符号的值或变量的...
  • 如何修改动态符号

    千次阅读 2013-10-08 10:30:42
    ELF 文件中代码、连接信息和注释是以节(section)为单位存放的,并存有一个节头表(section header)。对每一节,在节头表中都有一个表项(节头表项)与之对应,表项记录了该节的一些信息,例如该节在文件中的位置信息和...
  • ios 动态执行的代码

    2015-01-14 12:08:00
    objc中可以通过动态运行的方法调用第三方库的函数 通过可以用下面的方法判断工程是否引入了第三方的库,如果引入,则可以通过NtSdkIMP获取到对应方法的函数指针去执行代码。如果没有引入,则不执行。 通过获取方法...
  • 动态符号冲突的一个解决办法

    千次阅读 2017-09-08 15:27:24
    之前去某公司面试讨论到如果两个so里有符号冲突了怎么办,我想指定用哪个而不是先加载哪个库用哪个库里的符号 之前是android 某项目用定制库和系统库有冲突 刚看qcom代码发现可以用dlopen处理这个问题 gligc dl-...
  • 背景最近比赛遇到了一个题目, 32位静态链接去符号了. 所以用IDA分析的时候很多libc的库函数都无法识别, 就需要在 IDA 中引入 sig 文件....有了 sig 文件后静态分析是没问题了, 但是动态调试的时候因为没有符号...
  • 1.需求:为了实现分表操作,我们所有的数据库创建的时候需要根据operatorId进行分表,所以每次创建一个operator时就需要创建一系列属于该operator的表,就是...然后我用operatorId去动态的替换该符号,然后再java代码里执...
  • 动态库和PIC-位置无关代码

    千次阅读 2016-06-12 15:31:27
    一、前言 本文主要描述了动态库以及和动态库有紧密联系的位置无关代码的相关资讯。首先介绍了动态库和位置无关代码的源由,了解...最后,我们自己动手编写一个简单的动态库,并解析了一些symbol Visibility、动态符号

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,508
精华内容 603
关键字:

动态符号代码