Skip to content

Commit 0f5844f

Browse files
committed
Merge branch 'v1.2'
2 parents af51b2a + 78e9431 commit 0f5844f

22 files changed

+1498
-813
lines changed

ropgenerator/Architecture.py

+34
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ def __init__(self):
3131
self.bits = None
3232
self.octets = None
3333
self.minPageSize = None
34+
self.endianness = None
35+
self.regs = None
3436

3537
# BARF Information
3638
self.archMode = None
@@ -70,11 +72,29 @@ def n2r(name):
7072
global regNameToNum
7173
return regNameToNum[name]
7274

75+
##############
76+
# Endianness # 
77+
##############
78+
class EndiannessType(Enum):
79+
BIG = "BIG"
80+
LITTLE = "LITTLE"
81+
7382
###########################
7483
# Supported architectures #
7584
###########################
7685

7786
currentArch = None
87+
def setArch(arch):
88+
global currentArch, ssaRegCount, regNumToName, regNameToNum
89+
currentArch = arch
90+
ssaRegCount = 0
91+
regNumToName = dict()
92+
regNameToNum = dict()
93+
for reg in arch.regs:
94+
regNumToName[ssaRegCount] = reg
95+
regNameToNum[reg] = ssaRegCount
96+
ssaRegCount += 1
97+
7898

7999
# X86
80100
ArchX86 = Architecture()
@@ -88,6 +108,9 @@ def n2r(name):
88108
ArchX86.disassembler = X86Disassembler(architecture_mode=ARCH_X86_MODE_32)
89109
ArchX86.irTranslator = X86Translator(architecture_mode=ARCH_X86_MODE_32)
90110
ArchX86.minPageSize = 0x1000
111+
ArchX86.endianness = EndiannessType.LITTLE
112+
ArchX86.regs = ['eax','ebx','ecx','edx','esi','edi','esp','eip'\
113+
, 'cf', 'pf', 'af', 'zf', 'sf']
91114

92115
# X86-64
93116
ArchX64 = Architecture()
@@ -101,6 +124,11 @@ def n2r(name):
101124
ArchX64.disassembler = X86Disassembler(architecture_mode=ARCH_X86_MODE_64)
102125
ArchX64.irTranslator = X86Translator(architecture_mode=ARCH_X86_MODE_64)
103126
ArchX64.minPageSize = 0x1000
127+
ArchX64.endianness = EndiannessType.LITTLE
128+
ArchX64.regs = ['rax', 'rbx', 'rcx', 'rdx', 'rsi', 'rdi', 'rsp', 'rbp', 'rip'\
129+
, 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15', 'sf', 'zf'\
130+
, 'af','cf','df','es', 'fs']
131+
104132

105133
available = [ArchX86.name, ArchX64.name]
106134

@@ -129,6 +157,12 @@ def current():
129157
def minPageSize():
130158
return currentArch.minPageSize
131159

160+
def isLittleEndian():
161+
return currentArch.endianness == EndiannessType.LITTLE
162+
163+
def isBigEndian():
164+
return currentArch.endianness == EndiannessType.BIG
165+
132166
#####################
133167
# Types of binaries #
134168
#####################

ropgenerator/CommonUtils.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# -*- coding:utf-8 -*-
2+
# CommonUtils module: useful functions
3+
import ropgenerator.Database as Database
4+
import ropgenerator.exploit.Scanner as Scanner
5+
6+
7+
def set_offset(offset):
8+
if( not Database.set_gadgets_offset(offset)):
9+
return False
10+
elif( not Scanner.set_offset(offset)):
11+
return False
12+
return True
13+
14+
def reset_offset():
15+
Database.reset_gadgets_offset()
16+
Scanner.reset_offset()

ropgenerator/Constraints.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def verify(self, gadget):
6262
if( gadget.retType == RetType.UNKNOWN ):
6363
if( self.ret ):
6464
for p in gadget.getSemantics(Arch.ipNum()):
65-
if( isinstance(p.expr, MEMExpr)):
65+
if( (not gadget.spInc is None) and isinstance(p.expr, MEMExpr)):
6666
(isInc, inc) = p.expr.addr.isRegIncrement(Arch.spNum())
6767
# 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 )
6868
if( isInc and inc == (gadget.spInc - (Arch.octets())) ):

