CRC32:
CRC的全稱是循環冗余校驗,作用是為了檢測數據的完整性。
CRC32的檢測原理:
程序被編譯后,代碼段是固定的,因為已經被寫死了。
我們在調試程序的時候,打斷點或者修改代碼都會影響CRC32的值,這個時候只需要檢測CRC32的某一時刻值和最初的CRC32值是否一致就可以判斷代碼是否被修改了。
如果裝了好壓這個軟件可以直接通過右鍵查看到CRC32的值:
這里我找了一個簡單的CRC32的代碼來測試一下:
利用CRC32檢測自己程序是否被修改:
通過對代碼段進行CRC32判斷來處理。首先要拿到代碼段,通過Windows 的PE文件的結構體 Dos頭->NT頭->(采用VS里的結構體)拿到區段頭->然后通過區段頭得到區段的信息。
char *buffer=(char*)GetModuleHandleA(0);//參數為0就獲取當前進程的句柄
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + buffer);
PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader);
for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections - 1; i++)
{
}
判斷是否是代碼段:
代碼段顧名思義,就是執行代碼的東西。在PE文件中的區段頭里有一個字段可以判斷屬性:
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;//這個
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER
Characteristics這個字段標識了是否是可執行。在CFF里面查看:
這里通過我的測試,在修改可讀可寫的屬性時會修改最高字段的值,如果有就加2,然后別的就修改別的值,所以這里我們判斷首位是不是6就可以判斷是不是代碼段了。
void Crc32Test() { char *buffer=(char*)GetModuleHandleA(0);//參數為0就獲取當前進程的句柄 PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)buffer; PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + buffer); PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader); for (int i = 0; i < pNtHeader->FileHeader.NumberOfSections - 1; i++) { if (pSectionHeader->Characteristics / 0x10000000 == 6) { cout << pSectionHeader->Name << endl; auto CrcNum = make_crc((unsigned char*)(pSectionHeader->VirtualAddress + buffer), pSectionHeader->Misc.VirtualSize); cout << CrcNum << endl; } pSectionHeader++; } }
然后通過ollydbg隨便打一個int3斷點(因為int3斷點會添加一個CC在里面所以肯定的改變了代碼段的內容的)再運行來看CRC的值是否改變:
這里果然是改變了。
過CRC檢測
因為CRC的原理是要掃描你的整個代碼段,那么可以通過CE工具來通過代碼段的地址,查看是誰訪問了該代碼段,由此來找到CRC檢測的函數,從而進行魔改通過CRC檢測。要想逆一個東西,知道這個東西的原理再來逆會非常方便。
小結