CE Editor is a local memory modification tool. Its core logic is very pure: it scans and locates data residing in the program's local physical memory on the computer, then forcibly modifies it. Although it has long been renowned in game reversing and game vulnerability mining (commonly known as "cheating" or "memory hacking"), its application scenarios go far beyond that. We can absolutely use this tool to try and mine vulnerabilities in various APPs and even web-side business logic.

Regarding software acquisition, you can directly go to the Cheat Engine official website to download the latest version and perform a straightforward installation. The installation process is very simple and will not be reiterated here. To give you a more intuitive understanding of its powerful functions, this tutorial will casually open a game as a test subject. Using this game, I will guide you step-by-step through CE's core functions and how to use it to search and modify memory data, ultimately transforming these into practical approaches for vulnerability mining.


I. Environment Preparation and Process Attachment Mechanism

Before performing any operations with the CE editor, the most crucial prerequisite is "attaching to a process." This is because memory data exists dependent on a running program process.

1.1 Finding the Target Process

After opening the CE editor, in the upper-left corner of the interface, you will see a small computer icon with a magnifying glass. Clicking this icon will pop up a "Process List" window. This list displays all active processes currently running on the computer.

1.2 The Specificity of Emulator Processes

If we are testing a mobile game or a mobile APP, we typically use an Android emulator on the computer. For example, you can use LDPlayer. In the process list, you need to carefully look for a process named headless (the full process name usually has a specific prefix; for LDPlayer, it might be leidian or LdBox and other prefixes plus headless).

Different emulators may have vastly different process prefixes, but if you look closely, their backend rendering or core running processes will most likely have the headless identifier appended. After finding this target process, select it directly, then click the Open button in the lower right corner to successfully inject CE and attach it to the emulator's memory space.


II. Data Types and Search Modes

After attaching to the process, although CE's main interface seems to have many parameters, the logic for introductory game vulnerability mining (i.e., memory modification) is very simple:Enter the data we want to modify in the search box, then find it.

2.1 Deep Understanding of Data Types

On the right side of the CE search interface, there is a dropdown menu for selecting the data type. Data in the memory world is not uniform; they are divided into different types based on storage requirements:

  • 4 Bytes: This is CE's default option. In the vast majority of games and conventional applications, variables representing common values like quantities, states, and gold coins are generally stored using four-byte integers (Integer). Most likely, when testing games, the default four-byte type is sufficient for 90% of scenarios, and other types are almost never needed.
  • Other Type Overview: Of course, to handle complex business logic, CE also supports other types. For example, 8 Bytes is used for storing extremely large numerical values; Float and Double are often used to store precise data with decimal points (such as game character coordinates on X/Y/Z axes, complex attribute bonus ratios); additionally, there is the String type specifically for searching text, and various array types. They might all exist in memory, but beginners should firmly stick to "4 Bytes."

2.2 Exact Search and Range Search Strategies

After confirming the data type, we need to decide which scan type to use. CE provides extremely rich conditional filtering methods:

  1. Exact Value: The first option, and the most commonly used one. When we clearly know the specific value of something in the game (e.g., I currently have 10 gold coins), we perform an exact search for this specific number.
  2. Bigger than...: Used when a value is obscured or blurred, but you know it is definitely greater than a certain threshold. For example, you know the current value is greater than 10.
  3. Smaller than...: Similarly, used to filter memory addresses smaller than a certain value (e.g., smaller than 10). Combining the above two, you can manually approximate a range.
  4. Value between...: This allows you to directly define a range interval. For example, if you speculate that a hidden attribute's value is between 10 and 100, you can use this option for an initial broad search.

III. Exact Search for Known Values and "1 ≠ 1"

When we know the target value, the search seems simple, but in practice, we encounter a lot of noise. We will use the following example to demonstrate this process.

3.1 The "Information Explosion" of the First Scan

Suppose we now want to search for a value 10. After entering 10 in the input box, click First Scan.

At this moment, the address list on the left will instantly fill up, potentially scanning out hundreds of thousands of corresponding values.

  • What is a memory address? A memory address is like a "room number" or "coordinate" on the computer's local physical memory stick, specifically used to store these data. The left side shows the hexadecimal memory address, and the right side shows the current value corresponding to that address.

    Among these hundreds of thousands of addresses, only one or a few are what we truly need; the rest are all irrelevant caches from other applications within the emulator system or the system's underlying processes.

3.2 "1 Does Not Necessarily Equal 1" in Game Memory

Suppose we see an item or status displayed as 1 in the game. If its data type is four bytes, and the program's underlying logic indeed makes "displayed 1 equal to memory's 1," then we directly enter 1 in the input box and click First Scan.

The result is astonishing: the left side might show over 5 million memory addresses all with the value 1!

  • This first search means that CE, within the vast memory sea of the entire LDPlayer (including all other background applications running inside it, the Android system itself, and the currently tested game), has pulled out all memory addresses with the value 1. More importantly, in game development, 1 is extremely frequently used to represent a "state." For example, 1 represents "On/Activated," and 0 represents "Off/Deactivated." This is also why searching for just 1 can yield millions of records.

3.3 Sifting Through the Sand

Faced with 5 million addresses, we are at a loss. The solution is: go back to the game and find a way to make this value change.

  1. Value becomes 2: In the game, perform an action to increase the original 1, making it become 2.
  2. Next Scan: Switch back to CE, enter 2 in the input box, and click Next Scan.Note! This is not a new search, but a secondary filter. Its logic is: "Please filter out, from those 5 million+ addresses whose old value was 1, the addresses whose value has now just become 2."
  3. Instantly, the number of addresses might sharply decrease to over 2000.
  4. Continue the Cycle: We continue changing the value to 3 (this is often used when testing game item quantities or attribute point allocation). Enter 3 in CE and continue "Next Scan," meaning filter out from those two thousand addresses that just became 2, the ones that have now become 3. At this point, the addresses might be down to only 17.
  5. The Cruel Reality (Red Text Warning): When we try to change the value to 6 and search for 6 in CE, the left list suddenly becomes completely empty! The previously remaining addresses turn red (red indicates that the value at this memory address has automatically changed at this moment), but none of them have the value 6.
  • "In the game, 1 does not necessarily equal 1. It could equal any other bizarre value."

IV. Unknown Initial Value and Dynamic Filtering

When the "1 ≠ 1" situation occurs, or when we face attributes like health bars, mana bars, or model size that have no numerical display at all, we don't know what value to search for. At this time, we must enable the Unknown initial value scan mode.

4.1 The Vast Ocean of 900 Million Addresses

Select "Unknown initial value" in the scan type. This means we are asking CE to find all memory addresses within the emulator. After clicking First Scan, since there is no value filter, CE will capture a massive amount of data. They might be: "ones, tens, hundreds, thousands, ten thousands, hundred thousands, millions, ten millions, hundred millions... a full 900 million memory addresses!"

Faced with these 900 million addresses, how do we locate the unique memory controlling a specific attribute? The answer is: finding the pattern of change.

4.2 Tracking Increase/Decrease Patterns

Suppose we are testing a model size slider.

  1. We drag the slider from the 0 position to the right to enlarge it (for example, to the position marked 1). Although we don't know what the underlying number has become, we are certain that its value has increased.
  2. In CE, switch the scan type to "Increased value". This is another dynamic logic filter distinct from exact search and greater than/less than ranges.
  3. Click Next Scan. Its logic is: "Find all addresses among these 900 million memory addresses whose current value is larger than the previously recorded value."
  4. Instantly, the 900 million addresses are sharply reduced to 10 million (ones, tens, hundreds, thousands, ten thousands, hundred thousands, millions, ten millions).
  5. Continue making the model larger in the game, and scan again using "Increased value" to continuously narrow the scope.

4.3 The Clever Use of Unchanged Value

During the process of continuous enlargement, suppose we drag the slider to its maximum value 10, unable to exceed it further.