ropgenerator/Database.py

+70-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class QueryType(Enum):
4141
SYSCALL = "syscall"
4242
INT80 = "int 0x80"
4343

44+
def isMemWriteQuery(qtype):
45+
return (qtype in [QueryType.CSTtoMEM, QueryType.REGtoMEM, QueryType.MEMtoMEM])
46+
4447
#######################
4548
# List of all gadgets #
4649
#######################
@@ -101,6 +104,7 @@ def add(self, cst, gadget_num, preCond = CTrue() ):
101104
self.preConditions[cst].insert(index, preCond)
102105

103106
def find(self, cst, constraint, assertion, enablePreConds=False, n=1 , maxSpInc=None):
107+
global gadgets
104108
res = []
105109
if( not cst in self.values ):
106110
return []
@@ -426,7 +430,7 @@ def possibleMemWrites(self, reg, cst, constraint, assertion, n=1):
426430

427431
def possibleAddressWrites(self, reg, cst, constraint, assertion, n=1):
428432
"""
429-
: : nb of gadgets for each case !!
433+
n : nb of gadgets for each case !!
430434
"""
431435
global gadgets
432436
res = dict()
@@ -443,6 +447,25 @@ def possibleAddressWrites(self, reg, cst, constraint, assertion, n=1):
443447
if( addr_cst not in reg[addr_reg]):
444448
res[addr_reg][addr_cst] = []
445449
res[addr_reg][addr_cst] += found
450+
451+
def allPossibleWrites(self, constraint, assertion):
452+
"""
453+
n : nb of gadgets for each case
454+
"""
455+
global gadgets
456+
res = []
457+
for addr_reg in self.types[QueryType.REGtoMEM].registers.keys():
458+
for addr_cst in self.types[QueryType.REGtoMEM].registers[addr_reg]:
459+
# Get the lookUp for list of deps for MEM(addr_reg, addr_cst)
460+
lookUp = self.types[QueryType.REGtoMEM].registers[addr_reg][addr_cst]
461+
# Iterate through reg and cst
462+
for reg in lookUp.registers.keys():
463+
for cst in lookUp.registers[reg].values.keys():
464+
gadget_list = lookUp.registers[reg].find(cst, constraint, assertion, n=1)
465+
if( gadget_list ):
466+
res.append(((addr_reg, addr_cst),(reg,cst),gadget_list[0]))
467+
return res
468+
446469

447470

