unity3d手游破解(一)

重点知识:

1. \assets\bin\Data\Managed\Assembly-CSharp.dll扔进Reflector+reflexil环境

2.libs\libmono.so的mono_image_open_from_data_with_name函数


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

转:https://bbs.pediy.com/thread-226135.htm

最近找乐子破解了点手游玩玩,顺便分享一下,目标APK--发条XX。

1、大致分析

拿到APK先看看libs和assets,发现有libmono.so以及\assets\bin\Data\Managed\Assembly-CSharp.dll,可以确定是unity3d手游,可以尝试修改 Assembly-CSharp.dll来破解游戏,不过发条英雄的这个dll加密了,所以需要先解密。

2、解密dll

把 libmono.so扔进ida,找到mono_image_open_from_data_with_name函数,F5查看发现了解密代码:

在这个函数先判断加载的dll是否包含ssem字符串,接着判断前两个字节是否等于82(0x52),77(0x4d),因此可以确定下面的for循环是解密代码,比较简单,抄下来自己写一个解密程序(附件有一份),然后对这个 Assembly-CSharp.dll进行解密。

3、修改dll

把 Assembly-CSharp.dll扔进Reflector+reflexil环境进行修改(不会的同学百度学习一下),找到关键函数get_DamageValue,直接改成返回100W,然后攻击就变成了100W。

不过这个时候怪物攻击也是100W,因此再找到Player的applyDamage函数,修改这个函数直接ret,然后玩家就无敌了。

最后保存为一个新的dll并替换掉之前APK里面的 Assembly-CSharp.dll,解密后的dll头部不等于82(0x52),77(0x4d),因此so可以直接加载。

4、运行

重新签名,打包成新的APK,安装运行,一刀100W。

5、结束语

服务器信赖客户端的计算结果就导致这种情况,不过服务器加强数据校验也能检测出来。有兴趣的同学可以去改改dll实现竞技场百战百胜。

6、附件

decrypt.c

#include <stdio.h>
#include <elf.h>
#include <unistd.h>
#include <fcntl.h>
#include <error.h>
#include <errno.h>
#include <stdlib.h>

typedef char _BYTE;

int main(int argc, const char **argv) {
	
    if(argc != 3) {
    printf("usage:%s <in> <out>\n", argv[0]);
    return -1;
    }  


    FILE *fpDll;  
    fpDll = fopen(argv[1], "r");  
    if(fpDll == NULL)  
    {  
        printf("open  fail\n");  
    }  
    fseek(fpDll, 0, SEEK_END);  
    int len = ftell(fpDll);  
    fseek(fpDll, 0, SEEK_SET);  
    char *data = (char *)malloc(len);  
    fread(data, 1, len, fpDll);  
    fclose(fpDll);  

    signed int v11; // [sp+20h] [bp-18h]@3
  signed int v12; // [sp+24h] [bp-14h]@3
int v10;
size_t i;

v12 = 55;
      v11 = 89;
char *src = data;
int n = len;
 if ( *(_BYTE *)src == 82 && *((_BYTE *)src + 1) == 77 )
      {
        for ( i = 4; i < n; ++i )
        {
          v10 = v12 + v11;
          v12 = v11;
          v11 = v10;
          if ( v10 > 0x10000000 )
          {
            v12 = 1;
            v11 = 1;
          }
          *((_BYTE *)src + i) ^= v10;
        }
        *(_BYTE *)src = 77;
        *((_BYTE *)src + 1) = 90;
        *((_BYTE *)src + 2) = -112;
        *((_BYTE *)src + 3) = 0;
      }

FILE* pFile = fopen(argv[2],"wb");  
    fwrite(data,len,1,pFile);  
    fclose(pFile);     

}

 

 

Reflector+Reflexil 相结合实现对DLL文件修改

reflexil

https://github.com/sailro/Reflexil/releases

第一步:

下载Reflector 10和Reflexil 2.2,装好后将Reflexil的插件DLL文件加载到Reflector中

具体操作:Tools->Add-Ins->+->选择Reflexil的DLL文件Reflexil.Reflector.AIO.dll,点击确定加载到Reflector中

第二步:

2.1 Reflector加载需要编译的DLL或exe文件,找到对应的方法。

2.2 打开Tools->Reflexil  你将会看到对应方法的IL代码

选择Reflace all with code 对对应代码进行修改后,点击左下角的 Complie(编译),然后点击“确定”;

第三步:

确定操作完毕后,在左侧DLL或exe文件上右击

Save as 程序集编译成功!

 

Reflector反编译插件Reflexil 图文使用教程

