예제 #1
0
def regBeforeLastJmp(reg, jmpLvl):
    """
    Returns the SSA occurence of the register 'reg' that corresponds to it's value just before the jump number 'jmpLvl' was taken 
    Parameters:
        (reg) (SSAReg) The regiter we are considering 
        (jmpLvl) (int) The jump level we want to go before 
    """
    ind = reg.ind
    num = reg.num
    while( ind != 0 and CurrentAnalysis.graph.nodes[str(SSAReg(num, ind))].jmpLvl >= jmpLvl ):
        ind -= 1
    return SSAReg(num ,ind)
예제 #2
0
 def hasPossibleNormalRet(self):
     """
     Checks if the gadget can return normaly under certain conditions ! 
     Returns a pair
     (True, condition)
     (False, None)
     """
     if (self.sort != GadgetSort.REGULAR):
         False
     # Check
     ip = SSAReg(
         Analysis.regNamesTable[Analysis.ArchInfo.ip],
         self.graph.lastMod[Analysis.regNamesTable[Analysis.ArchInfo.ip]])
     sp_num = Analysis.n2r(Analysis.ArchInfo.sp)
     for dep in self.dep.regDep.get(ip, []):
         dep[0] = dep[0].simplify()
         if (isinstance(dep[0], MEMExpr)):
             addr = dep[0].addr
             (isInc, inc) = addr.isRegIncrement(sp_num)
             # Normal ret if the final value of the IP is value that was in memory before the last modification of SP ( i.e final_IP = MEM[final_sp - size_of_a_register )
             if (isInc and self.spInc
                     and inc == (self.spInc -
                                 (Analysis.ArchInfo.bits / 8))):
                 return (True, dep[1])
     return (False, None)
예제 #3
0
    def calculateSpInc(self):
        """
        Compute how much the stack pointer has advanced after this gadget is executed 
        """
        if (self.sort != GadgetSort.REGULAR):
            return

        if (self.duplicate):
            self.spInc = self.duplicate.spInc
            return

        sp_num = Analysis.regNamesTable[Analysis.ArchInfo.sp]
        if (not sp_num in self.graph.lastMod):
            self.spInc = 0
            return

        sp = SSAReg(sp_num, self.graph.lastMod[sp_num])
        if (not sp in self.dep.regDep):
            self.spInc = 0
            return

        for dep in self.dep.regDep[sp]:
            if (dep[1].isTrue()):
                (isInc, inc) = dep[0].isRegIncrement(sp.num)
                if (isInc):
                    self.spInc = inc
                    return
                else:
                    self.spInc = None
                    return
예제 #4
0
    def calculateRet(self):
        """
        Computes the return address, checks if it is valid or not... 
        /!\ MUST be called after calculateSpInc()
        
        """

        ip = SSAReg(
            Analysis.regNamesTable[Analysis.ArchInfo.ip],
            self.graph.lastMod[Analysis.regNamesTable[Analysis.ArchInfo.ip]])
        sp_num = Analysis.regNamesTable[Analysis.ArchInfo.sp]
        if (not self.spInc):
            self.normalRet = False
            return

        if (not ip in self.dep.regDep):
            self.normalRet = False
            return

        for dep in self.dep.regDep[ip]:
            if (dep[1].isTrue()):
                if (isinstance(dep[0], MEMExpr)):
                    addr = dep[0].addr
                    (isInc, inc) = addr.isRegIncrement(sp_num)
                    # Normal ret if the final value of the IP is value that was in memory before the last modification of SP ( i.e final_IP = MEM[final_sp - size_of_a_register )
                    if (isInc and inc == (self.spInc -
                                          (Analysis.ArchInfo.bits / 8))):
                        self.normalRet = True
                    else:
                        self.normalRet = False