448471
########################
@@ -476,6 +499,13 @@ def DBPossibleAddressWrites(reg, cst, constraint, assertion, n=1):
476499
Return the list of [addr_reg, addr_cst] such than mem(addr_reg, addr_cst) <- reg+cst
477500
"""
478501
return db.possibleAddressWrites(reg, cst, constraint, assertion, n)
502+
503+
def DBAllPossibleWrites(constraint, assertion):
504+
"""
505+
Return a list of [(addr_reg, addr_cst), (reg, cst), gadget]
506+
s.t gadget does: mem(addr_reg, addr_cst) <- reg+cst !
507+
"""
508+
return db.allPossibleWrites(constraint, assertion)
479509

480510
#############################
481511
# Build the list of gadgets #
@@ -556,3 +586,42 @@ def initDB():
556586
global db, gadgets
557587
gadgets = []
558588
db = Database()
589+
590+
591+
###################
592+
# Utils functions #
593+
###################
594+
_offset = 0
595+
def set_gadgets_offset( offset):
596+
"""
597+
adds offset to all gadget addresses
598+
returns True if success
599+
returns False if fail
600+
"""
601+
global gadgets, _offset
602+
603+
i = 0
604+
_offset = offset
605+
for gadget in gadgets:
606+
if( not gadget.addOffset(offset)):
607+
reset_gadgets_offset(i)
608+
return False
609+
i += 1
610+
_offset = offset
611+
return True
612+
613+
def reset_gadgets_offset(gadget_num=-1):
614+
"""
615+
decrements gadget addresses by offset until gadget_num (NOT included)
616+
if gadget_num = -1, do it for all gadgets
617+
"""
618+
global _offset, gadgets
619+
if( gadget_num <= 0 ):
620+
gadget_num = len(gadgets)
621+
i = 0
622+
for gadget in gadgets:
623+
if( i >= gadget_num ):
624+
return
625+
gadget.addOffset(-1*_offset)
626+
i += 1
627+
_offset = 0

ropgenerator/Expressions.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ class Op(Enum):
417417
OR = "Or"
418418
XOR = "Xor"
419419
BSH = "Bsh"
420+
421+
def __str__(self):
422+
return self.value
420423

421424

422425
class OpExpr(Expr):
@@ -438,7 +441,7 @@ def __init__(self, op, args):
438441
self.simplifiedValue = None
439442

440443
def __str__(self):
441-
return "%s%d(%s)" % ( self.op, self.size, ','.join(str(a) for a in self.args))
444+
return "%s%d(%s)" % ( str(self.op), self.size, ','.join(str(a) for a in self.args))
442445

443446
def replaceReg( self, reg, expr ):
444447
newArgs = []
@@ -622,6 +625,24 @@ def simplify(self):
622625
elif( left == right ):
623626
res = ConstExpr(0, left.size)
624627

628+
elif( op == Op.AND ):
629+
if( isinstance(left, ConstExpr) and isinstance(right, ConstExpr)):
630+
res = ConstExpr(left.value & right.value, left.size)
631+
elif( isinstance(left, ConstExpr)):
632+
if( left.value == 0 ):
633+
res = left
634+
elif( left.value == (0x1<<left.size)-1 ):
635+
res = right
636+
elif( isinstance(right, ConstExpr)):
637+
if( right.value == 0 ):
638+
res = right
639+
elif( right.value == (0x1<<right.size)-1 ):
640+
res = left
641+
elif( op == Op.BSH ):
642+
if( isinstance(left, OpExpr) and left.op == Op.BSH and isinstance(left.args[1], ConstExpr)):
643+
if( isinstance(right, ConstExpr)):
644+
res = OpExpr(Op.BSH, [left.args[0], ConstExpr(left.args[1].value+right.value, right.size)])
645+
625646
self.simplifiedValue = res
626647
return res
627648

@@ -1007,6 +1028,12 @@ def simplify(self):
10071028
elif( isinstance( simpExpr, MEMExpr ) and (self.low % 8 == 0) and self.size != simpExpr.size ):
10081029
# If we extract from the same address (from bit 0 )
10091030
res = MEMExpr(OpExpr(Op.ADD, [simpExpr.addr, ConstExpr(self.low/8,simpExpr.addr.size)]).simplify(), self.size)
1031+
elif( isinstance( simpExpr, ConstExpr )):
1032+
res_value = simpExpr.value << (simpExpr.size-self.high)
1033+
res_value = res_value % (0x1<< simpExpr.size)
1034+
res_value = res_value >> (self.low+simpExpr.size-self.high)
1035+
res = ConstExpr(res_value, self.high-self.low+1)
1036+
10101037
self.simplifiedValue = res
10111038
return res
10121039

ropgenerator/Gadget.py

+12
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,15 @@ def getSemantics(self, value):
182182
# Or return the same
183183
else:
184184
return [SPair(SSAExpr(num, 0), CTrue())]
185+
186+
def addOffset(self, offset):
187+
new_addresses = []
188+
for addr in self.addrList:
189+
new = addr+offset
190+
# Check if offset isn't too big
191+
if( new >= (0x1 << Arch.bits())\
192+
or new < 0 ):
193+
return False
194+
new_addresses.append(new)
195+
self.addrList = new_addresses
196+
return True

ropgenerator/Graph.py

+1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def getSemantics( self ):
126126
semantics.flattenITE()
127127
semantics.simplifyValues()
128128
semantics.simplifyConditions()
129+
semantics.customSemanticAdjust()
129130
return semantics
130131

131132
#####################################

ropgenerator/Load.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ def load(args):
171171
print("\tFound: " + arch.name)
172172
return
173173
elif( arch ):
174-
Arch.currentArch = arch
174+
Arch.setArch(arch)
175175
else:
176-
Arch.currentArch = user_arch
176+
Arch.setArch(user_arch)
177177

178178
# Init the binary scanner
179179
initScanner(filename)

ropgenerator/Main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
▒▒╔══▒▒║▒▒╔═══▒▒╗▒▒╔══▒╗
2121
▒▒▒▒▒▒╔╝▒▒║ ▒▒║▒▒▒▒▒▒║ G E N E R A T O R
2222
▒▒╔══▒▒╗╚▒▒▒▒▒▒╔╝▒▒╔═══╝
23-
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ════════════════════ v1.1
23+
╚═╝ ╚═╝ ╚═════╝ ╚═╝ ════════════════════ v1.2
2424
2525
2626
"""

