On the development principle of game plug-in -- Taking plant vs zombie memory as an example

Posted by faheemhameed on Wed, 09 Feb 2022 08:34:33 +0100

preface

I'm a little interested in plug-ins and get to know them

1, Game plug-in development principle

1. Plug in classification

Plug ins are generally divided into three types: analog keys, WPE packets and memory

  • Simulate the keyboard and mouse. This is called key simulation, also known as script wizard
  • Modifying data packets is called WPE packet plug-in. This plug-in is relatively stable, but it is also difficult for technical requirements. Because modifying WPE packets, you need to know and understand a series of knowledge such as encryption and decryption algorithms
  • It is relatively common to modify local memory. It is also a common game plug-in in the market. Relatively speaking, the technical requirements are not too high, and the data are relatively complete and popular

It is rare to modify the server memory. The technology is too high. Most people can't start with it

2. Memory hang

Button Simulation online script or more
WPE packets are reserved for later study
This article mainly studies the memory hanging

In fact, it's not very difficult to make a memory hook. There are only a few steps

  • Find the memory address and offset address of game data
  • Modify the value of memory address to achieve the purpose of plug-in
  • Write a program with programming language, which makes the plug-in convenient for carrying and transmission, and also convenient for direct use in the next game

In fact, the third step is to make it easy to use and sell. Most of the time, for an expert, there is no need to write it down. After recording the memory address and offsetting the address, you can modify it directly in the tool next time you go to the game. But if you often play a game, you can write it out without having to modify it every time you play the game.

2, Developing a memory hook -- Taking plants vs zombies as an example

1. Find game memory address

(1) Memory base address and physical address

Find the game memory address and offset address, which may be the most difficult step in the development of the whole game plug-in, because for a large online game, the memory base address of a skill or blood bar may be offset many times, and finally get a memory address, also known as the physical address

So, here's a question. Why should we find the memory base address of skill or blood bar? Isn't it just to modify the physical address directly? This is not possible, because the physical address will change; For example, every time the game is closed and restarted, the game process will change. Similarly, the storage location of the game code in the memory will change because the memory address is released after the game is over, and this memory address may be occupied by other programs, so it will change; When you close the game and re-enter, the physical address of the game skill or blood bar in memory will change. However, the memory base address of game skills or blood bars will not change. No matter how the physical address in memory changes, the memory base address will not change

So what is the relationship between memory base address and physical address? Look at the following formula:

Physical address = Primary offset address + Offset address
 Primary offset address = Secondary offset address + Offset address
 Secondary offset address = Tertiary offset address + Offset address
 Three level address offset = Game skill base address + Offset address

According to the above formula, the physical address of a game is equal to the base address of the game plus the offset address. Therefore, if you want to find the exact physical address and modify the value of the memory address every time you re-enter the game to achieve the purpose of plug-in, you must find the offset address and base address corresponding to the current physical address, Only in this way can we ensure that the value of the physical address can be modified every time we log in to the game.

(2) Using CE to find memory base address

First of all, we introduce a tool to find the base address of game memory, Cheat Engine, abbreviated as CE. Cheat Engine is a memory modification and editing tool, which allows you to modify the memory data of games or software to get some other functions. It includes hexadecimal editing, disassembly program and memory search tool. Compared with similar modification tools, it has powerful disassembly function, and it comes with a plug-in production tool, which can be used to directly generate plug-ins.

Next, open plants vs zombies, open CE, find plants vs zombies in CE and attach them to CE, as shown in the figure:


After the game is attached to CE, you can find the corresponding memory base address to see where you want to modify the content. How to find it?

For example, infinite sunshine; First of all, what is the initial sunshine? For example, if the opening sunshine is 50, enter 50 in the value item of CE, select the exact value for the scanning type, select 4 bytes for the value type, and then click the first search, as shown in the figure:


As shown in the figure above, there are so many addresses. Which one is the physical address we want? Next, you need to change the value of sunshine in the game, and then click search again, and the results will come out, as shown in the figure:



As shown in the second figure above, the physical address we want comes out. Add this address to the address list, and then modify the value of sunshine to confirm whether it is the desired address. However, it should be noted that when modifying, we need to click the value column of the line we pulled down in the address list, Others are used to modify the address and byte type. Do not move, as shown in the figure:

As shown in the figure above, this is the physical address we want. Here we can lock the value of this memory address, which is always 100 or 200 or more. Just click the previous activation column to select it, so as to achieve the effect of locking the sun value

But when you close the game and re-enter, this address is useless and needs to be found again. Therefore, we need to find the base address and offset address of the real sunshine value here. Then, how to find it? After we find the physical address, right-click and select to find out what rewrites the address, that is, the shortcut key F6. The Chinese effect of each version is different. A window will pop up here, which is blank. Then we will change the value of sunshine in the game and see the code in the blank window, as shown in the figure:



As shown in Figure 3 above, after analyzing these two codes, we can see that they finally point to a pointer value 17C88118

  • First, analyze the mov [edi+00005560],esi instruction. We can see in the details that the code in the register esi is 000026DE, and the value is exactly 9950 in decimal system. So how does this 9950 come from? In fact, when I was just doing the last step, I said to change the sunshine value in the game, so I first directly changed the sunshine value to 10000, and then planted a stone, which is exactly 50, so the sunshine value changed. This instruction mov [edi+00005560],esi is to put the sunshine value of 9950 in the register esi into the address edi+00005560. Who is this address? This address is the physical address just found, which just meets the previous formula: physical address = sunshine base address + offset address
  • Next, take a look at the add [eax+00005560] and ecx instructions. The add instruction means adding, and the previous mov means assigning or moving. The meaning of this code is to add the value in the ecx register to the value in the address of [eax+00005560], and then look at the address of register eax? It happens to be the pointer value of 17C88118 again. Then, we can determine one thing, that is, the pointer value of 17C88118 must be the pointer value of the address of the upper level. Then the upper level is either the base address or an offset address. This needs to be further confirmed
  • Put the pointer value of 17C88118 into ce again to search for a wave. See what the address corresponding to this value is, and see whether it is a dynamic address or a static address (in CE, the black address represents the dynamic address, and the green represents the static address). This value is hexadecimal, so when searching, you need to check hex in front of the search box, Click the new scan after filling in here. The first scan is as shown in the figure:


Click Scan again to filter out these red addresses, and then look at the remaining addresses, as shown in the figure:


After multiple clicks and scanning again, I found that 52 results were left no matter how clicked. Then I looked at these results. There was no green static address, and the first few digits of other addresses were more similar, but as shown in the figure, the two addresses were special, which may be the addresses we need

Baidu made a wave. The result is that the beginning is more like an array, that is, when we encounter this kind of address, it is basically not the address we need. Just give up, pull these two special addresses into the address list below, start analysis, double-click the address column, copy the address in the change address window, and then check the pointer option, Fill in the address just copied in the content box, and write the offset address of 00005560 just found in the above content box. The result is just the physical address of sunshine, and the final sunshine value is just the same as the current sunshine value. Moreover, these two addresses are the same and both dynamic addresses, as shown in the figure:



As shown in the figure above, the physical address of sunshine can be obtained from these two addresses plus the offset address. Right click - find out what accessed this address, that is, F5 of the shortcut key

After entering, a window will appear as before, but the contents in the two windows are different. The first address 0264A400 will appear in the window, but the second address 0956BD3C is blank in the window. Therefore, 0264A400 is the real first-order offset address we are looking for, as shown in the figure:



As shown in the second figure above, after finding the real primary offset address 0264A400, look at these code instructions in the window accessing this address. Through comparison, it is found that these codes point to the same pointer value 02649C98 and have offset address 00000768, as shown in the figure:


As shown in the above figure, since all codes point to the same pointer value 02649C98, continue to find the first level offset address in CE and continue the new hexadecimal search. After searching the pointer value 02649C98, the results shown in the following figure are obtained:


As shown in the figure above, a total of 923 addresses are searched, and there are several green static addresses. Here we can try to see if these green static addresses are the sunshine base address we want

In the same principle, we pull several green static addresses into the address list, double-click in the address column, copy the address in the change address window, then check the pointer option, fill in the address just copied in the content box, and write the offset address of 00000768 just found in the content box on the upper side, Then click Add offset and enter the offset address of 00005560 just found for the first time in the content box. The result is just the current value of sunshine physical address and sunshine, and the results of these static addresses are the same. Here we need to explain why we need to fill in two offset addresses here, because what we just found for the first time is the primary offset address, and this time is the secondary offset address, so here

Sunshine Physical Address = Primary offset address + Offset address
 Primary offset address = Sunshine base site + Offset address
 Sunshine Physical Address =Sunshine base site + First offset address + Second offset address




