HackShield 内存保护技术分析

内存效验 在游戏内存保护 壳保护等等地方都可以经常见到 通常都是对保护内存块算hash值 比如CRC
HackShield一般CRC效验分2个部分 一个是HS SDK CRC 另一个是HSCRC 第一个HS提供给游戏调用的SDK 是对游戏内存自身的效验 第二个是对第一个的效验保护 在HS5.3版本的时候 HSCRC patch的很简单 因为第二层比第一层的周期长很多 所以直接hook第一层 线程跑到的时候 恢复hook 睡眠去…就可以断开了一层一层的效验链 方法已由某大神在某论坛公开过 而SDK CRC的patch方法呢 和大多的patch方法一样 都是复制内存副本+hook过掉的
后来某公司也出了个内存保护 原理依然一样 多个内存效验 互相保护 互相效验CRC 只是多了个RVM(NtReadVirtualMemory)方式的读内存 以及对RVM的hook扫描(不过神奇的是只扫头5字节 – -)
这种互相效验的保护 如果是带有VM/花的话 通常多是用内存副本可以patch掉
最新的HS5.5版本 有动态生成的内存效验 也就是随机位置生成一段shellcode来对指定内存效验 虽然随机位置生成的内存效验 大大的增加了传统hook的难度 但是也有大大的缺点 动态生成出来是shellcode 太长的话不好处理 也难以加密代码 shellcode通常比较短 试想一下 如果动态效验发现内存被改 如何回传结果? 是直接自毁呢 还是返回结果呢? 通常是后者 因为shellcode比较短 自毁也太容易被发现 但不管怎样 总结一点 就是动态内存效验的死穴 是难以加密代码
HS5.5的动态效验 先是申请随机内存 然后对同一块内存 依次写入4个不同的shellcode(这里是指先执行完一个再覆盖下一个) 然后这里就出问题了 可以看一下第一个截下来的栈 随便找个地方(虽然已VM 但不影响) 断下 小睡数秒 可以有足够的时间对这段内存下写硬断 因为它是用同一段内存写4次shellcode 所以写下一个shellcode的时候 就可以被断下来 断到了生成shellcode的代码后 就可以随便patch了 HS5.5直接xor eax, eax/ret就可以 或者传统的内存副本方式patch 除了这个动态的内存效验 还另外3个0x2XXXX, 0x3XXXX, 0x6XXXX 跟5.3一样 互相效验 另外还有2个是来自TMD壳的内存效验

最后总结一下 ring3下常用的也就这几种方式 互相效验/RVM/动态效验 各有优缺点 但都不难patch 当然 想要加强一下难度的话 也可以 比如说故意制造大量的垃圾信息 扰乱对内存硬断时断下来的信息 又或者 可以放到ring0去 会有更多的手段可以耍

防SEH清零DR

先说下异常吧 当ring3发生异常 会先进入KiUserExceptionDispatcher进行处理
函数原型: KiUserExceptionDispatcher( PEXCEPTION_RECORD pExceptRec, CONTEXT * pContext )
不过 要注意的是 异常的发生是不可预料的 所以这函数的调用跟普通的API有点区别
esp直接指向第一个参数 而我们要看的是第二个参数pContext
从KiUserExceptionDispatcher往下看 第一个call即call RtlDispatcherException
该函数会依次调用事先设置好的异常处理过程

先换个话题 说一下利用SEH清零DR的原理
同上 先自己注册异常处理过程 然后自己制造异常 借传入的pContext擦除各个debug registers的值

要防止这种方法清零DR的话 可以先挂钩KiUserExceptionDispatcher 把现场环境pContext保存起来
然后让他一个个RtlDispatcherException call啊call 都call完了后
只要在call ZwContinue之前把刚才保存的环境pContext还原回去 就可以防止DR被擦除

HS与某公司的反多开原理分析

好久没更新博客了 随便写点什么吧 最近某公司的反多开又更新了 不过依然很水
我记得当初5.3.x.x版本的HS的反多开还是很简单 就1个Mutant和2个Section全局对象
不过呢 也不是单纯的创建个全局对象 还会和你耍耍技巧呀
比如说连续创建2次 看看是不是都能成功 或者 是创建后定时查询 又或者先创建 再删除再查询..
后来某公司自己也出一个反多开 和HS共同合作淫荡 主要也还是全局对象 加多了Event, Semaphore, File类型的
File Object的也就是传说中很多公司都使用的文件占坑了 不过这丫的玩阴的 用的一日志文件占…
HS5.5.x.x的反多开没折腾 貌似就换了对象名而已
而最近某公司更新的反多开就不是用的全局对象了 不过也不是第一次见了 学过PE结构的应该知道 节有shared属性
去掉可共享属性就可xx 不过别忘了人家有自动更新 可以动态patch一下
不过某大神教的一个很简单的方法..建个与更新临时文件同名的文件夹 就直接跳过更新了 – -
说一下全局对象的处理方法吧 我是写几个SSDT HOOK处理的 最好是把进程各自独立起来吧
比如原对象名+进程PID 创建对象的时候改名 查询的时候恢复名字 只要细节处理好就没问题
除了SSDT HOOK 在ring3关闭句柄的话也可以 不过要注意关闭句柄的时间

