#include "pe_reader.h"

void		decypher2(s_peconf	*conf, u_block_0 *block0, char *buf_end);
void		fix_iat(char		*final); /* sub 00401471 */
void		fix_section(char	*final);
void		swapints(int *array, int ndx1, int ndx2);
void		dump_from_section_data(char	*final,   u_image_section_header *sct_head);
char		*rc4_algo(const char *buf, int size, const char *rckey);
t_uint32	ror(t_uint32 val, int n);
t_uint32	rol(t_uint32 val, int n);

t_uint32	ror(t_uint32 val, int n)
{
  return ((val >> n) + (val << (32 - n)));
}

t_uint32	rol(t_uint32 val, int n)
{
  return ((val << n) + (val >> (32 - n)));
}

char		*rc4_algo(const char *buf, int size, const char *rckey)
{
  char		*cipher = NULL;
  int		a, b, i=0, j=0, k;
  int		ilen;
  int		sbox[256];
  int		key[256];

  if (!rckey)
    {
      ilen = 4;
      rckey = (char*)&size;
    }
  else
    ilen = strlen(rckey);

  printf("[+] Key for RC4 = %x\n", rckey);

  for (a=0; a < 256; a++)
    {
      key[a] = rckey[a % ilen];
      sbox[a] = a;
    }

  for (a=0, b=0; a < 256; a++)
    {
      b = (b + sbox[a] + key[a]) & 0xFF;
      swapints(sbox, a, b);
    }

  cipher = (char *)malloc(size);

  for (a=0; a < size; a++)
    {
      i = (i + 1) % 256;
      j = (j + sbox[i]) % 256;
      swapints(sbox, i, j);
      k = sbox[(sbox[i] + sbox[j]) & 0xFF];
      cipher[a] = buf[a] ^ k;
    }
  return (cipher);
}

void		swapints(int *array, int ndx1, int ndx2)
{
  int temp = array[ndx1];
  array[ndx1] = array[ndx2];
  array[ndx2] = temp;
}

void		fill_conf(char *file, s_peconf *conf)
{
  /* For Windows user */
  /* HANDLE	hMapp; */
  /* HANDLE	hFile; */

  if ((conf->sb = malloc(sizeof (struct stat))) == NULL)
    {
      perror("[-] malloc()");
      exit(EXIT_FAILURE);
    }
  if ((conf->fd = open(file, O_RDONLY)) == -1)
    {
      perror("[-] open()");
      exit(EXIT_FAILURE);
    }
  if (stat (file, conf->sb) == -1)
    {
      perror("[-] stait()");
      exit(EXIT_FAILURE);
    }
  if ((conf->p = mmap(NULL, conf->sb->st_size, PROT_READ, MAP_PRIVATE,
  		      conf->fd, 0)) == MAP_FAILED)
    {
      perror("mmap()");
      exit(EXIT_FAILURE);
    }
  /* hFile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); */
  /* hMapp = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); */
  /* conf->p = (char*)MapViewOfFile(hMapp, FILE_MAP_READ, 0, 0, 0); */
  /* if (conf->p == NULL) */
  /*   { */
  /*     printf("[-] Echec lors du mapping du fichier\n"); */
  /*     exit(EXIT_FAILURE); */
  /*   } */

}

void		hexdump(char	*buf, int size)
{
  int		i;

  for (i = 0; i < size; i++)
    {
      if (i % 128 == 0)
	printf("\n");
      if (isprint(buf[i]))
	printf("%c", (unsigned char)buf[i]);
      else
	printf(".");
    }
}

