Write a general game modifier process with MASM32

xiaoxiao2021-03-06  17

Author: Cai Jiangyu

This intent is directly announced, the "Fantasy Modifier 1.1" source code is calculated, but because most of its code is my first study MASM32 written, the annotation is small, the code is not standardized, it is extremely inconvenient for beginners. Therefore, it is better to write the idea of ​​writing this software directly, which is also a confession of those who support me.

Now, online games are rampant, stand-alone game modifiers are Yellow flowers yesterday, it seems that there is no use of martial arts. However, after we understand the programming principle of a single-machine version of the general game modifier, it should not be difficult to write "plug-in".

In fact, it is not difficult to write these game modifiers like "Jinshan Ranger", "FPE", and so on, but you don't know the idea of ​​these things. It is also no wonder that the tutorials on making a general game modifier can be said that it may be because of business resembling! Most of them are written for a dedicated modifier for a game. (Gossip less!)

I can't write one by one by time, I can only write some key parts to write. (I finally started!)

First, the initial preparation work.

First we can think about it, to override the data value of the game, you must have all permissions to overwrite the data in this game process. This allows us to change the lives, energy, lock money in the game you want to do. Since Windows is not read directly between processes, we must read and write in accordance with Windows requirements. Proceed as follows:

To read and write the data of a process, you must obtain the handle of this process, then use the readProcessMemory and WriteProcessMemory provided by Windows to read the memory of the game.

There are many ways to get process handles, I believe everyone should know! I still mention it, the first is to use createtoolhelp32snapshot, traverse all processes in the system, then get the process ID, then use openprocess, open, parameters must specify process_all_access, otherwise, after writing or check the target process data An error will occur. The second is to use EnuWindows (which is a recursive method), or getWindow to get all the handle of all forms, with getWindowThreadProcessID, get the process ID, and open it with openprocess. It should be noted that if you have a second method you have to filter it, because there are many system windows that are invisible and it is necessary to judge whether this window is not a parent window, whether the window title is empty.

So, add (iswindowVisible, getParent) to determine, or not, in front of the user is a lot of unused information.

The general Tong-game modifier is the second method used by the window of the window title to display only the corresponding title.

Due to time causes CreateToolhelp32Snapshot and Enumwindows I will not introduce, I use the first method

There are two more information above. I just said how to use getWindow!

Invoke getDesktopWindow; get the handle of the desktop window

Invoke getWindow, Eax, GW_CHILD; Looking for the first child window of the desktop window

Invoke GetWindow, Eax, GW_HWNDFIRST

Mov phwnd, Eax; looking for the first brother window for this sub-window.

Invoke getParent, EAX; judgment this window is not a parent window

.IF! EAX; if this window does not have a parent window, set the flag

Mov Parent, 1

.endif

Mov Eax, Phwnd

.While EAX

.IF Parent

Mov parent, 0; reset flag Invoke getWindowText, phwnd, addr titl, sizeof titl; get window title text

.IF EAX; if the title text is not sent to a combination list box.

Invoke Senddlgitemmessage, HwinMain, Combox1, CB_Addstring, 0, Addr Titl

.endif

.endif

Invoke getWindow, phwnd, gw_hwndnext; Looking for the next brothers window of this window

Mov phwnd, EAX

Invoke getParent, EAX

.IF! EAX

Invoke iswindowvisible, phwnd; again determined if this window is visible

.if EAX

Mov Parent, 1

.endif

.endif

Mov Eax, Phwnd

.endw

Invoke Senddlgitemmessage, Hwnd, Combox1, CB_SETCURSEL, 0, 0

This way we realize the target process selection function of the general game modifier. Everyone keeps the eligible window handle in the buffer in the process and sends the position of the window title text in the window to the combination list, which can be taken by the selected index number to take the buffer. relatively

The handle should be. Then get the process handle.

Second, query the target process memory usage.

In the previous step we got the handle of the game process. Now we can do it. How to operate?

Since we write the game modifier is universal, you have to scan memory (nonsense!), Because the appearance of virtual memory technology Windows can make each process arched 2GB of memory (2000, XP can provide 3GB). Do we go to a sweep? Of course, if so, the user has to wait for a long time. How to do it? Maybe you will say that if you know how much memory used this process, just scan the memory area it used, right. In the memory that it is submitted (used) memory. This will be much more, and the start address of the user mode in Win98's memory allocation is from: 0x0400000H ---- 0x7ffffffh. So we only need to query the process submitted by the process in this space (page). The memory area (page) has three states "free, reserved", "" "" "" "" "" Methods as below:

