Unity Android 动态更新 Assembly-CSharp.dll

来源:互联网 发布:socket长连接发送数据 编辑:程序博客网 时间:2024/06/06 03:00

http://blog.sina.com.cn/s/blog_9e5d42ee0102vvtg.html

1.流程

游戏启动后先加载包里面的Assembly-CSharp.dll --> 在splash屏下载新的Assembly-CSharp.dll --> 代码重启游戏 --> 在加载 Assembly-CSharp.dll 的地方 mono_image_open_from_data_with_name 里面 强制加载 /data/data/packname/files/Assembly-CSharp.dll




2.重新编译MONO 




MonoImage *

mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)

{

//修改开始1

int datasize =0;

if(strstr(name,"Assembly-CSharp.dll")){

    //重新计算路径

             constchar* _pack = strstr(name,"com.");

       const char* _pfie = strstr(name,"-");

       char _name[512];

        memset(_name,0,512);

       int _len0 = (int)(_pfie - _pack);

        memcpy(_name ,"/data/data/",11);

        memcpy(_name +11, _pack,_len0);

        memcpy(_name +11 + _len0 ,"/files/Assembly-CSharp.dll",26);

        

g_message("momo: path = %s\n", _name);

        

char* bytes = ReadStringFromFile (_name,&datasize);

if(datasize >0){

data = bytes;

data_len = datasize;

//data[0] -= (char)getKey();

//g_message("momo: key = %d\n", getKey());

}

}


//修改结束1


MonoCLIImageInfo *iinfo;

MonoImage *image;

char *datac;


MonoCLIImageInfo *iinfo;

MonoImage *image;

char *datac;


if (!data || !data_len) {

if (status)

*status = MONO_IMAGE_IMAGE_INVALID;

return NULL;

}

datac = data;

if (need_copy) {

datac = g_try_malloc (data_len);

if (!datac) {

if (status)

*status = MONO_IMAGE_ERROR_ERRNO;

return NULL;

}

memcpy (datac, data, data_len);

}

 

//修改开始2

if(datasize >0 && data != 0){

g_free (data); 

 

}


//修改结束2





//附so加密 放在image.c 的开始处吧


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

 

#include

#include

#include


//注意上面说解密算法里面的断. lclly就是这里,

//这里把getKey进行了加密,这样对方拿不到你的密钥都没法破解你的dll

int getKey()__attribute__((section (".lclly")));

int getKey(){

return88;

};

//这里就是.so初始化的时候,这里进行lclly断的解密工作

void init_getKey()__attribute__((constructor));

unsignedlong getLibAddr();

 

void init_getKey(){

 char name[15];

 unsigned int nblock;

  unsigned intnsize;

  unsigned longbase;

 unsigned long text_addr;

  unsigned inti;

  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");

}

 

unsignedlong getLibAddr(){

  unsigned longret = 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---------------加密----------------------


static FILE* OpenFileWithPath(const char* path )

{

   const char* fileMode ="rb";

   return fopen(path, fileMode );

}


staticchar* ReadStringFromFile(constchar* pathName,int* size)

{

    FILE* file = OpenFileWithPath( pathName);

   if (file == NULL)

       return 0;

    

    fseek(file,0, SEEK_END);

    

   int length = ftell(file);

    fseek(file,0, SEEK_SET);

   if (length < 0)

    {

        fclose( file );

       return 0;

    }

    *size = length;

   char* outData = g_try_malloc (length);

   int readLength = fread(outData, 1, length, file);

    

    fclose(file);

    

   if (readLength != length)

    {

        //if(readLength == length){

        //    JNI_OnLoad(0,0);

        //    JNI_OnUnload(0,0);

       //}

        g_free (outData);

       return 0;

    }

    

   return outData;

}



 

//SO---------------加载DLL-------------------





3.Java部分修改  放到 UnityPlayerActivity 中

publicvoid restartApplication() {  

newThread(){

publicvoid run(){

Intentlaunch=getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName());

launch.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

startActivity(launch);  

android.os.Process.killProcess(android.os.Process.myPid());

}

}.start();

finish();

 

}  



4.C# 下载资源

public class Download : MonoBehaviour {

    public Image bar = null;
    public Text label = null;
    float progress{
        get{ 
            if (bar != null) {
                return bar.fillAmount;
            }
            return 1.0f;
        }
        set{ 
            float v = value;
            if (v > 1.0f) {
                v = 1.0f;
            }
            if (bar != null) {
                bar.fillAmount = v;
            }
        }
    }
    WWW www = null;
    // Use this for initialization
    void Start () {
        progress = 0;
        #if UNITY_ANDROID
        StartCoroutine (loadAsset() );
        #endif
    }

    string version = "1.0";

    IEnumerator loadAsset()  
    {   
        #if UNITY_EDITOR
        WWW txt = new WWW ("http://192.168.0.101:8083/readme.txt");
        yield return txt;
        string text = txt.text;
        SaveBytes (Application.persistentDataPath+"/","readme.txt",txt.bytes);
        if (text != version) {
            www = new WWW ("http://192.168.0.101:8083/Assembly-CSharp.dll");
            yield return www;
            byte[] bytes = www.bytes;
            SaveBytes (Application.persistentDataPath+"/","Assembly-CSharp.dll",bytes);
            yield return new WaitForEndOfFrame ();
            restartApplication ();
        }
        #else
        string datapath Application.dataPath;
        int start datapath.IndexOf ("com.");
        int end datapath.IndexOf ("-");
        string packagename datapath.Substring (start,end-start);
        string path "/data/data/"+packagename+"/files/";
        WWW txt new WWW ("http://192.168.0.101:8083/readme.txt");
        yield return txt;
        string text txt.text;
        SaveBytes (path,"readme.txt",txt.bytes);
        if (text != version) {
            www new WWW ("http://192.168.0.101:8083/Assembly-CSharp.dll");
            yield return www;
            byte[] bytes www.bytes;
            SaveBytes (path,"Assembly-CSharp.dll",bytes);
            yield return new WaitForEndOfFrame ();
            restartApplication ();
        }
        #endif

    } 

    void SaveBytes(string path,string filename,byte[] bytes){
        Debug.Log (path+filename);
        label.text = path+filename;
        Directory.CreateDirectory (path);
        FileInfo file = new FileInfo(path+filename);
        if (file.Exists) {
            file.Delete();
        }
        var sw = file.Create();
        sw.Write(bytes, 0, bytes.Length);
        sw.Close();
        sw.Dispose();
    }

    void restartApplication(){
        Debug.Log ("restartApplication0");
        AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject jo = jc.GetStatic
<</span>AndroidJavaObject>("currentActivity");
        Debug.Log ("restartApplication1");
        jo.Call("restartApplication");
        Debug.Log ("restartApplication2");
    }
    
    
    // Update is called once per frame
    void Update () {
        if (www != null) {
            float _p = www.progress;
            if (progress 
<</span> _p) {
                progress = _p;
            }
        } else {
            progress += 0.01f;
        }
    }
}
 



其实还有另一种动态更新dll方案,就是 先启动一个androidapp 下载 dll 再启动游戏同样需要编译替换MONO中的加载

0 0
原创粉丝点击