首页
论坛
课程
招聘
[原创]如何在NP下读写游戏内存及如何进入NP进程
2007-1-4 13:28 73540

[原创]如何在NP下读写游戏内存及如何进入NP进程

2007-1-4 13:28
73540
******************************************************
*标题:【原创】如何在NP下读写游戏内存及如何进入NP进程 *
*作者:堕落天才                                       *
*日期:2007年1月4号                                   *
*版权声明:请保持文章的完整,转载请注明出处           *
******************************************************

   在上一篇文章《反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,找到的话就向主程序SendMessage;主程序,负责安装钩子,接收钩子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是等待接受窗体处理完毕才返回的,
                break;                               //所以进程就暂停在这里,我们有足够的时间去做事情
        case DLL_PROCESS_DETACH:
                break;
        }
        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);
                return;
        }       

    if(!InjectDll(dwProcessId)){//查找到就开始注入
          MessageBox(m_hWnd,"向游戏进程注入失败",注入",MB_OK);
                return;
     }
}
/////////////////////////////////////////////////
DWORD FindGameProcess(LPCSTR szGameName)//负责查找游戏进程
{
        HANDLE hSnapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
        if(hSnapshot==INVALID_HANDLE_VALUE)
                return 0;
        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;
                        break;
                }
        }
        CloseHandle(hSnapshot);
        return dwProcessID;
}
/////////////////////////////////////////////////
BOOL InjectDll(DWORD dwProcessId)//负责注入,参考自Jeffrey Richter《windows核心编程》
{
        CString strText;
        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  0x00000004,所以NP进程创建时就是暂停的
   
      在我们替换的CreateProcessA中,先让游戏创建NP进程(由于游戏创建时NP进程本来就是暂停的,所以不用担心NP的问题),让游戏进程暂停(SendMessage就可以了),然后再

向NP进程注入DLL,最后让游戏进程继续。这样我们的DLL就进入NP进程了。实现起来大概是这样子
BOOL
WINAPI
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传给负责注入的主窗体
                   NULL);
        return fRet;
}

四、注意问题
    由于我们是在不破解NP的前提下对游戏内存进行操作,所以一不小心的话,很容易就死游戏。NP保护了游戏进程的代码段,所以在NP启动后就不要再对其代码段进行修改,要

补丁或HOOK系统函数这些都要在NP启动前完成。当然读写游戏的数据段是没问题的,因为游戏本身也不断进行这样的操作。

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

