反調試——7——CRC檢測


反調試——7——CRC檢測

CRC32:

CRC的全稱是循環冗余校驗,作用是為了檢測數據的完整性。

CRC32的檢測原理:

程序被編譯后,代碼段是固定的,因為已經被寫死了。

我們在調試程序的時候,打斷點或者修改代碼都會影響CRC32的值,這個時候只需要檢測CRC32的某一時刻值和最初的CRC32值是否一致就可以判斷代碼是否被修改了。

如果裝了好壓這個軟件可以直接通過右鍵查看到CRC32的值:

 

 

這里我找了一個簡單的CRC32的代碼來測試一下:

#include<iostream>
uint32_t crc32_table[256];
int make_crc32_table()
{
   uint32_t c;
   int i = 0;
   int bit = 0;

   for (i = 0; i < 256; i++)
  {
       c = (uint32_t)i;

       for (bit = 0; bit < 8; bit++)
      {
           if (c & 1)
          {
               c = (c >> 1) ^ (0xEDB88320);
          }
           else
          {
               c = c >> 1;
          }

      }
       crc32_table[i] = c;
  }

   return 1;
}
uint32_t make_crc(unsigned char* string, uint32_t size)
{
   uint32_t crc= 0xFFFFFFFF;
   make_crc32_table();
   while (size--)
       crc = (crc >> 8) ^ (crc32_table[(crc ^ *string++) & 0xff]);

   return crc;
}

利用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檢測。要想逆一個東西,知道這個東西的原理再來逆會非常方便。

小結

CRC有點類似於hash函數,就是把一坨東西來計算一個值出來,由於一個程序寫好了之后代碼段是不會改變的,所以我們可以把它用來計算代碼段的內容,然后再程序里面時刻計算這個值有沒有改變來判斷是否被修改了代碼。

  完整代碼:反調試--CRC檢測 - Sna1lGo - 博客園 (cnblogs.com)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM