【dll解密】Dll加壳保护方案分析修复

分析背景
NGame游戏海外版出现了破解版,该版本在dump出游戏的dll中不能直接通过反编译工具查看修改后的游戏代码,导致无法确定外挂修改的直接逻辑点。本文主要针对AssemblyCSharp.dll模版,分析其dll保护的方法。

分析过程
1、拿到Encrypt_Assembly-CSharp.dll,拖进reflector中查看,发现文件不能被解析,提示说无效的COFF 头。
在这里插入图片描述
2、用010Editor打开Encrypt_Assembly-CSharp.dll查看文件,如下:

在这里插入图片描述
熟悉的MZ头,后面的“This program cannot be run in DOS mode”还被改成了黑客 网址,再看看后面的数据,基本确定是PE格式了。再看看这个网址,应该是这个组织把游戏给hack了再加上壳的。我们用010Editor来解析下这个PE文件,得到如下图在这里插入图片描述
可以得出DOS头通过e_lfanew解析出了NT头,但是奇怪的是NT头却没有解析出Section,让我们查看下NT头是否有不符合COFF格式的项。展开NT头,发现下面的Signature值有误,应该只是“PE”即 0x4550 两个字符,修改之。
在这里插入图片描述
修改后,重新运行下PE模板,就可以看到被解析的Section了。再次拖进reflector去解析dll,发现有如下错误:
在这里插入图片描述
我们知道,DataDirectory是PE文件很重要的一个结构,在 IMAGE_OPTIONAL_HEADER下的最后的位置,一般在NT头偏移+0x60的位置,像导入表,导出表,重定位表的RVA和size都放在这里。正常的DataDirectory有16项,分别如下:
在这里插入图片描述
以前的第15项是装 COM_DESCRIPTOR Directory 的RVA和size的,后来MS没有用这个,就把这个项装CLR信息了,也就是 .Net的所有信息。如果出现了reflector上面的DataDirectory数目不对的问题,那应该就是反编译器读取DataDirectory项数的时候出现了问题,也就是IMAGE_OPTIONAL_HEADER中的NumberOfRvaAndSizes错了,实质上应该是0x10才对,修复之,保存。
在这里插入图片描述
顺便查看一下我们要的CLR数据的RVA和size信息:
在这里插入图片描述
RVA为0x2008,size为 0x48

5、拖到reflector看看解析结果,如下:
在这里插入图片描述
出现了不允许非负数的情况,在这个时候,首先应该考虑到ILSpy的异常栈回溯查看问题,如下:
在这里插入图片描述
然而笔者觉得打log应该也是看不清的,但是唯一可以马上得出的两点结论是,metadata数量相关的索引被改成了负数,导致越界。

6、一般笔者分析metadata会利用CFF Explorer,把修复了部分的Encrypt_Assembly-CSharp.dll拖进CFF Explorer 中,发现了如下异常:
在这里插入图片描述
经验告诉我这个是Metadata Header的NumberOfStream 被改大了,改回 5就行了,正常的CLR数据一般只有5个流,分别为#~,#Strings,#US,#Blob,#GUID。

7、下面我们找到CLR的头去修复NumberOfStream,首先已知CLR头在0x2008位置,这个是虚拟地址,现在SectionHeader里面看看我们的这个虚拟地址落在哪个段上面:
在这里插入图片描述
原来是在.text段(其实一般也是在这个段中),根据虚拟地址0x2000和文件偏移的基址0x200转换下虚拟地址0x2008的文件地址,得到其文件偏移为 0x208。查看下这个位置的数据,如下:
在这里插入图片描述
这72个字节的结构是这样的:
在这里插入图片描述
NumberOfStream在MetaData里面,IMAGE_DATA_DIRECTORY结构就是RVA和size组成的。所以,在CLR头也就是.net目录结构头偏移 +8的位置可以得到MetaData的RVA为0x2F4E6C,转换成文件地址为 0x2F4E6C – 0x2000 + 0x200 = 0x2F306C。我们去0x2F306C的位置看看:
在这里插入图片描述
熟悉的BSJB出现在眼前,这个就是Metadata Header。红圈部分就是NumberOfStreams,修改成5即可,保存。

