各位老哥稳,到底怎样才可以设置出好记又不简单的密码啊?我头都快挠爆

制作自己的UCE彻底解决NP问题(软件名可自己改)任意版本NP存任你修改!  制作成功!(永久吸怪就在不远处)!把经验分享给大家,全英文的,金山词霸一个一个翻译吧,弄了个通宵实在痛苦!!为了方便大家偶牺牲很多饿,ppz的前辈门有好标标的LJ记得给我点(40几级的菜菜也用不了好东西)QQ: 为了陪老婆才玩的 555 - -B  本帖由kwonboa原创 转贴请保留以上信息 谢谢 做有素质的中国人
由于过程非常长和复杂,建议非无电脑基础的朋友不要浪费时间(其实会了也超级简单),我将分步为大家讲解安装! b下面说明下为什么要修改
修改函数变量是为了让NP不认识你这个新程序  修改软件名称LOGO什么的标志图片把他变成你自己的UCE程序吧  第一步:所需要的软件  1.CE5.4原码:
2.微软的DDK:
3.Delphi7地址自己在网上找,原发地址以不能下)  程序编译:(解压到CE原码文件夹)
第二步BK32.SYS(whatever.sys)制作 \ExW e~Za
1.解压CE原码到本地C盘
2.修改Driver.dat 记事本打开后修改(下面的whatever表示什么都可以 改成你要的个性名称)  CEDRIVER53 ----& Whatever1
DBKProcList53 ----& Whatever2
DBKThreadList53 ----&Whatever3
dbk32.sys ----& Whatever.sys
修改完毕保存关闭
3.进入DBKKernel目录  修改DBKDrvr.c文件
记事本打开改文件
搜索"//hideme(DriverObject)"  将前面的//去掉 保存关闭  修改sources.ce文件  同样记事本打开
将"TARGETNAME=DBK32"改为 "TARGETNAME=Whatever"(whatever为你刚刚的个性名称)
4.下面马上生成whatever.sys
先安装好DDK(过程略)
开始& 所有程序& Development Kits& Build Environments& Windows XP& Windows XP Free Build Environme
运行后键入代码:
CD C:\Cheat Engine Delphi\DBKKernel 回车  获得返回代码(无变化)
没事 接着输入:
得到C:\Cheat Engine Delphi\DBKKernel反馈路径
慢慢等吧 工作了 接下来就自动生成了您的whatever.sys
第三步:dpr文件的函数变量修改3a. 我们现在把dbk32目录中的文件"dbk32.dpr" 用Delphi7打开.
我们使用软件菜单 "VIEW" -"roject Manager" 会看到"dbk32.dll" 点旁边的+号打开分目录看到 "DBK32functions"打开它按下面修改
CEDRIVER52 &&& Whatever1 (这里的whatever不用我再解释了吧- -)
DBKProcList51 &&& Whatever2 (" ")  DBKThreadList51 &&& Whatever3 ("")
改好保存关闭 然后进入CE原码根目录 按F3搜索 包含下面变量(VQE OP OT NOP RPM WPM)的函数全部替换成您的WHATEVER4~10 详细请看下面
VQE ---& Whatever4
OP ---& Whatever5
OT ---& Whatever6  NOP ---& Whatever7  RPM ---& Whatever8
WPM ---& Whatever9
VAE ---& Whatever10
(友情提示下 我犯过的错 弄错文件全变LJ OP OT短的不能使用查好替换 因为里面代码有NOT 直接替换就变成"NWHATEVER6" 其实NOT不是变量是 是程序代码 不需要替换 没办法只能手动一个一个改OP变量)
好累啊!!!!!!!!!!!!!!!!大家记得回复我的帖子哦 谢谢了!~全部手动写不比复制  下面接着改文件(记住所有修改不只是改文件名 所有目录下的改文件内容中的也全部要做修改)
DBK32functions.pas &&& Whateverfunctions.pas ( 不想再说whatever什么意思 除非你是...保存到dbk32目录)
NewKernelHandler.pas &&& WhateverHandler.pas (保存到根目录) `
保存关闭所有  注意再提示下表忘了修改下面
dbk32.sys &&& Whatever.sys
dbk32.dll &&& Whatever.dll (下面一步生成)  用Delphi打开 Whatever.dpr(DBK32.DPR) 按Ctrl+F9. 生成上面的WHATEVER.DLL  如果发生错误请检查文件变量是否全部修改  文件CEHook.dpr 和hypermode.pas 改成Whatever54.(只能改whatever54)
现在用Delphi 打开CEHook.dpr(上面改名了)  Ctrl+F9生成文件  修改下面文件(修改包括文件名和所有文件内容)
newkernelhandler.pas &&& Whateverhandler  CeFuncProc .pas &&& Whatever56
CheatEngine &&& WhateverEngine (警告:cheatengine.bpg绝对不能修改 不然白做)
cheat engine &&& Whatever Engine
保存关闭  最后用Delphi打开 cheatengine.bpg 进行总的编译吧进入后按SHIT+F12选择CE主程序(MAIN什么的)进行编译 左修改参数LEFT为228(注意:这里不改看不到CE主程序)
下面就是最爽的时候了 哈哈 把所有的能改的地方全改了软件名字 版权什么的 你喜欢汉化就自己查中文意思改下标签的名字  最重要的修改:
"VIEW" -"roject Manager" 选中CHEATENGIN.EXE点OPTION什么的 里面有个  Versions Options
版本修改 里面都是CE什么什么的 全部改掉 为了就是NP不认识CE!~~~~~~~~~~~~~~能改多少改多少   最后就一键CTRL+F9生成您的自己的新软件 嘎嘎!~~~感觉一定不错!~~~不过别忘了 这里会发生很多错误 估计就是你函数没改全!~~仔细看文章 哪些改哪些 遇到没改的发生错误自动会停 马上改成我要你改的新名字就不会发生错误了!~最后搞定了 自动生成了您的新软件.EXE
因为原文是跟贴,而且不连续,所以现在把译文补全,总结成贴。  不当之处,还请斧正。  没有比这更简单的,相信我  嗨,各位。我决定做一个教程,因为当我想去破解但是没有UCE的时候我感觉自己多么“菜”,这个教程很长但是非常地详细而且非常地初级,这个教程非常值得一看。从法律的角度说,我没有这样说:“我没有鼓励破解,我简单地希望大家能够学习此教程”无论如何,回到CE的讨论,我们中的许多人已经读过一篇简单的教程,如Drkz from MPC, Vener88, or Rolling Dice(MPC论坛上的Drkz, Vener88,Rolling Dice),但是问题是…    Drkz: 它从来没起作用,我编译的时候总是遇到同样的错误      Vener88: 它用了740的文件,但是740已经被检测到了(740是NP的版本).      Rolling Dice: 这个教程我已经看熟,但它是好的教程却不是那么初级(不适合新手)。  当我学到这篇教程的时候我是幸运的,因为我有程序设计背景,不要误解我,我的意思是:假如你知道你在做什么,这将是一篇很好的教程。  这篇教程有点象Rolling Dice那篇,原因很简单,我正是认真地学习了他的那篇教程。  首先,一点点的忠告,我知道这是陈词滥调、但是  “龟兔赛跑乌龟胜了兔子”  这意味着,如果你要快速并且准确地做这件事情,抓紧你的时间检查好每一步,这总比快速地浏览完这篇教程然后犯错误好,那样知道你地错误的人就只有-_____- **  那么,我们开始  1.下载一些必要的软件
  -Actual Search and Replace  一个查找及替换软件    -CE Source (updated 5.24.06) CE的deiphi源代码。    -Delphi 7              Delphi 7 买光盘安装吧,很难下载到,也太大,1G左右。    -Windows DDK (Windows DDK (包含在 KMDF,核心模式驱动架构中)
    KMDF 下载:
2.创造DBK32.sys    2a.用记事本代开CE主目录里面的driver.dat ,做如下修改:      CEDRIVER53 && string1      DBKProclist53 && string2      DBKThreadList53 && string3      dbk32.sys && string.sys    2b. 用记事本打开DBKKernel文件夹下面的DBKDrvr.c,查找: hideme,跳过第一处,来到第    二处,你会看到这样的句子: //hideme (DriverObject). 然后将hideme前面的 // 去掉。    2C. 用记事本打开打开DBKKernel 文件夹下面的sources.ce,做如下修改:      TARGETNAME=DBK32 && TARGETNAME=string    2D. 现在编译 String.sys (也就是以前的DBK32.sys).
    把你的DBKKernel文件夹所在目录的地址复制下来(等会用)。    打开window DDK,从开始菜单&&程序里面打开(确定你已经安装了KMDF)      打开之后是一个CMD界面,输入 cd ××(××既你刚才复制的地址,现在粘贴到这里)      输入ce,确定      如果一切正常,你将会看到“files compiled. 1 Executable built”的字样,String.sys      也已经出现在你的CE主目录里面。  3. 替换已被检测字符  3a.用delphi 7(中文版) 打开dbk32文件夹下的dbk32.dpr。  查看&&工程管理器,然后展开dbk32.dll,双击DBK32functions打开它,做如下修改:    CEDRIVER52 && String1(跟CEDRIVER53是同一个东西)    DBKProcList51 && String2 (跟DBKProcList53是同一个)    DBKThreadList51 && String3 (跟DBKThreadList53是同一个)    都做完了么?然后保存,可以关掉delphi7了  然后打开文字替换工具(也就是Actual Search and Replace)    File& Settings & Editor,找到你的delphi 7目录的delphi运行文件,也就是delphi32.exe,    类似于"C:\Program Files\Borland\Delphi7\Bin\delphi32.exe" ,确定  点到 options 标签,确定"include subfolders"(包含子文件)已经被选上。
点到 Search and Replace标签,    在 "Masks" 里面,键入: newkernelhandler. DBK32functions. DBK32.dpr      在 "Path" 里面加入:CE主目录  然后把whole words 选上。  开始进行字符替换,在"to search"里填要替换的字符,在"to Replace or insert"填上要替换成的字符。  被替换和替换成的字符如下:  VQE && string4  OP &&  string5  OT &&  string6  RPM&& string7          WPM  ……(依次递推)          VAE            CreateRemoteAPC      ReadPhysicalMemory      WritePhysicalMemory      GetPhysicalAddress      GetPEProcess        GetPEThread        ProtectMe          UnprotectMe          IsValidHandle      GetCR4          GetCR3          SetCR3          GetSDT          GetSDTShadow        setAlternateDebugMethod  getAlternateDebugMethod    DebugProcess        StopDebugging        StopRegisterChange      RetrieveDebugData      GetThreadsProcessOffset  GetThreadListEntryOffset  GetDebugportOffset      GetProcessnameOffset    StartProcessWatch      WaitForProcessListData    GetProcessNameFromID    GetProcessNameFromPEProcess
GetIDTCurrentThread    GetIDTs          MakeWritable        GetLoadedState      ChangeRegOnBP        DBKSuspendThread      DBKResumeThread      DBKSuspendProcess      DBKResumeProcess      KernelAlloc          GetKProcAddress      Protect2          test            useIOCTL        DBKGetDC
3b. 现在我们将newkernelhandler.pas, DBK32functions.pas, 和DBK32.dpr改名.    用Delphi 7打开上面3个文件. Newkernelhandler 在CE主目录,另外两个文件在DBK32文件夹. 打开,    然后执行“文件 ”& “另存为”,3个文件分别另存为:    DBK32.dpr && String.dpr      DBK32functions.pas && Stringfunctions.pas
    New KernelHandler.pas && Stringfunctions.pas
  然后保存,退出。    现在,打开查找和替换工具,把 mask 改成 " *.* ". (Include Subfolders要选中)      做如下替换。      dbk32.sys && string.sys      dbk32.dll && string.dll      现在用delphi 7打开string.dpr . 我们将编译 string.dll. 执行 Project & compile string. 如果正常你将会    看到"警告"和"提示"窗口,否则你将看到"错误"窗口. 如果得到错误,那么检查你的步骤。    好的,如果一切正常,你就可以在CE主目录看到string.dll了  3c. 制作 CEHook  再次用到查找和替换工具,“Mask”里键入 CEHook.hypermode.pas  替换:myhook && string54  用delphi7打开CEHOOK文件夹下面的CEHook.dpr ,然后将user下面的system注释掉,也就是在system  前面加入“ // ”。  3d. 创造 Stealth - 打开stealth.dpr(在Stealth目录下) 并且编译它,这里什么都不需要变(HOHO…)  3e. 重新命名 NewKernelHandler 和 CeFuncProc
打开cheatengine.dpr(CE 主目录下).来到 工程管理器 ,再次打开NewKernelHandler.pas 和
  CeFuncProc.pas 执行文件 & 另存为". 保存到CE主目录,两文件分别保存为:    NewKernelHandler.pas && StringHandler.pas (replace? Yes!)      CeFuncProc.pas && String55.pas  保存,退出。  然后查找替换,Mask填:*.*,(取消 include subfolders)  NewKernelHandler && Stringhandler (改变所有文件除了Newkernelhandler.pas)
  CeFuncProc && String55  3f. 改变数值字符 (十六进制数值)  需要改变3个数值:0; ,  7FFFFFFF ,  0; 可以给3个数值加上同样的数,比如说加5他们就变成:0; 然后查找替换,(Include subfolders),Mask:"*.*"   
  7FFFFFFF &&
&& 0; 3g. 改变CheatEngine 图形界面里面的单词    再次查找和替换, (取消 include subfolders) ,Mask:"*.*"    nextscanbutton && String56
  scanvalue && String57
  scanvalue2 && String58
  ScanType && String59
  VarType && String60
  newscan && String61
  ScanText && String62
  /ce &&
(你可以改变为任何网站)  3h. 再次查找和替换,(取消 include subfolders). mask:"*.pas "    CheatEngine && StringEngine
  cheat engine && String Engine  3i.配置Cheat Engine 图形界面    打开CE主目录下的cheatengine.bpg. 然后工程管理器, 打开 MainUnit . 双击Cheat Engine图形界面就    弹出来了.    查找灰色显示的单词: "scan type" 和"value type",单击该下拉框来到scantype,这一步的目的就是检查你修改的字符是否正确,然后看左边的工程树和工程检测器,希望工程树下的 String59 是高亮显示的,现在向下滚动工程检测器,知道你看到"name",希望它的下一格也是String59    如果你这一步做正确了,那么继续重复做单词的检查。  最后,点击红色箭头下面的"ProtectMe2" 和"crash me",转到工程监测器,把它的标题上的单词删掉  这样,它们是存在的,可是我们却看不到它们了。  下面,是一些有关个性化你的UCE的方法:  改变版本信息:用工程管理器打开Cheatengine.exe,右键&选项,点击"版本信息"标签,自由发挥吧  改变应用程序名,帮助,和图标,同上,然后点击“应用程序”标签。  改变设置和关于…部分,分别用工程管理器打开formsettingsunit" 和 "aboutunit"  3j. 编译 cheatengine.exe  查看工程管理器,确定你现在选择的是cheatengine.exe而不是cheatengine.DEU / NLD / RUS    最小化DelPhi,然后用wendows资源管理器打开CE主目录,建立一个文本文件,然后改名为:  trainerwithassembler.exe    现在回到delphi,编译,这将会是很长的一步(但也是令人高兴的,因为你正接近成功)  当你尝试编译的时候,你也许会得到错误,类似:  [Error] autoassembler.pas(531): Undeclared identifier: 'KernelAlloc'    希望你已将你的改变如我要求的那样记录到一张纸上,现在去看你的记录,你将KernelAlloc变成了什么,  在该教程里,我改变为 String50    再次编译,如果你再次得到错误,处理它,再编译,直到没有错误。  (这是很长的一步,却是关键的一步)  4. 完成接触  4a. 编译UCE需要的文件    打开Delphi.
    编译systemcallsignal.dpr (在 SystemcallRetriever 文件夹下).
    编译Systemcallretriever.dpr(在 SystemcallRetriever 文件夹下).      编译Kernelmoduleunloader.dpr ( dbk32\kernelmodule unloader文件夹下)  4b. 另外的填充    首先.. 在你进行打包搞遭前,制作一个源文件的拷贝.      现在打开主目录下的cheatengine.bpg ,另存为stringengine.bpg
    再次打开cheatengine.bpg,在cheatengine.exe 上右击,选择"查看源文件",    另存 cheatengine.dpr 为 stringengine.dpr 然后 编译它,你就会得到StringEngine.exe. !! (CE主文件,在这里已经变成SE了)  4c. 希望现在你有了所有下面的文件..
  创造一个新的文件夹把他们放进去。    stringengine.exe
  driver.dat
  string.sys
  string.dll
  stealth.dll
  cehook.dll
  systemcallsignal.exe
  systemcallretriever.exe
  kernelmoduleunloader.exe    所所所所…有的事情已经做好!! 现在你仅需要去测试它。  5.测试你的UCE  我想大家都会测试吧…不翻译了。  夜深了,困死了  到这里,文章就基本翻译完了,有的地方没有按原文翻译,是因为原文有图片,发帖子似乎不能进行图文混排,所以就只能用文字表达,我想我基本已经表达清楚作者的意思了。  因为我自己也没有delphi7,也不会用delphi7所以没有进行具体的操作,所有有些关于delphi程序菜单的翻译是用类似BC的文字,我想差距也不会很大吧,大家应该都能明白。  HOHOHO,本文章只是提供改CE的控件名字,变量名等东西,没有涉及内部模块函数调用的改变,所以做的基本上只是表面文章,也许对了一般的反外挂程序还行,但是似乎对付不了NP、、、  翻译这篇文章,用了偶接近4个小时的时间,555  其实,这个过程也是自己整理思路的过程,同时把它发到论坛上来,也希望能与大家共享
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:0
21:21:25@echo off
;goto make
;write by 杀很大 同学
.model flat, stdcall
option casemap:none
include \masm32\include\w2k\ntstatus.inc
include \masm32\include\w2k\ntddk.inc
include \masm32\include\w2k\ntoskrnl.inc
include \masm32\include\w2k\w2kundoc.inc
includelib \masm32\lib\w2k\ntoskrnl.lib
include \masm32\Macros\Strings.mac
KeAttachProcess_address dd ?
KiAttachProcess_address dd ?
KiMoveApcState_address dd ?
KeStackAttachProcess_address dd ?
AntiKeStackAttachProcess proc
mov edi,edi
mov ebp,esp
push KeStackAttachProcess_address
add dword ptr [esp],5
AntiKeStackAttachProcess endp
AntiKeAttachProcess proc
mov edi,edi
mov ebp,esp
push KeAttachProcess_address
add dword ptr [esp],5
AntiKeAttachProcess endp
AntiKiAttachProcess proc
mov edi,edi
mov ebp,esp
push KiAttachProcess_address
add dword ptr [esp],5
AntiKiAttachProcess endp
AntiKiMoveApcState proc
mov edi,edi
mov ebp,esp
push KiMoveApcState_address
add dword ptr [esp],5
AntiKiMoveApcState endp
DriverEntry proc
mov eax, cr0
and eax,0fffeffffh
mov cr0, eax
push $CCOUNTED_UNICODE_STRING ("KeAttachProcess")
call MmGetSystemRoutineAddress
mov KeAttachProcess_address,eax
cmp byte ptr [eax],0e8h
mov edx,dword ptr [eax+1]
lea eax,dword ptr [edx+eax+5]
mov KiAttachProcess_address,eax
cmp byte ptr [eax],0e8h
mov edx,dword ptr [eax+1]
lea eax,dword ptr [edx+eax+5]
mov KiMoveApcState_address,eax
push $CCOUNTED_UNICODE_STRING ("KeStackAttachProcess")
call MmGetSystemRoutineAddress
mov KeStackAttachProcess_address,eax
mov eax,804d8000h
cmp ecx,216600h
je  @F
cmp byte ptr [eax],0e8h
mov edx,[eax+1]
lea edx,[eax+edx+5]
.if edx==KeStackAttachProcess_address
mov edx,offset AntiKeStackAttachProcess
sub edx,eax
mov [eax+1],edx
.elseif edx == KeAttachProcess_address
mov edx,offset AntiKeAttachProcess
sub edx,eax
mov [eax+1],edx
.elseif edx == KiAttachProcess_address
mov edx,offset AntiKiAttachProcess
sub edx,eax
mov [eax+1],edx
.elseif edx == KiMoveApcState_address
mov edx,offset AntiKiMoveApcState
sub edx,eax
mov [eax+1],edx
mov eax, cr0
or eax,10000h
mov cr0, eax
xor eax,eax
DriverEntry endp
end DriverEntry
set drv=AntiEngine
bin\ml /nologo /c /coff %drv%.bat
bin\link /nologo /driver /base:0x10000 /align:32  /out:%drv%.sys /subsystem:native %drv%.obj
del %drv%.obj
一、NP用户层监视原理
NP启动后通过WriteProcessMemory跟CreateRemoteThread向所有进程注入代码(除了系统进程smss.exe),代码通过np自己的LoadLibrary向目标进程加载npggNT.des。npggNT.des一旦加载就马上开始干“坏事”,挂钩(HOOK)系统关键函数如OpenProcess,ReadProcessMemory,WriteProcessMemory,PostMessage等等。挂钩方法是通过改写系统函数头,在函数开始JMP到npggNT.des中的替换函数。用户调用相应的系统函数时,会首先进入到npggNT.des模块等待NP的检查,如果发现是想对其保护的游戏进行不轨操作的话,就进行拦截,否则就调用原来的系统函数,让用户继续。
下面是NP启动前user32.dll中的PostMessageA的源代码(NP版本900,XP sp2)
8BFF MOV EDI,EDI
55 PUSH EBP
8BEC MOV EBP,ESP
56 PUSH ESI
57 PUSH EDI
8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C]
8BC7 MOV EAX,EDI
SUB EAX,145
74 42 JE SHORT USER32.77D1CBDA
83E8 48 SUB EAX,48
74 3D JE SHORT USER32.77D1CBDA
2D A6000000 SUB EAX,0A6
0F84 D4530200 JE USER32.77D41F7C
8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
MOV ECX,DWORD PTR DS:[77D70080]
F641 02 04 TEST BYTE PTR DS:[ECX+2],4
JNZ USER32.77D41FBE
8D45 10 LEA EAX,DWORD PTR SS:[EBP+10]
50 PUSH EAX
57 PUSH EDI
E8 FBFEFFFF CALL USER32.77D1CAC0
FF75 14 PUSH DWORD PTR SS:[EBP+14]
FF75 10 PUSH DWORD PTR SS:[EBP+10]
57 PUSH EDI
FF75 08 PUSH DWORD PTR SS:[EBP+8]
E8 ACBFFFFF CALL USER32.77D18B80
5F POP EDI
5E POP ESI
5D POP EBP
C2 1000 RETN 10
而下面是NP启动后user32.dll中的PostMessageA的源代码(NP版本900,XP sp2)
E9 A69AB8CD JMP npggNT.458A6630
56 PUSH ESI
57 PUSH EDI
8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C]
8BC7 MOV EAX,EDI
SUB EAX,145
74 42 JE SHORT USER32.77D1CBDA
83E8 48 SUB EAX,48
74 3D JE SHORT USER32.77D1CBDA
2D A6000000 SUB EAX,0A6
0F84 D4530200 JE USER32.77D41F7C
8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
MOV ECX,DWORD PTR DS:[77D70080]
F641 02 04 TEST BYTE PTR DS:[ECX+2],4
JNZ USER32.77D41FBE
8D45 10 LEA EAX,DWORD PTR SS:[EBP+10]
50 PUSH EAX
57 PUSH EDI
E8 FBFEFFFF CALL USER32.77D1CAC0
FF75 14 PUSH DWORD PTR SS:[EBP+14]
FF75 10 PUSH DWORD PTR SS:[EBP+10]
57 PUSH EDI
FF75 08 PUSH DWORD PTR SS:[EBP+8]
E8 ACBFFFFF CALL USER32.77D18B80
5F POP EDI
5E POP ESI
5D POP EBP
C2 1000 RETN 10
通过对比我们可以发现,NP把PostMessageA函数头原来的8BFF558BEC五个字节改为了E9A69AB8CD,即将MOV EDI,EDI PUSH EBP
MOV EBP,ESP 三条指令改为了JMP npggNT.458A6630。所以用户一旦调用PostMessageA的话,就会跳转到npggNT.des中的458A6630中去。
二、用户层反NP监视方法
1,把被NP修改了的函数头改回去
上面知道NP是通过在关键系统函数头写了一个JMP来进行挂钩的,因此,在理论上我们可以通过把函数头写回去来进行调用。在实际操作的时候,这种方法并不理想。因为npggNT.des也挂钩了把函数头改写回去的所有函数,还有它的监视线程也会进行检校判断它挂钩了的函数是不是被修改回去。因此实现起来很困难,随时都会死程序。
2,构建自己的系统函数(感谢JTR提供)
这种方法适用于代码比较简单的系统函数。下面我们看看keybd_event的函数源码
8BFF MOV EDI,EDI ; USER32.keybd_event
55 PUSH EBP
8BEC MOV EBP,ESP
83EC 1C SUB ESP,1C
8B4D 10 MOV ECX,DWORD PTR SS:[EBP+10]
AND DWORD PTR SS:[EBP-10],0
894D EC MOV DWORD PTR SS:[EBP-14],ECX
66:0FB64D 08 MOVZX CX,BYTE PTR SS:[EBP+8]
66:894D E8 MOV WORD PTR SS:[EBP-18],CX
66:0FB64D 0C MOVZX CX,BYTE PTR SS:[EBP+C]
66:894D EA MOV WORD PTR SS:[EBP-16],CX
8B4D 14 MOV ECX,DWORD PTR SS:[EBP+14]
894D F4 MOV DWORD PTR SS:[EBP-C],ECX
6A 1C PUSH 1C
33C0 XOR EAX,EAX
8D4D E4 LEA ECX,DWORD PTR SS:[EBP-1C]
40 INC EAX
51 PUSH ECX
50 PUSH EAX
8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX
E8 9B8DFCFF CALL USER32.SendInput
C2 1000 RETN 10
由上面我们看到keybd_event进行了一些参数的处理最后还是调用了user32.dll中的SendInput函数。而下面是SendInput的源代码
B8 F6110000 MOV EAX,11F6
BA 0003FE7F MOV EDX,7FFE0300
FF12 CALL DWORD PTR DS:[EDX] ; ntdll.KiFastSystemCall
C2 0C00 RETN 0C
SendInput代码比较简单吧?我们发现SendInput最终是调用了ntdll.dll中的KiFastSystemCall函数,我们再跟下去,KiFastSystemCall就是这个样子了
8BD4 MOV EDX,ESP
0F34 SYSENTER
最终就是进入了SYSENTER。
通过上面的代码我们发现一个keybd_event函数构建并不复杂因此我们完全可以把上面的代码COPY到自己的程序,用来替代原来的keybd_event。NP启动后依然会拦截原来的那个,但已经没关系啦,因为我们不需要用原来那个keybd_event了。
这种方法适用于源代码比较简单的系统函数,复杂的话实现起来就比较麻烦了。我是没有信心去重新构建一个PostMessageA,因为其中涉及到N个jmp和Call,看起来头都大。 还有在VC6里嵌入汇编经常死VC(这种事太烦人了),我想不会是我用了盗版的原因吧?
3,进入ring0(感谢风景的驱动鼠标键盘模拟工具)
由上面可以看到,NP用户层的监视不过是修改了一下系统的函数头,进行挂钩监视。因此,要反NP用户层监视的话,进入ring0的话很多问题就可以解决了。比如WinIO在驱动层进行键盘模拟,npggNT.des是拦截不到的。但是由于NP用了特征码技术,再加上WinIO名气太大了,所以WinIO在NP版本8××以后都不能用了。但是如果熟悉驱动开发的话,自己写一个也不是很困难的事。
说了那么多看起来很“高深”的东西,现在说一些象我这样的菜鸟都能明白的东西,呵呵,因为这是菜鸟想出来的菜办法。
我们知道NP是通过CreateRemoteThread在目标进程创建远程线程的,还有一点,很重要的一点就是:NP向目标进程调用了CreateRemoteThread后就什么都不管了,也就是说,凭本事可以对除游戏外的所有进程npggNT.des模块进行任何“处置”。这样我们可以用一个很简单的方法就是检查自己的线程,发现多余的话(没特别的事情就是NP远程创建的)就马上结束了它,这样NP就无法注入了。但是由于windows系统是多任务系统,而CreateRemoteThread的执行时间又极短,要在这么短的时间内发现并结束它的话是一件很困难的事。一旦CreateRemoteThread执行完毕而我们的监视线程还没有起作用的话,后果就惨重了,npggNT.des马上把程序“搞死”。因为我们一直试图关闭它的线程,而npggNT.des又拦截了TerminateThread,所以我们就只能不断地“重复重复再重复”去试图关闭npggNT.des的监视线程。如果我们很幸运地在其执行注入代码时就能断了它地线程地话,npggNT.des就无法注入了。这种方法在NP早期版本大概有百分之五十的成功率,现在能有百分之一的成功率都不错了。
5,断线程之线程陷阱
我知道“线程陷阱”这个词肯定不是我首创,但用“陷阱”这种方法来对付NP之前在网上是找不到的。为什么要叫“线程陷阱”?因为这确确实实是一个陷阱,在npggNT.des肯定要经过的地方设置一个“陷阱”,等它来到之后,掉进去自动就死掉了。而搭建陷阱的方法简单得令你难以相信。
上面我们从npggNT.des的监视原理可以看到,npggNT.des要来挂钩(HOOK)我们的系统函数,这种的方法我们也会,是不是?哪想想,这种挂钩方法需要用到哪些系统函数呢? 打开进程OpenProcess或GetCurrentProcess(因为npggNT.des已经进入了目标进程,所以没有必要再调用OpenProcess,肯定是用后者)、找模块地址GetModelHandle、找函数地址GetProcAddress、改写函数头的内存属性VirtualQuery&VirtualProtect、写内存WriteProcessMemory。嘿嘿,在这些地方设置陷阱就八九不离十了,肯定是npggNT.des干那坏勾当要经过的地方。
怎么设陷阱呢?选一个上面说的函数(我没有一一尝试),先自己挂钩(嘿嘿,NP会我们也会)。等到有人调用的时候,先判断当前的的线程是不是我们程序的,不是的话,那就断了它吧(一个ExitThread就可以了)。大概就像下面这个样子
HANDLE WINAPI MyGetCurrentProcess(VOID)//替换掉原来的GetCurrentProcess
DWORD dwThreadId=GetCurrentThreadId();//得到当前线程ID
if(!IsMyThread(dwThreadId)){//不是我们要保护的线程
ExitThread(0);//断了它吧
UnhookGetCurrentProcess(); //是我们要保护的线程调用就恢复函数头
HANDLE hProcess=GetCurrentProcess();//让它调用
RehookGetCurrentProcess();//重新挂钩
return hP //返回调用结果
这种方法去掉npggNT.des的监视是完全能够实现的,但是这个函数IsMyThread(dwThreadId)非常关键,要考虑周全,不然断错线程的话,就“自杀”了。
6,更简单的陷阱
原理跟上面一样,但是我们将替换函数写成这个样子
HANDLE WINAPI MyGetCurrentProcess(VOID)//替换掉原来的GetCurrentProcess
HMODLE hMod=GetModelHandle("npggNT.des");
if(hMod!=NULL){
FreeLibrary(hMod); //直接Free掉它
UnhookGetCurrentProcess(); //是我们要保护的线程调用就恢复函数头
HANDLE hProcess=GetCurrentProcess();//让它调用
RehookGetCurrentProcess();//重新挂钩
return hP //返回调用结果
这种方法就万无一失了,不用担心会“自杀”。
由上面可以看到在用户层上反NP监视是不是很简单的事?最简单有效的就是第六种方法,短短的几行代码就可以搞定了。但是不要指望去掉了npggNT.des就可以为所欲为了,还有NP还在驱动层做了很多手脚,比如WriteProcessMemory在用户层用没问题,但是过不了NP的驱动检查,对游戏完全没效果。要在NP下读写游戏内存,说起来又另一篇文章了《如何在NP下读写游戏内存》,请继续关注。
**********************************************************************
Bypass NP in ring0 (日):
1,Add MyService
2,hook sysenter
3,SystemServiceID-&MyServiceID
4,MyService JMP -&SystemService Function + N bytes(参考【原创】SSDT Hook的妙用-对抗ring0 inline hook )
1、2、3 -&绕过NP SSDT检测
4 -&绕过NP 内核函数头检测
NP968下通过
文章2:如何在NP下读写游戏内存及如何进入NP进程 作者:堕落天才
在上一篇文章《反NP监视原理》中说到要去掉NP的注入是很容易的事,但是去掉npggNT.des并不是说我们想对游戏怎么样都可以了,NP还挂钩了很多内核函数,所以很多关键系
统函数就算我们在用户层能用也对游戏没有什么效果。
如果我们想在不破解NP前提下读写游戏内存该怎么办呢,我想办法至少有两个
一、用驱动
在驱动下读写游戏内存是没问题,但是由于我不懂驱动,所以也没什么可说。
二、进入游戏进程
在用户层,如果我们想在不破解NP的前提下读写游戏内存的话,大概就只能进入游戏进程了。因为很简单,我们的程序无法对游戏使用OpenProcess、ReadProcessMemoery及
WriteProcessMemory这些函数(就算是去掉了NP监视模块npggNT.des),而NP又不可能限制游戏自身使用这些函数,所以只要我们能够进入游戏进程就能够读写游戏的内存。怎么
进入游戏呢?下面介绍两种方法:
1,最简单的办法 ―全局消息钩子(WH_GETMESSAGE)
看似很复杂的东西原来很简单就可以实现,大道至易啊。使用消息钩子进入游戏进程无疑是最简单的一种方法,具体编程大概象这样:一个消息钩子的DLL,里面包含一个消
息回调函数(什么都不用做),读写内存过程,跟主程序通讯过程或操作界面过程,当然在DLL_PROCESS_ATTACH要判断当前的进程是不是游戏的,是的话就做相应的处理;一个安
装全局消息钩子的主程序。大概这样就可以了。使用全局消息钩子的好处是简单易用,但是不足之处是要在游戏完全启动(NP当然也启动啦)后才能进入,如果想在NP启动前做一
些什么事的话是不可能的。
另外也简单介绍一下防全局钩子的办法,Windows是通过调用LoadLibraryExW来向目标进程注入钩子DLL的,所以只要我们在钩子安装前挂钩了这个函数,全局钩子就干扰不了
2,更麻烦的办法 ― 远程注入
知道远程注入方法和原理的人可能会说“有没有搞错,OpenProcess、WriteProcessMemory这些必备函数都不能用,怎么注入?”,当然啦,NP启动后是不能干这些事情,所
以我们要在NP启动前完成。这样一来,时机就很重要了。
游戏启动的流程大概是这样:游戏Main-&GameGuard.des-&GameMon.des(NP进程)。这里的做法是这样:游戏Main-&GameGuard.des(暂停)-&注入DLL-&GameGuard.des(继
续)-&GameMon.des。关键点就是让GameGuard.des暂停,有什么办法?我想到一个是全局消息钩子(还是少不了它啊)。要实现大概需要做下面的工作:一个全局消息钩子DLL,里面只
要一个消息回调函数(什么都不用做),DLL_PROCESS_ATTACH下进行当前进程判断找GameGuard.des,找到的话就向主程序SendM主程序,负责安装钩子,接收钩子DLL发来的
消息,接收到消息就开始查找游戏进程,向游戏进程注入内存操作DLL,返回给SendMessage让GameGuard.des继续,卸载钩子(免得它继续钩来钩去);内存操作DLL,负责对游戏
内存进行操作。
具体编写如下(有省略):
////////////////////////////////////////////////GameHook.cpp//////////////////////////////////////////////////////////////////
BOOL IsGameGuard();
//////////////////////////////////
LRESULT CALLBACK GetMsgProc(int nCode,WPARAM wParam,LPARAM lParam)
return (CallNextHookEx(m_hHook,nCode,wParam,lParam));//什么都不需要做
///////////////////////////////////////
BOOL WINAPI DllMain(HINSTANCE hInst,DWORD dwReason,LPVOID lp)
switch(dwReason){
case DLL_PROCESS_ATTACH:
if(IsGameGuard())//判断当前进程是不是GameGuard.des
SendMessage(m_hwndRecv,WM_HOOK_IN_GAMEGUARD,NULL,NULL);//向主窗体发送消息,SendMessage是等待接受窗体处理完毕才返回的,
//所以进程就暂停在这里,我们有足够的时间去做事情
case DLL_PROCESS_DETACH:
return TRUE;
///////////////////////////////////
GAMEHOOKAPI BOOL SetGameHook(BOOL fInstall,HWND hwnd)
////////////////////////////////////////
BOOL IsGameGuard()
TCHAR szFileName[256];
GetModuleFileName(NULL,szFileName,256);
if(strstr(szFileName,"GameGuard.des")!=NULL){//这样的判断严格来说是有问题的,但实际操作也够用了。当然也可以进行更严格的判断,不过麻烦点
return TRUE;
return FALSE;
//////////////////////////////////////////////////////Main////////////////////////////////////////////////////////////////////////
void OnGameGuard(WPARAM wParam,LPARAM lParam)//处理消息钩子DLL发来的消息就是上面SendMessage的那个
DWORD dwProcessId=FindGameProcess(m_strGameName);//开始查找游戏进程
if(dwProcessId==0){
MessageBox(m_hWnd,"没有找到游戏进程","查找游戏进程",MB_OK);
if(!InjectDll(dwProcessId)){//查找到就开始注入
MessageBox(m_hWnd,"向游戏进程注入失败",注入",MB_OK);
/////////////////////////////////////////////////
DWORD FindGameProcess(LPCSTR szGameName)//负责查找游戏进程
HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hSnapshot==INVALID_HANDLE_VALUE)
PROCESSENTRY32 pe={sizeof(pe)};
DWORD dwProcessID=0;
for(BOOL fOK=Process32First(hSnapshot,&pe);fOK;fOK=Process32Next(hSnapshot,&pe)){
if(lstrcmpi(szGameName,pe.szExeFile)==0){
dwProcessID=pe.th32ProcessID;
CloseHandle(hSnapshot);
return dwProcessID;
/////////////////////////////////////////////////
BOOL InjectDll(DWORD dwProcessId)//负责注入,参考自Jeffrey Richter《windows核心编程》
CString strT
char* szLibFileRemote=NULL;
HANDLE hProcess=OpenProcess(PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE,FALSE,dwProcessId);
if(hProcess==NULL){
// SetRecord("Open game process failed!");
return FALSE;
int cch=lstrlen(szDll)+1;
int cb=cch*sizeof(char);
szLibFileRemote=(char*)VirtualAllocEx(hProcess,NULL,cb,MEM_COMMIT,PAGE_READWRITE);
if(szLibFileRemote==NULL){
// SetRecord("Alloc memory to game process failed!");
CloseHandle(hProcess);
return FALSE;
if(!WriteProcessMemory(hProcess,(LPVOID)szLibFileRemote,(LPVOID)szDll,cb,NULL)){
// SetRecord("Write game process memory failed!");
CloseHandle(hProcess);
return FALSE;
PTHREAD_START_ROUTINE pfnThreadRtn=(PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(TEXT("kernel32")),"LoadLibraryA");
if(pfnThreadRtn==NULL){
// SetRecord("Alloc memory to game process failed!");
CloseHandle(hProcess);
return FALSE;
HANDLE hThread=CreateRemoteThread(hProcess,NULL,0,pfnThreadRtn, szLibFileRemote,0,NULL);
if(!hThread)
// SetRecord("Create remote thread failed!");
CloseHandle(hProcess);
return FALSE;
if(hThread!=NULL)
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
///////////////////////////操作游戏内存的DLL就不贴了,大家根据不同的需要各显神通吧///////////////////////////////////////////////////
这种方法比一个全局消息钩子麻烦一点,但是优点是显然易见的:可以在NP启动前做事情,比如HOOK游戏函数或做游戏内存补丁。下面进入NP进程还要用到这种方法。
三、进入NP进程
如果我们对NP有足够的了解,想对它内存补丁一下,来做一些事情,哪又怎样才可以进入NP的进程呢?嗯,我们知道游戏启动流程是这样的游戏Main-&GameGuard.des-
&GameMon.des(NP进程),其中GameGuard.des跟GameMon.des进程是游戏Main通过调用函数CreateProcessA来创建的,上面我们说到有办法在NP进程(GameMon.des)启动前将我们的
DLL注入到游戏进程里,因此我们可以在GameMon.des启动前挂钩(HOOK)CreateProcessA,游戏创建NP进程时让NP暂停,但是游戏本来创建NP进程时就是让它先暂停的,这步我们
可以省了。下面是游戏启动NP(版本900)时传递的参数
ApplicationName:C:\惊天动地Cabal Online\GameGuard\GameMon.des
CommandLine:\x01\x58\x6d\xae\x99\x55\x57\x5d\x49\xbe\xe4\xe1\x9b\x14\xe6\x88\x57\x68\x6d\x11\xb9\x36\x73\x38\x71\x1e\x88\x46\xa9\x97\xd4\x3a\x20\x90
\x62\xae\x15\xcd\x4b\xcd\x72\x82\xbd\x75\x0a\x54\xf0\xcc\x01\xad
CreationFlags:4
Directory:
其中的CommandLine好长啊,它要传递的参数是:一个被保护进程的pid,两个Event的Handle,以及当前timeGetTime的毫秒数 (感谢JTR分享)。
CreationFlags:4 查查winbase.h头文件,发现#define CREATE_SUSPENDED 0x,所以NP进程创建时就是暂停的
在我们替换的CreateProcessA中,先让游戏创建NP进程(由于游戏创建时NP进程本来就是暂停的,所以不用担心NP的问题),让游戏进程暂停(SendMessage就可以了),然后再
向NP进程注入DLL,最后让游戏进程继续。这样我们的DLL就进入NP进程了。实现起来大概是这样子
MyCreateProcessA(//替换原来的CreateProcessA
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
UnhookCreateProcessA();
BOOL fRet=CreateProcessA(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,
lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);
RehookCreateProcessA();
SendMessage(hwndRecv,//负责注入的窗体句柄
WM_HOOK_NP_CREATE,//自定义消息
(WPARAM)lpProcessInformation-&dwProcessId,//把NP进程ID传给负责注入的主窗体
四、注意问题
由于我们是在不破解NP的前提下对游戏内存进行操作,所以一不小心的话,很容易就死游戏。NP保护了游戏进程的代码段,所以在NP启动后就不要再对其代码段进行修改,要
补丁或HOOK系统函数这些都要在NP启动前完成。当然读写游戏的数据段是没问题的,因为游戏本身也不断进行这样的操作。
文章3:跳过nProtect更新 作者:XXX
首先要清楚,nProtect通过连接其更新服务器获得当前最新文件内容,然后与本地文件作比较,如发现服务器端的文件与本地的不一致,则从更新服务器重新下载文件更新本地的nProtect文件。如果nProtect更新成功,而新版nProtect又拦截外挂,那么理所当然地nProtect每更新一次外挂就失效一次了。
通过分析游戏客户端用于解析该游戏各程序与其对应远端连接的IP列表文件,找出nProtect更新服务器的地址,并分析出nProtect官方更新服务器上的目录文件结构。
目录文件结构一般为: "更新服务器的名称\\GameGuard"
先自己构建一台模拟nProtect更新服务器,服务器上目录文件结构与官方的相同,更新下载文件内容使用旧版nProtect的内容(旧的客户端先别忙着删除...)
将真实nProtect更新服务器的地址,解析到你构建的模拟nProtect更新服务器的IP地址.
例: 127.0.0.
写入到 system32\\drivers\\etc 的 host 文件中
这个 host 文件为系统TCP/IP协议配置IP解析服务, 没有后缀名,可用记事本或UE32打开编辑。
通常一个网游的顺利运行,是要连接服务器端多个IP的("nProtect服务","连接服务","数据服务","登陆服务","主服务"......)
而这一系列的服务都是由一个游戏主程序的启动运行来完成(如"命运"的"WYDLaucher.exe","奇迹"的"Main.exe","冒险岛"的"MapleStory.exe")
由于host文件已被修改过,其中nProtect更新的连接IP被解析为指向自己模拟的更新服务器,而模拟服务器上的"更新文件"是旧版本的,所以nProtect不但不会被更新为新版,反而会版本倒退。并且往后都不会再更新...
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:22
搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys
1.用RKU看一下SSDT和SSDTShadow,发现SSDT并没有被HOOK,SSDTShadow HOOK了5个调用:
NtUserBuildHwndList
NtUserFindWindowEx
NtUserGetDC
NtUserGetDCEx
NtUserGetForegroundWindow
想也不用想,肯定是为了防止其他软件找到他的窗口。
解决方法:在TesSafe加载前先加载自己的驱动,备份这5个调用的地址,等TesSafe加载后直接还原即可,或者直接用RKU还原,TesSafe并没有在这里加效验,所以比较容易。
2.既然SSDT没有没HOOK,那么肯定有inline hook,用windbg看一下,发现被inline hook的调用有如下几个:
NtReadVirtualMemory
NtWriteVirtualMemory
NtOpenProcess + 0x2xx Call ObOpenObjectByPointer处
NtOpenThread + 0x1xx Call ObOpenObjectByPointer处
KiAttachProcess
解决方法:
NtReadVirtualMemory
NtWriteVirtualMemory
这2个比较好解决,自己写2个调用,实现这2个调用的头10个字节,然后再跳转到这2个调用头10个字节后面的地址,再到SSDT表里把这2个调用地址改成我们自己的即可。
NtOpenProcess + 0x2xx
NtOpenThread + 0x1xx
在TesSafe加载前,先保存ObOpenObjectByPointer的地址(或者用MmGetSystemRoutineAddress获取),然后我们自己写一段代码,实现Call ObOpenObjectByPointer头N个字节(随便自己)以及Call ObOpenObjectByPointer,然后再jmp到Call ObOpenObjectByPointer后面的代码地址,如:
push dword ptr [ebp-38h]
push dword ptr [ebp-24h]
Call ObOpenObjectByPointer
然后在Call ObOpenObjectByPointer前面N个字节处jmp到我们自制的代码,这样的话就算TesSafe把Call ObOpenObjectByPointer改成Call到自己的函数,对我们也没有作用了。
注意:直接还原代码的话,势必会蓝屏。因为TesSafe对这个地址有代码效验
KiAttachProcess
由于这个调用并没有被导出,在SSDT表中也没有他的地址。所以我们首先要获取他的地址
虽然它没有被导出,但是调用它的另外一个调用KeAttachProcess却是被导出了的,我们可以先用MmGetSystemRoutineAddress获取KeAttachProcess的地址,再通过KeAttachProcess + 0x41的Call KiAttachProcess来取得KiAttachProcess的地址,然后直接还原它的代码即可(TesSafe并没有对这里进行代码效验)。
至此,TesSafe的所有HOOK都已恢复完毕,这时用OD附加游戏,发现OD会突然停止。
其实,上面那些HOOK大部分人都已经搞定,关键就是这最后一步,OD停止的原因是他收不到调试消息了,因为TesSafe有一个线程不停的向PEPROCESS-&DebugPort 写入NULL(0)。
DebugPort其实就是Debug_Object的指针。
UnHook的方法多种多样,稍微灵活变通下就能想出很多方法。
程序我就不传了,我相信这些分析比传一个程序有用的多
NP和HS也都大同小异,自己写系统调用,一样过他
以后我会介绍如果绕过NP,以及HS的保护
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:114
手把手教你使用WINDBG KO XXXX游戏驱动保护 神鬼传奇(2)
805b5394 就是原始 nt!NtWriteVirtualMemory 函数地址 我们记下这个结构
aa09640b PUSH DWORD PTR [EBP+18]     B8E6E603
aa09640e PUSH DWORD PTR [EBP+14]
aa096411 PUSH DWORD PTR [EBP+10]
aa096414 PUSH DWORD PTR [EBP+C]   aa096417 PUSH DWORD PTR [EBP+8]   aa09641a MOV EAX,[AA09AD1C]       aa09641f CALL EAX                 完美调用原始函数结构 现在知道了 关键代码 下面我们在回到函数头查看
aa09640b-aa09635c-5=AA
B8E6E603- B8E6E434-5=1CA
好的回到内存窗口打入aa09635c 切换为BYTE 字节查看打入E9 AA 00 00 00 好的流程被改写了这样这个nt!NtWriteVirtualMemory函数就被KO了怎么样是不是很简单?我们继续完成后面个函数切换 windbg 命令窗口打入[b]uf 0xaa0961ee 我这里的nt!NtReadVirtualMemory HOOK 地址
aa0961ee PUSH EBP                 aa0961ef MOV EBP,ESP              aa0961f1 ADD ESP,-28              aa0961f4 CALL AA0;           aa0961f9 JMP SHORT AA096218
aa096218 PUSH AA0961FB            aa09621d PUSH AA0962FD            aa096222 PUSH AA0;           aa096227 PUSH DWORD PTR FS:[0]    aa09622e MOV FS:[0],ESP           aa096235 MOV DWORD PTR [EBP-4],C0000023
aa09623c MOV DWORD PTR [EBP-C],0
aa096243 CALL AA099D96            aa096248 MOV [EBP-8],EAX          aa09624b CMP DWORD PTR [EBP+8],-1
aa09624f JNZ SHORT AA09625D       aa096251 MOV DWORD PTR [EBP-C],-1
aa096258 JMP AA0;            aa09625d PUSH EDI                 aa09625e LEA EDI,[AA09ACC4]       aa096264 MOV ECX,50               aa096269 SHR ECX,2                aa09626c MOV EAX,[EBP-8]          aa09626f CLD                      aa096270 REPNE SCAS BYTE PTR ES:[EDI]
aa096271 SCAS DWORD PTR ES:[EDI]
aa096272 POP EDI                  aa096273 OR ECX,ECX               aa096275 JE SHORT AA0;       aa096277 JMP SHORT AA0;      aa096279 LEA EAX,[EBP-10]         aa09627c PUSH EAX                 aa09627d PUSH 18                  aa09627f LEA EAX,[EBP-28]         aa096282 PUSH EAX                 aa096283 PUSH 0                   aa096285 PUSH DWORD PTR [EBP+8]   aa096288 CALL AA099CF4            aa09628d OR EAX,EAX               aa09628f JNZ SHORT AA0;      aa096291 PUSH DWORD PTR [EBP-18]
aa096294 POP DWORD PTR [EBP-C]    aa096297 JMP SHORT AA0962AB       aa096299 PUSH EAX                 aa09629a PUSH 1                   aa09629c PUSH 82                  aa0962a1 CALL AA093ACB            aa0962a6 ADD ESP,C                aa0962a9 JMP SHORT AA0;      aa0962ab CMP DWORD PTR [EBP-C],0
aa0962af JNZ SHORT AA0;      aa0962b1 JMP SHORT AA0;      aa0962b3 MOV EAX,[EBP-C]          aa0962b6 CMP EAX,[EBP-8]          aa0962b9 JNZ SHORT AA0962BD       aa0962bb JMP SHORT AA0;      aa0962bd PUSH ESI                 aa0962be MOV EAX,20               aa0962c3 SHR EAX,2                aa0962c6 MOV ECX,[EBP-C]          aa0962c9 LEA ESI,[AA09C118]       aa0962cf JMP SHORT AA0;      aa0962d1 CMP [ESI],ECX            aa0962d3 JE SHORT AA0962DD        aa0962d5 ADD ESI,4                aa0962d8 DEC EAX                  aa0962d9 OR EAX,EAX               aa0962db JNZ SHORT AA0;      aa0962dd POP ESI                  aa0962de OR EAX,EAX               aa0962e0 JE SHORT AA0;       aa0962e2 JMP SHORT AA0962FD       aa0962e4 PUSH DWORD PTR [EBP+18]
aa0962e7 PUSH DWORD PTR [EBP+14]
aa0962ea PUSH DWORD PTR [EBP+10]
aa0962ed PUSH DWORD PTR [EBP+C]   aa0962f0 PUSH DWORD PTR [EBP+8]   aa0962f3 MOV EAX,[AA09AD18]       aa0962f8 CALL EAX                 aa0962fa MOV [EBP-4],EAX          aa0962fd MOV EAX,[EBP-4]          aa096300 POP DWORD PTR FS:[0]     aa096307 ADD ESP,C                aa09630a DEC DWORD PTR [AA09ADB8]
aa096310 LEAVE                    aa096311 RETN 14                  [b]是不是很眼熟啊?[b]对滴还记的哪个结构不?
aa0962e4 PUSH DWORD PTR [EBP+18]
aa0962e7 PUSH DWORD PTR [EBP+14]
aa0962ea PUSH DWORD PTR [EBP+10]
aa0962ed PUSH DWORD PTR [EBP+C]   aa0962f0 PUSH DWORD PTR [EBP+8]   aa0962f3 MOV EAX,[AA09AD18]       aa0962f8 CALL EAX   [/b][/b][/b]
aa096349 PUSH AA0;           aa09634e PUSH DWORD PTR FS:[0]    aa096355 MOV FS:[0],ESP           aa09635c MOV DWORD PTR [EBP-4],C0000023 传入参数C0;   B8E6E434
aa096363 MOV DWORD PTR [EBP-C],0        传入参数0
aa09636a CALL AA099D96                  初步效验
aa09636f MOV [EBP-8],EAX                返回值赋予局部变量
aa096372 CMP DWORD PTR [EBP+8],-1       比较是否-1也就是 0FFFFFFFFh
aa096376 JNZ SHORT AA0;             aa096378 MOV DWORD PTR [EBP-C],-1
这里我们就直接KO它 改写aa09635c执行流程 让它直接执行到aa09640b
JMP aa09640b  这个怎么算的 目标地址-当前地址-5
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:45
手把手教你使用WINDBG KO XXXX游戏驱动保护 神鬼传奇(1)
【破解过程】需要工具 windbg 6.7汉化版 RkUnhooker 3.7 (请自行网上下载资源很多)首先安装后windbg 并运行它与 RkUnhooker (无先后分别)然后运行神鬼传奇并将它更新到最新版本游戏运行完后停在登陆界面切换到 RkUnhooker  点 SCAN  向下看我们看到
nt!NtOpenProcess             //我0XB8E6E298
nt!NtReadVirtualMemory    //我0XB8E6E3EC
nt!NtWriteVirtualMemory   //我0XB8E6E50F
这3个函数显示 YES 表示被HOOK 记下Address地址我们用WINDBG 去看看
好切换到WINDBG 菜单-打开-内核调式-本地的-确定提示是否保存选是菜单-查看-命令浏览器我们打入命令 uf 0xaa096314 (我这里的Address 和你的也许不同注意看清楚!!)
aa096314 PUSH EBP                 aa096315 MOV EBP,ESP              aa096317 ADD ESP,-28              aa09631a CALL AA0;           aa09631f JMP SHORT AA09633F   简单浏览 CALL AA096091 非处理函数我们直接入命令 uf AA09633F
aa09633f PUSH AA0;           aa096344 PUSH AA0;           aa096349 PUSH AA0;           aa09634e PUSH DWORD PTR FS:[0]    aa096355 MOV FS:[0],ESP           aa09635c MOV DWORD PTR [EBP-4],C0000023
aa096363 MOV DWORD PTR [EBP-C],0
aa09636a CALL AA099D96            aa09636f MOV [EBP-8],EAX          aa096372 CMP DWORD PTR [EBP+8],-1
aa096376 JNZ SHORT AA0;      aa096378 MOV DWORD PTR [EBP-C],-1
aa09637f JMP AA09640B             aa096384 PUSH EDI                 aa096385 LEA EDI,[AA09ACC4]       aa09638b MOV ECX,50               aa096390 SHR ECX,2                aa096393 MOV EAX,[EBP-8]          aa096396 CLD                      aa096397 REPNE SCAS BYTE PTR ES:[EDI]
aa096398 SCAS DWORD PTR ES:[EDI]
aa096399 POP EDI                  aa09639a OR ECX,ECX               aa09639c JE SHORT AA0;       aa09639e JMP SHORT AA09640B       aa0963a0 LEA EAX,[EBP-10]         aa0963a3 PUSH EAX                 aa0963a4 PUSH 18                  aa0963a6 LEA EAX,[EBP-28]         aa0963a9 PUSH EAX                 aa0963aa PUSH 0                   aa0963ac PUSH DWORD PTR [EBP+8]   aa0963af CALL AA099CF4            aa0963b4 OR EAX,EAX               aa0963b6 JNZ SHORT AA0;      aa0963b8 PUSH DWORD PTR [EBP-18]
aa0963bb POP DWORD PTR [EBP-C]    aa0963be JMP SHORT AA0;      aa0963c0 PUSH EAX                 aa0963c1 PUSH 1                   aa0963c3 PUSH 83                  aa0963c8 CALL AA093ACB            aa0963cd ADD ESP,C                aa0963d0 JMP SHORT AA09640B       aa0963d2 CMP DWORD PTR [EBP-C],0
aa0963d6 JNZ SHORT AA0963DA       aa0963d8 JMP SHORT AA09640B       aa0963da MOV EAX,[EBP-C]          aa0963dd CMP EAX,[EBP-8]          aa0963e0 JNZ SHORT AA0;      aa0963e2 JMP SHORT AA09640B       aa0963e4 PUSH ESI                 aa0963e5 MOV EAX,20               aa0963ea SHR EAX,2                aa0963ed MOV ECX,[EBP-C]          aa0963f0 LEA ESI,[AA09C118]       aa0963f6 JMP SHORT AA0;      aa0963f8 CMP [ESI],ECX            aa0963fa JE SHORT AA0;       aa0963fc ADD ESI,4                aa0963ff DEC EAX                  aa096400 OR EAX,EAX               aa096402 JNZ SHORT AA0;      aa096404 POP ESI                  aa096405 OR EAX,EAX               aa096407 JE SHORT AA09640B        aa096409 JMP SHORT AA0;      aa09640b PUSH DWORD PTR [EBP+18]
aa09640e PUSH DWORD PTR [EBP+14]
aa096411 PUSH DWORD PTR [EBP+10]
aa096414 PUSH DWORD PTR [EBP+C]   aa096417 PUSH DWORD PTR [EBP+8]   aa09641a MOV EAX,[AA09AD1C]       aa09641f CALL EAX                 aa096421 MOV [EBP-4],EAX          aa096424 MOV EAX,[EBP-4]          aa096427 POP DWORD PTR FS:[0]     aa09642e ADD ESP,C                aa096431 DEC DWORD PTR [AA09ADB8]
aa096437 LEAVE                    aa096438 RETN 14                  我们简单的上下看了一下基本结构很清晰 aa09640b 这里开始是nt!NtWriteVirtualMemory 5个参数
aa09641a MOV EAX,[AA09AD1C]   应该指向原始函数地址我们去看看菜单-查看-内存在Virtual中打入 AA09AD1C 看到没有如果你看不习惯可以这样选long hex 这样很直观了吧?
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:77
最新绕过TX驱动保护TesSafe.sys方法(现在可以用)3
***********************************************************************************************************
#include&ntddk.h&
typedef struct _SERVICE_DESCRIPTOR_TABLE
PVOID ServiceTableB
PULONG ServiceCounterTableB
ULONG NumberOfS
ULONG ParamTableB
}SERVICE_DESCRIPTOR_TABLE,*PSERVICE_DESCRIPTOR_TABLE; //由于KeServiceDescriptorTable只有一项,这里就简单点了
extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorT//KeServiceDescriptorTable为导出函数
/////////////////////////////////////
VOID Hook();
VOID Unhook();
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
//////////////////////////////////////
ULONG JmpA//跳转到NtOpenProcess里的地址
ULONG OldServiceA//原来NtOpenProcess的服务地址
//////////////////////////////////////
__declspec(naked) NTSTATUS __stdcall MyNtOpenProcess(PHANDLE ProcessHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PCLIENT_ID ClientId)
DbgPrint("NtOpenProcess() called");
push 804eb560h //共十个字节
jmp [JmpAddress]
///////////////////////////////////////////////////
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
DriverObject-&DriverUnload = OnU
DbgPrint("Unhooker load");
return STATUS_SUCCESS;
/////////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
DbgPrint("Unhooker unload!");
/////////////////////////////////////////////////////
VOID Hook()
Address = (ULONG)KeServiceDescriptorTable-&ServiceTableBase + 0x7A * 4;//0x7A为NtOpenProcess服务ID
DbgPrint("Address:0x%08X",Address);
OldServiceAddress = *(ULONG*)A//保存原来NtOpenProcess的地址
DbgPrint("OldServiceAddress:0x%08X",OldServiceAddress);
DbgPrint("MyNtOpenProcess:0x%08X",MyNtOpenProcess);
JmpAddress = (ULONG)NtOpenProcess + 10; //跳转到NtOpenProcess函数头+10的地方,这样在其前面写的JMP都失效了
DbgPrint("JmpAddress:0x%08X",JmpAddress);
__asm{//去掉内存保护
mov eax,cr0
and eax,not 10000h
mov cr0,eax
*((ULONG*)Address) = (ULONG)MyNtOpenP//HOOK SSDT
__asm{//恢复内存保护
mov eax,cr0
or eax,10000h
mov cr0,eax
//////////////////////////////////////////////////////
VOID Unhook()
Address = (ULONG)KeServiceDescriptorTable-&ServiceTableBase + 0x7A * 4;//查找SSDT
mov eax,cr0
and eax,not 10000h
mov cr0,eax
*((ULONG*)Address) = (ULONG)OldServiceA//还原SSDT
mov eax,cr0
or eax,10000h
mov cr0,eax
DbgPrint("Unhook");
就这么多了,或许有人说,没必要那么复杂,直接恢复NtOpenProcess不就行了吗?对于象“冰刃”“Rookit Unhooker”这些“善良”之辈的话是没问题的,但是象NP这些“穷凶极恶”之流的话,它会不断检测NtOpenProcess是不是已经被写回去,是的话,嘿嘿,机器马上重启。这也是这种方法的一点点妙用。
现在我们把思路总结一下,首先在游戏启动前先把NtOpenProcess整个函数的代码保存下来,再SSDT Hook,把地址指向我的函数。但是发现TX的驱动还有个保护机制 ,每隔一段时间检测系统是否有调用NtOpenProcess函数。
解决方法可以在驱动里面做个函数,函数里面先调用被驱动修改的NtOpenProcess,丢弃返回值后再调用提前定义的代码,最后返回这次的句柄就可以了。其他函数也类似这种恢复方法,网上好象有类似的代码,大家可以找一下。
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:31
最新绕过TX驱动保护TesSafe.sys方法(现在可以用)2
3, ring0 inline hook
ring0 inline hook 跟ring3的没什么区别了,如果硬说有的话,那么就是ring3发生什么差错的话程序会挂掉,ring0发生什么差错的话系统就挂掉,所以一定要很小心。
inline hook的基本思想就是在目标函数中JMP到自己的监视函数,做一些判断然后再JMP回去。一般都是修改函数头,不过再其他地方JMP也是可以的。下面我们来点实际的吧:
lkd& u nt!NtOpenProcess
nt!NtOpenProcess:
8057559e e95d6f4271 jmp f199c500
e93f953978 jmp f890eae7
e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92)
同时打开“冰刃”跟“Rootkit Unhooker”我们就能在NtOpenProcess函数头看到这样的“奇观”,第一个jmp是“冰刃”的,第二个jmp是“Rootkit Unhooker”的。他们这样是防止被恶意程序通过TerminateProcess关闭。当然“冰刃”还Hook了NtTerminateProcess等函数。
        Undocumented Windows 2000 Secrets 这本书我有中文电子版,需要的可以找我。
早期一般的驱动这样恢复基本都可以,甚至一些防病毒的主动防御等等都类似这样,不过现在的保护已经不象以前了,问题在于他多了一个监视机制。
比如NP,多个发送验证包。如果对NP做了手脚,包发送不出去,那游戏也别想玩。 韩国NP好象就没这样BT,(听做韩国脱机朋友说的)
回到问题上,进行反HOOK。
我这里拿比较经典的 NtOpenProcess这个函数(这个函数比较重要,研究的人也就多一些),发现其在NtOpenProcess函数调用ObOpenObjectByPointer的地方下了个跳转,跳转到TX游戏自身的代码里面,从而使其他程序无法通过此函数获取TX游戏的进程句柄而达到保护的目的。
顺便说句这个函数:OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。 常用的还有 GetWindowThreadProcessId 这个函数获得指定线程的标识符,此线程创建了指定的窗口,并且随机的产生了这个标识符,要求必须知道窗口标题窗口类(SSDTShadow HOOK 保护的函数保护了这部分)。
参考wanleidawa的文章描述:
NtOpenProcess + 0x2xx Call ObOpenObjectByPointer处
NtOpenThread + 0x1xx Call ObOpenObjectByPointer处
NtOpenProcess + 0x2xx
NtOpenThread + 0x1xx
在TesSafe加载前,先保存ObOpenObjectByPointer的地址(或者用MmGetSystemRoutineAddress获取),然后我们自己写一段代码,实现Call ObOpenObjectByPointer头N个字节(
随便自己)以及Call ObOpenObjectByPointer,然后再jmp到Call ObOpenObjectByPointer后面的代码地址,如:
push dword ptr [ebp-38h]
push dword ptr [ebp-24h]
Call ObOpenObjectByPointer
然后在Call ObOpenObjectByPointer前面N个字节处jmp到我们自制的代码,这样的话就算TesSafe把Call ObOpenObjectByPointer改成Call到自己的函数,对我们也没有作用了。
注意:直接还原代码的话,势必会蓝屏。因为TesSafe对这个地址有代码效验
到底如何才能饶过保护又不被发现呢,大家可以参考下堕落天才的文章。
对付ring0 inline hook的基本思路是这样的,自己写一个替换的内核函数,以NtOpenProcess为例,就是MyNtOpenProcess。然后修改SSDT表,让系统服务进入自己的函数MyNtOpenProcess。而MyNtOpenProcess要做的事就是,实现NtOpenProcess前10字节指令,然后再JMP到原来的NtOpenProcess的十字节后。这样NtOpenProcess函数头写的JMP都失效了,在ring3直接调用OpenProcess再也毫无影响。
发布:admin | 分类:反NP保护 | 评论:0 | 引用:0 | 浏览:67
最新绕过TX驱动保护TesSafe.sys方法(现在可以用)
大牛们可以飘过啦,还有...有技术知识点错误或者错别字什么的,一定告诉我。我的希望是能让大家都能越过驱动保护这个门槛,共同提高到新的层次。
前段时间看过 wanleidawa 兄弟发的帖子【原创】搞定QQ游戏系列(寻仙,DNF等等)驱动保护TesSafe.sys,给我启发很大。
不过很多人可能对上面的内容不太能理解。我先简单说下他那里的意识,然后在描述下新的方法,来饶过现在的保护。
大家可以使用反ROOTKIT程序22中文\Yas 来查看被HOOK的函数。这里还要插入一个小话题,就是关于驱动开发环境的搭建,当初也郁闷了我将近一天的时间。
大家可以按照这里的介绍配置驱动环境。
使用Yas查看被HOOK 的函数基本没什么大的变化大家可以参考 wanleidawa 兄弟发的帖子,关于反HOOK有很多种方法了,由于他那里没有讲,所以我说一下这部分的内容
(借用部分堕落天才的文章)。
SSDT即系统服务描述符表,它的结构如下(参考《Undocument Windows 2000 Secretes》第二章):
typedef struct _SYSTEM_SERVICE_TABLE
PVOID ServiceTableB //这个指向系统服务函数地址表
PULONG ServiceCounterTableB
ULONG NumberOfS //服务函数的个数,NumberOfService*4 就是整个地址表的大小
ULONG ParamTableB
}SYSTEM_SERVICE_TABLE,*PSYSTEM_SERVICE_TABLE;
typedef struct _SERVICE_DESCRIPTOR_TABLE
SYSTEM_SERVICE_TABLE //ntoskrnl.exe的服务函数
SYSTEM_SERVICE_TABLE win32k; //win32k.sys的服务函数,(gdi.dll/user.dll的内核支持)
SYSTEM_SERVICE_TABLE NotUsed1;
SYSTEM_SERVICE_TABLE NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,*PSYSTEM_DESCRIPTOR_TABLE;
内核中有两个系统服务描述符表,一个是KeServiceDescriptorTable(由ntoskrnl.exe导出),一个是KeServieDescriptorTableShadow(没有导出)。两者的区别是,
KeServiceDescriptorTable仅有ntoskrnel一项,KeServieDescriptorTableShadow包含了ntoskrnel以及win32k。一般的Native API的服务地址由KeServiceDescriptorTable分派,
gdi.dll/user.dll的内核API调用服务地址由KeServieDescriptorTableShadow分派。还有要清楚一点的是win32k.sys只有在GUI线程中才加载,一般情况下是不加载的,所以要Hook
KeServieDescriptorTableShadow的话,一般是用一个GUI程序通过IoControlCode来触发(想当初不明白这点,蓝屏死机了N次都想不明白是怎么回事)。
2,SSDT HOOK
SSDT HOOK 的原理其实非常简单,我们先实际看看KeServiceDescriptorTable是什么样的。
lkd& dd KeServiceDescriptorTable
8055aba0 00
8055abb0 00
在windbg.exe中我们就看得比较清楚,KeServiceDescriptorTable中就只有第一项有数据,其他都是0。其中804e3d20就是
KeServiceDescriptorTable.ntoskrnel.ServiceTableBase,服务函数个数为0x11c个。我们再看看804e3d20地址里是什么东西:
lkd& dd 804e3d20
804e3d20 716ef 81b5c
804e3d30 837b80 39d4e
804e3d40 647
804e3d50 8062f4ec 51f
如上,716ef 81b5c 这些就是系统服务函数的地址了。比如当我们在ring3调用OpenProcess时,进入sysenter的ID是0x7A(XP SP2),然后系统查
KeServiceDescriptorTable,大概是这样KeServiceDescriptorTable.ntoskrnel.ServiceTableBase(804e3d20) + 0x7A * 4 = 804E3F08,然后804E3F08 -&8057559e 这个就是
OpenProcess系统服务函数所在,我们再跟踪看看:
lkd& u 8057559e
nt!NtOpenProcess:
c4000000 push 0C4h
push offset nt!ObReferenceObjectByPointer+0x127 (804eb560)
e8e5e4f6ff call nt!InterlockedPushEntrySList+0x79 (804e3a92)
805755ad 33f6 xor esi,esi
原来8057559e就是NtOpenProcess函数所在的起始地址。
嗯,如果我们把8057559e改为指向我们函数的地址呢?比如 MyNtOpenProcess,那么系统就会直接调用MyNtOpenProcess,而不是原来的NtOpenProcess了。这就是SSDT HOOK
原理所在。
如果您想留下此文,您可以将其发送至您的邮箱(将同时以邮件内容&PDF形式发送)
相关文章推荐
(Ctrl+Enter提交) &&
已有0人在此发表见解
&在& 12:03收藏到了
&&在信息爆炸的时代,您的知识需要整理,沉淀,积累!Lai18为您提供一个简单实用的文章整理收藏工具,在这里您可以收藏对您有用的技术文章,自由分门别类,在整理的过程中,用心梳理自己的知识!相信,用不了多久,您收藏整理的文章将是您一生的知识宝库!
· 蜀ICP备号-1

我要回帖

更多关于 彼得老哥腿模杂志 的文章

 

随机推荐