int				dump_other_file(char	*final)
{
  s_peconf			conf;
  int				i;
  u_image_section_header	section_header;
  int				size;
  char				*dump;
  int				offset = 0;
  int				j;
  int				fd;

  printf("[+] Now Dump Other Files\n");
  conf.p = final;
  conf.dos_header.p = conf.p;
  conf.file_header.p = conf.p + conf.dos_header.idh->e_lfanew + 4;
  if (conf.file_header.ifh->SizeOfOptionalHeader)
    conf.optional_header.p = conf.file_header.p + image_file_header_length;
  printf("\tNbsections = %d\n", conf.file_header.ifh->NumberOfSections);
  for (i = 0; i < conf.file_header.ifh->NumberOfSections; i++)
    {
      section_header.p = conf.optional_header.p +
	image_optional_header_length + i * image_section_header_length;
      if (!strcmp(section_header.ish->Name, ".config"))
	break;
    }
  printf("[+] Section .config found !\n");
  while (offset < section_header.ish->u.VirtualSize)
    {
      size = *((t_uint32*)&final[section_header.ish->PointerToRawData + offset]);
      printf("[+] Size actual file = %x\n", size);
      dump = rc4_algo(final + section_header.ish->PointerToRawData + offset +
		       4, size, NULL);
      offset += size + 4;
      hexdump(dump, size);
      fd = open("4.dmp", O_RDWR);
      write(fd, dump, size);
      close(fd);
      printf("\n[+] Dump ok \n");
    }
  for (i = 0; i < conf.file_header.ifh->NumberOfSections; i++)
    {
      section_header.p = conf.optional_header.p +
	image_optional_header_length + i * image_section_header_length;
      if (!strcmp(section_header.ish->Name, ".data"))
	break;
    }
  printf("\n[+] Section .data found !\n");
  dump_from_section_data(final, &section_header);
  return (0);
}

void		dump_from_section_data(char	*final,   u_image_section_header *sct_head)
{
  int		i;
  int		j;
  char		*dump = NULL;
  int		tab_offset[] = {0x8, 0x1C0, 0x628, 0x1268, 0x20B0, 0x7EC0};
  int		tab_size[] = {0x1B2, 0x466, 0x0C3E, 0x0E48, 0x5E0A, 0x3000};
  int		fd;

  for (i = 0; i < 6; i++)
    {
      dump = rc4_algo(final + sct_head->ish->PointerToRawData + tab_offset[i], tab_size[i], NULL);
      hexdump(dump, tab_size[i]);
      printf("\n");
    }
}


void				fix_section(char	*final)
{
  s_peconf			conf;
  int				i;
  u_image_section_header	section_header;

  printf("[+] Now Fix Sections\n");
  conf.p = final;
  conf.dos_header.p = conf.p;
  conf.file_header.p = conf.p + conf.dos_header.idh->e_lfanew + 4;
  if (conf.file_header.ifh->SizeOfOptionalHeader)
    conf.optional_header.p = conf.file_header.p + image_file_header_length;
  printf("\tNbsections = %d\n", conf.file_header.ifh->NumberOfSections);
  for (i = 0; i < conf.file_header.ifh->NumberOfSections; i++)
    {
      section_header.p = conf.optional_header.p +
	image_optional_header_length + i * image_section_header_length;
      printf("\t\tName = %s\n", section_header.ish->Name);
      printf("\t\tPtrToRawData = %x\n", section_header.ish->PointerToRawData);
      printf("\t\tPtrToRawData(NewValue) = %x\n", section_header.ish->VirtualAddress);
      section_header.ish->PointerToRawData = section_header.ish->VirtualAddress;
    }
  dump_other_file(final);
}


t_uint32	rvatooffset(t_uint32 rva, s_peconf	*conf)
{
  int		i;

  for (i = 0; i < conf->file_header.ifh->NumberOfSections; i++)
    if (conf->section_header[i].ish->VirtualAddress <= rva)
      if ((conf->section_header[i].ish->VirtualAddress +
	   conf->section_header[i].ish->u.VirtualSize) > rva)
	{
	  rva -= conf->section_header[i].ish->VirtualAddress;
	  rva += conf->section_header[i].ish->PointerToRawData;
	  return (rva);
	}
  return (0);
}

int				count_nb_dll(s_peconf	*conf)
{
  u_image_import_descriptor	iid;
  int				i = 0;
  char				*p = NULL;

  p = conf->p + rvatooffset(conf->optional_header.ioh->DataDirectory[1].VirtualAddress,
			    conf);
  do
    {
      i++;
      iid.p = p;
      p += image_import_descriptor_length;
    } while ((iid.iid->u.OriginalFirstThunk != 0) ||
	     (iid.iid->TimeDateStamp != 0) ||
	     (iid.iid->ForwarderChain != 0) ||
	      (iid.iid->FirstThunk != 0));
  return (i - 1);
}

int			count_nb_api(s_peconf	*conf)
{
  int			i;
  int			j;
  u_image_thunk_data	itd;
  int			offset;
  char			*p = NULL;

  for (i = 0; i < conf->nb_dll; i++)
    {
      j = 0;
      if (conf->import_descriptor[i].iid->FirstThunk != 0)
	offset = rvatooffset((int)conf->import_descriptor[i].iid->FirstThunk,
			     conf);
      else
	offset = rvatooffset((int)conf->import_descriptor[i].iid->u.OriginalFirstThunk,
			     conf);
      p = conf->p + offset;
      do
	{
	  j++;
	  itd.p = p;
	  p += image_thunk_data_length;
	  /* if (itd.itd->u.AddressOfData != 0) */
	  /*   printf("Nom api = %s\n", conf->p + rvatooffset((int)itd.itd->u.ForwarderString, conf) + 2); */
	} while ((itd.itd->u.AddressOfData != 0) ||
		 (itd.itd->u.ForwarderString != 0) ||
		 (itd.itd->u.Function != 0) ||
		 (itd.itd->u.Ordinal != 0));
    }
  return (0);
}

static void	fill_info(s_peconf	*conf)
{
  int		i;

  conf->dos_header.p = conf->p;
  conf->file_header.p = conf->p + conf->dos_header.idh->e_lfanew + 4;
  if (conf->file_header.ifh->SizeOfOptionalHeader)
    conf->optional_header.p = conf->file_header.p + image_file_header_length;
  if (!(conf->section_header = malloc(sizeof(u_image_section_header) *
				      conf->file_header.ifh->NumberOfSections)))
    {
      perror("[-] malloc()");
      exit(EXIT_FAILURE);
    }
  for (i = 0; i < conf->file_header.ifh->NumberOfSections; i++)
    {
      conf->section_header[i].p = conf->optional_header.p +
	image_optional_header_length + i * image_section_header_length;
    }
  conf->nb_dll = count_nb_dll(conf);
  if (!(conf->import_descriptor = malloc(sizeof(u_image_import_descriptor) *
				      conf->nb_dll)))
    {
      perror("[-] malloc()");
      exit(EXIT_FAILURE);
    }
  if (!(conf->name_dll = malloc(sizeof(char*))))
    {
      perror("[-] malloc()");
      exit(EXIT_FAILURE);
    }
  for (i = 0; i < conf->nb_dll; i++)
    {
      conf->import_descriptor[i].p = conf->p +
	rvatooffset(conf->optional_header.ioh->DataDirectory[1].VirtualAddress,
		    conf) + i * image_import_descriptor_length;
      conf->name_dll[i] =
	strdup(conf->p + rvatooffset(conf->import_descriptor[i].iid->Name, conf));
      /* printf("Name = %s\n", conf->name_dll[i]); */
    }
  count_nb_api(conf);
}

void		sub_004011C0(char *buf, size_t size, int key)
{
  int		k = key;
  int		res;
  int		current;
  int		i = 0;

  size -= 3;
  do
    {
      res = key ^ *((t_uint32*)buf);
      *((t_uint32*)buf++) = res;
      key = ror(key, 9) - size;
      size -= 1;
    }while (size);

}