예제 #5
0
    def calculateRet(self):
        """
        Computes the return address, checks if it is valid or not... 
        /!\ MUST be called after calculateSpInc()
        
        """
        if (self.sort != GadgetSort.REGULAR):
            return

        if (self.duplicate):
            self.ret = self.duplicate.ret
            self.retValue = self.duplicate.retValue
            return

        ip = SSAReg(
            Analysis.regNamesTable[Analysis.ArchInfo.ip],
            self.graph.lastMod[Analysis.regNamesTable[Analysis.ArchInfo.ip]])
        sp_num = Analysis.regNamesTable[Analysis.ArchInfo.sp]
        if (self.spInc == None):
            self.ret = RetType.UNKNOWN
            return

        if (not ip in self.dep.regDep):
            self.ret = RetType.UNKNOWN
            return

        for dep in self.dep.regDep[ip]:
            if (dep[1].isTrue()):
                if (isinstance(dep[0], MEMExpr)):
                    addr = dep[0].addr
                    (isInc, inc) = addr.isRegIncrement(sp_num)
                    # Normal ret if the final value of the IP is value that was in memory before the last modification of SP ( i.e final_IP = MEM[final_sp - size_of_a_register )
                    if (isInc and inc == (self.spInc -
                                          (Analysis.ArchInfo.bits / 8))):
                        self.ret = RetType.RET
                    else:
                        self.ret = RetType.UNKNOWN
                elif (isinstance(dep[0], SSAExpr)):
                    # Try to detect gadgets ending by 'call'
                    if (self.ins[-1]._mnemonic[:4] == "call"):
                        self.ret = RetType.CALL_REG
                        self.retValue = dep[0].reg.num
                    else:
                        self.retValue = dep[0].reg.num
                        self.ret = RetType.JMP_REG
                return
        self.ret = RetType.UNKNOWN
예제 #6
0
    def _getReg(self, regStr):
        """
        Given a register name ( eax, edx, ... ) this function translates it into a generic R0_ R1_ ...
        This is meant to return the current state of a register under the form of a SSA register, by checking into the regCount dictionnary. If eax ( whose id is 2 for example ) have been modified 2 times, then the current value of eax will be _getReg("eax") = SSAReg(2,2)
        If the register had never occured before, either in the gadget, or during the whole analysis, then it's ID is created and added to the regNamesTable. 
        If the argument does not depict a full register the translation of the full register is returned
        ---> e.g _getReg("AH") -> _getReg("RAX") -> R3
        Parameters :
            regStr - (str) The string of the register we want to get 
        """
        # We first find the corresponding full register ( like AH ---> RAX )
        aliasMapper = Analysis.ArchInfo.currentArchInfo.alias_mapper
        if (aliasMapper.get(regStr) != None):
            if (aliasMapper[regStr][0] != "rflags"
                    and aliasMapper[regStr][0] != "eflags"):
                fullReg = aliasMapper[regStr]  # Couple (reg, offset)
                regStr = fullReg[0]

        # If first occurence of this register in analysis : we translate it in the table
        if (Analysis.regNamesTable.get(regStr) == None):
            Analysis.regNamesTable[regStr] = Analysis.ssaRegCount
            Analysis.revertRegNamesTable[Analysis.ssaRegCount] = regStr
            self.regCount[Analysis.ssaRegCount] = 0
            reg = SSAReg(Analysis.ssaRegCount, 0)
            regExpr = SSAExpr(reg)
            Analysis.ssaRegCount += 1
            # Create basic node
            node = SSANode(reg, regExpr)
            node.jmpLvl = 0
            self.graph.nodes[str(reg)] = node
        # Else if register already have an ID
        else:
            reg = SSAReg(Analysis.regNamesTable[regStr], None)
            # First occurence in this gadget -> ind set to 0 and node created
            if (self.regCount.get(reg.num) == None):
                reg.ind = 0
                self.regCount[reg.num] = 0
                # Create basic node
                node = SSANode(reg, SSAExpr(reg))
                node.jmpLvl = 0
                self.graph.nodes[str(reg)] = node
            else:
                reg.ind = self.regCount[reg.num]
                if (self.graph.nodes.get(str(reg)) == None):
                    self.graph.nodes[str(reg)] = SSANode(reg, SSAExpr(reg))
        # Returning corresponding expression
        return SSAExpr(reg)
예제 #7
0
 def __init__(self, reg, expr):
     Node.__init__(self)
     self.reg = SSAReg(reg.num, reg.ind)
     self.expr = expr
