Unity3D安卓导出包加密学习--加密libmono.so

1.加密

直接复制李明华的代码
http://www.xuanyusong.com/archives/3571
修改char target_section[] = “.mytext”;为自己image.c里解密dll函数的section名

encrypt_section.c

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
/* 32-bit ELF base types. */
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;

#define EI_NIDENT 16

/*
 * ELF header.
 */

typedef struct {
  unsigned char  e_ident[EI_NIDENT];  /* File identification. */
  Elf32_Half  e_type;    /* File type. */
  Elf32_Half  e_machine;  /* Machine architecture. */
  Elf32_Word  e_version;  /* ELF format version. */
  Elf32_Addr  e_entry;  /* Entry point. */
  Elf32_Off  e_phoff;  /* Program header file offset. */
  Elf32_Off  e_shoff;  /* Section header file offset. */
  Elf32_Word  e_flags;  /* Architecture-specific flags. */
  Elf32_Half  e_ehsize;  /* Size of ELF header in bytes. */
  Elf32_Half  e_phentsize;  /* Size of program header entry. */
  Elf32_Half  e_phnum;  /* Number of program header entries. */
  Elf32_Half  e_shentsize;  /* Size of section header entry. */
  Elf32_Half  e_shnum;  /* Number of section header entries. */
  Elf32_Half  e_shstrndx;  /* Section name strings section. */
} Elf32_Ehdr;

/*
 * Section header.
 */

typedef struct {
  Elf32_Word  sh_name;  /* Section name (index into the
             section header string table). */
  Elf32_Word  sh_type;  /* Section type. */
  Elf32_Word  sh_flags; /* Section flags. */
  Elf32_Addr  sh_addr;  /* Address in memory image. */
  Elf32_Off sh_offset;  /* Offset in file. */
  Elf32_Word  sh_size;  /* Size in bytes. */
  Elf32_Word  sh_link;  /* Index of a related section. */
  Elf32_Word  sh_info;  /* Depends on section type. */
  Elf32_Word  sh_addralign; /* Alignment in bytes. */
  Elf32_Word  sh_entsize; /* Size of each entry in section. */
} Elf32_Shdr;

int main(int argc, char** argv){
  char target_section[] = ".mytext";
  char *shstr = NULL;
  char *content = NULL;
  Elf32_Ehdr ehdr;
  Elf32_Shdr shdr;
  int i;
  unsigned int base, length;
  unsigned short nblock;
  unsigned short nsize;
  unsigned char block_size = 16;

  int fd;

  if(argc < 2){
    puts("Input .so file");
    return -1;
  }

  fd = open(argv[1], O_RDWR);
  if(fd < 0){
    printf("open %s failed\n", argv[1]);
    goto _error;
  }

  if(read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
    puts("Read ELF header error");
    goto _error;
  }

  lseek(fd, ehdr.e_shoff + sizeof(Elf32_Shdr) * ehdr.e_shstrndx, SEEK_SET);

  if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
    puts("Read ELF section string table error");
    goto _error;
  }

  if((shstr = (char *) malloc(shdr.sh_size)) == NULL){
    puts("Malloc space for section string table failed");
    goto _error;
  }

  lseek(fd, shdr.sh_offset, SEEK_SET);
  if(read(fd, shstr, shdr.sh_size) != shdr.sh_size){
    puts("Read string table failed");
    goto _error;
  }

  lseek(fd, ehdr.e_shoff, SEEK_SET);
  for(i = 0; i < ehdr.e_shnum; i++){
    if(read(fd, &shdr, sizeof(Elf32_Shdr)) != sizeof(Elf32_Shdr)){
      puts("Find section .text procedure failed");
      goto _error;
    }
    if(strcmp(shstr + shdr.sh_name, target_section) == 0){
      base = shdr.sh_offset;
      length = shdr.sh_size;
      printf("Find section %s\n", target_section);
      break;
    }
  }

  lseek(fd, base, SEEK_SET);
  content = (char*) malloc(length);
  if(content == NULL){
    puts("Malloc space for content failed");
    goto _error;
  }
  if(read(fd, content, length) != length){
    puts("Read section .text failed");
    goto _error;
  }

  nblock = length / block_size;
  nsize = base / 4096 + (base % 4096 == 0 ? 0 : 1);
  printf("base = %d, length = %d\n", base, length);
  printf("nblock = %d, nsize = %d\n", nblock, nsize);

  ehdr.e_entry = (length << 16) + nsize;
  ehdr.e_shoff = base;

  for(i=0;i<length;i++){
    content[i] = ~content[i];
  }

  lseek(fd, 0, SEEK_SET);
  if(write(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr)){
    puts("Write ELFhead to .so failed");
    goto _error;
  }

  lseek(fd, base, SEEK_SET);
  if(write(fd, content, length) != length){
    puts("Write modified content to .so failed");
    goto _error;
  }

  puts("Completed");