int		sub_00401652(char	*addr, size_t	size)
{
  int		val = -2;
  int		res = 0;
  int		i;

  for (i = 0; i < size; i++)
    {
      res = (val + 0x368D5CB4) *
	(16 * ~(val + 0x368D5CB4) * (~((addr[i] & 0xff) *
				       rol(1, val & 0xf))+ 0x2C) + 0x368D5CB6) - 1;
      val = res;
    }
  return (res);
}

void		decypher1(s_peconf	*conf, char	*buf_end)
{
  char		block_0[0x28];
  int		offset = 0;
  int		i = 0;
  int		save = 0;
  int		size = 0;
  int		offset_buf_end = 0;
  int		ebx = 0;
  int		j;
  int		fd;
  int		total = 0;
  char		final[0x1000000];
  int		new_len;
  int		(*ucl_code)();
  u_block_0	block0;

  printf("ImageBase = %x\n", conf->optional_header.ioh->ImageBase);
  printf("NbSymbols = %x\n", conf->file_header.ifh->NumberOfSymbols);
  offset = conf->file_header.ifh->NumberOfSymbols + 0x14;

  memcpy(block0.buf, conf->p + rvatooffset(offset, conf), 0x28);

  printf("[+] Test ouput of memcpy of block_0\n");
  for (i = 0; i < 0x28; i++)
    printf("%02x ", (unsigned char)block0.buf[i]);
  printf("\n\n\n");

  sub_004011C0(block0.buf, 0x28, 0x2FCCA34E);

  printf("[+] Test ouput of memcpy of block_0 after decyphering using key 0x2FCCA34E\n");
  for (i = 0; i < 0x28; i++)
    printf("%02x ", (unsigned char)block0.buf[i]);
  printf("\n");

  save = block0.block_0.val_24;
  block0.block_0.size += -2 * save;
  block0.block_0.SizeOfImage -= save;
  block0.block_0.size2 += save;
  block0.block_0.val_18 += -16 * save;
  block0.block_0.val_0 += -8 * save;

  size = *((t_uint32*)(conf->p + rvatooffset(conf->file_header.ifh->NumberOfSymbols + 0xC, conf)));
  ebx = conf->file_header.ifh->NumberOfSymbols;
  for (i = 0; i < 4; i++)
    {
      memcpy(buf_end + offset_buf_end, conf->p + rvatooffset(offset, conf), size);
      printf("Offset = %x\n", offset_buf_end);
      offset_buf_end += size;
      ebx = *((t_uint32*)(conf->p + rvatooffset(ebx + 0x10, conf))) ^ 0x521d558;
      size = *((t_uint32*)(conf->p + rvatooffset(ebx + 0xC, conf)));
      offset = ebx + 0x14;
    }
  printf("[+] Block_0 is now fully decyphered\n");
  hexdump(block0.buf, 0x28);
  printf("\n[+] End Block_0\n");

  memcpy(block_0, block0.buf, 0x28);

  printf("[+] Information About block_0 [+]\n");
  printf("Val_0 = %x\n", block0.block_0.val_0);
  printf("Val_4 = %x\n", block0.block_0.val_4);
  printf("Size = %x\n", block0.block_0.size);
  printf("SizeOfImage = %x\n", block0.block_0.SizeOfImage);
  printf("Key = %x\n", block0.block_0.key);
  printf("Val_14 = %x\n", block0.block_0.val_14);
  printf("Val_18 = %x\n", block0.block_0.val_18);
  printf("size2 = %x\n", block0.block_0.size2);
  printf("val_loop = %x\n", block0.block_0.val_loop);
  printf("val_24 = %x\n", block0.block_0.val_24);
  printf("\n[+] End information block_0\n");

  decypher2(conf, &block0, buf_end);
  printf("\n[+] Decypher 2 Ok\n");

  ucl_code = malloc(326);
  if (ucl_code == NULL)
    {
      perror("malloc()");
      exit(EXIT_FAILURE);
    }
  if (mprotect(ucl_code, 326, PROT_READ | PROT_EXEC | PROT_WRITE) == -1)
    {
      perror("mprotect()");
      exit(EXIT_FAILURE);
    }
  memcpy(ucl_code, buf_end + block0.block_0.size + 0x28, 326);
  /* I tried to use ucl lib but without result */
  /* That's why i do this ugly thing */
  ucl_code(buf_end + 0x28, final);
  asm volatile("sub $0x8, %esp\n");
  printf("\n[+] UCL Algorithm ok\n");

  hexdump(final, 0x1000);
  printf("\n\n");
  fix_iat(final);
  fix_section(final);
  fd = open("my.dmp", O_RDWR);
  write(fd, final, 0x100000);
  close(fd);
}

