測試環(huán)境:XP3
編譯環(huán)境:VS2005
一般的程序保護(hù)中監(jiān)測代碼只檢查程序中的代碼是否遭到了篡改是不夠的, 應(yīng)監(jiān)測代碼相互之間也要進(jìn)行防篡改檢查, 如果監(jiān)測代碼相互之間不進(jìn)行防篡改檢查, 就會很容易地被攻擊者各個擊破,
代碼保護(hù)之網(wǎng)
。將被檢查的代碼區(qū)域組成一張網(wǎng), 組成這張網(wǎng)的代碼區(qū)域可以是程序中的代碼, 也可以是監(jiān)測代碼或者響應(yīng)代碼, 監(jiān)測代碼計算一或多個代碼區(qū)域的HASH值, 一旦監(jiān)測代碼發(fā)現(xiàn)某個區(qū)域中的代碼遭到了篡改, 響應(yīng)代碼就會用存放在其他地方的備份代碼替換掉該區(qū)域中的代碼(或者做其它事), 多個監(jiān)測代碼可以檢查同一個區(qū)域, 這樣可能通過增加監(jiān)測和響應(yīng)代碼的數(shù)量或者使它們之間關(guān)系變得更為復(fù)雜.
下面是簡單的小示例:
1.要計算某個函的的hash值,得獲得該函數(shù)大小.
代碼:
//獲取函數(shù)的大小: 參數(shù) address 指向函數(shù)的起始地址uint32 GetFunSize(addr_t address){ BYTE Fun_end[] = {0x88, 0x88, 0x88, 0x88}; //函數(shù)結(jié)尾的標(biāo)志 uint32 Fun_size = 0; while(TRUE) { if(!memcmp((BYTE*)address + Fun_size, Fun_end, sizeof(Fun_end))) //找到結(jié)束標(biāo)志 { while(TRUE) { if ( 0XC3 == *((BYTE*)address+ Fun_size))//找到返回 { return Fun_size; } Fun_size++; } } Fun_size++; }}
2.計算函數(shù)hash值.
代碼:
//獲取Hash值: 參數(shù) address 指向函數(shù)的起始地址, Size函數(shù)大小uint32 hash(addr_t addr, int Size){ if (NULL == addr || 0 == Size) { return 0; } uint32 h = *addr; for (int i=1; i<Size; i++) { addr++; h ^= *addr;; } return h;}
3.簡單調(diào)用,監(jiān)測是否被修改,如果遭到了篡改,拷貝備份好的修復(fù).
代碼:
int Decrypt(int User_Key, int Data){ DWORD lpflOldProtect = 0; uint32 FunSize = GetFunSize((addr_t)GetKey); uint32 hGetKeyVal = hash((addr_t)GetKey, FunSize); printf("GetKey 大小為 : %X\n",FunSize); printf("GetKey HASH為 : %X\n",hGetKeyVal); //判斷是否被修改,被修改后恢復(fù) if( hGetKeyVal != GetKeyHASH ) { //將備份函數(shù)拷過去 VirtualProtect(GetKey,FunSize, PAGE_EXECUTE_READWRITE, &lpflOldProtect); memcpy(GetKey, GetKey_Back, FunSize); VirtualProtect(GetKey,FunSize, lpflOldProtect, &lpflOldProtect); } int key = GetKey(User_Key); __asm { JMP END _emit 0x88 _emit 0x88 _emit 0x88 _emit 0x88 }END: return Data ^ key;}
4.運(yùn)行成功后如下圖所示
5.具體請看源碼
http://up./2013/1011/20131011020536403.rar
http://up./2013/1011/20131011020538143.zip