MUGEN Cheap Wiki
Advertisement

In this tutorial, we will explain how to use the most basic exploits: %n/%f method and these sample codes will be provided at the end.

%n and %f use the same sctrl: DisplayToClipboard or for short, DtC. They both write a byte to the specified memory, where %n is a method to write a data (byte) to the memory address, and %f is a function call relocation execution method (described as a return value in the Chinese Mainland community, which is wrong).

When %n modifies the address of the function called by %f, it will call this function address (call dword ptr [0x4B48E8] in M.U.G.E.N.), and it will go to our own code location to start executing our own code.

As an example, we have created a new character and named it "HelloWorld", and now we can start to write the code.

Tutorial2-1

“1”=0x31

Assuming we need to write a "1" at an address, what should we do?

We need to determine the address, which must be readable and writable. If you want to execute it, it must also be executable.

If you don't know what readable, writable, and executable are, you can refer to the article on MSDN: memory-protection

If you go to a place that is not writable or does not exist (displayed as "??" in the Cheat Engine memory), it will trigger the "EXCEPTION_ACCESS_VIOLATION" exception, which is commonly known as the 0xC0000005 exception.

In most cases, many places are not writable by default and in the memory space of M.U.G.E.N, there is a block of memory with a page attribute of "PAGE-EXECUTE_READWRITE", which is located between [0x004B7000~0x004C0000] and has sufficient space in this interval. Similarly, there is a small block of memory in the 0x004B4000 position, but do not use it unless your code is very long.

Next, we will demonstrate how to write "1" (as a string!) in 0x004B7000.

The following are three common code formulas for %n, all of which are used to write a byte to a specified memory address:

Assuming X is a decimal number, it will be converted in a hexadecimal value. For example, the string "1" is 31 in hexadecimal.

;For general %n write data, we have the following format:
;If X is an unsigned char, that is, a byte, 
;and Y is an address, 
;then these codes will write X to address Y
;Where X and Y are both decimal

[State ]
Type     = DisplayToClipboard
Trigger1 = 1
Text     = "%Xu%hn"
Params   = 1, Y

[state ]
type = DisplayToClipboard
trigger1 = 1
text = "%*d%hn%d"
params = X,0,Y

[state ]
type = DisplayToClipboard
trigger1 = 1
text = "%*d%n%d"
params = X,0,Y

X is decimal, so converting 0x31 to decimal is 49, Y is also decimal, so converting 0x004B7000 to decimal would be 4943872. So we got the following code:

[State ]
Type     = DisplayToClipboard
Trigger1 = 1
Text     = "%49u%hn"
Params   = 1, 4943872

[state ]
type = DisplayToClipboard
trigger1 = 1
text = "%*d%hn%d"
params = 49,0,4943872

[state ]
type = DisplayToClipboard
trigger1 = 1
text = "%*d%n%d"
params = 49,0,4943872

Choose any one of these three controllers to add to the character's code. After entering the round, we used Cheat Engine and found that the position of 0x004B7000 changed to 0x31,

But these are just strings, which are essentially the same as code. Almost every byte can be assembly code, but its meaning is very different from what we think. When we need to modify another memory address, we cannot use the "execute string 'Address=1234'" method. Assembly language is a "compiled language", and it must change from code string to bytecode to complete your expression

How to use basic assembly language code syntax? You can see here: Easy tutorial: A tutorial on assembly language knowledge commonly used in the "Cheap Character Community"

in (A) Necessary Preparations, We can use assembly tools such as nasm for assembly language compilation, and our code editors can be notepad++, Sakura Editor, VSCode, or even Windows Notepad. I usually use notepad++for assembly code writing.

In this tutorial, we use nasm with notepad++ to writeing codes.

first of all, we will create a .txt file, then name it with a sentence you like, and I call it first Code, then rename it with suffix .asm, so we can identify it as a assembly language source code. then use notepad++ to open it.

the first line, we should input as following line:

BITS 32


this will tell nasm.exe that this file is a 32 bit ASM source file but not 16 bit, then write our first code such as this:

mov dword [0x004b4000],'Hell'
mov dword [0x004b4004],'o Wo'
mov dword [0x004b4008],'rld'

these codes will write an string "Hello World" to memoey address 0x004b4000, we use mov instruction to move our immediate data to memory address. This code need to be compiled by nasm.exe, so we can use a command:

cmd /k pushd "$(CURRENT_DIRECTORY)" & "F:\asm\nasm.exe" -f bin "$(FULL_CURRENT_PATH)" -o "$(NAME_PART).bin" & PAUSE & EXIT

this command need notepad++, we can use run->run(R)... in menu of notepad++ to input this. don't forget to overwrite "F:\asm\nasm.exe" to your nasm.exe file path.

if we success, we will find a file in your source code dir, and it named by your source code name but suffix with ".bin".

then we should think about return to original because of %f exploit

[state ]
type = DisplayToClipboard
trigger1= 1
text = "%f"
params = pos X
ignorehitpause = 1

when we use this sctrl, mugen will call a pointer function at 0x4B48E8 to convert float value to string, that mean if we overwrite this pointer to our address, then mugen can execute our code automatically when we use %f, if you wonder why this pointer in 0x4B48E8, I will tell you after we know all basic knowledge. How can we overwrite this pointer? we can use %n, %n will write a byte to a address. before we use this, we should remember original value in 0x004B48E8: 0x00496651. this is a pointer to original function, we should jump back after our code being executed. so we need this code to the last line of our asm codes:

mov dword [0x4b48e8],0x496651;fix original value
push 0x00496651 ; push original function address to stack
ret ;ret can use current stack value to jump and add esp by 4

in this article we use 0x004b7000 to store our code, then we use %n as this:

[state -2,write 0]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 0,0,4933864;<-the last parameter convert to hex is 0x004B48E8
ignorehitpause = 1
[state -2,write 0x70]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 112,0,4933865 ;0x004B48E9
ignorehitpause = 1
[state -2, write 0x4b]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 75,0,4933866 ;0x004B48EA 
ignorehitpause = 1
[state -2, write 0]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 0,0,4933867 ;0x004B48EB
ignorehitpause = 1
;this code will set value of 0x004B48E8 to 0x004B7000

we can use %n converter to convert our asm codes to DtC sctrl.

after we converted them to DtC, we should insert original function modifer code(%n) to the head of our controllers, and insert %f to the tail

then we run the game, and use Cheat Engine to watch how the address value:

We success!

We sucess in the first try of Exploits


and our codes in 0x004b7000:

First try code

full code:

[state -2,write 0]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 0,0,4933864;<-the last parameter convert to hex is 0x004B48E8
ignorehitpause = 1
[state -2,write 0x70]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 112,0,4933865 ;0x004B48E9
ignorehitpause = 1
[state -2, write 0x4b]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 75,0,4933866 ;0x004B48EA 
ignorehitpause = 1
[state -2, write 0]
type = displaytoclipboard
trigger1= 1
text = "%.*d%n%d"
params = 0,0,4933867 ;0x004B48EB
ignorehitpause = 1
;this code will set value of 0x004B48E8 to 0x004B7000

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=199,0,4943872
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=5,0,4943873
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943874
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=64,0,4943875
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=75,0,4943876
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943877
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=72,0,4943878
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=101,0,4943879
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=108,0,4943880
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=108,0,4943881
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=199,0,4943882
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=5,0,4943883
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=4,0,4943884
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=64,0,4943885
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=75,0,4943886
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943887
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=111,0,4943888
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=32,0,4943889
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=87,0,4943890
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=111,0,4943891
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=199,0,4943892
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=5,0,4943893
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=8,0,4943894
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=64,0,4943895
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=75,0,4943896
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943897
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=114,0,4943898
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=108,0,4943899
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=100,0,4943900
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943901
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=199,0,4943902
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=5,0,4943903
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=232,0,4943904
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=72,0,4943905
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=75,0,4943906
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943907
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=81,0,4943908
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=102,0,4943909
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=73,0,4943910
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943911
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=104,0,4943912
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=81,0,4943913
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=102,0,4943914
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=73,0,4943915
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=0,0,4943916
ignorehitpause=1

[state Yoaijitsu]
type = DisplayToClipboard
trigger1 = 1
text="%.*d%n%d"
params=195,0,4943917
ignorehitpause=1

[state ]
type = DisplayToClipboard
trigger1= 1
text = "%f"
params = pos X
ignorehitpause = 1


Information provided by Sak.

Advertisement