Reflexil 它是Reflector的一个插件,结合Reflector,可以进行DLL代码注入等工作,实践证明完全可用,方便开发人员对.NET程序进行修改;可以作为一个Reflector插件修改程序集的IL并保存到磁盘文件,也可以在自己的.NET程序中调用进行更为灵活的.NET程序集修改。

下载好Reflexil后,在Add-ins 界面,点"+",选择Reflexil.Reflector.AIO.dll,然后Close

现在在Tool中会多一个Reflexil选项

它的界面

用法:

把我刚才写的Hello world拖进Reflector,我们选中程序集,命名空间,类名,方法, Reflexil的界面都是不一样的.

这里可以知道,我们能注入类,接口,枚举,方法,等,也可以重命名,删除.

现在我们来添加一个方法试试,选择Inject method 。 Item Name:Demo(此时只能声明无参,无返回值的方法,后面会讲什么添加这些)

点ok会给出警告

 意思就是,做大改动(注入,删除,重命名)时你是看不见结果,让你保存一次在导入新的dll文件,那就保存一次

保存好后,把新dll拖到Reflector中,就会发现在 Programe中多了一个Dmeo方法.

现在来给Demo 写实现

选择Demo 后右边的界面为:

选择Main:

instructions 中是IL指令, 高级玩家可以直接修改添加指令,但不是高级玩家咋办?

我们选择Replace all with code... 替换所以代码.

不过在这之前 先在Parameters添加一个参数string name,并在Attributes 将Return type设为stirng

我再次点击Replace all with code...  代码已经更新为

修改完成后,点compile 如果没有错误,就会生成IL指令,点ok就行

现在在来修改一下Main方法,调用Demo

代码已经改完,现在保存看看执行效果:

原程序:

修改后程序:

 

https://www.52pojie.cn/thread-271347-1-1.html

Reflector 之reflexil使用

潜水潜了那么久,上来换口气..
昨天和小伙伴一起玩一个CrackMe(C#),打算一起来写KeyGen,他用的是爆破的方法,我修复程序后发现里面常量各种溢出...无奈,只能用reflexil注入方法,然后写出KeyGen.
分享下使用reflexil常用的几个方法..

Reflector 之reflexil使用

先写个简单的控制台程序

工具,添加插件.

选中reflexil 1.6 (1.7从来没附加成功过.不知道为啥..)

一 直接修改操作数

可以直接编辑IL

Update 后

在程序集中右键

另存程序.

执行刚保存的程序

还可以直接添加IL 接着让后面继续输出

二 直接注入IL

右键,新建(new Create),填写对应的操作码,选择类型,

值得注意的是右边的按钮,append(添加),接着是插入在选择之前,然后是插入在选择之后;别选错了.

注意    注入的时候操作数的类型别选错了.

然后继续参照上面的,将程序另存一次.

三 替换代码

如果不想折腾IL,直接选择 替换所有代码.

不过这意味着你要重写所有代码(大多数时,我都会用在重写某个方法上)…然后提交一下,他会自动编译, 然后继续参照上面的,将程序另存一次.

提交完成后会自动编译,并且再右侧区域会生成对应的IL.

然后继续参照上面的,将程序另存一次.

执行下…

四  注入方法

别选错地方了.是你要将方法注入到某个类中,不是注入class所以,一定是在类上右键

暂时只能注入返回值为void的方法

对了,点击OK后会有个该死的提示,这提示的大致意思是:

当你在执行,增加,删除,重命名,等动作时,你不会直接看见相应的操作,他们是不同步的.

你必须要重新加载程序集才可以看见.

当然,你还需要将程序另存一次.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

然后你需要关闭程序集,接着重新打开刚才另存的 

现在方法已经注入进去了.

然后我需要给它添加点内容..

让方法输出个InjectedMethod字符串

在方法中添加IL

接着修改Main方法,并且调用刚才注入的方法.

另存下..

执行结果.

Ps:   如果是替换代码的话,先更改injectmethod时不用实现main方法,只需要修改injectmethod()方法,然后再去修改Main方法.调用时因为injectmethod方法不是static所以需要实例化Program

接下来说说添加有参数,有返回值的方法:

先在参数(parameter)标签,中添加一个参数.

然后在属性标签中修改返回值为string.

接着使用替换代码的功能

可以看见方法已经带有参数并且有返回值.

修改下这个方法

打印下传进来的名字,并且打印当前时间

修改主函数调用

编译,然后不要忘记另存….

Good Job .

Have Fun .

By McevilRock

9-7/2014

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值