欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]常见反调试手段及其规避方法(二)-检测进程名

[原创]常见反调试手段及其规避方法(二)-检测进程名

所谓检测进程名,指软件会获取所有当前正在运行的进程的名字,初步筛选出可疑进程,接着配合其他手段确认可疑进程是否真的是调试器的进程,如果是就将它关闭。

调试器:OllyDbg

环境:win7 64位真机


首先配置OD:在主界面点击选项-调试选项-异常


忽略所有异常,如图示。

来到“ 安全 ”选项卡-勾上:前三个和允许单步步入到未知命令,点确定。如下图


载入后,ctrl+n打开函数列表,发现很多很多函数,我们找到GetProcAddress,使用MSDN搜索,可知是获取另一个函数的地址。如果函数列表里没有可以的函数,说明他被隐藏,就是通过这个函数获取隐藏函数的地址的。


从MSDN上查阅函数的功能。百度百科上的内容可能不太准确。

翻译为:“从特定的动态链接库文件(DLL)中抽取出输出函数或者变量的地址”

什么意思呢?比如,函数列表里没有MessageBoxA,使用bp MessageBoxA是无法下段的。因为系统找不到。除非你用GetProcAddress获取这个函数的地址才能下断。

我们在GetProcAddress段首下断,观察堆栈窗口,hModule=0400000,ProcNameOr=”_CPPdebugHook


这个是该函数的 基址以及该函数的名字,当ctrl+f9后才能获取真正的地址。地址会返回给eax,注意95%的函数都是返回给eax。(还记得前面讲到的条件记录断点吗?这里留一个小作业给大家:用条件记录断点记录GetProcAddress函数的ProcNameOriginal参数)

知道函数的名字,还知道了他的首地址,就能在我们感兴趣的隐藏函数那下断了 。

一直f9,在堆栈窗口找可疑函数,如果你不知道是啥函数,就用MSDN查找。这是每一个初学者必须经过的过程。

F9,直到EnumProcess获取当前进程列表里边所有的进程的PID(如下图),就是任务管理器里所有进程的PID,ctrl+f9后直接bp eax,因为该地址在eax里面。这时记住要到B窗口里注释一下函数名称,不然以后肯定忘。


PID就是系统分配给当前每一个正在运行的进程的编号或者叫标识符。只要这个进程还存在,不被关闭,那么它的PID就不会变。当他再次打开以后,会获得一个新的编号,新的PID,虽然程序还是那个程序。任务管理器里的PID里是十进制数,2668(抱歉这里图上没有显示出来),那么是十六进制.0xA6C

我们还对EnumPeocessMOdules感兴趣,获得指定进程中所有模块的句柄。也下段,加注释。

我们对GetModuleBaseName感兴趣,通过进程句柄,进而获取进程名字,也下段,也加注释。

然后会执行到EnumProcess这里,断在段首时,ESP指向的一定是返回地址,ESP+4一定是函数的第一参数,这里的ESP+4是一个堆栈地址,我们在数据窗口跟随这个堆栈地址,这里就是存放进程列表的PID的,以这个地址为开头存储,每四字节存储一个PID。我们找到到 6C 0A 00 00,就是A6C,这里是PID为2668的OD调试器的PID。然后就选中这四字节,设置一个内存访问断点,既然我们获取了这个PID,我看看谁在获取这个值,接下来又执行了什么。

稍等一会儿,不要连续按,让子弹飞一会。

来到 OpenProcess ,我们来观察堆栈:

ProcessID=A6C     显然程序动了这块数据,把它提取出来压入堆栈了

Inheritable=FALSE

Access:VM_READ|QUERY_INFORMATION

来看看OpenProecess能干嘛:


翻译:“打开一个已经存在的本地进程”。

如果一个程序获取了另一个程序的句柄,,那他就可以操作另一个程序,比如关闭。比如外挂可以操作游戏。

这个函数的作用是获取当前PID的句柄,会把句柄返回到EAX中,请看MSDN中关于该函数返回值的陈述:


翻译为,“如果函数成功运行,返回值就是一个特定进程的句柄,如果函数执行失败,返回值为空。使用GetLastError函数获取扩展错误信息”

执行完后EAX是88,注意是十六进制数。

F9,执行EnumProcessModules,这个函数的作用是通过句柄,来获取这个进程的基址。断在在段首时我们看到ESP的下一行,就是第一参数,是00000088,0x88正是OD的句柄。

ctrl+f9,看堆栈,第一行是返回地址,第二行是我们的句柄88,这是OD的句柄。第三行是一个堆栈地址,这个地址在数据窗口跟随后,就是该函数的基址了。

然后F9,就是GetModuleBaseNameA,这个就是通过句柄来获取对应进程的名字了。就是任务管理器里的映像名称,第一列。再执行这个函数,ctrl+f9后,堆栈第一行是返回地址,第二行是88句柄,第三行是4000000这是基址,这两个参数刚刚被获取。第四行就是进程的名称了Ollydbg.exe。看来我们获取了OD的名字了

返回程序领空后,来到CloseHandle这里了

hObject=000088

CloseHNDLE

就是关闭句柄为88的进程,这就是要关闭OD的节奏吗?

来到H窗口,发现的确没有0x88这个句柄了。

继续F8,来到下一个函数,进入以后发现这里是在比较字符串。显然是在根据这个进程的其他特征在确认是不是调试器本身。

确认过眼神,是想干掉的人。OD已经暴露了,接着程序调用OpenProcess,根据PID获取其句柄( 因为它刚把句柄关了)。

Call <JMP.&kernal32.OpenProcess>

Mov [ebp-24],eax                                          把获取到的句柄给出去

Cmp [ebp-24],0                                             看看这个PID对应的句柄是不是为0

Je short 00401e0f                                         句柄显然不是0,不跳出去

接着就开始执行TerminateProcess了,这个句柄作为参数传入,将调试器进程关闭。

Push 0                                 ExitCode=0

Pusn [ebp-24]                      hProcess

Call TerminateProcess        TerminateProcess



总结:

因为有的函数被隐藏,或在函数列表里未找到可疑函数,所以利用getprocaddress捕捉它是否间接调用其他隐藏函数,它获取了几个关键函数

EnumProcess

EnumProcessModule

GetmodulebasenameA

这三个函数EnumProcess获取所有进程PID

接着调用openprocess获取对应PID的句柄

利用EnumProcessModule利用句柄获取该函数模块的基址

再调用GetmodulebasenameA获取当前符合两参数的模块名称(就是进程名)

获取完成了就立即关闭这个句柄,不再占用资源

将进程名与指定字符串比较。

如果相等,利用openprocess重新获取句柄,调用结束进程函数

如果不等,由于之前关闭了句柄,所以不会造成无用句柄的大量堆积

以上就是检测进程名的完整过程

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功