LEA EDI, LPBASEADDR; the buffer of each memory page base address will be stored.

Lea ESI, LPSIZE; a buffer that will be stored and the page range corresponding to the above.

.while min <= 7ffffffh; min = 0x00400000H

Invoke VirtualQueryex, HProcess, Min, Addr LPM, SizeOf LPM

.IF lpm.state == MEM_COMMIT; if it is submitted

.IF lpm.protect & (Page_Readwrite or Page_Execute_readwrite)

Push lpm.baseaddress; returns the base address of the submitted memory page.

POP [EDI]; save for scanning

Push lpm.regionsize; Returns the submitted memory page size.

POP [ESI]

Add Edi, 4

Add ESI, 4

Inc Pagenum1; page counter, how many pages have been submitted in statistics, and then scan these pages when scanned

.

.endif

.endif

Mov edx, lpm.regions; check one page

Add min1, EDX

.endw

In this way, we submit the base address of each memory page submitted by the process, and save the corresponding page area in the variable lpBaseAddr and LPSIZE. The start address and range of each page can be continuously removed from these two variables later. The HProcess is the handle of the target process to be queried, and min is the start address of the query.

LPM is a pointer to the MEMORY_BASIC_INFORMATION structure, (About this structure can take a look in Windows.inc) for returning information of memory space; the fourth parameter is the length of this "structure".

LPM.Protect & (Page_Readewrite ...) is to determine if this submitted page is readily read or written. (I.e., filtering it again).

Ok, the above code is filtered out of the memory area that we want to scan.

Third, start search

We have known the memory area to be scanned, and below is a model with "double word" lookup.

.While EBX <= Pagenum1; Pagenum1 is the total amount of memory pages for the previous query

.

.

.

Invoke ReadprocessMemory, HProcess, Baseaddress, Addr DBuffer, Size, Null

.

.

.

BaseAddress is the base address of the nth page, that is, a page saved in the variable lpbaseaddr when queries in the previous step.

The base address value. Size is the page size of the submitted nth page (ibid, saved in a range of memory pages in LPSIZE)

.

DBUFFER: Yes from the base address of this page to the Size (range) data into the DBuffer buffer.

.

.

.

Lea EDI, DBUFFER; getting the first site of the buffer, is ready to compare it to it.

Mov Eax, DSearch; dsearch = The value you entered will search.

.while ECX.

.

SCASD; string scanning instruction, finds a value equal to DSEARCH.

JNZ Continue

Inc Total; found number of addresses plus 1

.

.

.

Save the address that meets the conditions.

CONTINUE:

Inc ECX

.endw

Inc EBX

The base address of the next page is obtained, and the page is scanned until all memory pages submitted in the scan will complete the first memory.

search for.

.

.endw

This way we got the first search address. The second and nth searches don't have to say it. It is possible to change it slightly, just read all values ​​and target values ​​again from the first saved address value. Repeatedly sieve it!

It should be noted that you also need to judge the byte, word, or double words, etc. during the process of writing.

Fourth, how to lock the value.

If the life of the characters in the game is invincible, I still feel very magical when I started, after I wrote it, I know that it is simple to complete this step, just need to write a timer process, and set the time After the specified time, Windows will call your timer process and write to this address to the value you want to lock. (This is finished?) But if I lock multiple addresses, for example to lock life, it is necessary to lock energy, but also to lock .... Due to the locked address, the lock value is different. You can't write a process for every timer! And you don't know how many addresses are to be locked. How to do? Maybe you think, right, use the "Link" Don't underestimate the boring things in the "Data Structure", it will still work. Why use the "Link" because the first: You don't know how many addresses are to lock. Second: Each lock address and lock value are different, maybe this address I lock 8000, the address is also to lock 10000, and it is a sharing a timer process. So I think that the use of the chain is a relatively possible way. The idea is as follows: First define a timer structure to store the lock value you entered, and addresses, and timer IDs. Timer struct

IDTIMER DD?; Storage Timer ID,

Address DD?; Store the target address to be locked.