ropgenerator/Semantics.py

+56-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# -*- coding: utf-8 -*-
22
# Semantics module: structure to store gadget semantics
33
from ropgenerator.Conditions import Cond, CT, CTrue, CFalse
4-
from ropgenerator.Expressions import SSAReg
4+
from ropgenerator.Expressions import SSAReg, Concat, Extract, SSAExpr, Op, OpExpr, ConstExpr
55
from ropgenerator.Architecture import r2n
66

77
class SPair:
@@ -169,9 +169,61 @@ def customSemanticAdjust(self):
169169
"""
170170
Make some adjustments in semantics so that it is easier to process by the search engine
171171
"""
172-
## Adjust Cat(0, Extract( x, 0, E))
173-
## --> E if E < 2^(x-1) €z
174-
pass # TODO
172+
def adjustSemantic(spair):
173+
"""
174+
returns a list of SPair
175+
"""
176+
expr = spair.expr
177+
cond = spair.cond
178+
if( isinstance(expr, Concat) and len(expr.args) == 2):
179+
upper = expr.args[0][0]
180+
lower = expr.args[1][0]
181+
if( isinstance(upper, ConstExpr) and upper.value == 0):
182+
if( isinstance(lower, OpExpr)):
183+
left = lower.args[0]
184+
right = lower.args[1]
185+
# IF there is a Const it will be on the right ;)
186+
if( not isinstance(right, ConstExpr)):
187+
tmp = left
188+
left = right
189+
right = left
190+
# Reg + cst
191+
if( lower.op == Op.ADD and (isinstance(left, Extract) and isinstance(left.args[0], SSAExpr) and left.low == 0)\
192+
and isinstance(right, ConstExpr)):
193+
new_cond = Cond(CT.AND,
194+
Cond(CT.AND, cond, Cond(CT.LT, left.args[0], \
195+
ConstExpr((0x1<<(left.high+1))-right.value, left.args[0].size))),
196+
Cond(CT.GE, left.args[0], ConstExpr(0, left.args[0].size)))
197+
new_cond.customSimplify()
198+
new_expr = OpExpr(Op.ADD,[left.args[0], ConstExpr(right.value,left.args[0].size)])
199+
return [SPair(new_expr, new_cond)]
200+
201+
# Reg - cst...
202+
elif( lower.op == Op.SUB and (isinstance(left, Extract) and isinstance(left.args[0], SSAExpr) and left.low == 0)\
203+
and isinstance(right, ConstExpr)):
204+
new_cond = Cond(CT.AND,
205+
Cond(CT.AND, cond, Cond(CT.LT, left.args[0], \
206+
ConstExpr(0x1<<(left.high+1),left.args[0].size ))),
207+
Cond(CT.GE, left.args[0], ConstExpr(right.value, left.args[0].size)))
208+
new_cond.customSimplify()
209+
new_expr = OpExpr(Op.SUB,[left.args[0], ConstExpr(right.value,left.args[0].size)])
210+
return [SPair(new_expr, new_cond)]
211+
# Other cases ? :)
212+
else:
213+
pass
214+
return []
215+
216+
## Adjust semantics
217+
for reg in self.registers.keys():
218+
newPairs = []
219+
for p in self.registers[reg]:
220+
newPairs += adjustSemantic(p)
221+
self.registers[reg] += newPairs
222+
for addr in self.memory.keys():
223+
newPairs = []
224+
for p in self.memory[addr]:
225+
newPairs += adjustSemantic(p)
226+
self.memory[addr] += newPairs
175227

176228

177229
def simplifyConditions(self):

0 commit comments

Comments
 (0)