As shown in the above four figures, the final results of the four static addresses are the same and can be used as the sunshine base address, so just take any one. In this way, the base address and offset address of Yangguan are found. The base address and offset address of sunshine are as follows:

Sunshine base site: 006 A9EC0
 Primary offset: 00000768
 Secondary offset: 00005560

For the same reason, we can also find the plant cooling time, but the idea of finding the cooling time is different, because we don't know the specific value of the cooling time. We can find it by finding the unknown initialization value or by bytes

2. Modify the address of the game memory

This step is simple, for example, the value of sunshine. After finding it, each time we play the game, we can manually add the address in the address list box of CE, fill in the base address and offset address like when we verify these base addresses above, and then double-click in the value column to modify the value to become the sunshine value we want, This step is not enough to mention

3. Write game plug-ins

To write the plug-in, just find out the memory base address and offset of the desired function, and directly write the read and write memory address in the program. The following is the easy language source code of the plug-in of plant vs. zombie. A simple analysis of the wave:

.Version 2

.Assembly window assembly_Launch window
.Assembly variable process ID, Integer type
.Assembly variable a, Integer type

.subroutine __Launch window_Creation complete, , , After the window is created, the sun value is obtained and output by using the clock event

process ID = Fetch process ID ("PlantsVsZombies.exe")
Clock 1.Clock cycle = 999

.subroutine _Clock 9_Periodic events

Label prompt information.left = Label prompt information.left - 2
.If true (Label prompt information.left = -300)
    Label prompt information.left = 300
.If it's really over

.subroutine _Clock 1_Periodic events, , , Get the sun value and output it
.Local variable reading base address, Integer type
.Local variable read offset address I, Integer type
.Local variable sunshine physical address, Integer type

Reading sunshine base site = Read memory integer type (process ID, Sixteen to ten ("006A9EC0"), )
Read offset address I = Read memory integer type (process ID, Reading sunshine base site + Sixteen to ten ("768"))
Sunshine Physical Address = Read memory integer type (process ID, Read offset address I + Sixteen to ten ("5560"), )
Label current sun value.title = "Current sun value: + To text (Sunshine Physical Address)

.subroutine _Enter the sun value in the edit box_Get focus, , , Set the input box to edit the content of the box after the focus is obtained

Enter the sun value in the edit box.content = ""

.subroutine _Button to increase sunlight_Be clicked, , , Increase sunlight value
.The local variable takes the sunshine base address, Integer type
.The local variable takes the offset address one, Integer type
.The local variable takes the physical address of sunlight, Integer type

Take sunshine base site = Read memory integer type (process ID, Sixteen to ten ("006A9EC0"), )
Take offset address one = Read memory integer type (process ID, Take sunshine base site + Sixteen to ten ("768"))
Take the physical address of sunshine = Read memory integer type (process ID, Take offset address one + Sixteen to ten ("5560"), )
a = To integer (Enter the sun value in the edit box.content)
Write memory integer (process ID, Take offset address one + Sixteen to ten ("5560"), Take the physical address of sunshine + a)

.subroutine _Button reduces sunlight_Be clicked
.The local variable takes the sunshine base address, Integer type
.The local variable takes the offset address one, Integer type
.The local variable takes the physical address of sunlight, Integer type

Take sunshine base site = Read memory integer type (process ID, Sixteen to ten ("006A9EC0"), )
Take offset address one = Read memory integer type (process ID, Take sunshine base site + Sixteen to ten ("768"))
Take the physical address of sunshine = Read memory integer type (process ID, Take offset address one + Sixteen to ten ("5560"), )
a = To integer (Enter the sun value in the edit box.content)
Write memory integer (process ID, Take offset address one + Sixteen to ten ("5560"), Take the physical address of sunshine - a)

.subroutine _Button to lock the sun value_Be clicked, , , Lock sun value

Clock 2.Clock cycle = 100

.subroutine _Clock 2_Periodic events, , , Lock sun value clock event
.Local variable lock base address, Integer type
.Local variable lock offset address I, Integer type
.Local variable lock physical address, Integer type

Lock sun base address = Read memory integer type (process ID, Sixteen to ten ("006A9EC0"), )
Lock offset address 1 = Read memory integer type (process ID, Lock sun base address + Sixteen to ten ("768"))
Lock physical address = Read memory integer type (process ID, Lock offset address 1 + Sixteen to ten ("5560"), )
Write memory integer (process ID, Lock offset address 1 + Sixteen to ten ("5560"), 1000)

.subroutine _Button unlocks the sun_Be clicked, , , Unlock sun value

Clock 2.Clock cycle = 0

.subroutine _Button lock cooling 1_Be clicked, , , Lock cooling 1

Clock 3.Clock cycle = 100

.subroutine _Clock 3_Periodic events, , , Lock cooldown 1 clock event
.Local variable locking cooling base address, Integer type
.Local variable lock cooling offset address one, Integer type
.Local variable lock cooling one offset address two, Integer type
.Local variable lock cooling a physical address, Integer type

Lock a base address = Read memory integer type (process ID, Sixteen to ten ("006A9F38"), )
Lock cooling offset address one = Read memory integer type (process ID, Lock a base address + Sixteen to ten ("768"))
Lock cooling one offset address two = Read memory integer type (process ID, Lock cooling offset address one + Sixteen to ten ("144"), )
Lock physical address I = Memory read integer (process ID, Lock cooling one offset address two + Sixteen to ten ("70"), )
Write memory integer (process ID, Lock cooling one offset address two + Sixteen to ten ("70"), 1)

.subroutine _Button unlock cooling 1_Be clicked, , , Unlock cooling 1

Clock 3.Clock cycle = 0

.subroutine _Button lock cooling 2_Be clicked, , , Lock cooling 2

Clock 4.Clock cycle = 100

.subroutine _Clock 4_Periodic events, , , Lock cooldown 2 clock event
.Local variable locking cooling second base address, Integer type
.Local variable lock cooling 2 offset address 1, Integer type
.Local variable lock cooling two offset address two, Integer type
.Local variable lock cooling II physical address, Integer type

Lock cooling base 2 = Read memory integer type (process ID, Sixteen to ten ("006A9F78"), )
Lock cooling 2 offset address 1 = Read memory integer type (process ID, Lock cooling base 2 + Sixteen to ten ("768"))
Lock cooling 2 offset address 2 = Read memory integer type (process ID, Lock cooling 2 offset address 1 + Sixteen to ten ("144"), )
Lock the second physical address = Read memory integer type (process ID, Lock cooling 2 offset address 2 + Sixteen to ten ("C0"), )
Write memory integer (process ID, Lock cooling 2 offset address 2 + Sixteen to ten ("C0"), 1)

.subroutine _Button unlock cooling 2_Be clicked, , , Unlock cooling 2

Clock 4.Clock cycle = 0

.subroutine _Button lock cooling 3_Be clicked, , , Lock cooling 3

Clock 5.Clock cycle = 100

.subroutine _Clock 5_Periodic events, , , Lock cooldown 3 clock event
.Local variable locked cooling three base address, Integer type
.Local variable lock cooling three offset address one, Integer type
.Local variable locking cooling three offset address two, Integer type
.Local variable lock cooling three physical addresses, Integer type

Locked cooling base address = Read memory integer type (process ID, Sixteen to ten ("006AA00C"), )
Lock cooling three offset address one = Read memory integer type (process ID, Locked cooling base address + Sixteen to ten ("768"))
Lock cooling three offset address two = Read memory integer type (process ID, Lock cooling three offset address one + Sixteen to ten ("144"), )
Lock three physical addresses = Read memory integer type (process ID, Lock cooling three offset address two + Sixteen to ten ("110"), )
Write memory integer (process ID, Lock cooling three offset address two + Sixteen to ten ("110"), 1)

.subroutine _3. Unlock the cooling button_Be clicked, , , Unlock cooling 3

Clock 5.Clock cycle = 0

.subroutine _Button lock cooling 4_Be clicked, , , Lock cooling 4

Clock 6.Clock cycle = 100

.subroutine _Clock 6_Periodic events, , , Lock cooling 4 Clock event
.Local variable locking cooling four base address, Integer type
.Local variable locking cooling four offset address one, Integer type
.Local variable locking cooling four offset address two, Integer type
.Local variable locking cooling four physical addresses, Integer type

Locked cooling four base address = Read memory integer type (process ID, Sixteen to ten ("006AA00C"), )
Lock cooling four offset address one = Read memory integer type (process ID, Locked cooling four base address + Sixteen to ten ("768"))
Lock cooling four offset address two = Read memory integer type (process ID, Lock cooling four offset address one + Sixteen to ten ("144"), )
Lock four physical addresses = Read memory integer type (process ID, Lock cooling four offset address two + Sixteen to ten ("160"), )
Write memory integer (process ID, Lock cooling four offset address two + Sixteen to ten ("160"), 1)

