CRC detection of software security

CRC introduction

When playing some games, such as fps games, you want to modify some specific values ​​to achieve some functions. At this time, your account or even the machine code may be banned. Because you changed the data in the game, which caused the receiver to receive "wrong data". In order to improve the accuracy of the data received by the receiver as much as possible, it is necessary to perform error detection on the data before receiving the data. This kind of detection is what we call CRC detection.

CRC is also called Cyclic Redundancy Check Code. It belongs to a class of cryptography algorithms and is often used for data verification. It is generally used to detect whether the program has been unpacked or modified to achieve the purpose of preventing cracking. The CRC operation is actually to perform a modulo 2 operation on the data k to obtain the remainder n, and then splicing n to the back of k to generate k+n as the word length of the cyclic redundancy check code. Then send k+n to the receiver as the dividend and perform modulo 2 calculation to judge whether the remainder is 0. If the remainder is not 0, the CRC detects that the data has been modified. To put it simply, it is to perform cyclic XOR processing on the data to be verified and the generator polynomial.

PS:

1. The sender and the receiver will agree on a specific divisor, which is a fixed value, and we also call the divisor a generator polynomial.

2. When calculating the remainder, the dividend, that is, the data k, needs to be supplemented with 0s, and the number of supplemented 0s is the length of the generator polynomial - 1 zeros.

3. The length of the remainder must be consistent with the length of zero padding

flow chart:

Image

Having said so much, it is better to give an example to understand

Example 1: The data here is 1110101, and the generator polynomial is 101, then the data we want to pass to the receiver is 1110101 (data) + 10 (remainder) = 111010110

image-20230314201253238

This is the calculation principle of CRC

Two ways of CRC calculation

1. Direct calculation method

Here we explain through examples, Example 2:

image-20230314201309003

First we see that the generated item here is 1101, and then the divisor in the calculation (marked in blue font) is mostly 1101 and sometimes 0000. When the divisor is 1101, the first digit of the dividend is 1, and when the first digit is not 1, it is 0000. Then we might as well make an assumption, since the first digit of the dividend and the divisor will be eliminated when it is 1, then we don’t need four-bit XOR, and change it to three-bit XOR. And the last three digits of the divisor, when the first digit of the dividend is 1, move one bit to the left to let the new three digits XOR with the last three digits of the divisor (generated item); when the digit shifted out of the dividend is 0, XOR 000, and then Repeat this step until complete. (Here is for this example, when your generated item is n, you take n-1 bit XOR)

Then someone will ask how many times it needs to be repeated before it is over?

The number of processing times = the number of digits to be processed (the number of digits of the dividend) = the number of digits of the quotient (the number of times for this question is 6 times)

For example, the divisor of this question is 100 for the first time, shifted one bit to the left to get 001, then XOR with 101 to get 100. Shift 100 to the left by one bit to get 000, then XOR with 101 to get 101. Shift 101 to the left one bit to get 010, then XOR with 101 Get 111. Shift 111 to the left to get 110, then XOR with 101 to get 011. Shift 011 to the left to get 110, then XOR with 000 to get 110 (XOR value with 000 remains unchanged). Shift 110 to the left by one bit to get 100 and XOR with 101 to get 001 to get the remainder exactly 6 times.

To help you study cybersecurity, you can receive a full set of information for free:
① Mind map of cybersecurity learning and growth path
② 60+ classic cybersecurity toolkits
③ 100+ SRC analysis reports
④ 150+ e-books on cybersecurity attack and defense techniques
⑤ The most authoritative CISSP Certification Exam Guide + Question Bank
⑥ More than 1800 pages of CTF Practical Skills Manual
⑦ Collection of the latest interview questions from network security companies (including answers)
⑧ APP Client Security Testing Guide (Android+IOS)

2. Drive table method

The driving table method is not as intuitive as the direct calculation method, but the efficiency is higher than the direct calculation method. So how to realize it? We know that the direct calculation method is to get the result step by step from top to bottom by XOR. During the calculation process, there will be many generated items of XOR, and the generated items are unchanged. So can it be calculated in advance and the previous few data What about the sum of the corresponding generated items and then XOR?

Then we calculate all the generated items in the range of 0000 0000 ~ 1111 1111 and store them as a table. When calculating, take the first byte of the data for indexing, find the XOR sum of the corresponding generated items in the table, and compare the data with the first byte removed. XOR will do.

table formation

Finally, we are over to the table. Here we use the algorithm to realize the table, so that you can clearly understand its principle. Here we take the formation of the CRC32 table as an example. First, we must understand what the generated items of the CRC32 are.