8、拖进CFF Explorer正常解析了,然后结果如下图:
在这里插入图片描述
9、这个时候用反编译器还是不能解析的,因为游戏逻辑是保存在#中的,那么我们进入#里面的Tables看看是否解析成功,发现CFF Explorer卡死了,和预期一样。正常的dll文件应该在点击Tables的时候会显示出每一个Table及其项数。
在这里插入图片描述
这里说一下MaskValid的意义,把这个值变成二进制表示为:
在这里插入图片描述
上面的最右边(最低位)为索引00,该值为 1,表示存在该表(为0即表示不存在),该表名为Module,如下:
在这里插入图片描述
其余类推。统计了一下,总共有24个1。是不是理论上会有24个表存在呢?其实不是的,细心的读者会发现第43个1没有对应的表,所以0x1E093FB7BF57值只能代表23个表。

10、我们看看#~保存的表的位置:在这里插入图片描述
可以看到,在MetaData头偏移 +0x6C 的位置保存着我们的#~的header,也就是0x2F306C + 0x6C = 0x2F30D8 的位置。如下蓝色覆盖的地方为我们的#~的header:
在这里插入图片描述
这个时候很容易就想到了为什么reflector会出现这样的情景:
在这里插入图片描述
其实很容易能够想到只要把这三个数据的高位字节(小端存储)patch成00就可以了,然而抱着严谨的态度我们还是去看看NGame破解版的libmono.so到底是怎么解析这一块数据的,查看开源的mono代码找到相关的解析位置load_tables,然后反汇编libmono.so即可,如下:
在这里插入图片描述
这个函数破解版和原版的解析方式是一致的,可以看出load_tables只取了低位24个字节。而到了这里我们可以知道reflector和ILSpy解析了32个字节所以导致出错了,我们把这三个数据的高位字节patch成00,保存下。

11、用reflector或者ILspy查看修复后的Encrypt_Assembly-CSharp.dll,如下:
在这里插入图片描述
原理总结
外挂针对dll的保护处理主要包括如下四个方面:

1、修改NT头的Signature。

2、修改IMAGE_OPTIONAL_HEADER中的NumberOfRvaAndSizes。

3、修改了CLR头指向的MetaData中的NumberOfStream。

4、修改了MetaData指向的#~堆中的tables数据项数。

外挂保护dll做的工作本质还是对抗主流的反编译器,防止其他人对外挂进行分析,实质上对mono源码基本没有进行大的修改。只要掌握一定的PE和.Net文件结构格式知识,就可以直接修复被修改的数据。

外网也存在一些修改elf文件的so保护机制,针对的是链接视图甚至是执行视图的修改,也是防止静态分析工具如IDA等进行分析,但是本质也是没有动linker所需要用到的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/780561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spark-Scala语言实战(7)

在之前的文章中,我们学习了如何在IDEA中导入jars包,并做了一道例题,了解了RDD。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点赞,谢谢…

Linux 操作系统 022-串口/U盘/共享文件夹

Linux 操作系统 022-串口/U盘/共享文件夹 本节关键字:Linux、centos、串口、U盘、共享文件夹 本节相关指令:echo、cat、mkdir、mount 1、串口 #(1) 查看串口是否可用,可以对串口发送数据比如: $ echo helloworld >/dev/ttyS…

167-两数之和II

题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] &#xff0c;则 1 < index1 < index2 < num…

04-JavaScript函数

函数&#xff08;重点&#xff09; 1.为什么使用函数? 用函数来解决代码重用的问题。 2.函数的意义 函数其实就是封装&#xff0c;把可以重复使用的代码放到函数中&#xff0c;如果需要多次使用同一段代码&#xff0c;就可以把封装成一个函数。这样的话&#xff0c;在你需…

Redis中处理处理没有ACK确认的Stream

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 Stream是一个只能追加内容的数据类型。也就是说Stream这种数据类型,我们…

vue的创建、启动以及目录结构详解

vue的创建、启动以及目录结构详解目录 一. vue项目的创建 二. vue的目录结构 三. src的目录结构 四. vue项目的启动 4.1 方法1 4.2 方法2 一. vue项目的创建 创建一个工程化的Vue项目&#xff0c;执行命令&#xff1a;npm init vuelatest 注意&#xff1a;如果你在这个目…

pdf在浏览器上无法正常加载的问题

一、背景 觉得很有意思给大家分享一下。事情是这样的&#xff0c;开发给我反馈说&#xff0c;线上环境接口请求展示pdf异常&#xff0c;此时碰巧我前不久正好在ingress前加了一层nginx&#xff0c;恰逢此时内心五谷杂陈&#xff0c;思路第一时间便放在了改动项。捣鼓了好久无果…

银河麒麟、统信UOS、Centos、欧拉以及红帽系linux服务器版本安装Mysql