.subroutine _Button unlock cooling 4_Be clicked, , , Unlock cooling 4

Clock 6.Clock cycle = 0

.subroutine _Button lock cooling 5_Be clicked, , , Lockout cooling 5

Clock 7.Clock cycle = 100

.subroutine _Clock 7_Periodic events, , , Lockout cooling 5 always event
.Local variable locking cooling base address, Integer type
.Local variable lock cooling five offset address one, Integer type
.Local variable locking cooling five offset address two, Integer type
.Local variable lock cooling five physical addresses, Integer type

Locked cooling base address = Memory read integer (process ID, Sixteen to ten ("006AA00C"), )
Lock cooling five offset address one = Memory read integer (process ID, Locked cooling base address + Sixteen to ten ("768"))
Lock cooling five offset address two = Memory read integer (process ID, Lock cooling five offset address one + Sixteen to ten ("144"), )
Lock five physical addresses = Memory read integer (process ID, Lock cooling five offset address two + Sixteen to ten ("1B0"), )
Write memory integer (process ID, Lock cooling five offset address two + Sixteen to ten ("1B0"), 1)

.subroutine _Button unlock cooling 5_Be clicked, , , Unlock cooling 5

Clock 7.Clock cycle = 0

.subroutine _Button lock cooling 6_Be clicked, , , Lock cooling 6

Clock 8.Clock cycle = 100

.subroutine _Clock 8_Periodic events, , , Lock cooldown 6 clock event
.Local variable locking cooling six base address, Integer type
.Local variable lock cooling six offset address one, Integer type
.Local variable lock cooling six offset address two, Integer type
.Local variable locked physical address, Integer type

Locked cooling six base address = Memory read integer (process ID, Sixteen to ten ("006AA00C"), )
Lock six offset address one = Memory read integer (process ID, Locked cooling six base address + Sixteen to ten ("768"))
Lock six offset address two = Memory read integer (process ID, Lock six offset address one + Sixteen to ten ("144"), )
Lock six physical addresses = Memory read integer (process ID, Lock six offset address two + Sixteen to ten ("200"), )
Write memory integer (process ID, Lock six offset address two + Sixteen to ten ("200"), 1)

.subroutine _6. Unlock the cooling button_Be clicked, , , Unlock cooling 6

Clock 8.Clock cycle = 0

After the plug-in software is started, read the game process ID of Plants vs. Zombies, and then read the physical address of sunshine for output and display. Then, when the startup window is created, a clock is added to achieve the purpose of real-time monitoring the sunshine value, and then several buttons are set, including increasing sunshine, locking sunshine, locking cooling time and reducing sunshine Unlock sunlight, unlock cooldown:

  • Increase sunshine
    Adding sunshine defines a global variable. Get the value in the input box from the variable, and then add the value in the sunshine physical address to the input value to achieve the purpose of adding sunshine
  • Reduce sunlight
    Reducing sunlight is as like as two peas in increasing sunlight, but setting the value in the physical address of the sun to reduce the value of the input, which is the goal of reducing the sun's pass.
  • Lock sunlight
    Lock sunshine defines a clock, sets the clock cycle to 999 milliseconds, and then sets the fixed value of sunshine to 1000. When the button to lock the sunshine is clicked, the clock cycle of the clock will be executed, that is, the code under the clock will be executed every 999 milliseconds, that is, the value of sunshine will be changed to 1000 in the physical address of sunshine, so as to achieve the purpose of locking the sunshine
  • Unlock sunlight
    To unlock sunshine is to set the clock cycle of the lock sunshine clock to 0. When the unlock sunshine button is clicked, the clock cycle event will be executed, and the code under the clock will not be executed, so as to achieve the purpose of unlocking sunshine

The principle of locking and unlocking the cooling time later is the same as that of locking and unlocking the sunshine above. Here, separate cooling locking and unlocking are made for the plants in each field, so the code is relatively long. In fact, when looking for the plant cooling time, you can cooperate with OD to directly find the cycle in front of the cooling time, So the cooling time of all plant columns is gone

epilogue

Whether it is a stand-alone game or an online game, the principle is the same. However, different types of games may require different things. For example, shooting games need D3D technology to do the positioning of character perspective, and so on

Topics: Cyber Security