TLS回调函数也可以实现反调试-实验(难度:高级)
2022-12-20 10:22:44 Author: 寰宇卫士(查看原文) 阅读量:16 收藏

实验操作手册

####请先下载实验文件

  • 实验环境

    • 操作机: Windows XP

  • 实验工具:

ToolsPath
IDA ProC:\Tools\Ida61
OllyICEC:\Tools\OllyICE
PEiDC:\Tools\PEid
Spy++C:\Tools\spy++
  • 实验文件:

    • Lab16-02.exe

请访问http://172.16.4.2/46c6f0b7下载实验文件

提示

  • 在本次实验中,请注意实验工具、实验文件存放路径,不同的文件路径可能会出现不一样的实验结果。

  • 在实验环境中无法连接互联网,请使用您本地的网络环境。

这里我们结合实验问题来分析这次的恶意程序

###解答第一题

####在命令行中运行Lab16-02.exe时,会发生什么?

我们打开命令提示符(cmd.exe),尝试运行这次的恶意程序:

可见,程序输出了一行字符串,要求我们输入4个字符的密码。

###解答第二题

####当使用猜测的命令参数运行Lab16-02.exe时,会发生什么?

我们可以尝试一下,随便输入4个字符的密码:

可见,如果我们输入的密码不正确,程序给我们回应的是“Incorrect password,Try again”

###解答第三题

####命令行密码是什么?密码是byrr

###解答第四题

####使用IDA Pro加载Lab16-02.exe。在main函数的何处可以找到strncmp函数

由这问题我们可以知道,程序应该使用的是strncmp函数对密码进行匹配的。我们可以利用IDA Pro来分析一下这个程序:

可见,程序在0x0040123A的位置调用了strncmp函数

###解答第五题

####在默认设置下,将这个恶意代码加载到OllyDbg中会发生什么?

我们可以使用OD载入这个程序,并且尝试在0x0040123A的位置下一个断点。但是由于我们所使用的OD自身具备很强的反调试能力,因此这里我们使用原版的OD来实验一下。将这次的程序载入原版的英文OD,可以发现程序直接停止了,来到了retn的位置:

###解答第六题

####Lab16-02.exe中PE结构的独特之处是什么?

这里我们使用PEiD来查看一下这个程序的区段表:

可以发现,这里有一个.tls的区段。通常情况下,可执行程序是不会使用.tls区段的,如果我们在分析某一个程序的时候发现了这个区段,那么这也就说明,该程序很可能使用了反调试技术。.tls的区段中包含有TLS回调函数,该函数可以在程序入口点处的代码执行之前,得到执行。那么我们现在可以怀疑,之所以原版的OD载入程序后就直接停止了,很可能就是在执行入口代码之前,执行了TLS回调函数。

###解答第七题

####回调(callback)发生在哪些位置?(提示:在IDA Pro中使用Ctrl+E组合键。)

在IDA中,我们利用快捷键Ctrl+E,就可以查看这个程序的每一个入口点的情况:

可以看到,TlsCallback就是回调函数的位置,它的地址为0x00401060

###解答第八题

####恶意代码使用哪一种反调试技术使它在调试器中立即终止运行?如何避免这种检查?

在IDA中来到0x00401060的位置进行分析:

这个TLS回调函数一开始,就将arg_4和1进行比较,来确定TLS回调函数是否作为启动过程的一个结果被调用。也就是说,这种反调试技术仅仅在程序启动过程中被执行。可以看到,程序调用了FindWindowA这个函数,用于查找当前所打开的窗口中,是否有类名为“OLLYDBG”的这个窗口(注意这里检查的是窗口的类名,而不是窗口标题栏的名称)。如果这个窗口存在,那么返回值就是该窗口的句柄值,它是一个非零值。这也就解释了,为什么当我们使用英文原版OD载入程序时,会直接来到retn的位置。就是由于在执行入口点代码之前,执行了TLS回调函数,检测到了OD已经打开,所以直接调用了exit函数。可以使用spy++查看窗口的类名。比如我们所使用的原版英文OD的类名如下:

其类名为“OLLYDBG”,所以这次的实验程序所采用的反调试技术能够很好地针对我们的OD。再看一下我们平时所采用的加强版的OD:

可见其类名为“1212121”,这样就能够很好地对抗采用了FindWindow这个函数的反调试技术了。为了对抗这种反调试技术,我们可以使用OD的PhantOm插件。由于我们当前使用的OD是原版的,它是不包含有插件的,我们可以手动来进行添加。首先在我们当前的OD目录中新建一个名为“plugin”的文件夹,将“PhantOm”插件拷贝过来。之后修改ollydbg.ini这个文件,将“Plugin path”的内容修改为我们所创建的插件文件夹的路径。然后利用OD载入实验程序,来到PhantOm的选项界面,勾选“load driver”以及“hide OllyDbg windows”即可。

###解答第九题

####当你禁用反调试技术后,你在调试器中看到的命令行密码是什么?

现在我们就可以用原版的OD来调试这次的实验程序了。打开OD,选择“File”中的“Open”,选择这次的实验文件,并且加上四个字符的“密码”,比如“1234”,再点击打开:

在strncmp的位置,也就是0x0040123A的位置下一个断点,并执行过来。通过栈空间的情况可以知道,程序似乎在比较我们所输入的“1234”以及“[email protected]”这两个字符串前4个字节的内容。那么也就可以推测,这个程序的密码可能就是“bzqr”

###解答第十题

####调试器中找到的密码在命令行中运行有效吗?

可以尝试一下,在命令行中尝试使用“bzqr”这个密码:


可见,这里依旧显示密码不正确,说明我们还需要进一步的研究。

###解答第十一题

####哪种反调试技术为调试器和命令行设置不同的密码?如何防御它们?

这里我们首先在IDA中对strncmp的第二个参数重新设置一下,方便接下来的分析。首先双击进入这个参数:

由于程序只验证前四个字符,所以这里我们可以将其转化为4个字节的数组。在“Str2”上单击鼠标右键,选择“Array”,并且设置4个字符的大小,再单击OK。之后给它改个名字,比如“encoded_password”(注意设置名称的长度)。接下来,可以看到在strncmp函数调用之前,有一个CreateThread的函数调用。为了查看这个函数调用所创建的线程代码,我们可以双击查看一下它的lpStartAddress参数情况。可以发现这个线程函数似乎是一个解密的过程,因为它包含对encoded_password数组中的内容的多种运算操作。这里我们不必理会解密的原理,即便是利用IDA的F5功能,也不容易分析出其解密方式,这里我们只关注几个重要的地方。进一步检查这个解密的过程,可以发现它使用了BeingDebugged这个属性:

在0x0040112B的位置,程序将PEB的地址赋给了ebx,接着在0x0040118B的位置,将BeingDebugged属性保存在了bl寄存器中。之后再用bl与encoded_password进行运算。为了对抗使用了BeingDebugged属性的反调试技术,我们需要保证它的值为0。上节课讲过应对的方法,这次我选择使用PhantOm插件。之后进入OD,勾选“PhantOm”插件中的“hide form PEB”。再载入程序,执行到0x0040123A的位置,查看当前栈空间的情况。可见此时的密码已经变成了“bzrr”。但是如果我们在命令行中使用这个密码,那么又会出现密码错误的情况。

我们再回到IDA中的解密函数:

程序在0x0040109B的位置将byte_40A968赋给了bl,并在0x00401111的位置,将bl与encoded_password进行运算。双击进入byte_40A968查看,它的初始值为0。对其进行交叉引用:

可见它的值在sub_401020处被修改。来到这个位置进行分析:

可以看到,程序首先在0x0040102F的位置调用了SetLastError函数,用于将错误码设置为0x3039。接下来在0x0040103A处调用了OutputDebugStringA这个函数,它可以向调试器发送一个字符串,让调试器打印显示(本实验中所打印的是“b”)。之后使用GetLastError,并比较当前的错误码是否还是0x3039。这也就说明,假设我们是在调试器中运行这个程序,那么错误码就不会改变,依旧是0x3039。并且下面将byte_40A968的值赋给cl,再将cl的值加1,之后再赋给byte_40A968,也就是实现了byte_40A968自增的操作。如果是在命令行中运行此程序,错误码就会改变,那么byte_40A968就不会自增。这也就解释了为什么在命令行中输入“bzrr”依旧会得出不正确的结果。

由于这里我们是希望无论在什么情况下,cl都是自增1的。那么为了对抗这种验证方式,我们可以将0x00401051处的语句用nop代替,这里使用OD修改即可。然后用OD载入修改后的程序,再次来到0x0040123A的位置查看密码,那么密码就是“byrr”。在命令行中测试新修改的文件与密码:

可见,此时验证就得到通过了。接下来继续研究TLS函数

当前这个流程是在利用FindWindow函数,没有检测到OD的存在时,所走的流程。这里一开始就将arg_4与2进行比较,之前曾经与1进行比较,说明在进程启动的时候,调用TLS函数。而这里的2表示一个线程启动时,调用TLS函数。如果有3的话,则说明表示进程终止时调用。因此,当CreateThread运行,并使得OutputDebugStringA运行时,TLS回调函数会被调用。

原文来自「鸢尾楚楚」|侵删

中电运行是专业专注培养能源企业IT工匠和提供IT整体解决方案的服务商,也是能源互联网安全专家。我们每天都会分享各种IT相关内容,如果您有任何关于IT疑问,欢迎给我们留言

小白必读!寰宇卫士手把手教你栈溢出(上)

手把手教你栈溢出(中)

手把手教你栈溢出(下)

《信息安全知识》之法律关键常识汇总

CTF经验分享|带你入门带你飞!


文章来源: http://mp.weixin.qq.com/s?__biz=MzIwMzU0NDY5OA==&mid=2247495947&idx=1&sn=70611fd7e0567425bbe875897aa7655b&chksm=96cf701ea1b8f908ea5c5d70a180348556221c65d24a9c833d597f1ba6232c0e1b13df9e4ece#rd
如有侵权请联系:admin#unsafe.sh