00:00
啊,然后开始咱们今天的这个课程啊,今天呢咱们还是讲反调式啊,今天呢也是有两种反调式方式啊,我们今天呢,第一种呢,就是使用这个实时调试器的检测。实时调试器检测,还有一种呢,就是什么呢?第二种啊就是啊TLS啊,线程局部存储啊这个东西啊,来进行这个反调试啊,我们今天就讲这么两种,呃,我们第一种呢是实时调试器,那实时调试器是一个什么样的概念呢?比如说我们打开一下虚拟机啊,我们现在呢,有这个OD啊,我用这个系统它比较纯净啊,所以给大家演示一下啊,我这儿呢,打开一下这个RG啊E。嗯。Reg啊,我说不能没用啊,我们把它打开啊,打开之后呢,这个东西呢,它32位下和64位下这个地址是不一样的啊,所以你在写的时候也需要注意一下啊,它这个东西我们在这个设置的时候,它有一个实时调试器的设置啊,你比如说设置这个欧率八为实时调试器这种啊,那它这是什么意思呢?就是你在这个操作系统上啊,如果有一个程序崩溃了,你想直接用调试器进行接管,那这时候呢,它是由什么调试器进行接管的呢?其实就是由实时调试器进行接管的啊,那我们现在呢,这个东西呢,就是啊问你要不要把这个only debug设置成这个实时调试器,那我现在呢,先先带大家来看一眼啊,你看这个位置上,我现在呢,已经给它找到了啊,我可以带大家重新找一遍,比如说这个在它这里边有几个,这个五个根目录嘛,这个五根目录里,我们选择这个第三个啊,这个local,这个本地的,然后啊这个啊这个软件啊Microsoft,然后里边呢还有一个。
01:47
Windows nt啊,Windows nt里头有一个ae debug a deb里面你可以看到啊,这有一个什么啊,User debug啊,这个hot key啊,就是热键啊,那我们现在呢,不管这个东西啊,我们在这个ae debug这儿啊,我们先停着,现在呢,我们设置only debug为实时调试器啊,它这个没设置上啊,是因为这个需要一个权限才能设置啊,所以我们要右键啊,以管理员身份打开我们的onlybug。
02:11
然后现在呢,选项啊,实时调试器设置啊,直接点击设置,设置完事之后呢,在这个位置按F5实行刷新,你可以看到它出出来一个叫debug的一个呃键啊,这个键呢,它的类型呢,是一个字符串啊,RGZ字符串,它的字符串的一个值呢,你可以打开看一下,其实就是什么,就是你的onlybug的一个路径啊,然后后边呢,是加了一些参数啊,那么所以说呢,这个东西就是什么东西呢?就是说它设置之后在注册表里是有一个体现的啊,那么这个时候呢,我们就可以干嘛呀,我们就可以打开注表的这个键啊,然后来获取啊,它的里边的一个值啊,来知道里边到底是不是我们的这个,呃,实时调试我是是我们的调试器啊,这个其实就是耍流氓啊,就什么我不管你有没有这个,呃调试我,但是只要你是有实时调试器的啊,而且实时调试器不是像什么VS之类,而是onlybug之类的东西,那我就认为你是调试器啊,那我就直接干掉你啊,现在呢,我把它这个给它删掉,删掉之后呢,我们一刷新啊FF51刷新,刷新之后没了啊,没了之后你可以看到这边啊,它这个实时调试器设置啊,就恢复了啊,就没了啊,让你重。
03:12
重新设置啊,这个呢,是这个32位的这么一个路径啊,我们直接给他这个复制一下这个橡皮擦。好,这是32位的啊,那我们直接来看一下64位的啊,Rig e啊一样啊。那64位的呢,他呢稍微有一个区别啊,其实呢,路径基本一致啊,你可以看到啊。它是什么,它是这个也是logo啊,然后软件microof的Windows nt啊,但是呢,它多了一个,诶,而且好像跟那个三呃跟那个。64跟32位好像是一样的。啊,不对不对不对,它应该是有一个不一样的啊,我来看一下啊。Oft,然后呢,它应该不是直接是这个Microsoft,我看一下啊,应该是这个六十四三十二node啊里边啊,这应该是有一个,它这有两个东西啊,你看这里边也有一个64位的这个啊,然后64位这里边啊,我们来看一下啊,这里边有一个这个。
04:18
嗯,我看一下在哪C。诶,这里没有吗。Window啊Windows nt啊,差一层啊,我记错了啊,首先先找到Windows nt啊,你看找到这儿啊,找到这儿之后有它,找完它之后呢,这里边呢,有一个AB诶看到了吧,这个就是啊,然后呢,我这本机上的它的一个实时调试剂呢,是一个VS啊VS啊这个路径呢,稍许有点差异啊。上边呢这个是叉八六的,下边这个呢是叉六四的啊可以看到呢,稍微有点区别啊,那我们现在呢,就来这个去查找它对不对啊,那现在呢,我们就来把这个差呃这个ch bug这个函数,而且给它实现出来。
05:09
好,那首先呢,我们要判断一下是32位还是64位啊,那所以说呢,我们来一个这个IS64的一个标记啊,然后我们用呃,IS64啊,Process啊来进行一个判断,判断它是不是64位的啊,然后呢,这个函数呢,它有两个参数,第一个参数呢,是一个当前的进程的一个句柄啊,第二个呢,是不是啊,由它进行一个out,一个返回,那我们首先呢,要传入一个句柄,那我们可以直接用get CR ENT啊,Process啊进行传入,传入之后第二个呢,就是我们的一次呃,一次64啊,直接一个引用地址传进去,传进去之后呢,它会进行返回啊,现在呢,我们就可以判断是32位还是64位了,那现在呢,我们如果是这个32位的啊,这个rag。
06:03
RG啊,那么这个情况下啊,我就给他啊,用32的一个路径。呃,不包括根目录啊,根目录呢,一会儿我们会单填进去啊,我们现在呢,是由后边这部分就可以了。这个字符串里边呢,注意它的所有斜杠啊,都需要进行一个转移啊,这种的都需要进行转移啊,就是说多加一个斜杠,把斜杠转成斜杠。好,这是呢,32位的啊,如果是这个64位的,我们就把64位的放进来,RG64啊。我看一下啊,123。
07:02
诶。啊,前面写错了啊。好,那现在呢,我们32位的和64位的就都有了,都有之后呢,我们现在呢,就可以来给他这个进行一个判断。啊,判断什么判断是32和64嘛,我们直接把这个1464啊放在这,如果是处的情况下,它是64位啊,如果是false的情况下呢,就是32位啊就啊打开这个key。用个A版吧啊,我们用这个ask字符串,首先呢,要给它传入它的这个跟根目录啊,根目录呢,就采用这个啊,我们直接把它放上去,你可以看到形成了一个红啊,接下来下一位呢,就是我们是路径啊,那我们现在呢,如果是64位的情况下呢,就给它放64位的。然后呢,第三个啊,就是你要返回一个这个K啊,那这个K呢,你需要在上面呢,给它进行一个这个声明,不对啊,是一个HK。
08:17
取地址啊进行返回啊,现在呢,这是64位的,然后32位的呢一样。啊,效果是一样的,然后呢,我们如果打开了啊,过来之后啊,我们现在呢,要进行一个获取啊,那么这时候呢,我们要获取的是什么呀?获取的是它这里边的一个这个呃键啊,刚才有一个这个键在的啊,那我现在呢,因为这个东西被我删掉了,所以它没了啊那我可以重新设置一下选项啊实时诶点错了啊点选项啊实时调试设置啊,然后给它设置上,设置上之后呢,我们在这儿啊F5进行刷新,哎,你看我们要查的呢,就是这个东西啊,我们现在把它的名字啊给它复制出来。然后呢,把它删掉。好在这个位置呢,我们申声明一个变量,好这样就行了啊,然后呢,我们现在呢,就来开始找他了啊,首先呢,我们要把这个查到的这个字符串啊返应回来,因为你在查之后,它里边有一个这个实时调数器的一个路径嘛,那么我们要把这个路径返回来,我们需要一个这个呃,临时变量啊进行一个存储。
09:23
好,那现在呢,我们就开始进行一个这个件的一个查询啊。Igqer。Y啊,然后是这个V6EXA,好,然后呢,我们现在要查询,首先第一个啊,它的第一个参数我们可以看一下,它是一个key,这个key呢,就是我们刚才通过上面这里啊打开的这个key啊,无论是32位还是64位,我们只要打开了一个啊就把它传进来,第二个呢,就是你要查找的它的一个值的这个名字啊,就是这个debug啊,那我们现在把这个debug传进来,第三个参数呢,是我们的一个这个,呃,这啥玩意儿,我F1一下啊看一下。
10:14
啊,保留的啊,我们必须是闹啊,我们直接给他传个到就行了。好,然后再下一个啊,再下一个是它的一个这个类别啊,那这个类别呢,是一个传出的,我们直接一个D啊,然后一个DW。DW啊,然后tap就可以了,然后地址传进去。地址传进去之后呢,下一个呢,就是什么,第二下一个就是你这个东西取出来之后放在哪啊,那取出来之后我们肯定放在这个tap里啊,所以说呢,我们把这个东西传过来啊,但是它有个类型不符,这时候呢,我们S12跟进去啊,直接给它转成什么,转成我们这边这个类型LP贝。再下一个参数是什么,再下一个参数是一个长度啊,那这个长度呢,我们跟它一样长就行了啊,我们直接来进行一个一个设置。
11:11
啊不对,这是传出的啊,那传出的我们直接给他传个零其实就可以啊,然后取举例子放进去。啊,这样就行啊,这个其实不用设置长度啊,这个是取出的,然后呢,我们取出之后呢,我们就要判断什么判断这里边包不含包含我们要判断的这个实时调试器啊,比如说我们现在呢,就判断这个only debug。那我们要怎么判断呢?首先呢,我们就进行什么,进行STSTR,就是判断一个串里有没有另一个串的这个判断啊,那我们用这个啊,取出来这个东西进行判断,然后第二个是什么,第二个比如说我要判断有没有only debug啊,我就直接only啊,这个大写小写应该是debug。好,然后不等于now,这就是判断了一个啊,如果你要再判断一个调试器,比如说这样判断啊,你再来一个啊,然后里边写什么,比如说我这儿判断only debug,我这儿呢,再判断一个就是only ice。
12:10
这样就可以了啊,如果找到了呢,我就直接一个什么一个true,如果没找到的情况下呢,我就直接一个else else,什么else return,一个false,好,现在呢,我给它进行一个调用啊,没问题啊,我重新生成一下。好,取出我的这个可时常去啊,然后放到我的这个虚拟机里。现在啊,我们普通运行。你可以看到它一直是个run啊,然后这个时候呢,我把这个实时调试给它射上去啊。
13:01
你可以看到直接就变成debug了,然后呢,我就把这个刷新一下。F5啊,刷新完之后把它再删掉。然后你看又又变成乱了啊,这就是检查什么啊,检查这个坐表路径里头到底有没有实时调试器啊,有这个我们目标的实时调试器啊,就会触发我们的这个调试条件啊,然后它就会触发成这样,好,那这个呢,就是咱们今天讲的这个第一种方式啊,就是采取实时调试器检测这么一种方式,然后接下来呢,咱们讲啊,怎么去用这个线程局部存储这个东西啊,来进行这个反调式啊,那线程局部存储这个东西呢,就是我们的这个TLS啊这个东西,如果说大家这个在这个学过PE的情况下,应该对它呢,还是有一定的这个了解的,我们可以呢,用这个load PE啊,随便打开一个这个我们的这个呃,可执行程序啊,然后呢,现在呢,这里边的区段数据目录,数据目录里边你可以看到这有一个这个TLS表,我们直接点开你看到了吧,它这有一个TLS一个表啊,这边有一些字段相关的一些信息啊,那这里边比较重要的呢,主要是这个call back table va啊,这里边它其实是一个数组啊好,那现在呢,我们首先呢,知道了这个PE里边有这个TRRS的一个相关信息啊,那么接下来呢,我们现在呢,来了解一下这个TRS。
14:11
个具体的内容啊,TS这个东西啊,那就是我们首先想啊直接。呃,线程局部存储这个东西啊,它首先呢,它是这个和我们这个线程相关的一个东西,已经是非常明显的了啊,那它是什么时机创建出来的呢?它这个东西的创建,它为什么可以用来做反调试呢?主要这个东西的执行时机的一个问题啊。执行时机的一个问题啊,就是这个东西啊,这个TLS它是有一个回调函数,有一个或多个回调函数,准确的来说啊,就不止一个啊,那如果说它有一个回调函数的情况下啊,每次你在创建或终止啊进程的线程啊,这个时候就会自动的去执行啊,也就是说你无论是创建线程还是终止线程它都会执行啊,创建这个主线程的时候也会自动去调用啊,所以说呢,就是什么呢?就是说啊,如果说你是在这个注册之后,那么你在这个注册这个创建主线程的时候,也就是main函数没有跑起来之前啊,那就怎么样,它就会去执行它的回调函数,它跑的是优于什么呢?优于我们的入口代码的啊,那么这个时候我们反调式技术又是怎么样呢?就可以在这个啊,这个没函数之前啊,然后先把我们的反调式给加进去啊,那么这种情况下,如果你的调试器没有经过特殊设置啊,他就不在那个位置停啊,在没函数的时候他就已经退了啊,这个东西呢,但是只能欺负欺负小白啊,稍微有点经验的呢,一看这个在。
15:42
之前崩了,他大致上应该就有一定的了解,知道是怎么回事了。然后呢,没点关注的点点关注啊,咱们每周六周日都有直播啊,周中呢,这个有时候会有直播。呃,然后呢,有需要咨询课程或者领取课程的呢,可以咨询咱们老板啊,在这个公屏上直接找他就行了。
16:03
好,然后呢,我们现在呢,了解一下啊,我们首先呢,那么我们已经知道了它是什么一个状况,那实际上就是什么呢?就是进程创建啊,然后呢,我们接下来下一步是什么,下一步是主线程,主线程启动啊,主线程启动的时候呢,它要干嘛呢?它就会去执行。执行啊,这个TLS回调函数啊,执行TLS回调函数,然后再去执行什么,然后才会去执行啊这个主线程代码,也就是说什么,也就是所谓的这个EP代码入口代码。那么这这样,他这个东西呢,有这么一个圈啊,所以说呢,我们现在就可以来利用这一点了,对吧?啊,那我现在来注册一个这个东西,这个东西其实注册起来也非常的简单啊,那我先把我底下这些这个呃,这些东西啊,我先给他这个去掉啊,先给它去掉。它这个东西我想想啊,应该是不需要这么来回调来执行啊,啊,不需要线程来执行啊,我们先把这个线程去掉啊,我们可以直接来这个执行它。
17:08
好,那我怎么去写它呢?首先呢,我要用这个东西的时候呢,我先要对这个编器啊,给他声明一下啊,我要包含TS了。啊,首先生于,哎,这是不是写错了。Link啊,没错,它怎么是这个颜色?好,然后呢,接下来呢,我们要开始这个注册他的这个回调函数啊,现在只是声明了有这个TS啊,但是还没有说他有这个回调函数啊,现在呢,我们现在呢,要来给他注册这个回调函数了啊,那回调函数如何去注册呢?首先呢,我们注函数啊,在这个我们的这个数据里啊进行一个注册。
18:13
啊,这实际上就相当于这个data segment啊数据段啊,然后呢,我们现在呢,在这个数据段里边呢,我们要给他写一个东西点CT啊,然后。Dollar符啊,Dollar符啊XLX,那这个是什么意思呢?这个呢是这个注册我们这个T,这个TRS函数的一个声明啊,我们底下呢,还要有一个对应的就是结束的一个部分,这个结束的部分里边就不需要写这个字符串了,那这个字符串的意思呢,我们需要简单的来介绍一下啊,那其中的这个T啊,点T啊,这个T是什么意思,这T实际上指的是一个缩啊是什么?是C语言的这个。啊,C语言的time啊,实际上就是下题,也就是说什么使用使用C语言的运行时机制啊,使用序言的运行时机制,后边这个叉叉是什么东西啊,我们来看一下。
19:19
叉拉叉是什么意思啊?首先第一个X啊代表的是啊,名称随机啊,名称随机啊,第二个是什么意思啊,第二个L啊,这个L其实就是表示的是这个TLS啊TLS啊call back。啊,指的就是这个东西,那最后一个X呢,这个X其实是任意的啊,任意一个啊,任意一个这个B至Y之间的字符都可以啊,这个是都行的啊所以说呢,我们这个是这个作用啊,那接下来呢,我们要来给他声明什么,声明它的这个,呃,注册他的这个回调了啊,那注册回调了,现在呢,我们要来这个给他看一下里边的一个东西啊,那首先呢,他要找什么,怎么去注册呢?它里边有一个叫做P啊,Image PLS call back。
20:12
啊,这么一个东西啊,那我们可以直接F12跟进去,跟进去之后你可以发现它实际上就相当于一个什么一个函数指针,那你把这个函数指针拿出来对不对啊,拿出来之后啊,直接给它声明出来就可以了啊,就可以啊作为什么作为这个回调函数的原型,就跟我们现成的回调法原型是一样的,对不对啊,所以说呢,它也是类似的这么一个作用啊,那我们现在呢,前面这东西去掉啊,然后后边这东西也去掉,我们中间呢,要给它起一个名字,比如说我就直接给它起叫这个t ls call back,好,然后底下呢,要给它实现一个这个函数体啊,这个时候呢,你把它啊这里呢,给它这个写一个名字啊,你你这个是一个类型嘛,所以说你要给它来写一个名字TRS啊,How等于它啊,这个时候就指定了它为什么TR的一个回调函数啊,当然需要注意一点啊,我们这个程序里边不止可以注射一个TRS一个回调函数啊,它可以实际上可以注册多个的啊,我们F12直接看一下它底下有一个叫什么。
21:13
啊,这个有这么一个结构啊,这么一个结构里边你看这里啊,这个是什么,这是address of callbas啊注意这个S看到了吧,它这个是个S啊,然后而且后边他专门注意注意了一下什么是一个什么p ts call back,注意它是P啊ts call back啊是啥意思,它本身就已经是个指针了,然后是个指针,那这种情况下说明什么?说明它是一个数组,也就是说什么呢?是这个位置上是可以放多个的啊,是可以放多个的,如果你放多个呢,你就这样写啊,给它来一个,这样,然后呢,这样写啊就可以了啊,这样写就可以了啊这样写就是多个啊,如果说你只有一个呢,你就直接普普通通的给他放在这儿就行了啊,这个是需要声明的啊,就是说你如果是多个的情况下呢,它也是支持的啊,没点关注点点关注啊,然后有需要这个课程咨询的可以联系咱们老板啊,然后有需要领取课程的也可以联系老板啊,然后呢,咱们每周六周日都有直播,好,那现在呢,我现在呢已经给他注册好了,注册好了之后呢,我们现在呢就来来研究一下。
22:13
它的这个回调函数是怎么一回事了啊。我们首先看一下啊,这个东西呢,它这个东西长得和我们以前了解过的东西啊,就是动态链接库里边的D妹是不是特别相像啊。这个实际上而言,它就是加载机制,或者说叫模块句柄对不对。模块加载机。啊,就这个东西啊,那下边呢,这是什么,这是元音,这个东西啊是什么是元音。
23:07
调用回调函数的原因啊,那这个东西不用讲了啊,它这个模块机制其实就是拿到我们当前的一个模块机制啊,这个没有什么好讲的,这个原因呢,有一点这个东西。那我们原因呢,和我们的这个DR呢,一般情况下呢,也很接近,一共有四种啊啊,包括我们的首先呢是DR process啊这个。这是第一个代表什么,代表着啊进程加载进程啊,然后呢,还有什么对应的吧DLL。呃,应该说不不应该说是这个加载进程,我们应该说TRS的加载这个状况啊,我按TS来说,那就是什么就是进程啊,它的主线程啊,调用这个main函数之前啊,已经注册了这个回调的情况下,它就会被调用执行啊,因为所以说呢,这个时候它的值啊,就是什么是一啊,然后呢,就被调用了啊,也就是说我们在这个呃,主线程。
24:15
调用main函数之前调用TLS函数啊,这是然后呢,还有这个DLL。啊,这个那这个呢,很明显跟上边那个是一一对应的吧,对不对啊,那所以说上边那个呢,是加载,那这个底下是什么东西啊,这个就是什么,就是我们的这个呃,进程。进程终止。终止前main函数结束时。
25:02
TLS回调。回回调函数被调用啊,这是两种情况啊,一种是没函数之前,一种是结束之后,呃,结束之前啊,那还有两种呢,就是与线程相关的,上面两种是进程相关的啊,那下边这两种呢,就是DR。嗯,没写上啊,我重新写一下three啊这个,那这个是什么东西啊,这个东西啊,就是我们。就是线程启动的时候。May函数。开始执行。后创建用户线程时啊,这个调用执行用户线程代码前TLS回调函数被调用啊,就是这个原因啊。
26:12
然后最后一个B,这是什么?这是函数开始执行后啊,用户线程结束前最后一次。呃,用户线程结束前执行TRS回调函数啊,大致上就是这么四种情况啊,那我们现在呢,因为只是想简单的做一个反调式啊,其实是不用管它是什么乱七八糟的情况的啊,我们只需要调用一个最简单的东西啊,这个东西你可以跟前边我们讲那十来种这个调试那个反调试啊,任意来结合,它只是在这个前边,在函数前面加一个检测啊,它本身是不能检测的,你还是要依赖于我们之前讲的各种方法,比如说我们用一个最简单的bug。
27:15
好,然后呢,我们如果是这个情况下呢,我们就直接E啊,那么这个情况我们来直接运行一下啊。可以看到了吗?运行不起来啊。为什么呀,因为我们VS也是一种调试器啊,当它执行到这个没函数之前,它就直接崩掉了,那我现在呢,我直接啊打开一下我的这个项目啊,我把这个项目呢,是用我们的调试器进行打开。把它拖入我们的这个调试器当中。啊,现在呢,不是停下来了嘛,啊,在这个NTDRDR里,现在呢,我们直接运行啊,到主线程了啊,然后我们再运行啊,它就没了啊就没了,那这个时候呢,我们其实呢,这个如果想让它断下来啊,而且断刚才其实我们断下来啊,我们把这个保存去掉啊,然后重新打开一次啊,它应该不在那断的啊,我们运行啊,然后呢,直接啊。
28:17
哎,你看它就没了啊,进到主模块之前它就没了啊,然后我们再来一次啊,你看现在是这个上面是NTDR的DR啊,我们运行啊,它就没了啊,是这样的,那想让它停下来呢,在选项啊,选项里有一个异常啊,不是异常去了那个,呃,事件啊,事件这有个TLS回调函数,看到了吗?这个位置啊,然后我们把它勾选上,然后点击保存,保存之后呢,我们再运行啊,在这个DR,你看到DR这了吧,然后呢,我们直接运行啊,运行之后它不会直接进入到main函数,那而是停到哪,停到我们这个t ls call back这儿啊,也就是说呢,停到我们的这个回调函数这,然后我们直接F7跟进去啊,如果说啊,我们可以看到这里有一个这个反调式的函数啊,或者说把它给改掉啊,这种都可以啊,就可以干什么呢?就可以直接啊把这个反调式去掉了,但是如果说你对这个TRS不是特别熟,而且也不知道有TS这个东西啊,那你直接一运行就到什么,就到主函数那了啊,然后呢,但是主函数之前它会执行这一段代码,就把你这个东西给干嘛给干掉了啊,没有这个机会执行你的微函数里的。
29:18
代码啊会比较尴尬,好,那这个呢,就是咱们今天啊要讲的这个两种方式啊,一种方式呢,是基我们的实时调试器做表的,一种是基于我们的TRS回调函数的啊有没有什么问题,如果没有问题的话呢,我们就进行下一步啊,有没关注的点点关注啊,每周六周日晚上都有这个直播。
我来说两句