收藏
点赞0
打赏
分享
最新回复 (68)
雪    币: 1005
活跃值: 活跃值 (249)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9521 活跃值 2007-1-4 13:37
2
0
呵呵,强文呀
雪    币: 195
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lsrh 活跃值 2007-1-4 13:38
3
0
精品必留名!
雪    币: 700
活跃值: 活跃值 (5945)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 活跃值 8 2007-1-4 13:38
4
1
文章很精彩!
排版换行上有些问题,一般这情况我是这样解决的,文本先写在记事本里,复制到论坛时,菜单“格式/自动换行”切换一下,再帖到论坛上,就不会出现楼主这情况。
雪    币: 159
活跃值: 活跃值 (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ldsjlm 活跃值 2007-1-4 13:51
5
0
感谢楼主得无私奉献,另外问下怎么能用OD调试被保护得进程
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
堀北真希 活跃值 1 2007-1-4 14:15
6
0
9521说是强文那应该是强文了
建议楼主分析一下np的sys吧
分析完了,几十行关键的C代码就可以写一个NP下读写游戏内存的工具了,纯3环,不用注入和CreateRemoteThread, 直接ZwReadVirtualMemory, ZwWriteVirtualMemory
雪    币: 1
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DW_DLL 活跃值 2007-1-4 14:58
7
0
又见 堕落天才 呵呵
雪    币: 1
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
DW_DLL 活跃值 2007-1-4 15:01
8
0
最初由 堀北真希 发布
9521说是强文那应该是强文了
建议楼主分析一下np的sys吧
分析完了,几十行关键的C代码就可以写一个NP下读写游戏内存的工具了,纯3环,不用注入和CreateRemoteThread, 直接ZwReadVirtualMemory, ZwWriteVirtualMemory


windows提供用户的API 内部实现都用了很多 "不知道的函数",在里面动动手脚就可以
雪    币: 1005
活跃值: 活跃值 (249)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9521 活跃值 2007-1-4 15:24
9
0
最初由 堀北真希 发布
9521说是强文那应该是强文了
建议楼主分析一下np的sys吧
分析完了,几十行关键的C代码就可以写一个NP下读写游戏内存的工具了,纯3环,不用注入和CreateRemoteThread, 直接ZwReadVirtualMemory, ZwWriteVirtualMemory


,堀北真希其实我是你的粉丝,np后门问答无用
雪    币: 1831
活跃值: 活跃值 (719)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2007-1-4 15:50
10
0
太强了,完全技巧型选手
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
林海雪原 活跃值 6 2007-1-4 16:05
11
0
最初由 海风月影 发布
太强了,完全技巧型选手


完全技术型选手!
雪    币: 182
活跃值: 活跃值 (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
justlovemm 活跃值 2007-1-4 16:14
12
0
顶一下,支持楼主再写一个直接读取的工具
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
古德里安 活跃值 2007-1-4 17:40
13
0
真是好帖子,估计NP快要升级了,呵,谢谢楼主,我还是希望在ring 0下破NP
雪    币: 1005
活跃值: 活跃值 (249)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9521 活跃值 2007-1-4 18:00
14
0
最初由 古德里安 发布
真是好帖子,估计NP快要升级了,呵,谢谢楼主,我还是希望在ring 0下破NP


可以简单搞定的事情,干吗要把他复杂话,ring0不是万能的
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
仙剑太郎 活跃值 2 2007-1-4 18:06
15
0
Originally posted by 堀北真希
9521说是强文那应该是强文了
建议楼主分析一下np的sys吧
分析完了,几十行关键的C代码就可以写一个NP下读写游戏内存的工具了,纯3环,不用注入和CreateRemoteThread, 直接ZwReadVirtualMemory, ZwWriteVirtualMemory

顶顶``
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
windblast 活跃值 2007-1-4 19:03
16
0
强人就是强人,昨天期待,今天又见精彩!
雪    币: 191
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
fishxz 活跃值 2007-1-4 19:25
17
0
没啥可说的,埋头苦学
雪    币: 111
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
无奈无赖 活跃值 2007-1-4 22:24
18
0
要是NP又升级了,又咋弄呢。
雪    币: 202
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Hitman 活跃值 2007-1-4 23:42
19
0
等魔力游悬赏了 我一定提供线索,呵呵 你这个做外挂的坏蛋
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhucheba 活跃值 2007-1-5 13:07
20
0
好文章,学习学习
雪    币: 356
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
stupidass 活跃值 2007-1-5 16:03
21
0
"其中的CommandLine好长啊,它要传递的参数是:一个被保护进程的pid,两个Event的Handle,以及当前timeGetTime的毫秒数"
我想问问,如果把其中的参数PID改变为你的外挂的进程ID会有什么结果?
雪    币: 201
活跃值: 活跃值 (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
酷酷 活跃值 2007-1-11 04:52
22
0
感谢楼主分享

以前分析的一点点有限笔记

打开gameguard.des hgg=2ec 校验后关闭
CreateProcess gameguard.des参数为:
1.时间 GetTickTime的后32位,去掉后20位
2.game name
3.互斥体句柄
4.事件句柄
5.game进程ID
6.0

CreateProcess GameDon.des参数
1=当前时间产生
2=
3=
4=标准输入句柄,管道二hReadPipe2   2c8
5=标准输出句柄,管道一hWritePipe1  2c4
6=游戏name
7=hEvent3
8=hEvent1
9

"其中的CommandLine好长啊,它要传递的参数是:一个被保护进程的pid,两个Event的Handle,以及当前timeGetTime的毫秒数"
我想问问,如果把其中的参数PID改变为你的外挂的进程ID会有什么结果?

CommandLine是经过二次加密后,然后format得到的一个串
在GameMon.des中,会判断game name,有黑名单,也有服务用户
雪    币: 2329
活跃值: 活跃值 (503)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
kagayaki 活跃值 2007-1-13 03:56
23
0
顶一下!!!
雪    币: 1
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
精灵猪 活跃值 2007-1-22 15:40
24
0
果然是大手笔
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sinshan 活跃值 2007-2-7 12:06
25
0
学习中, 现在非常讨厌这个nProtect
游客
登录 | 注册 方可回帖
返回