VALUE DD?; Store the value to be locked.

NEXT DD?; Putting the address of a timer structure.

Timer Ends

This way you will generate a data structure as follows each time you have to lock an address.

0 4 8 12

----- ---------- ------- ........ -----------

Timer ID1 | Address 1 | Data 1 | The address of the next timer | ......... | Timer ID 9 | .......

---------------------........ -----------

It is the same in the container and the C language. If you do a change, I feel more simple to do it in the assembly.

This generates a timer chain. In the timer, you first get the first address of this timer table, and then traverse this linked list to remove the id value of the timer and the _idevent parameter in the timer process. If the corresponding address N is taken, the data N will be taken.

The timer process is as follows:

_lockadd proc _hwnd, umsg, _idevent, _dwtime

Local @ modv, @ moda

Pushhad

Mov Edx, Bhead; get the first address of the timer chain table

@@: MOV EAX, [EDX]; Take the timer ID value in the first chain point.

OR EAX, EAX

JZ EXIT; if the linked list is empty, exit.

Cmp Eax, _idEvent

JZ @f

MOV EDX, [EDX 12]; if this is not this node, take the first address of a node (traversal).

JMP @B

@@: MOV EAX, [EDX 4]; if equally, the address to be locked is removed.

Mov @ modv, EAX

MOV EAX, [EDX 8]; and remove the lock value you entered.

Mov @ moda, EAX

Invoke WriteProcessmemory, HProcess, @ modv, addr @ moda, size, null.

EXIT:

Popad

RET

_lockAdd Endp

This completes the locked multiple different addresses. If you cancel the lock, you only need to traverse this table, find out the "address" to cancel is "Address", and you can find the timer ID value corresponding to this address via the address. (The front moves in front of the pointer is the timer ID value) and then then the contents of the nodes of the pointer domain are completed in the pointer domain of the previous node, and complete the cancel lock. Write two processes when writing this feature, that is, a creation chain table process: createlist, and delete procedure: deletelist. It is particularly convenient to lock and unlock the lock. You may say why don't you use arrays? It is very convenient to use the array in establishment, but when you delete you, you will have a lot of time, and the number of applications cannot be explicitly determined. Maybe there is a better way, if you find that you can remember to tell me! Five, how to cut out from the game with hotkeys

This step is not a DX game, as long as the "keyboard hook" (wh_keyboard) then specifies a hotkey, for example, the F2 button, when the hook is hooked to the F2 button, then send a custom message to the main program (WM_HOOK). When the main program is received, check if the F2 button is pressed, if so, get the window handle of the front desk process (game), and then get the ID of the process through the window handle - and openprocess get the process handle. After getting it, you can go to the previous example.

The sample is operated.

The judgment process of the main program is as follows:

.IF EAX == WM_HOOK; if the message sent by the hook process

Mov Eax, WPARAM; WPARAM is stored in a virtual key

XOR EBX, EBX

MOV EBX, LPARAM; get the state of the key

And EBX, 80000000h; if the highest bit is 1, this button is bounced.

.IF EAX == VK_F2 && EBX

Invoke getForegroundWindow; get the window handle of the front process

.IF EAX! = hwnd; eax = window handle of the target process

Mov HWNDT, EAX

Invoke getWindowText, HWNDT, AddR CBuffer2, CCH; get the window title text of the target process.

Invoke GetWindowthreadProcessid, HWndt, AddR HProcid

Invoke closewindow, hwndt; minimizes the target window.

Invoke openprocess, Process_all_access, 0, HProcid

.endif

.endif

.endif

The above code is cut from the game from the game. It should be noted that if you press the hotkey on your own modifier, you must filter it out.

Therefore, the line EAX! = Hwnd is to determine if it is his own window handle to avoid unpredictable errors. Returns the game simply typing the following code.

`` `` .elseif AX == RGAME

Invoke setForegroundWindow, hwndt; set the game window to the front desk

Invoke OpenICON, HWNDT; and maximize this window

You can also try other methods, here is not described. (Small episode: If you want to bounce down in DX, you have to write COM, because Microsoft's "DX" is a COM. I didn't study this, it seems to be hooked to hook its function to implement the pop-up, everyone is interested in research together a bit.)

6. About blur search (low-order search).

