Analysis and production of game plug-ins and Analysis of game plug-ins
This chapter aims to explain the implementation principles of plug-ins and does not go deep into the code layer. I hope that I can communicate with more friends who are interested in this aspect. After all, the theory is dead and the routines are fixed. Only the experience in cracking is time-consuming and painstaking efforts.
- For standalone gamesThe vast majority of parameters (such as blood, Blue, energy, or gold coins) in the game are stored in the computer stack, if the progress is similar to the plot, the data is encrypted and written to the local custom configuration file;
- For web games, online games, and mobile gamesAlthough the server saves a large number of important parameters, the local memory must have some temporary variables because the client inevitably needs to load a large number of computing and resources, by judging the variation rules of these variables and the password-breaking function, find the parameters that benefit you, such as the damage value, and then find the memory address of the variable, and obtain the memory base address based on the pointer offset analysis, you can use the Windows API to write custom values to the memory block. Then, you can modify a value. Generally, you only need to crack a value, it is easier to crack other values by using the regular expression.
The general rule is the above. Some highly defensive games will set up difficulties in each of the above steps, waiting for us to crack them.
Before that, let's take a look at some basic knowledge:
- Data Type: The amount of blood, blue, and life in the game. We call them variables. variables include variable names and data types, and their names are "blood volume, life value", etc, the data type determines the method in which the value is stored in the computer's memory and the variables needed by the computer, if you can determine the Data Type of the variable or narrow the data type range of the variable based on speculation, it is helpful to quickly locate the variable. The following are common variable types:
Integer: this type may be used in games, such as blood volume and mana.
Byte: according to different editors, an integer occupies N Bytes (N> 1). This type is generally used in GBA games that were produced a long time ago to save costs.
Floating Point: a number with a decimal point. If a gold coin or damage value has a decimal point, it is likely to be stored in this data type.
Text Type: for example, the world call and name of a person, the text type is generally used to store such data.
We recommend that you read the data structure related books to better familiarize yourself with the data structure. If you have programming experience, you don't have to say much.
- Process: Each application/game is started, at least one Process is generated, and the Process name and PID are displayed in the task manager.
- Handle: HANDLE, an integer. The data address needs to be changed. After the change, someone needs to record the management changes, just like household registration management. Therefore, the system uses a handle to record the changes to the data address. Each folder, window, button, icon, and application can access the corresponding object information through a handle.
We recommend that you read books related to computer operating systems to learn more about computer principles.
Go to the topic and find out the information to be obtained based on the reverse direction of the objective, so that we can finally modify the value.
Modify the value of the variable → first find the memory address of the storage variable → first find the handle of the game window → first find the game process.
What is the basis for exporting routes?
The kernel32.dll library file of the Windows system library contains the memory operation API.VirtualQueryExThis interface is used to query the memory address information in the address space.
Function prototype:
/// <Summary> /// query the memory address storage information in the address space // </summary> /// <param name = "hProcess"> handle </param> /// <param name = "lpAddress"> memory address </param> /// <param name = "lpBuffer"> struct pointer </param> /// <param name = "dwLength"> struct size </param> // <returns> Number of written bytes </returns> [DllImport ("kernel32.dll")] public static extern int VirtualQueryEx (IntPtr hProcess, IntPtr lpAddress, out MEMORY_BASIC_INFORMATION lpBuffer, int dwLength );
We will analyze the parameters one by one:
HProcess: As the name implies, the Process Handle. to query the information stored by the address, you must first obtain the process handle.
LpAddress: the memory address to be queried. Enter the parameter and provide the address. But we do not know the address where the value is stored. We can only guess one page at a time, the information stored in a memory on a page is exactly the same as the information we need or has a function relationship. Second, the same value may appear in multiple places. For example, if the attack value of a person in a certain time range is equivalent to the defense value of 1200, it means that at least two addresses store the data. We need to filter out all these addresses.
LpBuffer: struct pointer, used to store memory information.
DwLength: the size of the struct.
Return Value: the number of bytes that the function writes to lpBuffer. If the number of bytes is equal to the size of the PMEMORY_BASIC_INFORMATION struct, the function is successfully executed.
However, this function is only responsible for obtaining memory information, while the specific stored values in the query memory information are used by another function.ReadProcessMemoryLet's take a look at the function prototype:
/// <Summary> /// read a memory space of the process according to the Process Handle /// </summary> /// <param name = "lpProcess"> Process Handle </param> /// <param name = "lpBaseAddress"> Start address of memory read </param> /// <param name = "lpBuffer"> write address </param> /// <param name = "nSize"> Number of written bytes </param> /// <param name = "BytesRead"> actual number of transmitted bytes </param> // /<returns> Read result </returns> [DllImportAttribute ("kernel32.dll ", entryPoint = "ReadProcessMemory")] public static extern bool ReadProcessMemory (IntPtr lpProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, IntPtr BytesRead );
This function reads a memory space of the process based on the handle, and writes the number of bytes read to a space we have opened, this space stores the "meaningful values" that we are struggling to find ". Some parameters of this function depend on the results produced by the previous VirtualQueryEx function.
Based on the above API, Let's first look at how to obtain the first parameter:Form handle, The same kernel32.dll providesOpenProcessTo open an existing process object and return the process handle.
Function prototype:
/// <Summary> /// open an existing process object, and return the Process Handle /// </summary> /// <param name = "iAccess"> desired access permission </param> /// <param name =" handle "> inherit Handle </param> /// <param name =" ProcessID "> process PID </param> /// <returns> Process Handle </returns> [DllImportAttribute ("kernel32.dll ", entryPoint = "OpenProcess")] public static extern IntPtr OpenProcess (int iAccess, bool Handle, int ProcessID );
DwDesiredAccess: the desired access permission. PROCESS_ALL_ACCESS | 0x1F0FFF is used by default to grant all possible permissions.
BInheritHandle: whether to inherit the handle. Set this parameter to FALSE.
DwProcessId: process identifier PID.
For various programming languages of the Process PID, you can use the C # language as an example (for non-Multi-open clients ):
// Obtain the PID public int GetPIDByPName (string ProcessName) {Process [] ArrayProcess = Process based on the Process name. getProcessesByName (processName); foreach (Process pro in ArrayProcess) {return pro. id;} return-1 ;}
After obtaining the PID of the process, we can call OpenProcess to obtain the form handle. Then, we can use the VirtualQueryEx function to traverse the memory to find the address information and use ReadProcessMemory to find the specific stored value based on the address, at last, WriteProcessMemory is used to write the modified value to this address. This completes a data modification. Let's take a look at the function prototype of the API:
/// <Summary> /// write the memory area of a process // </summary> /// <param name = "lpProcess"> Process Handle </param> /// <param name = "lpBaseAddress"> first address of the written memory </param> /// <param name = "lpBuffer"> pointer to the written data </param>/ // <param name = "nSize"> Number of bytes written </param> // <param name = "BytesWrite"> pointer to the actual number of bytes written </param> // /<returns> greater than 0 indicates success </returns> [DllImportAttribute ("kernel32.dll ", entryPoint = "WriteProcessMemory")] public static extern bool WriteProcessMemory (IntPtr lpProcess, IntPtr lpBaseAddress, int [] lpBuffer, int nSize, IntPtr BytesWrite );
The parameters are not explained one by one. Annotations are provided. The last parameter is Null or IntPtr. ZeroI by default.
At this point, the principles and routines of modifying game values have been quite clear. Even in terms of the game, if any application does not properly encrypt the data in the cache, there are great risks. This chapter mainly describes some common terms and the use of APIs. The next section describes how to use code to call APIs and analyze the logic of each step in more detail.
PS: Reprint Please attach the original path: http://www.cnblogs.com/lene-y/p/7096485.html, I have commissioned the "server guard" for my article to protect rights.
You are welcome to pay attention to the public account [analysis and production of game plug-ins]. If you have any questions or different opinions about this article, please leave a message and make a reply.