Image

If you want to know more about CRC and its generator polynomial, you can go here: http://www.ip33.com/crc.html

#include <windows.h>
#include <stdio.h>

int main()
{
    DWORD crc;
    for (DWORD i = 0; i < 256; i++)//256个元素
    {
        crc = i;
        for (DWORD k = 0; k < 8; k++)//因为这里异或是从数据的高位开始,所以需要计算的数据左移8位,这里就需要计算8次
        {
            if (crc & 1)//判断最高位是否为1
                crc = (crc >> 1) ^ 0xEDB88320;//最高位为1,右移一位,然后与0xEDB88320异或   
            else
                crc = crc >> 1;//最高位为0时,不用异或,整体数据右移一位。相当于例子2中110与000异或值是不变的
        }
        printf ("0x%08x, ", crc);
        if (((i+1)%6) == NULL )
            printf ("\n");
    }
}

/*CRC32表
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
*/

Pay attention to the right shift marked in red here. If it is based on the direct calculation method here, shouldn’t it be shifted to the left? Why is it shifted to the right again?

Image

Pay attention to the second-to-last of this table, CRC32, its input and output need to be reversed, which is equivalent to reverse, we have to modify the left shift to right shift

Of course, some people will ask if its polynomial should not be 0x04C11DB7, why it becomes 0xEDB88320 again?

This is because 0xEDB88320 is the inverse of 0x04C11DB7. The generation of this table is very simple. Generally, the inverted polynomial 0xEDB88320 is used. If the normal polynomial 0x04C11DB7 is used, bits must be swapped, which is obviously very troublesome.

Do a CRC detection program

I believe that everyone can almost understand the general process of CRC implementation. The above is mainly a general understanding of CRC, but what we really need to understand is CRC32. CRC32 is often used in games and some compression tools such as ARJ and LHA, so let's write a CRC32 detection program next.

#include <windows.h>
#include <stdio.h>
 
DWORD crc32_table[256];
 
void CRC32_Table()
{ 
    DWORD crc;
    //DWORD crc32_table[256];
    for (int i = 0; i < 256; i++)
    {
        crc = i;
        for (DWORD k = 0; k < 8; k++)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xEDB88320; 
            else
                crc >>= 1;
        }
        crc32_table[i] = crc; //生成并存储CRC32数据表
    }
}
 
//根据CRC32表计算CRC校验码
DWORD Check_CRC32(DWORD crc, PUCHAR Data, DWORD len)
{
    crc = 0xFFFFFFFF; //将CRC初始化为-1
    CRC32_Table();
    for (DWORD i = 0; i < len; i++)
    {
        crc = (crc >> 8) ^ crc32_table[(crc ^ Data[i]) & 0xff];
    }
    return ~crc;//输出的反转
}
 
int main()
{
    SetConsoleTitle("CRC32检测器");
    printf("开始检测"); 
    //初始内存校验值
    DWORD Original_CRC32 = Check_CRC32(0, (PUCHAR)0x400000, 0x112000);

    while (1)
    {
        //CRC循环校验实现实时检测
        DWORD Cycle_CRC32 = Check_CRC32(0, (PUCHAR)0x400000, 0x112000);//这里第二个参数是基址,第三个个参数是一个校验的范围,也就是程序主模块镜像大小。
 
        if (Cycle_CRC32 != Original_CRC32)
        {
            MessageBoxA(NULL, "已检测到您修改了代码!", "警告", MB_YESNO);
        }
        //为了防止频繁弹出信息框,这里使用的Sleep函数控制检测的周期,每5s弹出一次
        Sleep(5000);
    }
    getchar();
}

image-20230316204239892

The initialization here is because the content and length of the data to be tested are random. If the initial value of the register is 0, then the byte to be tested is 0x00 of 1 byte, and the byte to be tested is 0x00 of N bytes, and the calculated CRC32 The values ​​are all 0, then the CRC value is meaningless! So the register is initialized with 0xFFFFFFFF to avoid this problem

Image

The file size here corresponds to the size of the main module image

Whether the practice can be successful

Here we use CE to modify the data

Image

Image

Here we first manually add the address, and then change the value, I changed it to 11111 here, and then a warning popped up after 5 seconds. It can be seen that the detection program was successful!

Of course, some basic people will ask, isn’t CRC a code detection, why can you modify the value here and also detect it?

Because the CRC is implemented in the code segment, there is no substantial difference between the data and the code in memory.

Guess you like

Origin blog.csdn.net/qq_38154820/article/details/130226906
Recommended