Fuzzy search seems to be a necessary function, because the game is used for the "blood trough" to be used as a health, so we don't know the specific value when we modify such games, so you can't realize normal value findings. Therefore, the blur search is produced. In fact, writing a blur search is relatively simple, let's talk about our ideas: When we scan such games, first it is "?", Why do you want to enter "?", Because you don't know the specific value, so We want to read all submitted memory pages to a specific location in one time. The second assumption that you entered the ' ', once again read the value of all submitted memory pages and the previous read, keep the address greater than the previous data value, which completed the first Second vague lookup. The third time is the same, that is, read the value from the reserved address and then reserves the biggest. This makes it easy to find out, simple! It is necessary to mention that this feature is best to establish a memory map file to save all submitted memory page values ​​for one-time read. And the speed will be a lot. I created two memory mapping files when I wrote this feature, one for saving the value, one for saving the address, because the fuzzy search for the first time the data will be many. Here is only the first time memory image as an example. When the user enters "?" The operation process model is as follows:

_Image1 Proc

Local @sizen

MOV EBX, 1

Mov Edi, LPADDRESS1

Mov ESI, LPADDRESS2;

.While EBX <= PAGENUM1; Submitted Total Pages

Mov Edx, [EDI]

MOV Tempaddr, EDX

Mov Edx, [ESI]

Mov Tempsize, EDX

Pushhad

Invoke ReadprocessMemory, HProcess, Tempaddr, MData1, Tempsize, Null

Invoke Writefile, Hfile, MData1, Tempsize, Addr @ Sizen, NULL;

Insert

Popad

Inc EBX

Add Edi, 4

Add ESI, 4

Mov Eax, Length11

Add Eax, Tempsize

Mov Length1, EAX

Invoke setFilePointer, HFile, Eax, Null, File_Begin;

.endw

RET

_Image1 ENDP

This way we read all the data in the file when initialization. Use this file to create a memory mapping file:

Invoke CreateFilemapping, Hfile, Null, Page_Readwrite, 0, 0, Null

Mov Hfilemap, EAX

Invoke MapviewOffile, Hfilemap, File_Map_Write, 0,0,0

Mov LPMemory, EAX

Then follow the ' ', or '-' number of your second input, or the value starting from memory and the value starting with LPMEMORY, the first lookup is completed. The second and value findings are similar. You should be able to write it!

Seven, some suggestions

Everyone can refer to the example in writing: (Fantasy modifier 1.1 or 1.0).

Due to time, I can only write here this time, and some other technologies believe that everyone can write it out. For example, the pop-up function under DirectX sees 9CBS is implemented with hooks, which means that the modifier's dialog code is written during the hook. When you press the hotkey, your code is mapped into the target process in Windows so you will play directly in the game, I also wrote a simple dialog in "Star", but it seems that the mouse cannot work. It is estimated to write this drive yourself. Because I didn't touch the DX programming, I didn't go abroad, everyone can try, or write com. Estimate "Jinshan Ranger" is written by the latter! The latter seems to be more stable. (Personal guess) is if you want to improve performance using threads, multiple threads in a single processor do not speed up the running speed, because Windows uses time-cut rotation, threads are more threads. The longer the time is the longer. However, there is more time to have multiple threads that have multiple threads more than a single thread. Suppose the system is scheduled once in 20ms, for a single thread, if this thread runs more than 20ms will be hanged. The operation system is again schedering other processes using the CPU. If it is a multi-thread, if the first thread is suspended, it may allocate the 20ms of the 20ms of the 20ms of the 20ms to run again. When you implement the user interface, you can do it when searching in the background. In fact, everyone doesn't have to spend this software to worse this software, knowing how the working principle is.

If you want to write to recommend you to use these tools: Softice, VC , OLLYDBG (strongly recommended).

Ok, this time you come here. Because I have been officially exposed to Windows programming, I don't have half a year. Theory is naturally not talking, there is a shortage in the article and incorrect place, please tell me immediately and inform me, I will fix it. Finally, what I think, I feel that after going into Windows programming, the most important thing is the idea, and to be able to look at the essence, the function of a certain software is associated with it.

Author: Cai Jiangyu

Email: cjycjl@21cn.com

QQ: 23181484

Modified to: 2004.05.29

转载请注明原文地址:https://www.9cbs.com/read-41407.html

New Post(0)