基于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

转载于:https://my.oschina.net/iwuyang/blog/198610

猜你喜欢

转载自blog.csdn.net/weixin_33860528/article/details/91897376
今日推荐