1# coding=utf-8
2# Copyright 2018 Sascha Schirra
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# 1. Redistributions of source code must retain the above copyright notice, this
8# list of conditions and the following disclaimer.
9#
10# 2. Redistributions in binary form must reproduce the above copyright notice,
11# this list of conditions and the following disclaimer in the documentation
12# and/or other materials provided with the distribution.
13#
14# 3. Neither the name of the copyright holder nor the names of its contributors
15# may be used to endorse or promote products derived from this software without
16# specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" A ND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29from ropper.gadget import Category, Gadget
30from ropper.common.error import *
31from ropper.common.utils import *
32from ropper.rop import Ropper
33from ropper.arch import x86_64
34from ropper.ropchain.ropchain import *
35from ropper.loaders.loader import Type
36from ropper.loaders.elf import ELF
37from ropper.loaders.pe import PE
38from ropper.loaders.raw import Raw
39from ropper.loaders.mach_o import MachO
40from re import match
41import itertools
42import math
43import sys
44
45if sys.version_info.major == 2:
46    range = xrange
47
48class RopChainX86_64(RopChain):
49
50    MAX_QUALI = 7
51
52    def _printHeader(self):
53        toReturn = ''
54        toReturn += ('#!/usr/bin/env python\n')
55        toReturn += ('# Generated by ropper ropchain generator #\n')
56        toReturn += ('from struct import pack\n')
57        toReturn += ('\n')
58        toReturn += ('p = lambda x : pack(\'Q\', x)\n')
59
60        toReturn += ('\n')
61
62        return toReturn
63
64    def _printRebase(self):
65        toReturn = ''
66
67        for binary,section in self._usedBinaries:
68            imageBase = Gadget.IMAGE_BASES[binary]
69            toReturn += ('IMAGE_BASE_%d = %s # %s\n' % (self._usedBinaries.index((binary, section)),toHex(imageBase ,8), binary))
70            toReturn += ('rebase_%d = lambda x : p(x + IMAGE_BASE_%d)\n\n'% (self._usedBinaries.index((binary, section)),self._usedBinaries.index((binary, section))))
71        return toReturn
72
73    @classmethod
74    def name(cls):
75        return ''
76
77    @classmethod
78    def availableGenerators(cls):
79        return [RopChainSystemX86_64, RopChainMprotectX86_64]
80
81    @classmethod
82    def archs(self):
83        return [x86_64]
84
85    def _createDependenceChain(self, gadgets):
86        """
87        gadgets - list with tuples
88
89        tuple contains:
90        - method to create chaingadget
91        - list with arguments
92        - dict with named arguments
93        - list with registers which are not allowed to override in the gadget
94        """
95        failed = []
96        cur_len = 0
97        cur_chain = ''
98        counter = 0
99
100        max_perm = math.factorial(len(gadgets))
101        for x in itertools.permutations(gadgets):
102            counter += 1
103            self._printMessage('[*] Try permuation %d / %d' % (counter, max_perm))
104            found = False
105            for y in failed:
106
107                if x[:len(y)] == y:
108                    found = True
109                    break
110            if found:
111                continue
112            try:
113                fail = []
114                chain2 = ''
115                dontModify = []
116                badRegs = []
117                c = 0
118                for idx in range(len(x)):
119                    g = x[idx]
120                    if idx != 0:
121                        badRegs.extend(x[idx-1][3])
122
123                    dontModify.extend(g[3])
124                    fail.append(g)
125                    chain2 += g[0](*g[1], badRegs=badRegs, dontModify=dontModify,**g[2])[0]
126
127
128                cur_chain += chain2
129                break
130
131            except RopChainError as e:
132                pass
133            if len(fail) > cur_len:
134                cur_len = len(fail)
135                cur_chain = '# Filled registers: '
136                for fa in fail[:-1]:
137
138                    cur_chain += (fa[2]['reg']) + ', '
139                cur_chain += '\n'
140                cur_chain += chain2
141
142            failed.append(tuple(fail))
143        else:
144            self._printMessage('')
145            self._printMessage('Cannot create chain which fills all registers')
146        self._printMessage('')
147        return cur_chain
148
149    def _isModifiedOrDereferencedAccess(self, gadget, dontModify):
150
151        regs = []
152        for line in gadget.lines[1:]:
153            line = line[1]
154            if '[' in line:
155                return True
156            if dontModify:
157                m = match('[a-z]+ (e?[abcds][ixlh]),?.*', line)
158                if m and m.group(1) in dontModify:
159                    return True
160
161        return False
162
163
164
165    def _paddingNeededFor(self, gadget):
166        regs = []
167        for idx in range(1,len(gadget.lines)):
168            line = gadget.lines[idx][1]
169            matched = match('^pop (...)$', line)
170            if matched:
171                regs.append(matched.group(1))
172        return regs
173
174
175    def _printRopInstruction(self, gadget, padding=True, value=None):
176        toReturn = ('rop += rebase_%d(%s) # %s\n' % (self._usedBinaries.index((gadget.fileName, gadget.section)),toHex(gadget.lines[0][0],8), gadget.simpleString()))
177
178        value_first = False
179
180        if padding:
181            regs = self._paddingNeededFor(gadget)
182
183            if len(regs) > 0:
184                dst = gadget.category[2]['dst']
185                search = '^pop (%s)$' % dst
186                first_line = gadget.lines[0][1]
187                if match(search, first_line):
188                    value_first = True
189
190            padding_str = ''
191            for i in range(len(regs)):
192                padding_str +=self._printPaddingInstruction()
193
194            if value_first:
195                toReturn += value
196                toReturn += padding_str
197            else:
198                toReturn += padding_str
199                if value:
200                    toReturn += value
201
202        return toReturn
203
204    def _printAddString(self, string):
205        return ('rop += \'%s\'\n' % string)
206
207    def _printRebasedAddress(self, addr, comment='', idx=0):
208        return ('rop += rebase_%d(%s)\n' % (idx,addr))
209
210    def _printPaddingInstruction(self, addr='0xdeadbeefdeadbeef'):
211        return ('rop += p(%s)\n' % addr)
212
213    def _containsZeroByte(self, addr):
214        return self.containsBadbytes(addr,8)
215
216    def _createZeroByteFillerForSub(self, number):
217        start = 0x0101010101010101
218        for i in range(start, 0x0202020202020202):
219            if not self._containsZeroByte(i) and not self._containsZeroByte(i+number):
220                return i
221
222    def _createZeroByteFillerForAdd(self, number):
223        start = 0x0101010101010101
224        for i in range(start, 0x0202020202020202):
225            if not self._containsZeroByte(i) and not self._containsZeroByte(number-i):
226                return i
227
228    def _find(self, category, reg=None, srcdst='dst', badDst=[], badSrc=None, dontModify=None, srcEqDst=False, switchRegs=False ):
229        quali = 1
230
231        if reg and reg[0] != 'r':
232            return
233        while quali < RopChainSystemX86_64.MAX_QUALI:
234            for binary in self._binaries:
235                for gadget in self._gadgets[binary]:
236
237                    if gadget.category[0] == category and gadget.category[1] == quali:
238
239                        if badSrc and (gadget.category[2]['src'] in badSrc \
240                                       or gadget.affected_regs.intersection(badSrc)):
241                            continue
242                        if badDst and (gadget.category[2]['dst'] in badDst \
243                                       or gadget.affected_regs.intersection(badDst)):
244                            continue
245                        if not gadget.lines[len(gadget.lines)-1][1].strip().endswith('ret') or 'esp' in gadget.simpleString() or 'rsp' in gadget.simpleString():
246                            continue
247                        if srcEqDst and (not (gadget.category[2]['dst'] == gadget.category[2]['src'])):
248                            continue
249                        elif not srcEqDst and 'src' in gadget.category[2] and (gadget.category[2]['dst'] == gadget.category[2]['src']):
250                            continue
251                        if self._isModifiedOrDereferencedAccess(gadget, dontModify):
252                            continue
253                        if reg:
254                            if gadget.category[2][srcdst] == reg:
255                                self._updateUsedBinaries(gadget)
256                                return gadget
257                            elif switchRegs:
258                                other = 'src' if srcdst == 'dst' else 'dst'
259                                if gadget.category[2][other] == reg:
260                                    self._updateUsedBinaries(gadget)
261                                    return gadget
262                        else:
263                            self._updateUsedBinaries(gadget)
264                            return gadget
265
266            quali += 1
267
268
269    def _createWriteStringWhere(self, what, where, reg=None, dontModify=[], idx=0):
270        badRegs = []
271        badDst = []
272        while True:
273            popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs, dontModify=dontModify)
274            if not popReg:
275                raise RopChainError('Cannot build writewhatwhere gadget!')
276            write4 = self._find(Category.WRITE_MEM, reg=popReg.category[2]['dst'],  badDst=
277            badDst, srcdst='src')
278            if not write4:
279                badRegs.append(popReg.category[2]['dst'])
280                continue
281            else:
282                popReg2 = self._find(Category.LOAD_REG, reg=write4.category[2]['dst'], dontModify=[popReg.category[2]['dst']]+dontModify)
283                if not popReg2:
284                    badDst.append(write4.category[2]['dst'])
285                    continue
286                else:
287                    break;
288
289        if len(what) % 8 > 0:
290            what += ' ' * (8 - len(what) % 8)
291        toReturn = ''
292        for index in range(0,len(what),8):
293            part = what[index:index+8]
294
295            toReturn += self._printRopInstruction(popReg,False)
296            toReturn += self._printAddString(part)
297            regs = self._paddingNeededFor(popReg)
298            for i in range(len(regs)):
299                toReturn +=self._printPaddingInstruction()
300            toReturn += self._printRopInstruction(popReg2, False)
301
302            toReturn += self._printRebasedAddress(toHex(where+index,8), idx=idx)
303            regs = self._paddingNeededFor(popReg2)
304            for i in range(len(regs)):
305                toReturn +=self._printPaddingInstruction()
306            toReturn += self._printRopInstruction(write4)
307        return (toReturn,popReg.category[2]['dst'], popReg2.category[2]['dst'])
308
309
310    def _createWriteRegValueWhere(self, what, where, dontModify=[], idx=0):
311        badRegs = []
312        badDst = []
313        while True:
314
315
316            write4 = self._find(Category.WRITE_MEM, reg=what,  badDst=badDst, dontModify=dontModify, srcdst='src')
317            if not write4:
318                raise RopChainError('Cannot build writeregvaluewhere gadget!')
319            else:
320                popReg2 = self._find(Category.LOAD_REG, reg=write4.category[2]['dst'], dontModify=[what]+dontModify)
321                if not popReg2:
322                    badDst.append(write4.category[2]['dst'])
323                    continue
324                else:
325                    break;
326
327        toReturn = self._printRopInstruction(popReg2, False)
328        toReturn += self._printRebasedAddress(toHex(where,8), idx=idx)
329        regs = self._paddingNeededFor(popReg2)
330        for i in range(len(regs)):
331            toReturn +=self._printPaddingInstruction()
332        toReturn += self._printRopInstruction(write4)
333
334        return (toReturn,what, popReg2.category[2]['dst'])
335
336    def _createLoadRegValueFrom(self, what, from_reg, dontModify=[], idx=0):
337        try:
338            return self._createLoadRegValueFromMov(what, from_reg, dontModify, idx)
339        except RopChainError:
340            return self._createLoadRegValueFromXchg(what, from_reg, dontModify, idx)
341
342    def _createLoadRegValueFromMov(self, what, from_reg, dontModify=[], idx=0):
343        badRegs = []
344        badDst = []
345        while True:
346
347
348            load4 = self._find(Category.LOAD_MEM, reg=what,  badDst=badDst, dontModify=dontModify, srcdst='dst')
349            if not load4:
350                raise RopChainError('Cannot build loadwhere gadget!')
351            else:
352                popReg2 = self._find(Category.LOAD_REG, reg=load4.category[2]['src'], dontModify=[what,load4.category[2]['src']]+dontModify)
353                if not popReg2:
354                    badDst.append(load4.category[2]['src'])
355                    continue
356                else:
357                    break;
358
359        toReturn = self._printRopInstruction(popReg2, False)
360        toReturn += self._printRebasedAddress(toHex(from_re,8), idx=idx)
361        regs = self._paddingNeededFor(popReg2)
362        for i in range(len(regs)):
363            toReturn +=self._printPaddingInstruction()
364        toReturn += self._printRopInstruction(load4)
365
366        return (toReturn,what, popReg2.category[2]['dst'])
367
368    def _createLoadRegValueFromXchg(self, what, from_reg, dontModify=[], idx=0):
369        badRegs = []
370        badDst = []
371        while True:
372
373
374            load4 = self._find(Category.XCHG_REG, reg=what,  badDst=badDst, dontModify=dontModify, srcdst='src')
375            if not load4:
376                raise RopChainError('Cannot build loadwhere gadget!')
377            else:
378                mov = self._find(Category.LOAD_MEM, reg=load4.category[2]['dst'],  badDst=badDst, dontModify=[load4.category[2]['dst']]+dontModify, srcdst='dst')
379                if not mov:
380                    badDst.append(load4.category[2]['dst'])
381                    continue
382
383                popReg2 = self._find(Category.LOAD_REG, reg=mov.category[2]['src'], dontModify=[what,load4.category[2]['src']]+dontModify)
384                if not popReg2:
385                    badDst.append(load4.category[2]['src'])
386                    continue
387                else:
388                    break;
389
390
391
392        toReturn = self._printRopInstruction(popReg2, False)
393        toReturn += self._printRebasedAddress(toHex(from_reg,8), idx=idx)
394        regs = self._paddingNeededFor(popReg2)
395        for i in range(len(regs)):
396            toReturn +=self._printPaddingInstruction()
397
398        toReturn += self._printRopInstruction(mov)
399
400        toReturn += self._printRopInstruction(load4)
401
402        return (toReturn,what, popReg2.category[2]['dst'])
403
404    def _createNumberSubtract(self, number, reg=None, badRegs=None, dontModify=None):
405        if not badRegs:
406            badRegs=[]
407        while True:
408            sub = self._find(Category.SUB_REG, reg=reg, badDst=badRegs, badSrc=badRegs, dontModify=dontModify)
409            if not sub:
410                raise RopChainError('Cannot build number with subtract gadget for reg %s!' % reg)
411            popSrc = self._find(Category.LOAD_REG, reg=sub.category[2]['src'], dontModify=dontModify)
412            if not popSrc:
413                badRegs.append=[sub.category[2]['src']]
414                continue
415            popDst = self._find(Category.LOAD_REG, reg=sub.category[2]['dst'], dontModify=[sub.category[2]['src']]+dontModify)
416            if not popDst:
417                badRegs.append=[sub.category[2]['dst']]
418                continue
419            else:
420                break;
421
422        filler = self._createZeroByteFillerForSub(number)
423
424        toReturn = self._printRopInstruction(popSrc, False)
425        toReturn += self._printPaddingInstruction(toHex(filler,8))
426        regs = self._paddingNeededFor(popSrc)
427        for i in range(len(regs)):
428            toReturn += self._printPaddingInstruction()
429        toReturn += self._printRopInstruction(popDst, False)
430        toReturn += self._printPaddingInstruction(toHex(filler+number,8))
431        regs = self._paddingNeededFor(popDst)
432        for i in range(len(regs)):
433            toReturn += self._printPaddingInstruction()
434        toReturn += self._printRopInstruction(sub)
435        return (toReturn, popDst.category[2]['dst'],popSrc.category[2]['dst'])
436
437    def _createNumberAddition(self, number, reg=None, badRegs=None, dontModify=None):
438        if not badRegs:
439            badRegs=[]
440        while True:
441            sub = self._find(Category.ADD_REG, reg=reg, badDst=badRegs, badSrc=badRegs, dontModify=dontModify)
442            if not sub:
443                raise RopChainError('Cannot build number with addition gadget for reg %s!' % reg)
444            popSrc = self._find(Category.LOAD_REG, reg=sub.category[2]['src'], dontModify=dontModify)
445            if not popSrc:
446                badRegs.append=[sub.category[2]['src']]
447                continue
448            popDst = self._find(Category.LOAD_REG, reg=sub.category[2]['dst'], dontModify=[sub.category[2]['src']]+dontModify)
449            if not popDst:
450                badRegs.append(sub.category[2]['dst'])
451                continue
452            else:
453                break;
454
455        filler = self._createZeroByteFillerForAdd(number)
456
457        toReturn = self._printRopInstruction(popSrc, False)
458        toReturn += self._printPaddingInstruction(toHex(filler,8))
459        regs = self._paddingNeededFor(popSrc)
460        for i in range(len(regs)):
461            toReturn += self._printPaddingInstruction()
462        toReturn += self._printRopInstruction(popDst, False)
463        toReturn += self._printPaddingInstruction(toHex(number - filler,8))
464        regs = self._paddingNeededFor(popDst)
465        for i in range(len(regs)):
466            toReturn += self._printPaddingInstruction()
467        toReturn += self._printRopInstruction(sub)
468
469        return (toReturn, popDst.category[2]['dst'],popSrc.category[2]['dst'])
470
471    def _createNumberPop(self, number, reg=None, badRegs=None, dontModify=None):
472        if self._containsZeroByte(0xffffffff):
473            raise RopChainError("Cannot write value with pop -1 and inc gadgets, because there are badbytes in the negated number")
474        while True:
475            popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify)
476            if not popReg:
477                raise RopChainError('Cannot build number with xor gadget!')
478            incReg = self._find(Category.INC_REG, reg=popReg.category[2]['dst'], dontModify=dontModify)
479            if not incReg:
480                if not badRegs:
481                    badRegs = []
482                badRegs.append(popReg.category[2]['dst'])
483            else:
484                break
485
486        value = self._printPaddingInstruction(toHex(0xffffffff,8))
487        toReturn = self._printRopInstruction(popReg, value=value)
488        for i in range(number+1):
489            toReturn += self._printRopInstruction(incReg)
490
491        return (toReturn ,popReg.category[2]['dst'],)
492
493
494    def _createNumberXOR(self, number, reg=None, badRegs=None, dontModify=None):
495        while True:
496            clearReg = self._find(Category.CLEAR_REG, reg=reg, badDst=badRegs, badSrc=badRegs,dontModify=dontModify, srcEqDst=True)
497            if not clearReg:
498                raise RopChainError('Cannot build number with xor gadget!')
499            if number > 0:
500                incReg = self._find(Category.INC_REG, reg=clearReg.category[2]['src'], dontModify=dontModify)
501                if not incReg:
502                    if not badRegs:
503                        badRegs = []
504                    badRegs.append(clearReg.category[2]['src'])
505                else:
506                    break
507            else:
508                break
509
510        toReturn = self._printRopInstruction(clearReg)
511        for i in range(number):
512            toReturn += self._printRopInstruction(incReg)
513
514        return (toReturn, clearReg.category[2]['dst'],)
515
516    def _createNumberXchg(self, number, reg=None, badRegs=None, dontModify=None):
517        xchg = self._find(Category.XCHG_REG, reg=reg, badDst=badRegs, dontModify=dontModify)
518        if not xchg:
519            raise RopChainError('Cannot build number gadget with xchg!')
520
521        other = xchg.category[2]['src'] if xchg.category[2]['dst'] else xchg.category[2]['dst']
522
523        toReturn = self._createNumber(number, other, badRegs, dontModify)[0]
524
525        toReturn += self._printRopInstruction(xchg)
526        return (toReturn, reg, other)
527
528    def _createNumberNeg(self, number, reg=None, badRegs=None, dontModify=None):
529        if number == 0:
530            raise RopChainError('Cannot build number gadget with neg if number is 0!')
531        if self._containsZeroByte((~number)+1):
532            raise RopChainError("Cannot use neg gadget, because there are badbytes in the negated number")
533        neg = self._find(Category.NEG_REG, reg=reg, badDst=badRegs, dontModify=dontModify)
534        if not neg:
535            raise RopChainError('Cannot build number gadget with neg!')
536
537        pop = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs, dontModify=dontModify)
538        if not pop:
539            raise RopChainError('Cannot build number gadget with neg!')
540
541        value = self._printPaddingInstruction(toHex((~number)+1, 8)) # two's complement
542        toReturn = self._printRopInstruction(pop, value=value)
543        toReturn += self._printRopInstruction(neg)
544        return (toReturn, reg,)
545
546    def _createNumber(self, number, reg=None, badRegs=None, dontModify=None, xchg=True):
547        try:
548            if self.containsBadbytes(number):
549                try:
550                    return self._createNumberNeg(number, reg, badRegs,dontModify)
551                except RopChainError as e:
552
553                    if number < 50:
554                        try:
555                            return self._createNumberXOR(number, reg, badRegs,dontModify)
556                        except RopChainError:
557                            try:
558                                return self._createNumberPop(number, reg, badRegs,dontModify)
559                            except RopChainError:
560                                try:
561                                    return self._createNumberSubtract(number, reg, badRegs,dontModify)
562                                except RopChainError:
563                                    return self._createNumberAddition(number, reg, badRegs,dontModify)
564
565                    else :
566                        try:
567                            return self._createNumberSubtract(number, reg, badRegs,dontModify)
568                        except RopChainError:
569                            return self._createNumberAddition(number, reg, badRegs,dontModify)
570            else:
571                popReg =self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify)
572                if not popReg:
573                    raise RopChainError('Cannot build number gadget!')
574                value = self._printPaddingInstruction(toHex(number,8))
575                toReturn = self._printRopInstruction(popReg, value=value)
576                return (toReturn , popReg.category[2]['dst'])
577        except RopChainError:
578            return self._createNumberXchg(number, reg, badRegs, dontModify)
579
580    def _createAddress(self, address, reg=None, badRegs=None, dontModify=None):
581        popReg = self._find(Category.LOAD_REG, reg=reg, badDst=badRegs,dontModify=dontModify)
582        if not popReg:
583            raise RopChainError('Cannot build address gadget!')
584
585        toReturn = ''
586
587        toReturn += self._printRopInstruction(popReg,False)
588        toReturn += self._printRebasedAddress(toHex(address, 8), idx=self._usedBinaries.index((popReg.fileName, popReg.section)))
589        regs = self._paddingNeededFor(popReg)
590        for i in range(len(regs)):
591            toReturn +=self._printPaddingInstruction()
592
593        return (toReturn,popReg.category[2]['dst'])
594
595    def _createSyscall(self, reg=None, badRegs=None, dontModify=None):
596        syscall = self._find(Category.SYSCALL, reg=None, badDst=None, dontModify=dontModify)
597        if not syscall:
598            raise RopChainError('Cannot build syscall gadget!')
599
600        toReturn = ''
601
602        toReturn += self._printRopInstruction(syscall)
603
604        return (toReturn,)
605
606    def _createOpcode(self, opcode):
607        gadget = self._searchOpcode(opcode)
608
609        if gadget:
610            if (gadget.fileName, gadget.section) not in self._usedBinaries:
611                self._usedBinaries.append((gadget.fileName, gadget.section))
612            return self._printRopInstruction(gadget)
613
614
615    def _searchOpcode(self, opcode):
616        r = Ropper()
617        gadgets = []
618        for section in self._binaries[0].executableSections:
619            vaddr = section.virtualAddress
620            gadgets.extend(r.searchOpcode(self._binaries[0],opcode=opcode,disass=True))
621
622        if len(gadgets) > 0:
623            return gadgets[0]
624        else:
625            raise RopChainError('Cannot create gadget for opcode: %s' % opcode)
626
627    def create(self):
628        pass
629
630
631class RopChainSystemX86_64(RopChainX86_64):
632
633    @classmethod
634    def usableTypes(self):
635        return (ELF, Raw)
636
637    @classmethod
638    def name(cls):
639        return 'execve'
640
641    def _createCommand(self, what, where, reg=None, dontModify=[], idx=0):
642        if len(what) % 8 > 0:
643            what = '/' * (8 - len(what) % 8) + what
644        return self._createWriteStringWhere(what,where, idx=idx)
645
646    def create(self, options):
647        cmd = options.get('cmd')
648        address = options.get('address')
649        if not cmd:
650            cmd = '/bin/sh'
651        if len(cmd.split(' ')) > 1:
652            raise RopChainError('No argument support for execve commands')
653
654        self._printMessage('ROPchain Generator for syscall execve:\n')
655        self._printMessage('\nwrite command into data section\nrax 0xb\nrdi address to cmd\nrsi address to null\nrdx address to null\n')
656        chain = self._printHeader()
657        gadgets = []
658        can_create_command = False
659        chain_tmp = '\n'
660        if address is None:
661            section = self._binaries[0].getSection('.data')
662
663            length = math.ceil(float(len(cmd))/8) * 8
664            nulladdress = section.offset+length
665            try:
666                cmdaddress = section.offset
667                chain_tmp += self._createCommand(cmd,cmdaddress)[0]
668                can_create_command = True
669
670            except RopChainError as e:
671                self._printMessage('Cannot create gadget: writewhatwhere')
672                self._printMessage('Use 0x4141414141414141 as command address. Please replace that value.')
673                cmdaddress = 0x4141414141414141
674            if can_create_command:
675                badregs = []
676                tmpx = ''
677                while True:
678
679                    ret = self._createNumber(0x0, badRegs=badregs)
680                    tmpx = ret[0]
681                    try:
682                        tmpx += self._createWriteRegValueWhere(ret[1], nulladdress)[0]
683                        break
684                    except BaseException as e:
685                        #raise e
686                        badregs.append(ret[1])
687
688                chain_tmp += tmpx
689                gadgets.append((self._createAddress, [cmdaddress],{'reg':'rdi'},['rdi','edi', 'di']))
690                gadgets.append((self._createAddress, [nulladdress],{'reg':'rsi'},['rsi','esi', 'si']))
691                gadgets.append((self._createAddress, [nulladdress],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh']))
692                gadgets.append((self._createNumber, [59],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah']))
693        if address is not None and not can_create_command:
694            if type(address) is str:
695                cmdaddress = int(address, 16)
696            nulladdress = options.get('nulladdress')
697            if nulladdress is None:
698                self._printMessage('No address to a null bytes was given, 0x4242424242424242 is used instead.')
699                self._printMessage('Please replace that value.')
700                nulladdress = 0x4242424242424242
701            elif type(nulladdress) is str:
702                nulladdress = int(nulladdress,16)
703
704            gadgets.append((self._createNumber, [cmdaddress],{'reg':'rdi'},['rdi','edi', 'di']))
705            gadgets.append((self._createNumber, [nulladdress],{'reg':'rsi'},['rsi','esi', 'si']))
706            gadgets.append((self._createNumber, [nulladdress],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh']))
707            gadgets.append((self._createNumber, [59],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah']))
708
709        self._printMessage('Try to create chain which fills registers without delete content of previous filled registers')
710        chain_tmp += self._createDependenceChain(gadgets)
711
712        try:
713            self._printMessage('Look for syscall gadget')
714            chain_tmp += self._createSyscall()[0]
715            self._printMessage('syscall gadget found')
716
717        except RopChainError:
718            try:
719                self._printMessage('No syscall gadget found!')
720                self._printMessage('Look for syscall opcode')
721
722                chain_tmp += self._createOpcode('0f05')
723                self._printMessage('syscall opcode found')
724
725            except RopChainError:
726                chain_tmp += '# INSERT SYSCALL GADGET HERE\n'
727                self._printMessage('syscall opcode not found')
728
729
730        chain += self._printRebase()
731        chain += 'rop = \'\'\n'
732
733        chain += chain_tmp
734        chain += 'print rop'
735        return chain
736
737
738class RopChainMprotectX86_64(RopChainX86_64):
739    """
740    Builds a ropchain for mprotect syscall
741    rax 0x7b
742    rdi address
743    rsi size
744    rdx 0x7 -> RWE
745    """
746
747    @classmethod
748    def usableTypes(self):
749        return (ELF, Raw)
750
751    @classmethod
752    def name(cls):
753        return 'mprotect'
754
755    def _createJmp(self, reg=['rsp']):
756        r = Ropper()
757        gadgets = []
758        for section in self._binaries[0].executableSections:
759            vaddr = section.virtualAddress
760            gadgets.extend(r.searchJmpReg(self._binaries[0],reg))
761
762
763
764        if len(gadgets) > 0:
765            if (gadgets[0].fileName, gadgets[0].section) not in self._usedBinaries:
766                self._usedBinaries.append((gadgets[0].fileName, gadgets[0].section))
767            return self._printRopInstruction(gadgets[0])
768        else:
769            return None
770
771    def __extract(self, param):
772        if not match('0x[0-9a-fA-F]{1,16},0x[0-9a-fA-F]+', param) or not match('0x[0-9a-fA-F]{1,16},[0-9]+', param):
773            raise RopChainError('Parameter have to have the following format: <hexnumber>,<hexnumber> or <hexnumber>,<number>')
774
775        split = param.split(',')
776        if isHex(split[1]):
777            return (int(split[0], 16), int(split[1], 16))
778        else:
779            return (int(split[0], 16), int(split[1], 10))
780
781
782    def create(self, options={}):
783        address = options.get('address')
784        size = options.get('size')
785        if not address:
786            raise RopChainError('Missing parameter: address')
787        if not size:
788            raise RopChainError('Missing parameter: size')
789
790        if not match('0x[0-9a-fA-F]{1,8}', address):
791            raise RopChainError('Parameter address have to have the following format: <hexnumber>')
792
793        if not match('0x[0-9a-fA-F]+', size):
794            raise RopChainError('Parameter size have to have the following format: <hexnumber>')
795
796        address = int(address, 16)
797        size = int(size, 16)
798
799        self._printMessage('ROPchain Generator for syscall mprotect:\n')
800        self._printMessage('rax 0xa\nrdi address\nrsi size\nrdx 0x7 -> RWE\n')
801
802        chain = self._printHeader()
803
804        chain += 'shellcode = \'\\xcc\'*100\n\n'
805
806        gadgets = []
807        gadgets.append((self._createNumber, [address],{'reg':'rdi'},['rdi','edi', 'di']))
808        gadgets.append((self._createNumber, [size],{'reg':'rsi'},['rsi','esi', 'si']))
809        gadgets.append((self._createNumber, [0x7],{'reg':'rdx'},['rdx','edx', 'dx', 'dl', 'dh']))
810        gadgets.append((self._createNumber, [0xa],{'reg':'rax'},['rax','eax', 'ax', 'al', 'ah']))
811
812        self._printMessage('Try to create chain which fills registers without delete content of previous filled registers')
813        chain_tmp = ''
814        chain_tmp += self._createDependenceChain(gadgets)
815        try:
816            self._printMessage('Look for syscall gadget')
817            chain_tmp += self._createSyscall()[0]
818            self._printMessage('syscall gadget found')
819        except RopChainError:
820            chain_tmp += '\n# ADD HERE SYSCALL GADGET\n\n'
821            self._printMessage('No syscall gadget found!')
822
823        self._printMessage('Look for jmp esp')
824        jmp_esp = self._createJmp()
825        if jmp_esp:
826            self._printMessage('jmp esp found')
827            chain_tmp += jmp_esp
828        else:
829            self._printMessage('no jmp esp found')
830            chain_tmp += '\n# ADD HERE JMP ESP\n\n'
831
832        chain += self._printRebase()
833        chain += '\nrop = \'\'\n'
834        chain += chain_tmp
835        chain += 'rop += shellcode\n\n'
836        chain += 'print(rop)\n'
837
838        return chain
839