本帖最后由 艾莉希雅 于 2019-7-4 18:27 编辑
最近有人询问我关于mono的保护,刚刚好最近学期结束在找实习然后又找不到有点空。
就简单的写一系列的文章来简单的介绍一下mono下如何保护自己的软件不被人艹翻天。
简单的介绍一下替换mono内opcode来保护软件的思路。
能在mono上用的东西,自然也就能在unity上用咯!
众所皆知mono下跑的东西,随随便便动一下就能直接报废根本就不能好好保护。
能做的也就混淆之类的操作容易被还原,而unity游戏在没有启用il2cpp下Assembly-Csharp.dll又是一个超级软柿子。
所幸,mono是开源的玩意,可以让我们看到原始码,甚至自己修改出一份自己专属的mono。
今天给大家介绍的就是大街上偶尔会见到的opcodes替换。
不过opcode替换居然还没烂大街,本人表示震惊。
这个帖子默认大家都会编译mono,如果真的很多人不会的话……再水一贴美滋滋
那么先介绍一下今天的主角opcodes是什么玩意。
所谓的opcodes实际上就是告诉mono,接下来这个操作是要干什么的,因为C#并不是编译型语言,所以必然存在解释器。
接下来我们通过一个简单的例子介绍一下。
[C++] 纯文本查看 复制代码 typedef enum{
NOP = 0,
ADD = 1,
SUB = 2,
AND = 3,
OR = 4,
XOR = 5,
IN = 6,
NOT = 7,
} CODES;
void vm_exec(VM *vm, int start){
int sp;
int ip;
int a;
int b;
a = b = 0;
int addr;
ip = start;
sp = -1;
int opcode = vm->code[ip];
while(opcode != HALT && ip < vm->code_size){
ip++;
switch(opcode){
case ADD:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a + b;
break;
case SUB:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a - b;
break;
case MUL:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a * b;
break;
case AND:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a & b;
break;
case OR:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a | b;
break;
case XOR:
b = vm->stack[sp--];
a = vm->stack[sp--];
vm->stack[++sp] = a ^ b;
break;
case NOT:
a = vm->stack[sp--];
vm->stack[++sp] = a ? false : true;
break;
default:
printf("Invalid opcode");
exit(1);
}
opcode = vm->code[ip];
}
}
在这个Virtual-Machine例子中,我们遇见了1,那么所要做的就是找到1也就是add进行我们的操作
而今天的话题就是:如果1与2互换呢?今天我们就要在mono中把opcodes替换掉,来嗨一下。
至于mono的opcode在哪里?为什么不问问我们厉害的搜索功能呢!
mono-master\mono\cil,就是我们要找的目标。
打开定义opcode的文件opcode.def我们可以看到
嗯?第一行就告诉我们不要手改这个文件,要修改cil-opcodes.xml再重新生成。
在这里给大家做一个提醒,如果手改本文件可能会造成编译失败。
本人就是不信邪去手改了它,导致来回折腾然后不得不低头。
那么这个opcode.def要怎么才能生成呢?
我们后面再讲。我们先去看看cil-opcodes.xml里面是什么东西。
一一对应,不是吗……
在本次的例子中我们就把这个call与jmp换一下好的!对换的魔法来了!
如图所示!换了完事!接下来来看看怎么生成opcode.def。
十分简单!只需要一句话make-opcodes-def.pl cil-opcodes.xmlopcode.def
但是这句话没有在百度中找到也没有在谷歌找到,需要建议同学们记一下笔记
其实这句话是跟着代码中的$ARGV分析make-opcodes-def.pl文件整的,居然没有找到资料。
到底其他的开发者是怎么生成那个opcode.def我对此感到奇怪。
替换完opcodes后,重新编译mono即可。
此时mono的opcode中的jmp与call已经被对换。是不能运行正常的C#程序的。
所以接下来我们要修改程序以及其依赖的库,把jmp与call的opcode也对换掉。
这里以这个HelloWorld为例子简单的介绍一下手改的方法。
如图所示有两个call,而我们已经把call换成了jmp。
而jmp是27,所以我们手动将其改完27后保存即可。
修改后保存即可……然后我们在替换了opcode的mono中运行一下
完美!我们再拖去反编译看看怎么样了。
反编译的结果果然是错误的。仅仅对换call与jmp即可达到这个效果。
如果再替换掉其他opcode那事情就会变得更为精彩。
自然的,这个技术在unity游戏中也是可以使用的。
老样子换掉mono,然后再把库的opcode换掉。
如图所示跑的好好的不是吗
编译好的测试程序附件可以拿来玩哦
mono-replace-jmpcall.7z
(2.41 MB, 下载次数: 33)
这里留一个课后作业
思考一下怎么才能不用手改opcode的方法批量替换opcode呢 |