예제 #8
0
    def buildGraph(self, irsb):
        # (1) Initialisations...
        self.valuesTable = {}  # Keys are whatever, Values are Expr
        self.graph = Graph()  # Empty graph
        CurrentAnalysis.gadget = self
        CurrentAnalysis.graph = self.graph
        self.regCount = {}
        # Update the index counts and nodes for registers that already have a translation into generic IR
        for reg in Analysis.regNamesTable.values():
            self.regCount[reg] = 0
            node = SSANode(SSAReg(reg, 0), SSAExpr(SSAReg(reg, 0)))
            self.graph.nodes["R%d_0" % reg] = node
        self.graph.nodes["MEM"] = MEMNode()
        memAccCount = 0  # Hold the number of the next arc incoming/outgoing to/from the memory node

        # (2) Graph construction...
        # Iterate through all reill instructions :
        for i in range(0, len(irsb)):
            instr = irsb[i]
            self.nbInstr = self.nbInstr + 1
            # Translating different types of instructions
            if (instr.mnemonic == ReilMnemonic.NOP):
                pass
            # Basic operations ( ADD, SUB, MUL, etc )
            elif (isCalculationInstr(instr.mnemonic)):
                if (instr.operands[2]._name[0] == "t"):
                    expr = self.barfCalculationToExpr(instr.mnemonic,
                                                      instr.operands[0],
                                                      instr.operands[1],
                                                      instr.operands[2].size)
                    self.valuesTable[instr.operands[2]._name] = expr
                else:
                    expr = self.barfCalculationToExpr(instr.mnemonic,
                                                      instr.operands[0],
                                                      instr.operands[1],
                                                      instr.operands[2].size)
                    regExpr = self._getReg(instr.operands[2]._name)
                    reg = regExpr.reg
                    expr = self.translateFullRegAssignement(
                        expr, instr.operands[2])
                    reg = SSAReg(reg.num, reg.ind + 1)
                    self.valuesTable[str(reg)] = expr
                    # Adding the node
                    node = SSANode(reg, expr)
                    # Adding arcs toward other nodes and memory
                    for dep in expr.getRegisters():
                        # Dep is a SSAReg on which node depends
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes[str(dep)]))
                    for mem in expr.getMemAcc():
                        addr = mem[0]
                        size = mem[1]
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes["MEM"], memAccCount, addr,
                                size))
                        memAccCount += 1
                    self.graph.nodes[str(reg)] = node
                    self.regCount[reg.num] += 1

            # Memory load instruction
            elif (isLoadInstr(instr.mnemonic)):
                expr = self.barfLoadToExpr(instr.operands[0],
                                           instr.operands[2])
                if (instr.operands[2]._name[0] == "t"):
                    self.valuesTable[instr.operands[2]._name] = expr
                else:
                    regExpr = self._getReg(instr.operands[2]._name)
                    reg = regExpr.reg
                    expr = self.translateFullRegAssignement(
                        expr, instr.operands[2])
                    reg.ind += 1
                    self.regCount[reg.num] += 1
                    self.valuesTable[str(reg)] = expr
                    # Adding node towards memory
                    node = SSANode(reg, expr)
                    for mem in expr.getMemAcc():
                        addr = mem[0]
                        size = mem[1]
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes["MEM"], memAccCount, addr,
                                size))
                        memAccCount += 1
                    self.graph.nodes[str(reg)] = node

            # Memory store instruction
            elif (isStoreInstr(instr.mnemonic)):
                expr = self.barfOperandToExpr(instr.operands[0])
                addr = self.barfOperandToExpr(instr.operands[2])
                #if( isinstance( instr.operands[0], ReilImmediateOperand )):
                #node = ConstNode( instr.operands[0].immediate, instr.operands[0].size )
                #self.graph.nodes["MEM"].outgoingArcs.append( Arc( node, memAccCount, addr, expr.size ))
                if (isinstance(expr, ConstExpr)):
                    node = ConstNode(expr.value, expr.size)
                    self.graph.nodes["MEM"].outgoingArcs.append(
                        Arc(node, memAccCount, addr, expr.size))
                elif (not expr.getRegisters()):
                    raise GadgetException(
                        "Expression is neither ConstExpr nor has registers and should be written in memory ? - not yet supported!"
                    )
                else:
                    self.graph.nodes["MEM"].outgoingArcs.append(
                        Arc(self.graph.nodes[str(expr.getRegisters()[0])],
                            memAccCount, addr, expr.size))
                self.graph.nodes["MEM"].storedValues[memAccCount] = expr
                memAccCount += 1

            # Transfer value into register
            elif (isPutInstr(instr.mnemonic)):
                if (instr.operands[2]._name[0] == "t"):
                    expr = self.barfOperandToExpr(instr.operands[0])
                    if (instr.operands[2].size != expr.size):
                        expr = Convert(instr.operands[2].size, expr)
                    self.valuesTable[instr.operands[2]._name] = expr
                else:
                    regExpr = self._getReg(instr.operands[2]._name)
                    reg = regExpr.reg
                    expr = self.barfOperandToExpr(instr.operands[0])
                    if (instr.operands[0].size < instr.operands[2].size):
                        expr = self.translateFullRegAssignement(
                            expr, instr.operands[2])
                    else:
                        expr = Convert(instr.operands[2].size, expr)
                    if (instr.operands[2].size != REGSIZE.size):
                        expr = self.translateFullRegAssignement(
                            expr, instr.operands[2])
                    regDep = expr.getRegisters()
                    memDep = expr.getMemAcc()

                    # Adding node and arcs to the graph
                    reg = SSAReg(reg.num, reg.ind + 1)
                    node = SSANode(reg, expr)
                    for r in regDep:
                        node.outgoingArcs.append(Arc(self.graph.nodes[str(r)]))
                    for mem in memDep:
                        addr = mem[0]
                        size = mem[1]
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes["MEM"], memAccCount, addr,
                                size))
                        memAccCount += 1
                    self.graph.nodes[str(reg)] = node
                    self.regCount[reg.num] += 1
                    self.valuesTable[str(reg)] = expr

            # Boolean IS Zero instrution
            # BISZ( a, b ) has the following effects :
            #    b <- 1 if a == 0
            #    b <- 0 if a != 0
            elif (instr.mnemonic == ReilMnemonic.BISZ):
                zero = ConstExpr(0, instr.operands[0].size)
                ifzero = ConstExpr(1, instr.operands[2].size)
                ifnotzero = ConstExpr(0, instr.operands[2].size)
                testedValue = self.barfOperandToExpr(instr.operands[0])
                # If operands[0] == 0 then the value assigned to operands[2] is 1.
                # If operands[0] != 0 then operands[2] becomes 0
                cond = Cond(CT.EQUAL, testedValue, zero)
                expr = ITE(cond, ifzero, ifnotzero)
                if (instr.operands[2]._name[0] == "t"):
                    self.valuesTable[instr.operands[2]._name] = expr
                else:
                    regExpr = self._getReg(instr.operands[2]._name)
                    reg = regExpr.reg
                    reg.ind += 1
                    self.regCount[reg.num] += 1
                    self.valuesTable[str(reg)] = expr
                    # Adding node to the graph
                    # Creation of the ite node
                    iteNode = ITENode(cond, ifzero, ifnotzero)
                    # Link the real node to the ITE node
                    node = SSANode(reg, Convert(REGSIZE.size, expr))
                    node.outgoingArcs.append(Arc(iteNode))
                    self.graph.nodes[str(reg)] = node

            # Conditionnal jump
            elif (instr.mnemonic == ReilMnemonic.JCC):
                # Determine the address where to jmp
                # If jmp to a fixed location
                if (isinstance(instr.operands[2], ReilImmediateOperand)
                        and instr.operands[2].size != 40
                        and instr.operands[2].size != 72):
                    addr = ConstExpr(instr.operands[2].immediate)
                    addr.size = REGSIZE.size
                # If it is a pointer
                elif (instr.operands[2].size == 40
                      or instr.operands[2].size == 72):
                    #We test if the value is less than 0x100
                    # If yes, then we ignore the condition because unable to compute dependencies
                    # This kind of small values depict an instruction simulated in many basic blocks
                    # We do not handle conditions for the Instr Pointer INSIDE a gadget
                    if (isinstance(instr.operands[2], ReilImmediateOperand) and
                        (instr.operands[2].immediate >> 8) - self.addr < 0x1):
                        raise GadgetException(
                            "REIL instruction(s) too complicated to emulate in gadget:\n"
                            + self.asmStr)
                    # We also test if there is a jump inside the bounds of the gadget
                    # For now those are also not supported
                    # Sadly, this also suppresses some conditional conditions
                    if (isinstance(instr.operands[2], ReilImmediateOperand) and
                        (instr.operands[2].immediate >> 8) - self.addr <
                        (len(self.hexStr) / 4)):

                        raise GadgetException(
                            "Jumps inside the gadget are not handled yet in gadget:\n"
                            + self.asmStr)
                    # Get the real return/jump address with an 8 bit SHR
                    expr = self.barfOperandToExpr(instr.operands[2])
                    addr = Extr(expr.size - 1, 8, expr)
                else:
                    addr = self.barfOperandToExpr(instr.operands[2])
                ip = self._getReg(
                    Analysis.ArchInfo.ip).reg  # Get the instruction pointer
                ip.ind += 1
                # Quick check if simple 'ret' so the expression is easier to read
                # A jump is always taken if first argument is a constant != 0
                if (isinstance(instr.operands[0], ReilImmediateOperand)
                        and instr.operands[0].immediate != 0):
                    self.valuesTable[str(ip)] = addr
                    expr = addr
                    node = SSANode(ip, Convert(REGSIZE.size, addr))
                    for dep in addr.getRegisters(ignoreMemAcc=True):
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes[str(dep)]))
                    for mem in addr.getMemAcc():
                        address = mem[0]
                        size = mem[1]
                        node.outgoingArcs.append(
                            Arc(self.graph.nodes["MEM"], memAccCount, address,
                                size))
                        memAccCount += 1
                    self.regCount[ip.num] += 1
                    self.graph.nodes[str(ip)] = node
                # Else processing conditional jump
                else:
                    # Create node and stuff
                    reg = ip
                    zero = ConstExpr(0, instr.operands[0].size)
                    cond = Cond(CT.NOTEQUAL,
                                self.barfOperandToExpr(instr.operands[0]),
                                zero)
                    # Update the info about conditional jumps in Graph.py module
                    self.graph.condJmps.append(cond)
                    self.graph.condPath.append(
                        Cond(CT.AND, cond.invert(),
                             self.graph.condPath[self.graph.countCondJmps]))
                    # TODO : this seems not to put the good address into nextInstrAddr ???
                    nextInstrAddr = ConstExpr(irsb[i + 1].address >> 8,
                                              REGSIZE.size)
                    # 1 - FIRST STEP : ITE Node to say : IP takes new value OR stays the same
                    expr = ITE(cond, addr,
                               ConstExpr(instr.address >> 8, REGSIZE.size))
                    self.valuesTable[str(reg)] = expr
                    # Adding node to the graph
                    # Creation of the ite node
                    # We consider that either the jump is taken ( to addr )
                    #   or the value stays the one of the current instruction ( instr.address >> 8 )
                    iteNode = ITENode(
                        cond, addr, ConstExpr(instr.address >> 8,
                                              REGSIZE.size))
                    for dep in addr.getRegisters():
                        iteNode.outgoingArcs.append(
                            Arc(self.graph.nodes[str(dep)]))
                    for mem in addr.getMemAcc():
                        address = mem[0]
                        size = mem[1]
                        iteNode.outgoingArcs.append(
                            Arc(self.graph.nodes["MEM"], memAccCount, address,
                                size))
                        memAccCount += 1
                    #iteNode.outgoingArcsCond.append( Arc( self.graph.nodes[str(prevOcc(reg))], -1, None))
                    # Link the real node to the ITE node
                    node = SSANode(reg, expr)
                    node.outgoingArcs.append(Arc(iteNode))
                    self.graph.nodes[str(reg)] = node
                    # And do not forget
                    self.regCount[reg.num] += 1
                    self.graph.countCondJmps += 1
                    # 2 - SECOND STEP
                    # We update the register again with the address of the next instruction
                    reg = SSAReg(reg.num, reg.ind + 1)
                    node = SSANode(reg, nextInstrAddr)
                    self.graph.nodes[str(reg)] = node
                    self.regCount[reg.num] += 1
            else:
                raise GadgetException(
                    "REIL operation <%s>  not supported in gadget:\n%s" %
                    (ReilMnemonic.to_string(instr.mnemonic), self.asmStr))