基於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
相關文章
- 關於程式的實體記憶體RSS記憶體
- Go實戰 | 基於本地記憶體的快取的應用及實現Go記憶體快取
- oracle實驗記錄 關於記憶體的幾個viewOracle記憶體View
- js實現的信用卡校驗程式碼例項JS
- CRC32碰撞的實現
- SpringBoot SpringSecurity 介紹(基於記憶體的驗證)Spring BootGse記憶體
- java記憶體模型的實現Java記憶體模型
- 程式間通訊——基於共享記憶體和訊號量實現共享佇列記憶體佇列
- 7.7 實現程式記憶體讀寫記憶體
- 一百行js程式碼實現一個校驗工具JS
- C++記憶體管理:簡易記憶體池的實現C++記憶體
- 伺服器報記憶體奇偶校驗錯誤!伺服器記憶體
- leveldb原始碼分析(1)--arena記憶體池的實現原始碼記憶體
- 在 Go 專案中基於本地記憶體快取的實現及應用Go記憶體快取
- 【Java基礎】實體記憶體&虛擬記憶體Java記憶體
- CRC冗餘校驗碼的介紹和實現
- 如何編碼實現記憶體洩露記憶體洩露
- 如何編碼實現記憶體溢位記憶體溢位
- 7.1 實現程式記憶體塊列舉記憶體
- 記憶體管理篇——實體記憶體的管理記憶體
- 精準實現身份證號碼格式校驗程式碼例項
- Redis的記憶體和實現機制Redis記憶體
- 分析高效記憶體池的實現方式記憶體
- Linux共享記憶體的核心實現Linux記憶體
- java程式碼實現檢視Tomcat記憶體使用情況JavaTomcat記憶體
- Java 常見記憶體溢位異常與程式碼實現Java記憶體溢位
- node實現基於token的身份驗證
- QuarkUI基於AntDesignPro的低程式碼引擎,歡迎大家體驗!UI
- CRC校驗原理簡介及C程式碼實現說明C程式
- 基於YOLO實現滑塊驗證碼破解YOLO
- 程式的記憶體模型記憶體模型
- 基於MySql主從分離的程式碼層實現MySql
- MixPHP:基於 Swoole 的常駐記憶體型 PHP 框架PHP記憶體框架
- 一種基於記憶體的檔案系統tmpfs記憶體
- C++記憶體池的實現例項C++記憶體
- 實現基於內容的電影推薦系統—程式碼實現
- C實現奇偶校驗
- 高階記憶體管理程式設計指南-實用的記憶管理記憶體程式設計