00:00
呃,今天的内容不多啊,今天是讲反调试的这个最后一节,然后下节课开始呢,就讲其他的专题了,好然后今天的专题呢,我们是基于一个叫做CRC32的这么一个算法啊,那么这个呢,我们主要是基于什么?基于一种叫做完整性检查啊,完整性检查啊,然后呢,它是什么意思呢?首先呢,我们要了解这个C2732对完整性检查进行反调试,这一点我们需要了解几个点,首先第一啊这个断点啊,第二是这个PE,然后第三啊是我们的这个CRC啊,我们要了解这三点之后啊,才能对我们的这个CRC完整性检查有一个这个了解啊,那首先第一点啊,我们为什么要这个什么是我们首先要了解什么是完整性检查啊,完整性检查CC这个东西啊,首先我们要。
01:00
要了解的是它这个东西实际上是对你一块内存啊,给他干嘛计算出一块唯一值啊,计算出一块唯一啊,那计算的是什么内存呢?啊,那这块我们就来回来看一下这个PE这么一个东西。我们直接打开啊,首先PE这个东西呢,包括我们Windows上的这一些好多东西都是PE文件啊,你包括P这个文件它是PE文件啊,这个DR文件它是PE文件,Siss文件也是PE文件,它就是什么呢?Windows下的可执行程序都是PE文件啊,就是这么一回事,然后我们把这个东西呢,放在我们的load PE里啊,进行加载,然后来展示一下啊,首先呢,我们来看一下这个区段。啊,我们这个区段呢,打开之后你可以看到有这么多啊不同的区段啊,然后呢,有什么TSTB,这个BSS啊,TST data data,什么I data啊,这这很多很多的这个几页啊,对不对啊,这个区段,那其中呢,我们要关注的是什么呢?是这个段啊,这个段啊,这个什么代码段啊,代码段啊,一般情况下我们是关注这个名字啊,当然也有可能它这个代码端叫其他名字啊,这也是说不准的,所以说你在处理的时候呢,有可能需要自己去关注一下,它到底的这个代码叫什么,那现在呢,我们假设它代码段是这个点TS么,这种时候呢,我们就什么呢,我们就要了解到我们这块,它实际上就是一块内我们可以看啊16进制啊,你可以把它打开,诶,你看这么这一块啊,这什么,这是一块内存啊,那我们已知啊,我们的这个代码段是一块内存,而我们代码段呢,其实呢,就是我们程序里真正的这些这个代码函数所在的这么一个位置啊,正常情况下,我们代码段里的那个内存它是不变动的啊,除非你去这个修改它,而我们的这个。
02:40
个数据段里的内容呢,可能是经常变动的,那我们如果说代码段的内容不变动的情况下,你就可以了解一点啊,就是我们可以什么呢?我们可以通过CRC啊,对啊,内存中啊,对内存中的这个代码段计算出一个唯一值啊,计算出一个唯一值啊,这个值呢,我们先把它干嘛呢?写入到啊,写入的文件啊的某一个位置,或者实时啊,存储啊,实时存储,也就是说你可以干嘛写可以写到文件里啊,把它写成一个死的也可以干嘛呢,在程序启动的时候计算一次啊,然后呢,要开始进行这个运算,那我们如果说这个为什么要这么做呢?因为首先呢,我们知道了我们这个TST里有这个区。
03:40
不提什么呢,先不提这个硬件断点和软软件断,不是硬件断点和内存断点啊,我们只说我们最常见的软件断点,软件断点这个东西呢,是INT3啊,也就是什么呢?也就是0XC,它其实呢是对什么是对内存修改一字节啊,一字节啊,把这个字节呢修改成什么?修改成0XCC,用以用以触发什么触发断点异常啊啊用以触发断点异常,所以说呢,它是改了内存的,而我们CC这种算法,CRC32这种算法呢,对内存中计算之后,哪怕你改了一字节啊,它再次计算出来之后的值啊,都跟原来的值不一样了,所以说呢,你就看可以干嘛呢,可以通过啊后计算的CC的值对跟前边计算的CRC的值呢,进行一个对比啊,然后看它是不是一样,如果不一样呢,就说明什么,就被修改了,或者说打了补丁,或者加息下了断点,那我们首先呢,我们来看一下啊,加息这个东西呢,你完全不需要。
04:40
自己去搞啊,这个东西网上成熟的非常多,这儿呢我已经给你考了一个算法了,上边呢是这些算法的一些连接和原理啊,我们首先看一下它这个实现。啊,你可以看到这是C32的一个这个校验原理啊,就是什么就是什么这个循环于校验啊,啊然后呢,我们来看一下它这底下呢,有一些这个它的这个对于原理的一些描述啊,比如说啊这个你要这个和这个多项式啊,生产出这个CC码,然后呢,这个和这个进行这个一同发送,然后在里边进行计算对比啊但不重要啊,重要的是呢,我们要调什么呢?我们要调这里边这两个算法啊,你可以看到就这两个啊,这两个呢,实际上就是我考出这两个啊,我们有了这两个之后呢,就可以干嘛呢,就可以对我们的这个CRC呢,进行一个这个验了啊一个验了。
05:29
呃,应该说不是校验啊,应该说什么,应该说是就能对它进行一个这个初始化了啊,然后呢,我们初化之后呢,我们就可以来循环的去校验它了,那这个呢,是它的这个实现方法啊,然后呢,我们这儿呢,我还给大家准备了一个链接啊,这个链接。这是它S732加密算法的一个原理啊,就是如何算出这些东西的啊,啊,当然咱们今这节课的重点啊,不是这些东西啊,这个呢,如果你有兴趣呢,可以回去自己研究一下啊,咱们呢主要来实现它,那首先呢,我们已经有这两个算法了,我们肯定不用自己写了,我们把它先拿出来。
06:16
好,然后呢,接下来呢,我们要来写什么呀,来写我们如何去获取到我们的这个,呃,获取到我们那什么获取到我们的这个,呃,代码段啊,我们因为我们现在呢,还需要拿到它的这个代码段,才能对它这个代码段进行这个CRC的一个校验嘛,点TS这个拿点拿到它,那以说呢,我们现在要一个代码这个东西。好,那我们开始编写这个代码啊,你要返回两样东西啊,一个是你可以正常返回,你也可以直接啊这边一个布尔值,然后呢,呃,在这边给它直接用这个参数的方式啊,给它传出啊也可以啊,就是get。
07:04
呃,TST in,好,那我们要传出的一共两样东西啊,一个是我们的这个,嗯。一个是我们的这个加载的一个位置啊,加载的位置我们要拿到。被然后还有一个呢,就是你这个驱动有多大。啊,这两个啊,这个有多大呢,我们看一下啊在这。它前边这个这这个位置,呃,这个啊,然后后边这呢,你看没这就是啊,然后呢,我们要找啊,要找一个是它的base,一个是size啊,然后呢,因为我们要通过参数把它值取回去啊,所以说我们要么引用,要么用这个指针啊,两种方式都是可以的。
08:15
好啊,没点关注的点点关注啊,有需要领取往期课程的可以联系咱们这个老板啊,老板就在公屏上,然后现在呢,我们就可以来这个进行获取了啊,首先呢,我们获取一下自己这个主模块啊,因为我们这里边实际上一个这个程序里头是有很多很多的这个模块的,比如说我用它来给大家看一下。这个东西啊,我直接点开啊,然后放上去,诶你看啊,这底下有很多很多的模块啊,那我们现在要找的呢,是它这个同名的这个点ESE的模块里的什么这个东西啊,所以说呢,我现在呢,要干嘛呢,要找到它啊,那找到它呢,这个方式呢,其实非常简单的啊,首先我们用一个模块get model handle get handle呢,它这里边呢,实际上呢,是这个让你传这个模块名的啊。
09:06
啊,你可以看到啊,这里边呢,传的是名字啊,但是呢,因为我们现在呢,呃,如果不传名字,它有另一种选择,就是你可以直接传个闹进去,如果传个闹进去呢,它们什么意思呢,就是。获取默认的啊主模块的加载机制。啊,默认的主模块的加载器时啊,那所以说呢,我们现在呢,就看完了就给它加载这个主模块,然后呢,我们之后呢,要分析它的这个P文件啊,首先呢,我们要找到它的这个倒子头。七道S等于用我们这个加载机制啊进行分析,它直接就相当于一块指向某一块内存的一个指针啊,所以说我们在这啊给它指向好,那我们现在拿到了到子头,拿到到头之后呢,我们现在拿这个NT头。
10:50
强转啊,用我们的这个道字头啊,进行这个NT头的一个获取。
11:24
好,现在呢,我们就拿到了我们NT头了,然后呢,我们现在要来获取一下,我们一共有多少个区段。在我们N地头的这个里有一个number of这个。这个就是区段的个数,拿到区段个数之后呢,现在呢,我们就来拿这个区段的这个机制。
12:47
获取完,嗯,等一下我想一下是不是啊,获取完机制之后,我们开始循环遍历这些区段。嗯,区段按区段总个数进行遍历,遍历之后呢,我们在其中主要是用来判断一下我们要找的名字。
13:11
如果说S7RCP对比对比我们的这个区段。区段里边有一个名字。Name啊,它这个类型不符吧,我看一下。啊对类型不符啊,需要类型强制转换一下,我们直接给他F12进去是一个看差星啊。然后对比啊,和我们的这个要找的这个啊,点TST,如果你的代码段不是叫这个名字,你就写成其他名字啊,反正总之呢,是要进行对比,然后呢,这个我们这个东西呢,因为它是STRCP,所以说呢,它的返回值呢,呃,和大家想的可能不太一样,它是一个int的返回值,并不是出false,所以说呢,当它等于零的时候才是相等啊,所以说我们要判断一下它是不是等于零。
14:09
好,判断完之后,呃,判断完它是不是等于零之后呢,如果是的情况下,就进入到这个位置是吗?那我们如果说在这处理就是返回,那如果说不是进到这儿呢,那就要干嘛呢?要给他进行什么,进行一个区段表的一个指针加加,让它执行到下一个区段上啊嗯,然后最后呢,如果不是的情况下呢,我们在最后给它两个东西都这个复制为零。啊,照到这说明没找没有找到啊,所以两个东西都复制为零。并且return一个false,那如果在这儿呢,那这两个东西就不是赋值为零了啊,我们就可以给它有正常的一个返回了啊,那首先呢,我们如果说他的这个size呢,它是有一个我们这我我们这个区段里边是有专门有这个有这个字段的啊。
15:01
啊,不是这是这这是鸡齿啊,点错了,呃,是我们的。点位是size啊,这个好,然后上面这个呢,就是我刚才放的那个啊。Rise啊,然后加上模块的加载机制。然后一个处好喝口水。好,那这个东西呢,它就已经返问回去了,我们现在获取到他这个infer了,已经啊,获取完iner之后呢,我们现在呢,就来再给他写一个这个彻bug。
16:05
上面是一啊,我们再来给他写一个二。首先呢,我们要获取相关的一个信息啊,两个东西一个。Size。啊de DW,然后还有一个DW啊这个贝斯,然后啊返回一个布尔石在他。
17:00
Test in数,然后把第第一个参数是base啊,然后把base地址传进去,然后把我们的size啊地址传进去,获取到,获取到之后呢,接下来呢,我们给它这个进行CC的一个这个表的一个创建。下期表创建完事之后呢,我们现在呢,开始计算我们的这个下期的一个值,这个flag啊,我们要计算一下啊,然后这个flag呢,是通过我们这个函数啊,给它计算出来的两个参数,一个是要计算的值,一个是它的一个尺寸啊,那值呢,肯定呢就是我们的这个base啊,我们这个base作为一个值啊给它传进去啊,但是呢,因为类型不符,所以说呢,我们要给它强制转换成一个这个叉形类型啊,然后给它传进去,后边呢,就是它的一个尺寸啊,就是我们获得的DW size,好计算完这个flag之后呢,我们现在呢,就可以在里边进行一个循环判断啊,但是呢,这样的话,它每嗯这样也无所谓啊啊,我们应该把这个东西放外头啊,放外头调用啊,就是类似于全局的啊,就是在比如说放TS里什么的啊,然后给他计算一下这个东西。
18:21
嗯,这两个都是啊,我给大家写一个函数吧,啊,比如说我现在呢,有一个布尔。In it。C2C。但这俩东西在上面获取啊,那我现在首先在这儿获取一下。好,现在呢是获取啊,获取到获取到信息,然后呢,对他们进行一个计算啊,计算出得到一个这个flag,这个flag呢,我们给他这个放一下全局。
19:06
好,然后呢,我们在这边呢,我们就是第二次嘛,第二次呢,我们就获取完之后呢,主要就是为了跟上一个进行一个对比啊,那所以说呢,我们还是要来计算出一个这个32的这么一个,呃,Flag。Int啊,这是临时flag,好计算完这个临时flag之后呢,实际上我们就是在里头进行这个运算啊,判断判断我们的这个flag。和我们之前初始化时候判断的flag。是不是一个值,如果说是一个值啊,那就return一个false,说明没有被调试,那如果不是一个值呢,我们就直接给它return一个这个啊,Return一个这个处啊,说明设备调试了。
20:02
我看一下啊,这两个啊flag,然后获取,获取完之后计算。嗯,应该是没有问题啊,应该是没有问题,然后初始false啊,然后呢,这个东西呢,我们直接啊,在这个我们用之前呢,在所有的这个循环用之前,我们先给它进行初始化,初始化之后呢,再进这个外循环啊,进外循环之后呢,我们用这个二啊来进行调用,好,那现在呢,我们重新生成。理论上而言呢,我们现在如果是这个正常运行的情况下,应该是没有问题的啊,你们可以看到啊,因因为我没有改它内存,所以说它是一直是,然后呢,我们把它打开啊打开。打开之后呢,我们直接在这儿啊,双击运行它应该也是run啊,也没有问题啊,但是呢,如果说我们用这个调试器。啊,进去。运行运行这样的话,它是没问题的啊,它不会有问题的,它真正出问题会出在哪儿呢?就是你下断点的时候,比如说我们找到它的这个字符串啊,所有模块。
21:13
嗯,Debug啊,我在。比如说我在这儿,我给它下个断点,下个断点之后呢,它会停下来啊,然后呢,你在运行的时候,你就会发现它都是打印的是debug了,因为什么?因为它重新计算完之后,会发现这个已经了。而且呢,我是下载了这个检测线程里啊,如果你是下在了主线程里啊,它就是干嘛计算代码段的时候,既会干嘛,既会发现是调试又不会被断下来啊,因为你正常情况下,你的检测线程是不应该被人发现的啊,发现人就过掉了啊,是这么回事的。好,那么这个呢,就是咱们今天要讲的这个西32的这么一个反调式啊,其实呢,它也可以反补啊,就是说比如说有人要你啊,那这个时候你也可以用这种方式啊,对趟他的这个hook,因为你如果代码段进行了这个这种操作之后啊,他再去改你的这个代码段里的内容,他的话也会干嘛呢,也会遇到夏西三那啊。
22:07
啊,那么有什么问题可以问啊,没点关注的点点关注,有需要咨询的和有需要领取这期或前期的这个呃课程。
我来说两句