原理:
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