目标程序
程序下载:DaXXoR
解压密码:9unk
程序简介:本程序运行之前会检测杀死 x32dbg 进程。
任务目标:绕过反调试机制,正确运行程序。
进程名检测原理
先打开 DaXXoR(32).ExE,然后再运行 x64dbg,发现 x64dbg 马上就退出了。如果我们用 x64dbg 加载该 CrackMe 然后运行起来,会发生两者一起退出了。
面对这种情况,我们先用 x64dbg 加载程序到主模块。
“Ctrl+N”,先看一下这个程序使用了哪些 API。
从上图中可以看到很多 API 函数,但都不是用于检测进程名的,可能这些重要的 API 函数被隐藏起来了,没出现该列表中。显然如果程序不直接导入某些 API 的话,会使用 GetProAddress 这个 API 函数来获取这些 API 函数的地址进行间接调用。
使用 GetProAddress 函数加载的一些 API 函数并不会出现该 API 函数列表中,我们给 GetProAddress 设置一个断点。
运行起来,此时程序断在 GetProAddress API 处。当前获取的函数是 _CPPdebugHook,该函数与检测进程名没有关系,继续运行。
我们继续按 “F9” 运行程序直到获取的 API 是与检测进程名相关为止,这里带获取的 API 函数是 EnumProcesses。
这里使用 “Ctrl+F9” 执行到返回,这个时候 eax 寄存器中保存的就是 EnumProcesses 这个 API 函数的地址。
我们右键 “EAX”—>在反汇编中转到,定位到这个 API 之后,并设置断点。
继续按照上面的步骤操作,继续按 “F9” 看看程序还用到了哪些 API。
这里是获取枚举进程模块函数地址,我们还是执行到返回,接着给使用命令 “bp eax” 把 EAX 中保存的地址设置断点。
这里另外一个可以的 API 函数 GetModuleBaseNameA,我们跟之前一样给函数设置断点。
然后继续运行 “F9” 运行程序,此时断在了 EnumProcesses 函数入口处。
我们看一下 EnumProcesses 函数的参数信息
EnumProcesses 函数就是获取所有进程的 pid,并给它设置一个数组
- lpidProcess:表示这个数组的指针
- cb:表示数组的大小
- lpcbNeeded:表示数组的数据
也就是说我们实际的所有进程 pid 数据都存在第 3 个(lpcbNeeded)参数中。
我们先计算一下 pid 的十六进制。
接下来我们转到第 3 个参数位置处
我们执行到返回,把当前的 pid 数据加载到数组中。
这里的 pid 数据太多了,为了快速查找到位置,我们对内存数据部分进行搜索,快捷键 “Ctrl+B”
双击搜索的字符串,x64dbg 自动跳转到内存数据窗口。
“F9” 继续运行程序,可以看到此时断在 GetModuleBaseNameA
我们看一下这个 API 函数的参数和返回值。
该函数是获取指定进程模块的名称,lpBaseName 这个参数是用来保存模块名称
我们运行到返回看一下获取到的参数和返回值
1D0 就是 ECAgent.exe 的句柄
我们继续按 “F9” 运行,此时又断在了 GetModuleBaseNameA
继续执行到返回,可以看到这一次获取的是 SGTool.exe 模块
我们继续按上面的操作进行,直到获取到 x32dbg.exe 模块
可以看到 x32dbg.exe 模块的句柄是 1CC
继续单步运行程序,可以看到这里用了 CloseHandle 函数。
CloseHandle 函数是用来关闭指定句柄
我们步入看一下 CloseHandle 函数的返回值
我们继续单步执行,这里指向了两个进程名
继续步入查看这个子程序的功能
从上面的图片可以看出这是将获取的进程名转换成大写
继续单步执行,可以看到这里把要比较的进程名弹出,很明显下一步要开始进行比较
继续步入查看子程序,获取两个进程名,初始化寄存器
判断两个进程的第一个字母是否相等,不相等就跳出循环
判断获取的进程名是否为空,值为空就跳出循环
判断第2、3、4个字符串,最后再继续循环
比较结束后,继续单步执行到 OpenProcess 函数
注意:这里使用的是 sub 指令,也就是进程名相同 eax 的返回值就是 0
继续单步执行,如果 eax 不为 0 就跳出关闭进程的子程序
我们看到下面有一个 OpenProcess 函数
我们执行到返回,可以看到此时 x64dbg 的句柄是 1C4
把旧的句柄替换成新的句柄
下面使用 TerminateProcess 杀死进程
总结一下整个检测过程: EnumProcesses(获取所有进程的 pid)—> GetModuleBaseNameA(获取一个个进程名)—> CloseHandle(关闭获取的句柄) —> 判断进程名是不是 x32dbg.exe —> OpenProcess(打开 x32dbg.exe 进程并获得其句柄)—> TerminateProcess(杀死进程的句柄)
方法一(修改指令)
这里把关键跳转的命令(jne)改成(jmp)
程序运行时有异常,这里把内存空间设为异常忽略
再次运行程序,发现此时程序正常运行
方法二(修改程序名)
方法三(插件)
SharpOD 勾选 “Hide Process” 和 “Hook *ZwFunctions” 然后保存。
重启 x32dbg ,就可以调试运行程序了。
reference
WindowsAPI详解——TerminateProcess 终止|杀死其它进程
C++进阶—> CloseHandle详解及CloseHandle后线程未停
GetModuleBaseNameA function (psapi.h)
- 本文标题:x64dbg-反调试二
- 本文作者:9unk
- 创建时间:2021-01-02 21:26:28
- 本文链接:https://9unkk.github.io/2021/01/02/x64dbg-fan-diao-shi-er/
- 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!