FAT32文件系统学习笔记

- – 没写过笔记 不知道从哪写起呢 囧
感谢炉子大牛的指点及指正

一. 名词解释
1.扇区 扇区是磁盘最小的物理存储单元, 通常为512个字节大小
2.簇 由于操作系统无法对数目众多的扇区进行寻址, 所以操作系统就将相邻的扇区组合在一起, 形成一个簇, 每个簇可以包括1、2、4、8、16、32、64或128个扇区

二. FAT32文件系统结构简介
1. DBR及其保留扇区 – 记录了该文件系统的一些重要信息 以及引导程序
2. FAT表1 – File Allocation Table 即文件分配表
3. FAT表2 – FAT1的备份
4. 数据区 – 存放目录数据及文件内容的地方

三. DBR结构

1. 跳转代码 – 用于跳到引导程序处
2. OEM代号
3. PBP结构(BIOS Parameter Block)
4. 引导程序
5. 结束标记
计算机启动时 先由BIOS读入MBR的内容 以确定各个逻辑驱动器和起始地址 然后调入活动分区的DBR 由DBR来引导系统 额 MBR和分区表下次另写一篇补充下吧
DBR位于分区的第一扇区 占512字节大小 现在主要是要讲PBP结构

这图是WINHEX自带的模板 在这里先说一下怎么用WINHEX模板看吧
打开WINHEX->工具->打开磁盘->选一个FAT32分区->OK
现在已经打开了一个FAT32分区 你所看到的是第一扇区的内容 也就是DBR 把光标放到第一字节
然后 视图->模版管理器->选 Boot Sector FAT32
嗯 就说几个等会要用到的 要一一详细介绍的请参考wiki

1. 每扇区字节数 – 通常为512 但不是一定的 也可以是1024/2048/4096
2. 每簇扇区数 – 由多少个扇区组成一个簇
3. DBR保留扇区数 – 是DBR本身的扇区及其后保留的扇区数总和 也就是DBR到FAT1之间的扇区总数
4. FAT个数 – 通常为2 FAT2是FAT1的备份
5. 隐藏扇区数 – 是指本分区之前使用的扇区数 也就是MBR到DBR之间的扇区数
6. 总扇区数 – 指本分区的总扇区数 也就是分区大小
7. 每FAT扇区数 – 每个FAT表的扇区数 每个FAT表大小都是相等的

最后提一下引导程序 在windows2K以后 引导程序负责将NTLDR装入 对于没有安装操作系统的分区 这段程序没用

四. FAT表

先说下怎么定位到FAT表1 在WinHex按Ctrl+G 在Sector输入刚才PBP结构的”DBR保留扇区数” 就来到FAT表1了
FAT32里 每个FAT项占用4字节 0号1号保留 0号项描述了介质类型
FAT项的意义如下

前边说过 FAT32是用簇为单位管理的 每一个FAT项都映射一个簇的情况

0 – 表示该簇还没使用
0xffffff7 – 映射的是一个不可用的坏簇
0xffffff8~0xfffffff – 表示该簇是某个文件的最后一个簇
0×2~0xfffffef – 该簇被某个文件占用 但不是该文件最后一个簇 该FAT项的值是指向该文件占用的下一个簇

再说一下簇 因为是用簇为单位存放文件 所以呢 如果一个文件大小不够一个簇大小 也要占用一个簇
一个文件占用的多个簇 物理上不一定是连着的 在FAT表里是用链表形式连起来 等会举个实际例子吧

五. 数据区
1. 数据区的位置 先到DBR看各项的值 (“DBR保留扇区数” + FAT个数 * “每FAT扇区数”) 计算得到数据区的位置
2. 数据区的内容
FAT32文件系统的数据区的存放内容主要分3种 根目录/子目录/文件内容
在数据区内 是以”簇”为单位管理这段空间的
我们跳去数据区看一下内容

在FAT32文件系统 分区根目录下的文件及文件夹的目录项 都存放在根目录区中
分区子目录下的文件及文件夹目录项 都存放在子目录区
在FAT32中 根目录区与子目录区都在数据区中
每个目录项占32字节 目录项大概可以分为4类
1. 短文件名目录项
2. 长文件名目录项
3. “.”和”..”目录项
4. 卷标目录项

先附一张目录项偏移0xb(文件属性)各个位的意义图 图引用自WIKI

我们先来看看卷标目录项 定位到数据区 用WINHEX看第一个目录项 光标定位到第一个字节 打开模板管理器 选”Fat Directory Entry(Short entry format)”