void				fix_iat(char		*final)
{
  int				pe_header;
  int				addr_iat;
  int				offset;
  int				first_thunk;
  int				offset_lib;
  u_image_import_descriptor	iid;

  printf("[+] Dump IAT Information\n");
  pe_header = *((t_uint32*)&final[0x3c]);
  printf("[+] Pe_header = %x\n", pe_header);
  addr_iat = *((t_uint32*)&final[pe_header + 0x80]);
  printf("[+] Addr IAT = %x\n", addr_iat);
  iid.p = final + addr_iat;
  offset = *((t_uint32*)&final[addr_iat + 0xC]);

  do
    {
      printf("[+] Offset = %x\n", offset);
      printf("\tLibrary = %s\n", final + offset);
      offset = *((t_uint32*)&final[addr_iat + 0x10]);
      first_thunk = *((t_uint32*)&final[addr_iat + 0x10]);
      offset = *((t_uint32*)&final[first_thunk]);
      do
	{
	  printf("\t\tName = %s\n", final + offset + 2);
	  first_thunk += 4;
	  offset = *((t_uint32*)&final[first_thunk]);
	} while (offset);
      addr_iat += 0x14;
      offset = *((t_uint32*)&final[addr_iat + 0xC]);
    }while (offset);
}

static inline void rdtsc(int *upper, int *lower)
{
  asm volatile("rdtsc\n" : "=a"(*upper), "=d"(*lower));
}

void		decypher2(s_peconf	*conf, u_block_0 *block0, char *buf_end)
{
  char		block_1[256];
  int		i = 0;
  int		val_loop;
  int		res = 0;

  memset(block_1, 0, 256);
  val_loop = block0->block_0.val_loop;
  printf("\nVAL LOOOP === %x\n", val_loop);
  while (val_loop != res)
    {
      sub_004011C0(buf_end + 0x28, block0->block_0.size, i);
      res = sub_00401652(buf_end + 0x28, block0->block_0.size);
      sub_004011C0(buf_end + 0x28, block0->block_0.size, i++);
    }
  i = i - 1;
  printf("\n[+] Key Found for decyphering pe is = 0x%x\n", i);
  printf("[+] Result of their fucking_create_hashes sub = 0x%x\n", res);
  sub_004011C0(buf_end + 0x28, block0->block_0.size, i);
  printf("\nKEY USE == %x\n", block0->block_0.key);
  sub_004011C0(buf_end + 0x28, block0->block_0.size, block0->block_0.key);
  block0->block_0.size = block0->block_0.size - block0->block_0.size2;
  printf("\n\n[+] SizeOfImage= %x\n", block0->block_0.SizeOfImage);
}

int		main(void)
{
  s_peconf	conf;
  s_peconf	conf2;
  char		buf_end[0x1000000] = {0};
  char		buf_end2[0x1000000] = {0};
  int		i;

  fill_conf("keygen_v.45.23.4.exe", &conf);
  fill_info(&conf);

  printf("+-----------+\n");
  decypher1(&conf, buf_end);
  printf("+-----------+");

  /* printf("[+] Now we will work with the driver\n"); */
  /* fill_conf("4.dmp", &conf2); */
  /* fill_info(&conf2); */
  /* decypher1(&conf2, buf_end2); */

  /* close(conf.fd); */
  /* free(conf.sb); */
  return (0);
}