_error:
  free(content);
  free(shstr);
  close(fd);
  return 0;
}

系统环境iMac
gcc编译,输入命令:gcc -o encry encrypt_section.c
生成encry的执行文件,输入命令:./encry libmono.so
新生成的libmono.so就是加密之后的文件,可以直接拷贝到Unity安装目录下(windows版)\Editor\Data\PlaybackEngines\androidplayer\release\libs\armeabi-v7a
使用unity导出新项目时就可自动替换。

mono解密dll代码段
还是直接使用李明华的代码
http://www.xuanyusong.com/archives/3571

//SO---------------加密----------------------

#include <sys/types.h>
#include <elf.h>
#include <sys/mman.h>

//注意上面说解密算法里面的断.mytext就是这里,
//这里把getKey进行了加密,这样对方拿不到你的密钥都没法破解你的dll了
int getKey() __attribute__((section (".mytext")));
int getKey(){
    return 2048;
};
//这里就是.so初始化的时候,这里进行mytext断的解密工作
void init_getKey() __attribute__((constructor));
unsigned long getLibAddr();

void init_getKey(){
  char name[15];
  unsigned int nblock;
  unsigned int nsize;
  unsigned long base;
  unsigned long text_addr;
  unsigned int i;
  Elf32_Ehdr *ehdr;
  Elf32_Shdr *shdr;

  base = getLibAddr();

  ehdr = (Elf32_Ehdr *)base;
  text_addr = ehdr->e_shoff + base;

  nblock = ehdr->e_entry >> 16;
  nsize = ehdr->e_entry & 0xffff;

  g_message("momo: nblock = %d\n", nblock);


  if(mprotect((void *) base, 4096 * nsize, PROT_READ | PROT_EXEC | PROT_WRITE) != 0){
    g_message("momo: mem privilege change failed");

  }
  //注意这里就是解密算法, 要和加密算法完全逆向才行不然就解不开了。
  for(i=0;i< nblock; i++){  
    char *addr = (char*)(text_addr + i);
    *addr = ~(*addr);
  }

  if(mprotect((void *) base, 4096 * nsize, PROT_READ | PROT_EXEC) != 0){
    g_message("momo: mem privilege change failed");
  }
  g_message("momo: Decrypt success");
}

unsigned long getLibAddr(){
  unsigned long ret = 0;
  char name[] = "libmono.so";
  char buf[4096], *temp;
  int pid;
  FILE *fp;
  pid = getpid();
  sprintf(buf, "/proc/%d/maps", pid);
  fp = fopen(buf, "r");
  if(fp == NULL)
  {
    g_message("momo: open failed");
    goto _error;
  }
  while(fgets(buf, sizeof(buf), fp)){
    if(strstr(buf, name)){
      temp = strtok(buf, "-");
      ret = strtoul(temp, NULL, 16);
      break;
    }
  }
_error:
  fclose(fp);
  return ret;
}

//SO---------------加密----------------------

这个必须放在image.c的最前面,因为这个init_getKey函数没有查找mytext段,直接取的第一个section。

看了下李明华文章下面的评论,使用hook mono_image_open_from_data_with_name还是能够提取出dll的,因为到了内存里dll就是解密好的原始文件。

参考:
http://www.xuanyusong.com/archives/3571
http://bbs.pediy.com/showthread.php?t=191649
http://0nly3nd.sinaapp.com/?p=695
http://blog.163.com/lhmood@126/blog/static/236614472009112693539253/
http://jzhihui.iteye.com/blog/1447570

ida pro
http://pan.baidu.com/s/1gd3lXtD
http://www.h4ck.org.cn/2014/08/ida-pro-6-5-with-hex-rays-x86-decompiler-v1-5-and-hex-rays-arm-decompiler-1-7/

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GrimRaider

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值