导入
在上篇教程中我们初步实现了对逃跑吧少年非法进程检测的处理,现在让我们回忆一下。
snake_pc_helper.dll+117A8E - C7 45 90 00000000 - mov [ebp-70],00000000 { 0 }
snake_pc_helper.dll+117A95 - C7 45 84 01000000 - mov [ebp-7C],00000001 { 1 }
snake_pc_helper.dll+117A9C - C7 85 78FFFFFF 00000000 - mov [ebp-00000088],00000000 { 0 }
snake_pc_helper.dll+117AA6 - C7 85 6CFFFFFF FCFF0000 - mov [ebp-00000094],0000FFFC { 65532 }
snake_pc_helper.dll+117AB0 - EB 0F - jmp snake_pc_helper.dll+117AC1
snake_pc_helper.dll+117AB2 - 8B 85 6CFFFFFF - mov eax,[ebp-00000094]
snake_pc_helper.dll+117AB8 - 83 E8 04 - sub eax,04 { 4 }
snake_pc_helper.dll+117ABB - 89 85 6CFFFFFF - mov [ebp-00000094],eax
snake_pc_helper.dll+117AC1 - 83 BD 6CFFFFFF 04 - cmp dword ptr [ebp-00000094],04 { 4 }
snake_pc_helper.dll+117AC8 - 0F86 59060000 - jbe snake_pc_helper.dll+118127//这里就是我们在上篇教程中修改的地方
snake_pc_helper.dll+117ACE - 68 2838D86F - push snake_pc_helper.dll+363828 { (221) }
snake_pc_helper.dll+117AD3 - E8 E80A0000 - call snake_pc_helper.dll+1185C0
snake_pc_helper.dll+117AD8 - 83 C4 04 - add esp,04 { 4 }
snake_pc_helper.dll+117ADB - 8B F4 - mov esi,esp
snake_pc_helper.dll+117ADD - 8B 85 6CFFFFFF - mov eax,[ebp-00000094]
snake_pc_helper.dll+117AE3 - 50 - push eax
snake_pc_helper.dll+117AE4 - 6A 00 - push 00 { 0 }
snake_pc_helper.dll+117AE6 - 68 FFFF1F00 - push 001FFFFF { (0) }
snake_pc_helper.dll+117AEB - FF 15 CCA8D86F - call dword ptr [snake_pc_helper.dll+36A8CC] { ->kernel32.OpenProcess }
[为了跳过下面的OpenProcess(打开进程),我们将snake_pc_helper.dll+117AC8 - 0F86 59060000 - jbe snake_pc_helper.dll+118127
修改为了snake_pc_helper.dll+117AC8 - E9 5A060000 - jmp snake_pc_helper.dll+118127
(后面自动补充的NOP这里忽略),按照上篇教程中猜想的进程检测流程我们只要阻止它去打开进程,那么也就实现了干掉这个非法进程检测。
但是实际上呢?其实在上篇教程结尾也稍微提到了,为了测试效果萌新我打开了一个易语言程序游戏的确没有提示检测到“外挂风险”,但是就在我们准备撒花庆祝胜利的时候游戏突然闪退了!
那么到底是什么地方出了问题呢?别急请听萌新我一一道来。
这里我们先来重新分析一下代码 看看能不能解决闪退的问题(什么?那你前面这么多废话是为了什么?上篇教程是骗评分的吗?)
填坑——代码分析 绕过闪退
咳咳,言归正传。其实这个闪退是上篇教程中我特意触发的(为了什么?不触发下我这篇教程怎么写 #^.^#)
于是我又复制了下上面的代码块(刚刚学会怎么用代码块 好兴奋(p≧w≦q)) 不过当然是有必要的啦~
snake_pc_helper.dll+117A8E - C7 45 90 00000000 - mov [ebp-70],00000000 { 0 }
snake_pc_helper.dll+117A95 - C7 45 84 01000000 - mov [ebp-7C],00000001 { 1 }
snake_pc_helper.dll+117A9C - C7 85 78FFFFFF 00000000 - mov [ebp-00000088],00000000 { 0 }
snake_pc_helper.dll+117AA6 - C7 85 6CFFFFFF FCFF0000 - mov [ebp-00000094],0000FFFC { 65532 } //将65532(10)赋值给[ebp-00000094]
snake_pc_helper.dll+117AB0 - EB 0F - jmp snake_pc_helper.dll+117AC1
snake_pc_helper.dll+117AB2 - 8B 85 6CFFFFFF - mov eax,[ebp-00000094] //将[ebp-00000094]中的值赋值给eax 下面会有跳转重新跳回这里进行循环
snake_pc_helper.dll+117AB8 - 83 E8 04 - sub eax,04 { 4 } //eax减去4
snake_pc_helper.dll+117ABB - 89 85 6CFFFFFF - mov [ebp-00000094],eax //再将eax的值重新赋值给[ebp-00000094]
snake_pc_helper.dll+117AC1 - 83 BD 6CFFFFFF 04 - cmp dword ptr [ebp-00000094],04 { 4 } //比较[ebp-00000094]和4的大小
snake_pc_helper.dll+117AC8 - 0F86 59060000 - jbe snake_pc_helper.dll+118127 //如果小于等于4那么就跳转到snake_pc_helper.dll+118127这个地址 即跳过下面的OpenProcess
snake_pc_helper.dll+117ACE - 68 2838D86F - push snake_pc_helper.dll+363828 { (221) }
snake_pc_helper.dll+117AD3 - E8 E80A0000 - call snake_pc_helper.dll+1185C0
snake_pc_helper.dll+117AD8 - 83 C4 04 - add esp,04 { 4 }
snake_pc_helper.dll+117ADB - 8B F4 - mov esi,esp
snake_pc_helper.dll+117ADD - 8B 85 6CFFFFFF - mov eax,[ebp-00000094] //将[ebp-00000094]赋值给eax
snake_pc_helper.dll+117AE3 - 50 - push eax //传入OpenProcess函数的第三个参数 即进程PID
snake_pc_helper.dll+117AE4 - 6A 00 - push 00 { 0 }
snake_pc_helper.dll+117AE6 - 68 FFFF1F00 - push 001FFFFF { (0) }
snake_pc_helper.dll+117AEB - FF 15 CCA8D86F - call dword ptr [snake_pc_helper.dll+36A8CC] { ->kernel32.OpenProcess } //根据传入的参数打开对应进程PID,如果成功则返回被打开进程的句柄 如果失败则返回0
snake_pc_helper.dll+117AF1 - 3B F4 - cmp esi,esp
snake_pc_helper.dll+117AF3 - E8 17ABFEFF - call snake_pc_helper.exit_game+893
snake_pc_helper.dll+117AF8 - 89 85 60FFFFFF - mov [ebp-000000A0],eax //将eax赋值给[ebp-000000A0] 即将用OpenProcess函数获取的进程句柄赋值给[ebp-000000A0]
snake_pc_helper.dll+117AFE - 83 BD 60FFFFFF 00 - cmp dword ptr [ebp-000000A0],00 { 0 } //对比[ebp-000000A0]和0 即判断OpenProcess是否成功
snake_pc_helper.dll+117B05 - 75 73 - jne snake_pc_helper.dll+117B7A //如果[ebp-000000A0]的值不等于0 即成功获取到了进程句柄 就跳转到snake_pc_helper.dll+117B7A这个地址 如果[ebp-000000A0]的值等于0 即获取进程句柄失败则继续向下运行
snake_pc_helper.dll+117B07 - 8B F4 - mov esi,esp
snake_pc_helper.dll+117B09 - FF 15 04A9686D - call dword ptr [snake_pc_helper.dll+36A904] { ->kernel32.GetLastError } //调用GetLastError函数查询OpenProcess失败的原因
snake_pc_helper.dll+117B0F - 3B F4 - cmp esi,esp
snake_pc_helper.dll+117B11 - E8 F9AAFEFF - call snake_pc_helper.exit_game+893 //调用这个call并且返回eax
snake_pc_helper.dll+117B16 - 3D E6030000 - cmp eax,000003E6 { 998 } //对比eax和998(10) 这里可以自行百度GetLastError返回值含义
snake_pc_helper.dll+117B1B - 75 58 - jne snake_pc_helper.dll+117B75 //如果真的相等则跳转实现
snake_pc_helper.dll+117B1D - 8B 85 6CFFFFFF - mov eax,[ebp-00000094]
snake_pc_helper.dll+117B23 - 50 - push eax
snake_pc_helper.dll+117B24 - 68 9878626D - push snake_pc_helper.dll+307898 { (-908932673) }
snake_pc_helper.dll+117B29 - 8D 8D 38FFFFFF - lea ecx,[ebp-000000C8]
snake_pc_helper.dll+117B2F - 51 - push ecx
snake_pc_helper.dll+117B30 - E8 544AFEFF - call snake_pc_helper.notify_hall_game_status_changed+61D
snake_pc_helper.dll+117B35 - 83 C4 0C - add esp,0C { 12 }
snake_pc_helper.dll+117B38 - 8D 85 38FFFFFF - lea eax,[ebp-000000C8]
snake_pc_helper.dll+117B3E - 50 - push eax
snake_pc_helper.dll+117B3F - 8B 4D 18 - mov ecx,[ebp+18]
snake_pc_helper.dll+117B42 - E8 8336FEFF - call snake_pc_helper.normal_exit_game+3E8
snake_pc_helper.dll+117B47 - 68 7078626D - push snake_pc_helper.dll+307870 { ("00000000000000000000000000000000") }
snake_pc_helper.dll+117B4C - 8B 4D 1C - mov ecx,[ebp+1C]
snake_pc_helper.dll+117B4F - E8 7636FEFF - call snake_pc_helper.normal_exit_game+3E8
snake_pc_helper.dll+117B54 - C6 85 EFFAFFFF 01 - mov byte ptr [ebp-00000511],01 { 1 }
snake_pc_helper.dll+117B5B - C7 45 FC FFFFFFFF - mov [ebp-04],FFFFFFFF { -1 }
snake_pc_helper.dll+117B62 - 8D 4D 08 - lea ecx,[ebp+08]
snake_pc_helper.dll+117B65 - E8 0DCFFEFF - call snake_pc_helper.process_protect+938
snake_pc_helper.dll+117B6A - 8A 85 EFFAFFFF - mov al,[ebp-00000511]
snake_pc_helper.dll+117B70 - E9 31060000 - jmp snake_pc_helper.dll+1181A6
snake_pc_helper.dll+117B75 - E9 38FFFFFF - jmp snake_pc_helper.dll+117AB2 //这里就是上面jne跳转实现后到的地方 无条件跳转到snake_pc_helper.dll+117AB2(自己翻上去看看咯)
好的....萌新通过各种途径,例如百度 向大佬请教等方式终于稍微分析了下上面的代码 相信大家应该可以理解了吧 上面的代码有一个循环[注:整个循环并没有完整 为了节省空间只是把关键的复制了过来]
(即65532(10)减4 减4 减4.......)
那么这些在干什么呢?回忆下上篇教程中说的OpenProcess函数原型
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId// 进程标示符
所以说上面的代码其实就是从65532这个PID开始打开进程 然后减4后尝试打开下一个进程 也就是说是一个遍历进程的神奇操作~~~ 那么我们现在明白了昨天我们改的jbe
其实就是无论进程PID等于多少都直接跳过OpenProcess(对啊 逻辑没错啊 那为什么会闪退呢?????敲你)
别急别急,我告诉你怎么不闪退可以了吧。先别急着打萌新!!
既然直接跳过下面的OpenProcess会闪退,那么我们就按他正常的逻辑来不去跳过OpenProcess试试
通过上面的分析我们可以知道打开进程必须要有进程PID 来看下面的代码 我们可以很清楚的看见进程PID是mov eax,[ebp-00000094]
赋值给eax
的
snake_pc_helper.dll+117ADD - 8B 85 6CFFFFFF - mov eax,[ebp-00000094] //将[ebp-00000094]赋值给eax
snake_pc_helper.dll+117AE3 - 50 - push eax //传入OpenProcess函数的第三个参数 即进程PID
snake_pc_helper.dll+117AE4 - 6A 00 - push 00 { 0 }
snake_pc_helper.dll+117AE6 - 68 FFFF1F00 - push 001FFFFF { (0) }
snake_pc_helper.dll+117AEB - FF 15 CCA8D86F - call dword ptr [snake_pc_helper.dll+36A8CC] { ->kernel32.OpenProcess } //根据传入的参数打开对应进程PID,如果成功则返回被打开进程的句柄 如果失败则返回0
那么我们在遵循他正常的跳转逻辑的前提下又想保证不被检测到“外挂风险”就可以通过修改PID入手了
思路1:
nop
掉mov eax,[ebp-00000094]
这句代码,让它不能赋值正确的PID。
思路2:
直接修改push eax
更改它传入的参数,即无论你前面怎么计算要打开的PID都与我无关 我就是要随便填一个数进去让你去打开比如 push edx
完美!经过实践 事实证明上面两种思路都可以完美的绕过闪退 对 就是绕过 注意用词!
(什么?你觉得这种方法太低端了不够体现出与众不同?那么还有其他方法吗?)
(我敲!这么多要求自己想去!)
咳咳,这里其实只是提供一种思路而已,至于还有没有其他方法,我可以很明确的告诉你 有!比如说上篇教程中就有人回复了可不可以Hook OpenProcess
这个函数来过检测 可以的!已经有大佬实践过了
可以通过Hook修改OpenProcess
的返回值来过检测 比如正常情况下你的“神仙工具”(不懂?就是外挂啦~)通过OpenProcess
函数后就会返回进程句柄 你可以Hook 修改它 这样自然就检测不到了。
那啥 条条大路通罗马 这里也同样适用
反思
1.为什么修改跳转就会闪退而修改传入的PID就不会闪退呢?
就像我们写程序防破解一样处处检测处处暗桩,一个游戏反作弊也可能有多处检测。直接修改跳转的话说不定人家在后面再验证下(有兴趣的朋友可以研究下为什么 看看是不是后面有其他检测 这里萌新我因为能力有限就没研究了) 比如PID为65532时你也跳转了 那么可能就有问题了所以执行闪退
2.为什么要特意触发一次闪退呢?
因为这其实是萌新我自己曾经踩过的一次坑,在上篇教程中完美的复现了一次,其实呢是想告诉大家一个道理 不要轻易放弃,稍微转变一点思路,或许就是柳暗花明又一村
继续挖坑
如果你偏偏就是喜欢改跳转,
如果你硬是不遵循游戏逻辑,
难道,
就只能面对游戏无情闪退吗?
错!