由文件属性(Attributes)可以看出 这是一个卷标目录项 卷标名为”KINGSTON”

再来看短文件目录项

1. 主文件名 – 一共占8字节 如果用不完8字节 用空格填充 这里重点是第一字节 如果为0 表示该目录项还没用过 如果为0xe5(一个特殊符号代替了本来的第一个字符) 表示该目录项曾经用过 但现在已经删除
2. 扩展名 – 3个字节的文件扩展名 如果为文件夹或无扩展名 则用空格填充
3. 文件属性 – 占用1字节 每个位对应一种属性 如果该字节为”0f” 表示该目录项为长文件名目录项
4. 文件起始簇号 – 即该文件的数据存放的簇号 在这个文件中 高16位为0 低16位为3 即该文件的数据存放在3号簇
5. 文件大小 – 记录该文件的文件大小 占用4字节
短文件名的其他属性 参考wiki

长文件名目录项
从windows95开始 文件名”8.3″格式被打破了 文件名可以超过8个字节 并且可以使用中文了 扩展名也超过3个字节了 这种格式就称为 长文件名
先新建一个suanzi.0ginr.com.txt 跳到根目录看一看

可以看到 这个文件占了3个目录项 前边2个为长文件目录项 最后个是短文件目录项
再看看长文件名目录项的结构

1. 序列号 – 如果文件名太长 会占用多个长文件名目录项 占用1字节 用来描述长文件名目录项的排序 0~4位描述排序 第7位为1表示该目录项是最后一项 如果该文件被删除 该字节也会被改为”E5″
2. 文件属性 – “0f”表示该目录项为长文件名目录项

“.”和”..”目录项后边说

六. 手工历遍
嗯 我先格式化一次分区 然后新建几个文件
如下图

然后再定位到根目录看看 也就是数据区的开始 也就是2号簇
对应的扇区为 (“DBR保留扇区数” + FAT个数 * “每FAT扇区数”)

可以依次看出为卷标”KINGSTON”/123.txt/456.txt/文件夹abc
然后现在定位到123.txt的文件数据看看 先看下123.txt的文件数据在第几簇

簇号高16位为0 低16位为3 文件大小6字节
再去3号簇看看 簇号对应的扇区计算公式为 DBR保留扇区数 + 2 * 每FAT扇区数 + (簇号 – 2) * 每簇扇区数

可以看到是内容为”suanzi” 6字节大小

现在再来看看名为abc的文件夹的目录项

这个目录项的起始簇号为5 不过5号簇存放的并不是一个文件数据 而是这个文件夹的子目录区
然后跳过去5号簇看看内容

看到有3个目录项 分别是”.”/”..”/”FAT.JPG”
但实际该目录只有一个FAT.JPG文件

这里说一下”.”和”..”目录项
“.”表示当前目录
“..”表示上级目录项
如果上级目录是根目录的话”..”目录项的簇号为0 否则为上级目录区的簇号

七. 文件删除的观察
在删除文件之前先补充点内容
看一下刚才那个FAT.jpg的目录项

文件数据存放在6号簇
再看看FAT表1现在的内容

看到6号FAT项的内容为7 刚才说过 如果文件用多个簇存放 FAT表会把这些簇号连起来 现在6号FAT项内容为7 表示下一个簇号为7 7号FAT项内容为8 一直链到
0xD号FAT项 内容为fffffff标记文件的最后一个簇号
现在删除FAT.JPG这个文件(如果删除到回收站 请清空回收站)
再看看本来的FAT.JPG的文件目录项

对比上图 可以看出 第一个字节已经变成E5 即删除标记
再看看现在FAT表1有啥变化

对比刚才的FAT表 可以看出 原本的6号FAT项到0xD号FAT项 已经全部变成0 即该簇还没使用
那么FAT.JPG文件实际的数据还在吗? 过去6号簇看一看内容

噢 内容还是在的 原来删除文件 只是在目录项标记E5 以及对应的FAT项改为未使用 如果数据没被覆盖的话 直接把数据复制出来(大小在目录项里没改变) 即可恢复文件

八. 其他
差不多就写到这了 说一下FAT12/16/32的一些区别
整体结构的话 FAT12/16比FAT32多了一个部分 是跟在FAT表2后的 名为FDT(File Directory Table)即文件目录表 也即FAT12/16的根目录 而FAT32则把根目录丢到数据区去了
FAT表的话 FAT12/16里每个FAT项占用大小为12/16位 也即1.5字节/2字节
其他的一些小区别 参考wiki

补充1: 在FAT32里 根/子目录区 如果内容超出1个簇大小(也就是目录里文件/文件夹太多的话) 会跟大文件一样 再分配新的簇 然后FAT表把这些簇连起来.

最后附上一个自己写的FAT32解析的Demo

Fat32Parser.7z