To continue filtering, we might change it back to 0, and then drag it back to 10.

At this moment, a fatal logical trap appears:

The end state of our last scan was the slider at 10. Now, after fiddling around, we've pulled it back to 10. If we search for "Increased value" again at this point, you'll find the target is gone! Because the current state's 10, compared to the last state recorded by CE, 10, has neither increased nor decreased; it is unchanged!

At this time, we must bring out the most crucial trick in CE filtering: Unchanged value.

Why does this option exist? Because when we cannot determine whether the value has increased or decreased (or when we've circled back to the origin as described above), as long as we know it has not changed relative to the last scan, we can use it for a major cleanup.

  • Cleaning Underlying Noise: In a computer system, countless memory addresses are frantically fluctuating every millisecond (system time, rendering frame rate, network heartbeat packets, etc.). For example, we can casually search for unchanged values; originally 39,000 addresses instantly become 3,900! Because those junk data points constantly jumping in the background are directly kicked out by the strict condition of "unchanged."
  • Repeated Filtering: We can click "Next Scan (Unchanged value)" multiple times in a row without changing the state in the game. You will see it continuously eliminating irrelevant memory addresses that secretly change, until the number of addresses completely stabilizes.

After repeated cross-filtering using "Increased value," "Decreased value," and "Unchanged value," the rate of address reduction will eventually slow down, possibly getting stuck at over 2000 addresses, no longer drastically shrinking as before.


V. Binary Search Method and Memory Freezing Mechanism

Why, after such rigorous filtering, are there still over 2000 addresses changing simultaneously?

Because certain functional points involve countless underlying programs. Dragging a slider not only changes the model parameters but might simultaneously trigger a series of chain reactions like UI rendering, shadow recalculation, and physics collision volume updates. These 2000 addresses are all faithfully changing according to your dragging.

But there is only one source address controlling the core logic! How do we pick it out from these 2000 identically synchronized changing addresses?

Below, we will introduce a method known as "the dumbest but also most unbeatable" — Binary Search Memory Freezing.

5.1 The Modification Area and Freeze Function

First, in the left address list, press Ctrl + A to select all these 2000+ memory addresses. Then click the small red diagonal arrow at the bottom right of the list to transfer all these addresses to the **"Modification Area"** at the bottom.

In this area:

  1. Double-clicking the value behind an address allows you to forcibly change it to any value.
  2. More crucially, there is a checkbox (Freeze box) at the very front. Once checked and frozen, it means CE will freeze this memory address at a very high frequency.No matter how you drag or change the state in the game, the data at this frozen memory address will be firmly nailed down and absolutely will not be changed!

5.2 Practical Freeze-and-Eliminate Drill

We will use this freeze feature to perform elimination:

  1. Maximize State: First, drag the slider to the maximum in the game, observing the obvious visual difference between large and small models.
  2. Freeze Half: In the modification area at the bottom, select the top batch of memory addresses (roughly half), hold down the Shift key and drag down to select a range, then gently tap the Spacebar on the keyboard. Instantly, freeze checkmarks appear in front of all these selected addresses.
  3. Verify In-Game: Go back to the game and try dragging the slider smaller.
    • Theoretical Logic: If the true controlling memory was frozen by us, then no matter how the slider moves, the model in the game should always remain in the "maximum" state (because the front-end data is frozen).
    • Actual Performance: After dragging the slider smaller, we find that the model actually shrinks! It was not affected. What does this indicate? It indicates that among the half of the addresses just frozen, all are useless; none contain the source value we are looking for.
  4. Ruthless Elimination: Since they are not the target, right-click this batch of addresses, select Delete (or directly press the keyboard shortcut Del), and delete them directly.
  5. Cyclical Approximation: Select half of the remaining addresses again, press Space to freeze, and observe in the game. No effect? Right-click and Delete again. Just like this, split in half, delete; split in half, delete again.
  6. Dawn Appears: When deleting a certain batch, go back to the game and drag the slider, and find that **"something is not right, the model is getting smaller and smaller, it's even caving in!"** What does this indicate? It indicates that this batch of frozen addresses finally contains the true core control address.
  7. Reverse Deduction: First, restore the caved-in model to normal by unfreezing. Since the target is in this upper batch, all the remaining addresses below are useless and can be deleted directly.
  8. Ultimate Freeze: Within this small pile of addresses containing the target, continue splitting. Freeze half, no reaction? Delete. Freeze the other half, there's a reaction! The scope narrows down to just two addresses. Test them one by one, eliminate the one that isn't the target, delete it.
  9. The Truth Revealed: Finally, scrutinize the last two remaining memory addresses. Modify the first address, and find that the game screen immediately undergoes an irregular drastic change ("getting more and more whatever"). At this point, we have successfully identified the unique controlling memory!

VI. From Memory Modification to Backend Business Logic Vulnerabilities

A lot of space was spent earlier explaining memory search and modification. Many people (especially those purely doing web penetration testing) will have a huge doubt:"I modified the memory locally, and only I can see the change on my own computer screen (commonly known as self-amusement). What use is this really?"

6.1 Case 1: Negative Number Bypass Vulnerability During Item Purchase

Suppose there is an item shop in the game, and items have their corresponding attributes and quantities.

Under normal circumstances, when we click to buy "one" item in the shop interface, the client (front-end) assembles a request at the low level and sends two key pieces of data to the server (backend):

  1. Item ID (e.g., 1001)
  2. Purchase Quantity (e.g., 1)

These two parameters, before being sent to the server, are genuinely lying in our local memory!

If at this moment, using the CE search techniques learned above, we precisely locate the memory address storing the "Purchase Quantity," and before it sends the request, we forcibly change the original 3 to -3 (negative three).

Here comes the core breakthrough point:

After we change it locally, we click the buy button again. The memory data grabbed by the client at this time is already -3, and it will pass this tampered negative number intact to the server.

If the backend developer, when writing the business logic, only validated "whether the gold coins are sufficient" but forgot to validate the purchase quantity for negative numbers, then the server will process this -3. The result is often: the player not only doesn't get charged but instead, because of "deducting the cost of -3 items," their gold coin balance skyrockets instantly! This is a serious business logic vulnerability caused by using local memory modification to directly affect front-end and back-end data interaction. Similarly, regarding the previously mentioned modification of character modeling parameters, if the backend receives and saves them, you can display a deformed/unique character that breaks conventional modeling in front of all server players.

6.2 Case 2: Using Hidden Class ID for Unauthorized Creation

Besides external data tampering, memory modification can also peek into and prematurely utilize unreleased features.

Class switching is an extremely typical disaster zone. Suppose the game backend has already implemented the class for the next major version update — "Gunner." The backend's code logic and data tables are all written, but the current client (front-end) has not yet released it, and the UI interface does not show this button.

What to do when the client doesn't show it? We can still pull out CE!

  1. Fuzzy Search to Locate ID: On the character creation screen, we repeatedly switch between existing classes. For example, first select Archer, use a fuzzy search (Unknown initial value); then switch to Warrior, search for "Changed value." Through continuous switching back and forth, filtering by changed and unchanged values, we finally pinpoint the memory address representing the "Class ID" in memory.
  2. Finding Neat Patterns: Such core IDs in games are usually designed to be very neat. Whether it's skill IDs, character IDs, or dungeon IDs, they are never chaotic. For example: the Warrior's class ID is 10101, the Mage's is 20101, the Taoist's is 30101. This is a highly standardized format.
  3. Guessing and Unauthorized Sending: After grasping the pattern, it's not hard to speculate that the hidden Gunner's ID might be 40101 or some very close value. In the found memory address, we forcibly tamper with the original Warrior ID to this hidden ID.
  4. The Finishing Blow: Click the "Create Character" button! If the backend only relies on the front-end UI to restrict players and forgets to perform a secondary check (authorization) at the interface, then our request to "create a Gunner" sent to the server will be given the green light. As an ordinary player, we have thus forcibly created a hidden class through privilege escalation! This is an extremely classic vulnerability point in game security testing.

6.3 Why Not Use Packet Capturing?

At this point, many readers knowledgeable in security testing will surely pose a soul-searching question: "Since the goal is to tamper with data sent to the server, wouldn't using Burp Suite or Fiddler to directly capture and modify packets be more direct and simpler? Isn't that right?"

Packet capturing is indeed simpler, but the problem lies in network protocols and encryption mechanisms!

  1. Obstacles from Non-HTTP Protocols: Nowadays, online games and mobile games, basically to ensure low latency and real-time communication, rarely use traditional HTTP/HTTPS protocols. The vast majority directly use underlying TCP or UDP protocols. Traditional web packet capturing tools are often helpless against this.
  2. The Garbled Dilemma of Encrypted Data: Not only that, game data is almost always highly encrypted before being sent. Even if we capture packets with Wireshark, what we capture is all a pile of meaningless garbled characters.
  3. High Decryption Threshold: If we take the packet capturing route and encounter encryption, we either need to possess extremely strong reverse engineering analysis skills to write a decryption tool ourselves, or spend money to buy a decryption script. Most people cannot write decryption tools, and forcing decryption is extremely tedious and difficult.

Why can CE ignore these difficulties?

Because no matter how garbled the data becomes after encryption during network transmission, at the moment it is just generated inside the client, before being processed by the encryption function, while still lying in the local physical memory, it is definitely in plaintext! Modifying it in memory is equivalent to swapping the goods before the data is encrypted, packaged, and "loaded onto the truck." Subsequently, the client's own encryption code will automatically perfectly encrypt this "fake data" for us and send it steadily to the server via TCP/UDP. This is an extremely elegant dimensional strike!

6.4 Case 3: Breaking APP Encryption for Unauthorized Live Streaming Room Vulnerability

This dimensional strike applies not only to games but also shines brilliantly in APP and web business lines.

When testing certain live streaming platforms, you might find that many core functional points of the live room do not use the HTTP protocol but use TCP/UDP, and the transmitted data is all encrypted. The captured packets are all garbled and cannot be decrypted at all. Unable to capture and modify packets, the testing hits a dead end.

At this time, the memory testing method becomes the only hope for breaking the deadlock:Unauthorized Broadcasting Vulnerability.

  1. We open CE and attach it to the live streaming APP's process.
  2. Through the pattern of numerical changes, we find the address storing "My Live Room Number" in local memory.
  3. Before clicking to start broadcasting, we forcibly change the value in this memory address toOther streamers' live room IDs.
  4. Click the "Go Live" button. The app frontend locally encrypted this tampered ID and smoothly transmitted it over the network to the backend server.
  5. Because the backend developers at this point over-trusted the (tightly encrypted) data stream coming from the frontend,they forgot to perform the extremely critical authorization check on the backend (verifying whether the requesting user's UID had permission to start a stream in that live room ID), ultimately triggering the vulnerability—we were now forcibly starting a stream in someone else's live room!

This also perfectly confirms that when hitting a dead end with encryption or non-standard protocols, memory modification is actually a very handy and powerful tool in specific business scenarios.


Seven, Nothing More Than Practice Makes Perfect

What is a memory modifier? How do you use it? Ultimately, the core boils down to two steps:

  1. Search for the value I want to find
  2. Modify the value I want to find

Cheat Engine is merely a sword in your hand. The moves seem simple, nothing more than "search" and "modify"; but how deep this sword can pierce and how accurately it can strike ultimately depends on the skill of the wielder.

There are no shortcuts on this path. You must get your hands dirty, dissecting dozens of games, chewing through the local memory interactions of hundreds of apps, repeatedly sifting and troubleshooting through massive amounts of data, until you close in on the single correct answer from the chaos. The process is often tedious, yet it is precisely for this reason that when the truth emerges, it is all the more fascinating.