查看当前目录home/xiaolin 创建mysql文件夹&#xff1a;mkidr mysql 检查系统自带的mysql安装包&#xff1a;rpm -qa | grep mariadb或者rpm -qa | grep mysql 请卸载通过 rpm -e --nodeps mariadb-libs-5.5.56-2.el7.x86_64命令装卸 mariadb 进入mysql文件夹&#xff1a;cd m…

Android 多层级列表实现

方法一&#xff1a; Element.java &#xff1a; package com.chy.ydy.tools.treeutil; /*** TreeView 元素* */ public class Element {/** 文字内容 */private String contentText;/** 在tree中的层级 */private int level;/** 元素的id */private int id;/** 父元素的id */…

动态链接dlopen/dlclose/..

dlopen&#xff0c;dlsym,dlclose可以在不去link shared library的前提下&#xff0c;在runtime时调用shared library里面的函数.这样可以实现shared library的覆盖或是省略编译阶段的链接检查.但dlopen/dlclose要谨慎使用,尤其是有些写的不是很好的shared library. 动态链接函…

搜索与图论——Prim算法求最小生成树

在最小生成树问题里&#xff0c;正边和负边都没问题 朴素版prim算法 时间复杂度O(n^2) 生成树&#xff1a;每一次选中的t点&#xff0c;它和集合的距离对应的那条边&#xff0c;就是生成树的一条边 算法流程和dijkstra算法非常相似 #include<iostream> #include<cs…

OKCC的API资源管理平台怎么用?

API资源管理平台&#xff0c;重点是“资源”管理平台&#xff0c;不是API接口管理平台。 天天讯通推出的API资源管理平台&#xff0c;类似昆石的VOS系统&#xff0c;区别是VOS是SIP资源管理系统&#xff0c;我们的API资源管理平台是API资源管理系统&#xff08;AXB、AX、回拨AP…

【御控物联】JavaScript JSON结构转换(7):数组To数组——键值互换属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、案例之《JSON数组 To JSON数组》三、代码实现四、在线转换工具五、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0c;生成新的JS…

【Spring Cache】基于注解的缓存框架 简化redis代码

文章目录 一、介绍二、常用注解三、快速入门3.1 EnableCaching3.2 CachePut3.3 Cacheable3.4 CacheEvict 一、介绍 Spring Cache 是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring Cache 提供了一层…

带你认识线程

线程的概念 前言&#xff1a; 一个程序运行起来&#xff0c;就会对应一个进程&#xff0c;例如&#xff0c;启动一个 Java 程序&#xff0c;就会创建一个 Java 进程。进程也被称为系统分配资源的基本单位。 一个进程可以包含一个线程&#xff0c;也可以包含多个线程&#xff…

政安晨:【Keras机器学习实践要点】(九)—— 保存、序列化和导出模型

目录 介绍 如何保存和加载模型 保存一个Keras模型 装回模型 设置 保存 例子&#xff1a; 自定义对象 向 load_model() 传递自定义对象 使用自定义对象范围 模型序列化 APIs 内存模型克隆 任意对象序列化和反序列化 保存模型权重 内存中的权重传递接口 无状态层…

MYSQL中update的low_priority

low_priority&#xff0c;低优先级 UPDATE [LOW_PRIORITY] tbl_name SET col_name1expr1,col_name2expr2,... mysql中update用low_priority让update不锁定表 MySQL允许你改变语句调度的优先级&#xff0c;它可以使来自多个客户端的查询更好地协作&#xff0c;这样单个客户端就…

蓝桥杯算法基础(32):素数,埃式筛法,快速幂,斐波那契与矩阵幂运算

素数 有些人认为一个人一生中有三个周期&#xff0c;从他或她出生的那一天开始。 这三个周期是身体周期&#xff0c;情感周期的和智力的周期&#xff0c;他们有周期的长度为23&#xff0c;28&#xff0c; 和33天。每一个周期都有一个高峰。在一个周期的高峰期&#xff0c; 一个…

新能源充电桩站场视频汇聚系统建设方案及技术特点分析

随着新能源汽车的普及&#xff0c;充电桩作为新能源汽车的基础设施&#xff0c;其安全性和可靠性越来越受到人们的关注。为了更好地保障充电桩的安全运行与站场管理&#xff0c;TSINGSEE青犀&触角云推出了一套新能源汽车充电桩视频汇聚管理与视频监控方案。 方案采用高清摄…

Springboot之RESTful风格

概述 Restful风格与传统的有一些不同&#xff0c;传统的资源请求中只有Get以及Post两种方式来传递参数&#xff0c;而Restful风格将资源请求按照CRUD增删改查这基本的数据操作分成了四个基本传递方式。其中&#xff0c;Put 和Delete是从Post中分离出来的&#xff0c;可以浅显的…