(收藏) 如何在nProtect下讀寫遊戲記憶體及如何進入nProtect進程

來源:互聯網
上載者:User
標 題: 如何在NP下讀寫遊戲記憶體及如何進入NP進程
作 者: 墮落天才
時 間: 2007-01-04,13:28
鏈 接: http://bbs.pediy.com/showthread.php?t=37417

   在上一篇文章《反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啟動前完成。當然讀寫遊戲的資料區段是沒問題的,因為遊戲本身也不斷進行這樣的操作。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.