基於crc32實現的內存的代碼校驗



原理:

a,crc32函數的實現

b,內存校驗:顧名思義,運行在內存代碼通過crc32得到一個值,當第二次運行可執行文件的時候,可以把第一次保存下來的值和第二次運行的結果相比較,從而根據比較結果判斷時候內存數據吧被修改。

 

1,crc32算法的實現部分:

DWORD CRC32(BYTE* ptr,DWORD Size)
{
  
       DWORDcrcTable[256],crcTmp1;
      
       //動態生成CRC-32表
       for(int i=0; i<256; i++)
        {
              crcTmp1 = i;
              for (int j=8; j>0; j--)
               {
                     if(crcTmp1&1) crcTmp1 = (crcTmp1 >> 1) ^ 0xEDB88320L;
                      else crcTmp1 >>= 1;
              }
 
               crcTable[i] = crcTmp1;
        }
       //計算CRC32值
       DWORDcrcTmp2= 0xFFFFFFFF;
       while(Size--)
       {
              crcTmp2 = ((crcTmp2>>8) &0x00FFFFFF) ^ crcTable[ (crcTmp2^(*ptr)) & 0xFF ];
              ptr++;
       }
      
       return(crcTmp2^0xFFFFFFFF);
}


2,代碼實現:

A,要保護的代碼:

ProtectStart:   //要保護的代碼的起始地址
       __asm
       {
              inc eax  //花指令
                dec eax
                push eax
                pop eax
       }
start:
          HMODULE hMod = GetModuleHandle(NULL);//同樣是花指令
          HMODULE hUser32 =LoadLibrary("user32.dll");
ProtectEnd:               //要保護代碼的終結地址
          DWORD dwThreadId = 0;
 
          STBINGLEPARAM stParam = {0};
      stParam.hEvent = CreateEvent(NULL,FALSE,FALSE,"bingle");
         
          DWORD dwAddr = 0;  //一個緩存空間
          __asm mov eax,offset ProtectStart  //計算代碼的起始地址
          __asm mov dwAddr,eax
          stParam.dwStart = dwAddr; //保存在我們自己定義的結構體裏
 
      __asm mov eax,offset ProtectEnd //計算保護代碼的結束地址,同樣保存在自己定義的                   結構體裏。
          __asm mov dwAddr,eax
          stParam.dwEnd = dwAddr;
         
          printf("開始了\n");
           CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)bingleProc,(LPVOID)&stParam,0,&dwThreadId);


B,創建了一個線程,用來計算校驗值。並且將線程的創建放在循環中,這樣保證在程序運行的過程中,會不斷的監視內存的數據是否改變。

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)bingleProc,(LPVOID)&stParam,0,&dwThreadId);
 
          DWORD dwRet = 0;
          dwRet =WaitForSingleObject(stParam.hEvent,INFINITE);
          while(dwRet == WAIT_OBJECT_0)
          {
              Sleep(5000);
          CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)bingleProc,(LPVOID)&stParam,0,&dwThreadId);
                dwRet = WaitForSingleObject(stParam.hEvent,INFINITE);
          }


上邊的代碼是創建線程的,根據創建線程的返回值來作爲循環條件。其中stParam是我自定義結構體生成的一個對象。這個對象保存在堆棧中。該結構體的定義如下:

#pragma pack(1)
typedef struct __STBINGLEPARAM
{
 HANDLE hEvent;  //用於同步的一個信號量
 DWORD dwStart;  //要校驗的代碼的起始地址
 DWORD dwEnd;   //要校驗的代碼的終結地址
}STBINGLEPARAM,*PBINGLEPARAM;
#pragma pack()


 

接下來是是線程函數了。

STBINGLEPARAM *stParam = (STBINGLEPARAM*)lpParameter;
  
       DWORDdwCodeSize = stParam->dwEnd - stParam->dwStart;
       BYTE*pbyteBuf = NULL;
       pbyteBuf= (BYTE *)stParam->dwStart;
      
       DWORDdwOldProtect = 0;
       VirtualProtect((LPVOID)stParam->dwStart,4*1024,PAGE_EXECUTE_READWRITE,&dwOldProtect);
       if(CRC32(pbyteBuf,dwCodeSize)!= 0xa0eb5866)
       {
          MessageBox(NULL,"bingle","代碼被修改了",NULL);
          printf("代碼被修改了\n");
 
          SetEvent(stParam->hEvent);
          ExitProcess(0);
       }
 
 
       SetEvent(stParam->hEvent);//執行完上邊的代碼開始傳信,讓主線程繼續運行



在這裏要說的是中的0xa0eb5866,這個是我在od中讓代碼運行起來找到的。

在創建的線程函數體中找到0x40100a,ctrl+g來到這個地址,F2下斷點,然後就來到線程函數了。

一直往下找,找到比較代碼cmpeax,0xa0eb5866這一句,把這個地址保存下來,就是我們要校驗的地址。可以直接用在代碼中。。

 

3,測試:

讓debug版本的程序運行起來,ce附加進程。

點擊Memory View,定位到我們要保護的代碼段。



找到我們要保護的代碼,然後用ce修改一下內存的數值試試,我想修改0x40127a。只要這個內存地址在我們要保護的代碼中就可以。

哈哈哈,還不錯吧。內存校驗不難吧。

轉自:http://bbs.pediy.com/showthread.php?t=140471

發佈了28 篇原創文章 · 獲贊 27 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章