Reverse Engineering "MixMaster MMORPG"
MixMaster
i like mmorpgs, they are fun to play and every time i play i respect the game more when i think about the technical stuff behind it as a developer. because of that i try every mmorpg i can find from different years good or bad. mixmaster is one of them. i never played it before, i dont even know what it is, and i started downloading it. the info i found about the game and the company was not the same as the info in the launcher, so i started thinking maybe this is a private server, maybe not. now lets start the game from the beginning.
below you can see the game files. the things that caught my eye are only mixmaster.dll and ddraw.dll. we also need to check the game folders. i worked before with mmorpgs that use popular engines and there are hundreds of sources/blog/forum posts online about them. but there is no info at all about this game. i would not say i am a reverse engineer good enough to fully understand an mmorpg, but i wanted to try. what we need to do is simple. run the game and check some things. look at the files and see the results of what we do in the game.

when we open the game there is not much in the launcher, but thats not the point we care about.

when we get to the server select screen, the texts are a bit higher than the mouse and that confused me. i dont think this is something acceptable for an mmorpg.

that made me a bit suspicious so i looked at mixmaster.exe, mixer.exe, and mixmaster.dll, but what caught my eye was mixmaster.dll. its 1.6mb so i thought maybe its packed, but there was nothing. now lets check the dll with ida.

since we will talk about many things i dont want to check every function one by one. the function
sub_6EA87F66();
is our main target, this is what we are curious about and where we will look to see why this game feels like a private server.

int sub_6EA87F66()
{
const char *v1; // [esp+24h] [ebp-24h]
const char *v2; // [esp+28h] [ebp-20h]
const char *v3; // [esp+2Ch] [ebp-1Ch]
const char *v4; // [esp+30h] [ebp-18h]
const char *v5; // [esp+34h] [ebp-14h]
const char *v6; // [esp+38h] [ebp-10h]
sub_6EA88C93((LPVOID)0x415317, (int)sub_6EA84F70, 5u);
sub_6EA88C93((LPVOID)0x482726, (int)sub_6EA86C30, 6u);
sub_6EA88C93((LPVOID)0x41630C, (int)sub_6EA84F04, 5u);
sub_6EA88C93((LPVOID)0x48B0D8, (int)sub_6EA84F2B, 5u);
sub_6EA88C93((LPVOID)0x49383B, (int)HideMonstersub_6EA8710A, 5u);
sub_6EA88C93((LPVOID)0x4853EF, (int)sub_6EA8752A, 5u);
sub_6EA88C93((LPVOID)0x487196, (int)sub_6EA87702, 5u);
sub_6EA87ECF();
sub_6EAD5660((LPVOID)0x425624, 12.71, 1);
sub_6EAB7286((LPCVOID)0x462AC0, sub_6EA87F52, (int)&dword_6EC04108);
sub_6EAB7634(0x462AC0);
v6 = sub_6EAD4F80();
v5 = sub_6EAD4F78();
v4 = sub_6EAD4F70();
v3 = sub_6EAD4F68();
v2 = sub_6EAD4F88();
v1 = sub_6EAD4F60();
sub_6EAD5560((LPVOID)0x468205, (int)v6, 1);
sub_6EAD5560((LPVOID)0x4682F3, (int)v5, 1);
sub_6EAD5560((LPVOID)0x406D60, (int)v4, 1);
sub_6EAD5560((LPVOID)0x406D98, (int)v3, 1);
sub_6EA878C0((LPVOID)0x52C040, (int)v2, 1);
sub_6EA878C0((LPVOID)0x52C060, (int)v1, 1);
sub_6EA86C46();
return sub_6EA86CF7();
}
the functions sub_6EA88C93, sub_6EAD5660, sub_6EAB7286, sub_6EAD5560, sub_6EA878C0, sub_6EAD55DC are all different, but they are basically memory write / hook codes. this makes me think the game might be a private server. but the sites and updates did not look like that to me, i do not know what they do. they all patch addresses inside the game (mixmaster.exe). if it is a private server, important info could be here, but there was not much important info.
(mixmaster.dll < > mixmaster.exe )

the place where we find the answer to why the mouse is behind the texts is sub_6EA87ECF. if we look at this pseudocode we see the following, this shows us:
char sub_6EA87ECF()
{
FARPROC ProcAddress; // eax
HMODULE ModuleHandleA; // eax
FARPROC lpAddress; // [esp+1Ch] [ebp-Ch]
LOBYTE(ProcAddress) = sub_6EAB7175() != 0;
if ( !(_BYTE)ProcAddress )
{
ModuleHandleA = GetModuleHandleA("gdi32.dll");//?
ProcAddress = GetProcAddress(ModuleHandleA, "CreateFontA");//?
lpAddress = ProcAddress;
if ( ProcAddress )
{
LOBYTE(ProcAddress) = sub_6EAB7286(ProcAddress, sub_6EA87D2E, (int)&dword_6EC04104) != 0;//?
if ( !(_BYTE)ProcAddress )
LOBYTE(ProcAddress) = sub_6EAB7634((int)lpAddress);
}
}
return (char)ProcAddress;
}
if i do this, the texts on the screen will be removed (i will explain this in the text).
the sub_6EA87D2E in the pseudocode shows the font. for now these explain why the texts in the game look like this.
int __stdcall sub_6EA87D2E(
int a1,
int a2,
int a3,
int a4,
int a5,
int a6,
int a7,
int a8,
int a9,
int a10,
int a11,
int a12,
int a13,
const char *a14)
{
const char *v14; // eax
int v16[6]; // [esp+48h] [ebp-40h] BYREF
int v17[6]; // [esp+60h] [ebp-28h] BYREF
int v18; // [esp+78h] [ebp-10h]
const char *v19; // [esp+7Ch] [ebp-Ch]
if ( a14 && *a14 )
v14 = a14;
else
v14 = "(null)";
v19 = v14;
if ( !a14 || !*a14 || !j_strcmp(a14, "Font") )
{
if ( (unsigned __int8)sub_6EAE8FB0(&off_6EC040EC) != 1 )
{
sub_6EB56190(&off_6EC040EC);
v18 = sub_6EAE8F10(46, 0);
if ( v18 != -1 )
{
sub_6EAE9120(v16, 0, v18);
sub_6EB567E0(v17);
sub_6EB56780(v17);
}
a14 = (const char *)sub_6EAE8F90(v16);
sub_6EB56780(v16);
}
else
{
a14 = "Segoe UI";
}
}
if ( !a12 )
a12 = 5;
return dword_6EC04104(a1, a2, a3, a4, a5, a6, a7, a8, dword_6EB8A010, a10, a11, a12, a13, a14);
}
i had to check everything in that dll one by one. i didnt say this in the blog but i had been analyzing this game for a month. i mixed old and new findings and the text might be a bit messy, sorry. because of that i might write a second blog about other findings, but for now i will focus on making a bot.
there were many functions in the dll. when i hooked them one by one i saw many didnt run. i forced them to run and called a debug function hoping to find something valuable, but i saw nothing.

later in august when i analyzed the game again my goal was to make a bot because i didnt want to waste so much time on a game that wont help me. if i hook gdi functions i could make a bot, right? i thought the sprites are drawn to the screen with gdi. if i find the x,y where a sprite is drawn by its name and send mouse clicks there (there was a function for this in mixmaster.dll) i could make a simple farmbot. but it didnt go as i thought. to test better i replaced ddraw with https://github.com/elishacloud/dxwrapper to see what happens. clearly the texts in the game were gone. the strings that stayed were not text, they were just images.

i did this to inject imgui. maybe you saw chams projects. with something like that i might see monsters. but i left that approach. maybe reading the game network would give me useful info. it was encrypted of course, but i wanted to check. for now forget the network part and let’s look at gdi stuff.

this let me see the strings in the game. whatever was on the screen was visible. with this i could see my x,y, the current map, the monster name when i hover, and dropped items.

this approach did not work because npcs are rendered differently in the game. if enemies were drawn with gdi i maybe would have finished the project.
next i tried to find my own x,y with cheat engine and do something. if i find my x,y and debug it and set a breakpoint and find offsets that use that address, and then use those functions to reach other objects, that would be great.
even if that does not work, my plan was clear:
- is there an anti cheat?
- can i decrypt the network?
- where do game objects come from and what files are in the game folder?
- where is the entity list?
first lets talk about anti cheat. i thought there was no anti cheat but maybe both yes and no. the easiest thing was to add cheats to the strings. it was faster than i expected lol.

given how old the game is i think this is acceptable.

but while looking at some functions i found code full of heavy encryptions.

but there was no xtrap dll in the game. i wasnt sure. while trying to decrypt the network i found the pseudocode below so i searched. i had no experience with xtrap before. i didnt know what these things were. when i searched the pseudocode on github i saw it was for xtrap.

because there was no xtrap dll and the xtrap functions didnt run, our only anti cheat was simple code that checks for cheat engine.
i found some things about the network but i do not want to show them. they probably trusted encryption so they did not think much. the game has many item duplicate bugs. if i show network stuff it could upset players.
just kidding, here is how i did it.
what i do in these games is the same. look at send and recv, hook them, and see the data.

if there is encryption, try the function more and look at xrefs where it is used, then hook that function.

all our network is here.

the encryption part is here. what we need is a packet sniffer using these. you can either make these functions decrypt in your project or hook the game functions, both work.

catch the encrypted and plain values with a4 in the function i showed, then let the game continue without changing them. this project is from august so i do not have full code now and i do not want to redo it. we can see what packets show.

understanding them can be hard. login packets are not what i care most about, but packets have strings like “devilco” which are npc names.
Len: 0014 | SubKey: 0xbd
f6 93 00 00 01 06 01 6e 61 6e 6d 65 65 35 34 34
35 00 00 00
ascii: .......nanmee5445...
Len: 0079 | SubKey: 0x1c
66 5a 7b 56 13 31 00 6e 61 6e 6d 65 65 35 34 34
35 00 00 0c 02 a1 00 95 30 16 00 73 23 00 00 f8
15 01 cd 01 00 00 00 00 00 e0 8f 01 00 00 00 00
00 a8 f0 01 00 00 00 00 00 07 00 00 66 00 29 00
31 00 30 00 35 00 21 00 18 00 1d 00 00 00 44 02
6f 00 44 02 6f 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 f6 93 00 00 01 00
00 00 00 00 00 00 00 00 00
ascii: fZ{V.1.nanmee5445.......0..s#.....................
----------------------------------------------------------------------
Len: 000c | SubKey: 0x1d
43 03 00 a1 00 02 a2 00 02 e7 01 01
ascii: C...........
----------------------------------------------------------------------
Len: 007e | SubKey: 0x1e
67 00 00 02 00 44 65 76 69 6c 63 6f 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01
00 00 1a 00 07 00 c0 04 00 00 00 00 00 00 79 03
00 00 00 00 00 00 78 05 00 00 00 00 00 00 00 00
00 0f 00 07 00 09 00 08 00 02 00 02 00 03 00 06
00 09 00 00 00 00 00 26 00 12 00 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
ascii: g....Devilco..................................y...
----------------------------------------------------------------------
Len: 007e | SubKey: 0x1f
67 00 01 cc 00 46 6c 6f 77 63 6f 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
00 00 1a 00 04 00 f1 00 00 00 00 00 00 00 8b 00
00 00 00 00 00 00 22 01 00 00 00 00 00 00 00 00
00 05 00 04 00 0a 00 05 00 01 00 01 00 02 00 04
00 06 00 00 00 00 00 19 00 0f 00 03 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
ascii: g....Flowco.......................................
if we wait and watch more we see other data. for now these look like meaningless numbers.
[04:44:21] DECRYPTED | Len: 007e | SubKey: 0x32
67 01 11 5d 00 4e 6f 73 69 65 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
00 00 20 00 07 00 79 03 00 00 00 00 00 00 79 03
00 00 00 00 00 00 78 05 00 00 00 00 00 00 03 00
00 05 00 09 00 08 00 05 00 02 00 02 00 03 00 06
00 03 00 1b 00 0f 00 1b 00 0f 00 02 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
ASCII: g..].Nosie........................ ...y.......y...
----------------------------------------------------------------------
[04:44:21] DECRYPTED | Len: 007e | SubKey: 0x33
67 01 12 e8 00 4a 61 6d 6f 6f 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01
00 00 1e 00 05 00 22 01 00 00 00 00 00 00 22 01
00 00 00 00 00 00 12 02 00 00 00 00 00 00 03 00
00 09 00 02 00 06 00 04 00 01 00 01 00 02 00 04
00 03 00 18 00 0e 00 18 00 0e 00 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
ASCII: g....Jamoo............................"......."...
----------------------------------------------------------------------
[04:44:21] DECRYPTED | Len: 007e | SubKey: 0x34
67 01 13 39 00 42 75 6d 61 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01
00 00 20 00 07 00 79 03 00 00 00 00 00 00 79 03
00 00 00 00 00 00 78 05 00 00 00 00 00 00 03 00
00 05 00 02 00 0f 00 05 00 02 00 02 00 03 00 06
00 03 00 1e 00 0f 00 1e 00 0f 00 03 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
ASCII: g..9.Buma......................... ...y.......y...
----------------------------------------------------------------------
[04:44:29] DECRYPTED | Len: 0fdb | SubKey: 0x7b
...
ASCII: 1.Dodge.7.100.101.102.103.104.105.106.-1.-1.1.1.1.
----------------------------------------------------------------------
[04:44:29] DECRYPTED | Len: 0115 | SubKey: 0x7b
31 09 bd ba c6 ae b6 f3 c0 cc c5 a9 09 33 30 09
30 09 31 09 31 09 31 09 38 09 31 35 09 31 09 30
09 31 30 09 30 09 30 09 35 30 30 30 0d 0a 31 09
31 09 30 09 30 09 30 09 30 0d 0a 31 09 32 09 30
09 30 09 30 09 30 0d 0a 32 09 32 09 30 09 30 09
30 09 30 0d 0a 30 09 30 09 30 09 30 09 30 09 30
0d 0a 31 09 31 09 30 09 30 09 30 09 30 0d 0a 30
09 30 09 30 09 30 09 30 09 30 0d 0a 32 09 32 09
30 09 30 09 30 09 30 0d 0a 30 09 30 09 30 09 30
09 30 09 30 0d 0a 31 09 31 09 30 09 30 09 30 09
30 0d 0a 2d 34 30 09 2d 34 30 09 30 09 30 09 30
09 30 0d 0a 38 39 09 39 30 09 30 09 30 09 30 09
30 0d 0a 33 30 09 33 31 09 30 09 30 09 30 09 30
0d 0a bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1 20
b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1 e2
bc fa 09 bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1
20 b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1
e2 bc fa 0d 0a
ASCII: 1............30.0.1.1.1.8.15.1.0.10.0.0.5000..1.1.
----------------------------------------------------------------------
[04:44:29] DECRYPTED | Len: 0115 | SubKey: 0x7b
32 09 bd ba c6 ae b6 f3 c0 cc c5 a9 09 34 30 09
30 09 31 09 31 09 31 09 38 09 31 35 09 31 09 30
09 31 36 09 30 09 30 09 35 30 30 30 0d 0a 31 09
31 09 30 09 30 09 30 09 30 0d 0a 31 09 32 09 30
09 30 09 30 09 30 0d 0a 32 09 32 09 30 09 30 09
30 09 30 0d 0a 30 09 30 09 30 09 30 09 30 09 30
0d 0a 31 09 31 09 30 09 30 09 30 09 30 0d 0a 30
09 30 09 30 09 30 09 30 09 30 0d 0a 32 09 32 09
30 09 30 09 30 09 30 0d 0a 30 09 30 09 30 09 30
09 30 09 30 0d 0a 31 09 31 09 30 09 30 09 30 09
30 0d 0a 2d 34 30 09 2d 34 30 09 30 09 30 09 30
09 30 0d 0a 38 39 09 39 30 09 30 09 30 09 30 09
30 0d 0a 34 30 09 34 31 09 30 09 30 09 30 09 30
0d 0a bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1 20
b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1 e2
bc fa 09 bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1
20 b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1
e2 bc fa 0d 0a
ASCII: 2............40.0.1.1.1.8.15.1.0.16.0.0.5000..1.1.
----------------------------------------------------------------------
[04:44:29] DECRYPTED | Len: 0115 | SubKey: 0x7b
33 09 bd ba c6 ae b6 f3 c0 cc c5 a9 09 34 30 09
30 09 31 09 31 09 31 09 38 09 31 35 09 31 09 30
09 32 33 09 30 09 30 09 35 30 30 30 0d 0a 31 09
31 09 30 09 30 09 30 09 30 0d 0a 31 09 32 09 30
09 30 09 30 09 30 0d 0a 32 09 32 09 30 09 30 09
30 09 30 0d 0a 30 09 30 09 30 09 30 09 30 09 30
0d 0a 31 09 31 09 30 09 30 09 30 09 30 0d 0a 30
09 30 09 30 09 30 09 30 09 30 0d 0a 32 09 32 09
30 09 30 09 30 09 30 0d 0a 30 09 30 09 30 09 30
09 30 09 30 0d 0a 31 09 31 09 30 09 30 09 30 09
30 0d 0a 2d 34 30 09 2d 34 30 09 30 09 30 09 30
09 30 0d 0a 38 39 09 39 30 09 30 09 30 09 30 09
30 0d 0a 34 30 09 34 31 09 30 09 30 09 30 09 30
0d 0a bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1 20
b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1 e2
bc fa 09 bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1
20 b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1
e2 bc fa 0d 0a
ASCII: 3............40.0.1.1.1.8.15.1.0.23.0.0.5000..1.1.
----------------------------------------------------------------------
[04:44:29] DECRYPTED | Len: 0115 | SubKey: 0x7b
34 09 bd ba c6 ae b6 f3 c0 cc c5 a9 09 34 30 09
30 09 31 09 31 09 31 09 38 09 31 35 09 31 09 30
09 33 31 09 30 09 30 09 35 30 30 30 0d 0a 31 09
31 09 30 09 30 09 30 09 30 0d 0a 31 09 32 09 30
09 30 09 30 09 30 0d 0a 32 09 32 09 30 09 30 09
30 09 30 0d 0a 30 09 30 09 30 09 30 09 30 09 30
0d 0a 31 09 31 09 30 09 30 09 30 09 30 0d 0a 30
09 30 09 30 09 30 09 30 09 30 0d 0a 32 09 32 09
30 09 30 09 30 09 30 0d 0a 30 09 30 09 30 09 30
09 30 09 30 0d 0a 31 09 31 09 30 09 30 09 30 09
30 0d 0a 2d 34 30 09 2d 34 30 09 30 09 30 09 30
09 30 0d 0a 38 39 09 39 30 09 30 09 30 09 30 09
30 0d 0a 34 30 09 34 31 09 30 09 30 09 30 09 30
0d 0a bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1 20
b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1 e2
bc fa 09 bb f3 b4 eb bf a1 b0 d4 20 c3 df b0 a1
20 b5 a5 b9 cc c1 f6 b8 a6 20 c1 d6 b4 c2 20 b1
e2 bc fa 0d 0a
ASCII: 4............40.0.1.1.1.8.15.1.0.31.0.0.5000..1.1.
next we need to know about game objects and npc names like “devilco”, how they work. the packets can look meaningless. so lets check the game files.

i couldnt find what some files (.an, .ani) do or how they are used. nothing seemed useful for me, so i focused on .sct files. there is a file called monster.sct, 145 kb. that could have interesting info.

i think monster.sct or .sct files in general look encrypted.


lets search for .sct files in ida.
before looking at all .sct things, lets pick one randomly. i want to check skillinfo.

our pseudocode looks like this:
int sub_425FB0()
{
FILE *v0; // eax
FILE *v1; // ebp
int v3; // esi
_BYTE *v4; // ebx
const char *v5; // eax
int v6; // eax
const char *v7; // eax
unsigned int v8; // esi
char *v9; // edi
const char *v10; // eax
const char *v11; // eax
int *v12; // edi
int v13; // ebp
const char *v14; // eax
int i; // edi
const char *v16; // eax
int j; // edi
const char *v18; // eax
const char *v19; // eax
char v20; // [esp+0h] [ebp-20h]
char v21; // [esp+7h] [ebp-19h]
int v22; // [esp+8h] [ebp-18h] BYREF
unsigned __int8 v23[8]; // [esp+Ch] [ebp-14h] BYREF
int v24; // [esp+1Ch] [ebp-4h]
sub_445B30(v23);
v24 = 0;
sub_446A40(250);
v0 = fopen(".\\Data\\script\\skillinfo.sct", "rb");
v1 = v0;
if ( !v0 )
{
sub_422950("file not found : skillinfo.sct", v20);
sub_44D870(&off_AB0CCC);
v24 = -1;
return sub_446A30(v23);
}
v3 = _filelength(v0->_file);
v4 = operator new(v3 + 1);
memset(v4, 0, v3 + 1);
fread(v4, v3, 1u, v1);
sub_446A60(v23, 0x7Bu, v3, (int)v4, (int)v4);
v4[v3] = 0;
fclose(v1);
v21 = 1;
v22 = 658697;
while ( v21 )
{
v5 = (const char *)sub_4FDE85(v4, (char *)&v22);
if ( !v5 )
goto LABEL_16;
v6 = j__atol(v5);
v21 = 0;
LABEL_9:
v8 = 208 * v6;
byte_6D6D6C[208 * v6] = v6;
v9 = (char *)&unk_6D6D6D + 208 * v6;
*(_DWORD *)v9 = 0;
*((_DWORD *)v9 + 1) = 0;
*((_DWORD *)v9 + 2) = 0;
*((_DWORD *)v9 + 3) = 0;
*((_DWORD *)v9 + 4) = 0;
v10 = (const char *)sub_4FDE85(0, (char *)&v22);
strncpy(v9, v10, 0x14u);
v11 = (const char *)sub_4FDE85(0, (char *)&v22);
byte_6D6D81[v8] = j__atol(v11);
v12 = &dword_6D6D88[v8 / 4];
v13 = 9;
do
{
v14 = (const char *)sub_4FDE85(0, (char *)&v22);
*v12++ = j__atol(v14);
--v13;
}
while ( v13 );
for ( i = 0; i < 5; ++i )
{
v16 = (const char *)sub_4FDE85(0, (char *)&v22);
byte_6D6DAC[v8 + i] = j__atol(v16);
}
for ( j = 0; j < 5; ++j )
{
v18 = (const char *)sub_4FDE85(0, (char *)&v22);
byte_6D6DB1[v8 + j] = j__atol(v18);
}
v19 = (const char *)sub_4FDE85(0, (char *)&v22);
strncpy(&byte_6D6DB6[v8], v19, 0x80u);
}
v7 = (const char *)sub_4FDE85(0, (char *)&v22);
if ( v7 )
{
v6 = j__atol(v7);
if ( v6 )
goto LABEL_9;
}
LABEL_16:
j_j__free(v4);
v24 = -1;
return sub_446A30(v23);
}
if we read this we can see what we need. but when i looked at other .sct functions i saw they parse differently, so we can limit our scope to some functions.
from the first function we saw, functions that use v24 are about encryption. our first functions (sub_445B30) give the table data for our xor function (sub_446A60). also our key is 123.

it is a bit confusing for me but if we put this into code i hope it will make a structure like a csv table for us. the tables used in this xor confused me a little but i managed to do it.
def build_T() -> bytes:
T = [0] * 512
def sc(x: int) -> int:
return x & 0xFF
assigns = {
6:-52,13:-52,
0:-34,1:-30,2:-83,3:-10,4:-110,5:4,7:79,8:-96,9:-48,10:-53,11:102,12:95,14:107,15:9,
16:47,17:105,18:-85,19:70,20:-67,21:51,22:52,23:57,24:-126,25:75,26:-13,27:34,28:-115,29:23,30:8,31:-70,
32:-125,33:56,34:-33,35:-56,36:-28,37:-68,38:-100,39:-17,40:-113,41:-107,42:-119,43:74,44:-6,45:59,46:-19,47:112,
48:-1,49:120,50:77,51:-1,52:-122,53:-120,54:108,55:-15,56:2,57:98,58:-36,59:-65,60:-11,61:101,62:-55,63:-78,
64:43,65:-46,66:-107,80:120,82:-12,101:-12,107:-90,124:-90,86:15,121:15,138:-20,139:-20,
67:84,68:110,69:-51,70:-104,71:-79,72:-32,73:-123,74:-69,75:22,76:-66,77:-111,78:-27,79:-18,81:-40,83:-4,84:-7,85:52,
87:-26,88:61,89:83,90:-77,91:-35,92:-15,93:-83,94:127,95:39,96:68,97:95,98:-91,99:66,100:-114,102:-46,103:-117,104:-62,
105:86,106:31,108:29,109:119,110:93,111:47,112:-118,113:-74,114:105,115:-39,116:98,117:-24,118:112,119:-67,120:-75,
122:26,123:44,125:121,126:-16,127:-85,128:76,129:-29,130:7,131:-42,132:40,133:-94,134:-49,135:-88,136:111,137:92,
140:-79,141:64,163:-84,178:-84,142:14,143:-108,144:24,145:82,146:70,147:-75,148:-9,149:49,150:117,151:-76,
161:-91,162:100,164:63,165:113,166:-78,167:-64,168:-29,169:65,170:-57,171:60,172:27,173:-6,174:83,175:24,176:75,177:89,
179:-16,180:90,181:-87,182:48,183:-41,184:74,185:8,186:81,187:-86,188:-8,189:46,190:-39,191:-25,192:60,193:68,
194:-31,195:125,196:-3,197:111,198:42,199:104,200:-68,201:78,202:-37,203:-105,204:65,205:25,206:-51,207:-73,
208:-123,209:55,210:-86,211:-113,212:4,213:41,214:-98,215:-97,216:-82,217:-71,218:-93,219:-72,227:-22,228:-22,246:6,265:6,
220:17,221:33,222:-112,223:-13,224:-56,225:127,226:101,229:124,230:-44,231:-19,232:103,233:-101,234:94,235:21,
236:35,237:-54,238:109,239:40,240:114,241:-77,242:57,243:-53,244:87,245:-37,247:85,248:19,249:2,250:41,251:-119,252:37,
253:-7,254:125,255:77,256:-99,257:-127,258:126,259:88,260:-120,261:53,262:99,263:-121,264:-108,266:82,267:54,268:104,
269:108,270:-45,271:-8,272:0x80,273:-62,274:11,275:-11,276:33,277:-122,278:-102,279:117,280:-48,281:110,282:-18,283:-47,
284:67,285:42,286:118,287:-66,288:62,289:-55,290:-81,291:63,292:-109,293:48,294:-17,295:-21,296:-95,297:118,311:-109,
318:-38,321:-38,324:-23,341:-23,298:23,299:-100,300:10,301:-14,302:18,303:36,304:44,305:11,306:-58,307:-49,308:-116,
309:28,310:-105,312:69,313:107,314:-73,315:71,316:-74,317:-9,319:-5,320:20,322:54,323:10,325:0x80,326:46,327:38,328:-42,
329:-28,330:121,331:-95,332:-47,333:37,334:1,335:122,336:21,337:-81,
342:-41,343:58,344:73,345:87,346:-117,347:116,348:-61,349:18,350:-87,351:-45,352:-35,353:93,354:36,355:-112,356:86,357:3,
358:-4,359:-115,360:-25,361:-60,362:-26,363:29,364:-59,365:-118,366:-76,367:-116,368:59,369:-89,370:-65,371:-31,372:32,
373:-125,374:-60,375:-92,381:72,386:72,399:80,404:80,376:9,377:20,378:16,379:-2,380:85,382:53,383:-103,384:-92,385:109,
387:99,388:-5,389:-126,390:124,391:45,392:12,393:-58,394:89,395:-80,396:25,397:13,398:3,400:13,401:30,402:-89,403:103,
405:115,406:-88,407:-32,408:84,409:-61,410:-64,411:26,412:78,413:100,414:88,415:-114,416:-121,417:32,418:-63,419:61,
420:45,421:-57,422:-14,423:-110,424:-30,425:-82,426:50,427:96,428:-43,429:1,430:-97,431:-59,432:34,433:-34,434:-50,
435:-99,436:-94,437:123,438:-40,439:-93,440:106,441:12,442:30,443:43,444:97,445:14,446:-72,447:27,448:38,449:-124,
450:56,451:31,452:119,453:-36,455:106,465:-106,484:-106,454:91,456:-24,457:62,458:51,459:16,460:-111,461:69,462:-103,
463:90,464:5,466:-80,467:-43,468:-10,469:-98,470:-124,471:-33,472:-101,473:81,474:116,475:-27,476:55,477:17,478:66,
479:5,480:-70,481:35,482:92,483:73,485:-102,486:28,487:-104,488:79,489:-50,490:96,491:-44,492:39,493:97,494:-127,
495:76,496:49,497:67,498:-2,499:-69,500:102,501:19,502:22,503:114,504:122,505:-96,506:123,507:-63,508:-71,509:94,510:-54,
511:50,
}
for idx, val in assigns.items():
T[idx] = sc(val)
s1 = [0x3A, 0x07, 0xEB, 0xFD, 0x71, 0x7E, 0x73, 0x00]
for k, b in enumerate(s1):
T[152 + k] = b
s2 = [0x47, 0x5B, 0x00]
for k, b in enumerate(s2):
T[338 + k] = b
return bytes(T)
def crypt(data: bytes, T: bytes) -> bytes:
c1 = T[247]
c2 = T[500]
out = bytearray(len(data))
for i, b in enumerate(data):
c3 = T[511 - 2 * (i & 0xFF)]
out[i] = b ^ c1 ^ c2 ^ c3
return bytes(out)
def main():
T = build_T()
sct_files = [f for f in os.listdir('.') if f.endswith('.sct')]
if not sct_files:
print("No .sct files found.")
return
for input_filename in sct_files:
output_filename = input_filename.replace('.sct', '.dec')
try:
with open(input_filename, "rb") as f:
enc = f.read()
plain = crypt(enc, T)
with open(output_filename, "wb") as f:
f.write(plain)
print(f"Decrypted: {input_filename} -> {output_filename}")
except Exception as e:
print(f"Error processing {input_filename}: {e}")
here are the encrypted and decrypted versions of skillinfo.sct.
encrypted:

decrypted:

i decrypted all .sct files, i’ll show the contents briefly.
item.dec
1 B 0 0 110327 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
2 C 0 0 110330 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
3 F 0 0 110333 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
4 G 0 0 110336 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
5 H 0 0 110339 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
6 J 0 0 110342 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
7 K 0 0 110345 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
8 L 0 0 110348 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 1 0 Event Item Used to complete LIEVO text. Complete the letters to find the event npc 0 0 0 FFA500
9 P 0 0 110351 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
10 Q 0 0 110354 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
11 U 0 0 110357 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
12 V 0 0 110360 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 1 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
13 W 0 0 110363 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
14 Y 0 0 110366 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
15 Z 0 0 110369 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Event Item An alphabet for events that presents a gift when you complete certain words 0 0 0 FFA500
16 Gift Exchange Ticket 1 0 0 110372 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
17 Gift Exchange Ticket 2 0 0 110375 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
18 Gift Exchange Ticket 3 0 0 110378 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
19 Gift Exchange Ticket 4 0 0 110381 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
20 Gift Exchange Ticket 5 0 0 110384 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
21 Gift Exchange Ticket 6 0 0 110387 0 0 999 0 0 0 0 0 0 0 0 0 0 0 0 6 0 Event Item You can exchange with real book if you gather certain amount of ticket. 0 0 0 FFA500
monster.dec
1 Draco 1 1 0 1 2 100 0 0 2 0 0
2 Devilco 2 2 1 1 2 100 0 0 2 0 0
3 Beasco 3 3 2 1 2 100 0 0 2 0 0
4 Birdco 4 4 3 1 2 100 0 0 2 0 0
5 Inseco 5 5 4 1 2 100 0 0 2 0 0
6 Weird Rabbit 615 343 2 40 8 31000 0 0 7 0 5024
7 Weird Rabbit 615 343 2 60 8 51000 0 0 7 0 5024
8 Weird Rabbit 615 343 2 80 8 131000 0 0 7 0 5024
9 Pikey 9 9 0 3 2 200 0 0 2 0 0
10 Weird Rabbit 615 343 2 100 8 231000 0 0 7 0 5030
11 Weird Rabbit 615 343 2 120 8 351000 0 0 7 0 5030
12 Mortar Rabbit 549 293 2 40 2 31000 810 0 7 0 0
13 Imon 10 10 0 5 2 300 0 0 2 0 0
14 Mortar Rabbit 549 293 2 60 2 51000 810 0 7 0 0
15 Mortar Rabbit 549 293 2 80 2 131000 810 0 7 0 0
16 Mortar Rabbit 549 293 2 100 2 231000 810 0 7 0 0
17 Noa 11 11 0 7 2 400 0 0 2 0 0
monster_01.dec
1 Draco 0 1 0 1 2 100 0 0 2 0 0
2 Devilco 0 2 1 1 2 100 0 0 2 0 0
3 Beasco 0 3 2 1 2 100 0 0 2 0 0
4 Birdco 0 4 3 1 2 100 0 0 2 0 0
5 Inseco 0 5 4 1 2 100 0 0 2 0 0
6 Weird Rabbit 0 343 2 40 8 31000 0 0 7 0 0
7 Weird Rabbit 0 343 2 60 8 51000 0 0 7 0 0
8 Weird Rabbit 0 343 2 80 8 131000 0 0 7 0 0
9 Pikey 0 9 0 3 2 200 0 0 2 0 0
10 Weird Rabbit 0 343 2 100 8 231000 0 0 7 0 0
11 Weird Rabbit 0 343 2 120 8 351000 0 0 7 0 0
12 Mortar Rabbit 0 293 2 40 2 31000 810 0 7 0 0
13 Imon 0 10 0 5 2 300 0 0 2 0 0
14 Mortar Rabbit 0 293 2 60 2 51000 810 0 7 0 0
15 Mortar Rabbit 0 293 2 80 2 131000 810 0 7 0 0
16 Mortar Rabbit 0 293 2 100 2 231000 810 0 7 0 0
gamemessage.dec
1 %s cannot receive a whisper now.
2 There is no acquisition authority about this item.
3 Request trade to %s.
4 %s is trading with others.
5 %s has offered a trade. Are you interested?
6 %s cancelled trading.
7 %s cancelled trading.
8 There has been an error in trading with %s.
9 Dealing with %s was a success.
10 %s order was received.
11 %s is controllable if the level of a character is more than %d.
12 %s has reached its maximum level.
13 Need %u GP for rank up. Would you like to rank up?
14 Your level is insufficient for a rank up. Rank up is possible if your level reaches %d.
15 An item cannot be thrown away in the current state.
16 An item cannot be used in the current state.
17 Choose the target.
18 The level of %s can not be more than %d levels higher than your Level.
19 You cannot use this equipment in the current state.
20 You do not have enough MP.
21 You do not have enough HP.
npc_pos.dec
1 69 129 129
2 57 180 129
3 57 180 51
4 59 37 62
5 60 90 43
6 63 66 68
7 67 38 188
8 84 131 124
9 111 97 134
10 57 118 79
map.dec
1 Mashimaro Zone 0 0 3 0 1 4
2 Herseba Entrance 335 494 4 0 1 0
3 Northern Magirita 487 538 4 0 1 0
4 Mashimaro Zone 0 0 3 0 1 4
5 Mashimaro Zone 0 0 3 0 1 4
6 Magirita West Sea 442 512 4 0 1 0
7 Mashimaro Zone 0 0 3 0 1 4
8 Mashimaro Zone 0 0 3 0 1 4
9 Kambu Zone 0 0 3 0 1 4
10 Kambu Zone 0 0 3 0 1 4
11 Kambu Zone 0 0 3 0 1 4
12 Kambu Zone 0 0 3 0 1 4
systemmessage.dec
1 @ User authentication failure
2 @ Connection of the existing connection person was cut.
3 @ Character deletion failure.
4 @ Same character name exists.
5 @ Character generation failure
6 @ Server connection failure
7 @ Zone move failure
8 @ Game storage information error (code : %d)
9 Connection to server was canceled (%d)
10 error : 114
11 error number : % d graphic card does not support 3D function.
i also looked at the interface function. maybe i could use it for UI things in the game but sadly i couldn’t.
below you can see the pseudocode.
int __thiscall sub_443BB0(int this, int a2)
{
int v3; // esi
int *v4; // ebp
void *v5; // eax
unsigned int v6; // edx
int v7; // ebp
char *v8; // eax
char v9; // cl
int v10; // edi
int v11; // esi
void *v12; // eax
int v13; // eax
int v14; // ebp
int v15; // ebp
int v16; // esi
bool v17; // cc
void *v18; // eax
unsigned int v19; // edx
int result; // eax
int v21; // edi
int v22; // esi
_DWORD *v23; // eax
char v24; // cl
_DWORD *v25; // eax
int v26; // eax
int v27; // ecx
int v28; // edx
int v29; // edi
int v30; // esi
int v31; // ebp
int v32; // esi
int v33; // [esp+10h] [ebp-128h]
int v34; // [esp+10h] [ebp-128h]
int v35; // [esp+14h] [ebp-124h]
int v36; // [esp+14h] [ebp-124h]
int v37; // [esp+14h] [ebp-124h]
int v38; // [esp+18h] [ebp-120h]
int v39; // [esp+1Ch] [ebp-11Ch]
int i; // [esp+1Ch] [ebp-11Ch]
_DWORD *v41; // [esp+20h] [ebp-118h]
int v42; // [esp+20h] [ebp-118h]
_DWORD *v43; // [esp+24h] [ebp-114h] BYREF
int v44; // [esp+28h] [ebp-110h]
int v45; // [esp+2Ch] [ebp-10Ch]
char v46[100]; // [esp+30h] [ebp-108h] BYREF
char v47; // [esp+94h] [ebp-A4h]
v45 = a2;
v3 = 0;
sub_443060();
if ( sub_448850((char *)byte_52B9ED, (int)".\\Data\\Interface", a2, 0) )
{
v4 = (int *)(this + 28332);
sub_448A70(this + 28332, 4, 1);
if ( *(_DWORD *)(this + 28332) )
{
v5 = malloc(444 * *(_DWORD *)(this + 28332));
v6 = 444 * *v4;
*(_DWORD *)(this + 12) = v5;
memset(v5, 0, v6);
v35 = 0;
if ( *v4 > 0 )
{
v33 = 0;
do
{
v7 = v33 + *(_DWORD *)(this + 12);
*(_DWORD *)v7 = v3;
v44 = v3 + 1;
sub_448A70(v46, 101, 1);
v8 = v46;
do
{
v9 = *v8;
v8[v7 - (_DWORD)v46 + 4] = *v8;
++v8;
}
while ( v9 );
sub_448A70(v46, 101, 1);
qmemcpy((void *)(v7 + 155), v46, 0x64u);
*(_BYTE *)(v7 + 255) = v47;
*(_BYTE *)(v7 + 255) = 0;
sub_448A70(v46, 257, 1);
sub_448A70(v7 + 54, 101, 1);
if ( !v46[0] )
*(_BYTE *)(v7 + 54) = 0;
sub_448A70(v7 + 256, 4, 1);
v41 = (_DWORD *)(v7 + 260);
sub_448A70(v7 + 260, 4, 1);
sub_448A70(v7 + 264, 4, 1);
sub_448A70(v7 + 268, 4, 1);
sub_448A70(v7 + 272, 4, 1);
sub_448A70(v7 + 276, 4, 1);
sub_4426D0(v45, v7);
sub_448A70(v7 + 281, 1, 1);
sub_448A70(v7 + 412, 1, 1);
v10 = v7 + 332;
v11 = 10;
do
{
sub_448A70(v10 - 40, 4, 1);
sub_448A70(v10, 4, 1);
sub_448A70(v10 + 40, 4, 1);
v10 += 4;
--v11;
}
while ( v11 );
sub_448A70(v7 + 288, 4, 1);
if ( *(_DWORD *)(v7 + 288) )
{
v12 = malloc(444 * *(_DWORD *)(v7 + 288));
*(_DWORD *)(v7 + 284) = v12;
memset(v12, 0, 444 * *(_DWORD *)(v7 + 288));
v39 = 0;
if ( *(int *)(v33 + *(_DWORD *)(this + 12) + 288) > 0 )
{
v43 = (_DWORD *)(v7 + 256);
v38 = 0;
do
{
v13 = v44;
v14 = v38 + *(_DWORD *)(v33 + *(_DWORD *)(this + 12) + 284);
*(_DWORD *)v14 = v44;
v44 = v13 + 1;
sub_448A70(v46, 101, 1);
strcpy((char *)(v14 + 4), v46);
sub_448A70(v46, 101, 1);
qmemcpy((void *)(v14 + 155), v46, 0x64u);
*(_BYTE *)(v14 + 255) = v47;
*(_BYTE *)(v14 + 255) = 0;
sub_448A70(v46, 257, 1);
sub_448A70(v14 + 54, 101, 1);
if ( !v46[0] )
*(_BYTE *)(v14 + 54) = 0;
sub_448A70(v14 + 256, 4, 1);
sub_448A70(v14 + 260, 4, 1);
sub_448A70(v14 + 264, 4, 1);
sub_448A70(v14 + 268, 4, 1);
if ( !lstrcmpA("ID_SUB_TUTORIAL_NEXTBUTTON_DISABLE", (LPCSTR)(v14 + 4)) )
--*(_DWORD *)(v14 + 268);
*(_DWORD *)(v14 + 256) = *v43;
*(_DWORD *)(v14 + 260) = *v41;
sub_448A70(v14 + 272, 4, 1);
sub_448A70(v14 + 276, 4, 1);
sub_448A70(v14 + 281, 1, 1);
sub_448A70(v14 + 412, 1, 1);
v15 = v14 + 332;
v16 = 10;
do
{
sub_448A70(v15 - 40, 4, 1);
sub_448A70(v15, 4, 1);
sub_448A70(v15 + 40, 4, 1);
v15 += 4;
--v16;
}
while ( v16 );
v17 = ++v39 < *(_DWORD *)(v33 + *(_DWORD *)(this + 12) + 288);
v38 += 444;
}
while ( v17 );
}
}
v3 = v44;
v17 = ++v35 < *(_DWORD *)(this + 28332);
v33 += 444;
}
while ( v17 );
}
}
}
*(_DWORD *)(this + 28428) = v3;
v18 = malloc(4 * v3);
v19 = 4 * *(_DWORD *)(this + 28428);
*(_DWORD *)(this + 16) = v18;
memset(v18, 0, v19);
result = *(_DWORD *)(this + 28332);
v21 = 0;
v36 = 0;
if ( result > 0 )
{
v22 = 0;
do
{
v23 = (_DWORD *)(v22 + *(_DWORD *)(this + 12));
*(_DWORD *)(*(_DWORD *)(this + 16) + 4 * v21) = v23;
v24 = *((_BYTE *)v23 + 281);
++v21;
v43 = v23;
if ( v24 == 1 )
{
v42 = *(_DWORD *)(this + 28);
v43 = (_DWORD *)sub_442FD0(v42, *(_DWORD *)(v42 + 4), &v43);
sub_443A90(1);
v25 = v43;
*(_DWORD *)(v42 + 4) = v43;
*(_DWORD *)v25[1] = v25;
}
v26 = *(_DWORD *)(v22 + *(_DWORD *)(this + 12) + 288);
if ( v26 )
{
v27 = 0;
if ( v26 > 0 )
{
v28 = 0;
do
{
*(_DWORD *)(*(_DWORD *)(this + 16) + 4 * v21++) = v28 + *(_DWORD *)(v22 + *(_DWORD *)(this + 12) + 284);
++v27;
v28 += 444;
}
while ( v27 < *(_DWORD *)(v22 + *(_DWORD *)(this + 12) + 288) );
}
}
result = v36 + 1;
v22 += 444;
++v36;
}
while ( v36 < *(_DWORD *)(this + 28332) );
}
v34 = 0;
v37 = 0;
if ( *(int *)(this + 28332) > 0 )
{
v29 = 0;
do
{
v30 = v29 + *(_DWORD *)(this + 12);
if ( *(_BYTE *)(v30 + 54) )
*(_DWORD *)(v30 + 416) = sub_441150((const char *)this, (char *)(v30 + 54), v34++);
else
*(_DWORD *)(v30 + 416) = 0;
v31 = 0;
for ( i = 0; i < *(_DWORD *)(v29 + *(_DWORD *)(this + 12) + 288); ++i )
{
v32 = v31 + *(_DWORD *)(v29 + *(_DWORD *)(this + 12) + 284);
if ( *(_BYTE *)(v32 + 54) )
*(_DWORD *)(v32 + 416) = sub_441150((const char *)this, (char *)(v32 + 54), v34++);
else
*(_DWORD *)(v32 + 416) = 0;
v31 += 444;
}
result = v37 + 1;
v29 += 444;
++v37;
}
while ( v37 < *(_DWORD *)(this + 28332) );
}
return result;
}
when i followed “this” i thought this function could hold some values. i was right.
int __thiscall sub_441150(const char *this, char *Str2, int a3)
{
int v5; // ebp
const char *v6; // esi
int v7; // eax
int v8; // eax
char *Str2a; // [esp+14h] [ebp+4h]
v5 = 0;
if ( *((_DWORD *)this + 7082) - 1 <= 0 )
{
LABEL_7:
v7 = sub_45BE80(&unk_280C160, Str2, a3, 4);
strcpy((char *)&this[56 * *((_DWORD *)this + 7082) + 328], Str2);
*(_DWORD *)&this[56 * *((_DWORD *)this + 7082) + 380] = v7;
v8 = *((_DWORD *)this + 7082) + 1;
*((_DWORD *)this + 7082) = v8;
return *(_DWORD *)&this[56 * v8 + 324];
}
v6 = this + 328;
Str2a = (char *)(this + 328);
while ( _stricmp(v6, Str2) )
{
LABEL_6:
v6 += 56;
++v5;
Str2a = (char *)v6;
if ( v5 >= *((_DWORD *)this + 7082) - 1 )
goto LABEL_7;
}
if ( strlen(v6) != strlen(Str2) )
{
v6 = Str2a;
goto LABEL_6;
}
return *(_DWORD *)&this[56 * v5 + 380];
}
here are the values that came out when i hooked this function:
[hook pre] this=0x071D3560, Str2=0x35AF873E, a3=0x00000000 Str2="chatoutline"
[hook post] ret=0x36A4E500
[hook pre] this=0x071D3560, Str2=0x2BEF866E, a3=0x00000001 Str2="chatguildicon"
[hook post] ret=0x36A4D508
[hook pre] this=0x071D3560, Str2=0x2BEF882A, a3=0x00000002 Str2="chatguildchat"
[hook post] ret=0x36A4E748
[hook pre] this=0x071D3560, Str2=0x2BEF89E6, a3=0x00000003 Str2="chatwhisper"
[hook post] ret=0x36A4FE18
[hook pre] this=0x071D3560, Str2=0x2BEF8BA2, a3=0x00000004 Str2="chatallchat"
[hook post] ret=0x36A4D2C0
[hook pre] this=0x071D3560, Str2=0x2BEF8D5E, a3=0x00000005 Str2="A_button_scrollup"
[hook post] ret=0x36A4D750
[hook pre] this=0x071D3560, Str2=0x2BEF8F1A, a3=0x00000006 Str2="A_button_scrolldown"
[hook post] ret=0x36A4C510
[hook pre] this=0x071D3560, Str2=0x2BEF90D6, a3=0x00000007 Str2="A_scroll_bar1"
[hook post] ret=0x36A4E990
[hook pre] this=0x071D3560, Str2=0x35AF88FA, a3=0x00000008 Str2="chatinput"
[hook post] ret=0x36A4EE20
[hook pre] this=0x071D3560, Str2=0x2E472BAE, a3=0x00000009 Str2="outdown"
[hook post] ret=0x36A50060
[hook pre] this=0x071D3560, Str2=0x35AF8AB6, a3=0x0000000A Str2="minimap"
[hook post] ret=0x36A502A8
[hook pre] this=0x071D3560, Str2=0x2E471D1E, a3=0x0000000B Str2="closewin"
[hook post] ret=0x36A4F068
[hook pre] this=0x071D3560, Str2=0x35AF8C72, a3=0x0000000C Str2="mainright"
[hook post] ret=0x36A50BC8
[hook pre] this=0x071D3560, Str2=0x2BEF505E, a3=0x0000000D Str2="QSlotNum1"
[hook post] ret=0x36A4F2B0
[hook pre] this=0x071D3560, Str2=0x2BEF521A, a3=0x0000000E Str2="QSlotNum2"
[hook post] ret=0x36A4F4F8
[hook pre] this=0x071D3560, Str2=0x2BEF652E, a3=0x0000000F Str2="QSlotNum2_up"
[hook post] ret=0x36A504F0
[hook pre] this=0x071D3560, Str2=0x2BEF66EA, a3=0x00000010 Str2="QSlotNum1_up"
[hook post] ret=0x36A50980
[hook pre] this=0x071D3560, Str2=0x35AF8E2E, a3=0x00000011 Str2="outright"
[hook post] ret=0x36A50738
[hook pre] this=0x071D3560, Str2=0x2E7001AE, a3=0x00000012 Str2="outleft"
[hook post] ret=0x36A4C9A0
[hook pre] this=0x071D3560, Str2=0x35AF8FEA, a3=0x00000013 Str2="outleft"
[hook post] ret=0x36A54DF0
[hook pre] this=0x071D3560, Str2=0x2E6FD5CE, a3=0x00000014 Str2="mainup"
[hook post] ret=0x36A52970
[hook pre] this=0x071D3560, Str2=0x35AF91A6, a3=0x00000015 Str2="mainupfaceout"
[hook post] ret=0x36A53048
[hook pre] this=0x071D3560, Str2=0x2E3E6C7E, a3=0x00000016 Str2="mainuphpbar"
[hook post] ret=0x36A554C8
[hook pre] this=0x071D3560, Str2=0x2E3E6E3A, a3=0x00000017 Str2="mainupmpbar"
[hook post] ret=0x36A53720
[hook pre] this=0x071D3560, Str2=0x2E3E6FF6, a3=0x00000018 Str2="A_expbar"
[hook post] ret=0x36A512A0
[hook pre] this=0x071D3560, Str2=0x35AF9362, a3=0x00000019 Str2="mainupfaceout"
[hook post] ret=0x36A53048
[hook pre] this=0x071D3560, Str2=0x2E3E8826, a3=0x0000001A Str2="mainuphpbar"
[hook post] ret=0x36A554C8
[hook pre] this=0x071D3560, Str2=0x2E3E89E2, a3=0x0000001B Str2="mainupmpbar"
[hook post] ret=0x36A53720
[hook pre] this=0x071D3560, Str2=0x2E3E8B9E, a3=0x0000001C Str2="A_expbar"
[hook post] ret=0x36A514E8
[hook pre] this=0x071D3560, Str2=0x35AF951E, a3=0x0000001D Str2="mainupfaceout"
[hook post] ret=0x36A53048
[hook pre] this=0x071D3560, Str2=0x2E3E7206, a3=0x0000001E Str2="mainuphpbar"
[hook post] ret=0x36A554C8
[hook pre] this=0x071D3560, Str2=0x2E3E73C2, a3=0x0000001F Str2="mainupmpbar"
[hook post] ret=0x36A53720
[hook pre] this=0x071D3560, Str2=0x2E3E757E, a3=0x00000020 Str2="A_expbar"
[hook post] ret=0x36A512A0
[hook pre] this=0x071D3560, Str2=0x35AF96DA, a3=0x00000021 Str2="mainupfaceout"
[hook post] ret=0x36A53048
[hook pre] this=0x071D3560, Str2=0x2E3EA3CE, a3=0x00000022 Str2="mainuphpbar"
[hook post] ret=0x36A554C8
[hook pre] this=0x071D3560, Str2=0x2E3EA58A, a3=0x00000023 Str2="mainupmpbar"
[hook post] ret=0x36A53720
[hook pre] this=0x071D3560, Str2=0x2E3EA746, a3=0x00000024 Str2="A_expbar"
[hook post] ret=0x36A512A0
[hook pre] this=0x071D3560, Str2=0x35AF9896, a3=0x00000025 Str2="maindown"
[hook post] ret=0x36A53968
[hook pre] this=0x071D3560, Str2=0x2FD67C5E, a3=0x00000026 Str2="maindown_store"
[hook post] ret=0x36A51978
[hook pre] this=0x071D3560, Str2=0x2FD67E1A, a3=0x00000027 Str2="maindown_master"
[hook post] ret=0x36A51730
[hook pre] this=0x071D3560, Str2=0x2FD67FD6, a3=0x00000028 Str2="maindown_core"
[hook post] ret=0x36A54960
[hook pre] this=0x071D3560, Str2=0x2FD68192, a3=0x00000029 Str2="maindown_item"
[hook post] ret=0x36A54288
[hook pre] this=0x071D3560, Str2=0x2FD6834E, a3=0x0000002A Str2="maindown_skill"
[hook post] ret=0x36A53290
[hook pre] this=0x071D3560, Str2=0x2FD6850A, a3=0x0000002B Str2="maindown_commu"
[hook post] ret=0x36A52E00
[hook pre] this=0x071D3560, Str2=0x2FD686C6, a3=0x0000002C Str2="maindown_quest"
[hook post] ret=0x36A54BA8
[hook pre] this=0x071D3560, Str2=0x2FD68882, a3=0x0000002D Str2="maindown_map"
[hook post] ret=0x36A52298
[hook pre] this=0x071D3560, Str2=0x2FD68A3E, a3=0x0000002E Str2="maindown_sytem"
[hook post] ret=0x36A53DF8
[hook pre] this=0x071D3560, Str2=0x35AF9A52, a3=0x0000002F Str2="statuswin"
[hook post] ret=0x36A524E0
[hook pre] this=0x071D3560, Str2=0x08880086, a3=0x00000030 Str2="A_button_x"
[hook post] ret=0x2F9C5170
[hook pre] this=0x071D3560, Str2=0x08880242, a3=0x00000031 Str2="in071"
[hook post] ret=0x36A54040
[hook pre] this=0x071D3560, Str2=0x088803FE, a3=0x00000032 Str2="in072"
[hook post] ret=0x36A51BC0
[hook pre] this=0x071D3560, Str2=0x088805BA, a3=0x00000033 Str2="A_button_plus"
[hook post] ret=0x36A52BB8
[hook pre] this=0x071D3560, Str2=0x08880776, a3=0x00000034 Str2="A_button_plus"
[hook post] ret=0x36A544D0
[hook pre] this=0x071D3560, Str2=0x08880932, a3=0x00000035 Str2="A_button_plus"
[hook post] ret=0x36A52BB8
[hook pre] this=0x071D3560, Str2=0x08880AEE, a3=0x00000036 Str2="A_button_plus"
[hook post] ret=0x36A52BB8
[hook pre] this=0x071D3560, Str2=0x35AF9C0E, a3=0x00000037 Str2="monsterinfo"
[hook post] ret=0x36A534D8
[hook pre] this=0x071D3560, Str2=0x2FA310E6, a3=0x00000038 Str2="A_button_x"
[hook post] ret=0x2F9C5170
[hook pre] this=0x071D3560, Str2=0x2FA312A2, a3=0x00000039 Str2="in071"
[hook post] ret=0x36A54040
[hook pre] this=0x071D3560, Str2=0x2FA3145E, a3=0x0000003A Str2="in072"
[hook post] ret=0x36A51BC0
[hook pre] this=0x071D3560, Str2=0x2FA3161A, a3=0x0000003B Str2="A_button_scrollup"
[hook post] ret=0x36A4D750
[hook pre] this=0x071D3560, Str2=0x2FA317D6, a3=0x0000003C Str2="A_button_scrolldown"
[hook post] ret=0x36A4C510
[hook pre] this=0x071D3560, Str2=0x2FA31992, a3=0x0000003D Str2="A_scroll_bar1"
[hook post] ret=0x36A4E990
[hook pre] this=0x071D3560, Str2=0x2FA31B4E, a3=0x0000003E Str2="A_select_box"
[hook post] ret=0x36A51E08
[hook pre] this=0x071D3560, Str2=0x2FA31D0A, a3=0x0000003F Str2="userselect"
[hook post] ret=0x2F9CDC98
[hook pre] this=0x071D3560, Str2=0x2FA31EC6, a3=0x00000040 Str2="A_select_box"
[hook post] ret=0x36A53BB0
[hook pre] this=0x071D3560, Str2=0x2FA35112, a3=0x00000041 Str2="henchitemcover"
[hook post] ret=0x36A54718
[hook pre] this=0x071D3560, Str2=0x35AF9DCA, a3=0x00000042 Str2="invenwin"
[hook post] ret=0x36A50E10
[hook pre] this=0x071D3560, Str2=0x36CA64E6, a3=0x00000043 Str2="A_button_x"
[hook post] ret=0x2F9C5170
[hook pre] this=0x071D3560, Str2=0x36CA66A2, a3=0x00000044 Str2="A_button_scrollup"
[hook post] ret=0x36A4D750
[hook pre] this=0x071D3560, Str2=0x36CA685E, a3=0x00000045 Str2="A_button_scrolldown"
[hook post] ret=0x36A4C510
[hook pre] this=0x071D3560, Str2=0x36CA6A1A, a3=0x00000046 Str2="A_scroll_bar1"
[hook post] ret=0x36A4E990
[hook pre] this=0x071D3560, Str2=0x36CA8952, a3=0x00000047 Str2="A_select_box"
[hook post] ret=0x36A51E08
[hook pre] this=0x071D3560, Str2=0x36CA9E22, a3=0x00000048 Str2="mix_sort_00"
[hook post] ret=0x36A55038
[hook pre] this=0x071D3560, Str2=0x36CAA19A, a3=0x00000049 Str2="mix_sort_01_push"
[hook post] ret=0x36A52728
[hook pre] this=0x071D3560, Str2=0x35AF9F86, a3=0x0000004A Str2="skillwin_New"
[hook post] ret=0x36A55280
[hook pre] this=0x071D3560, Str2=0x35B026D6, a3=0x0000004B Str2="A_button_x"
unfortunately none of these gave me anything useful. maybe they help later but my goal now is to make a farmbot. it felt like trying to build a catalytic converter before inventing fire, so i will not work with these functions.
do you remember something we saw in mixmaster.dll? search the page for “HideMonstersub_6EA8710A”. that is the function i mean. when we open it it shows the pseudocode below.
int HideMonstersub_6EA86DEE()
{
int result; // eax
int v1; // ebx
char v2[256]; // [esp+14h] [ebp-164h] BYREF
int v3; // [esp+114h] [ebp-64h] BYREF
int v4; // [esp+118h] [ebp-60h] BYREF
__int64 v5; // [esp+11Ch] [ebp-5Ch]
__int64 v6; // [esp+124h] [ebp-54h]
__int64 v7; // [esp+12Ch] [ebp-4Ch]
int v8; // [esp+134h] [ebp-44h]
__int64 v9; // [esp+138h] [ebp-40h]
int v10; // [esp+140h] [ebp-38h]
void *v11; // [esp+144h] [ebp-34h]
int v12; // [esp+148h] [ebp-30h]
int v13; // [esp+14Ch] [ebp-2Ch]
int v14; // [esp+150h] [ebp-28h]
int v15; // [esp+154h] [ebp-24h]
int v16; // [esp+158h] [ebp-20h]
int v17; // [esp+15Ch] [ebp-1Ch]
int v18; // [esp+160h] [ebp-18h]
int v19; // [esp+164h] [ebp-14h]
int v20; // [esp+168h] [ebp-10h]
int v21; // [esp+16Ch] [ebp-Ch]
result = (unsigned __int8)byte_6EC040A9;
if ( byte_6EC040A9 )
{
if ( dword_6EC040E0 == 345 )
byte_6EC040A9 = 0;
if ( dword_6EC040E0 == 155 )
{
v6 = sub_6EA8177C();
v20 = HIDWORD(v6);
v21 = v6;
if ( SHIDWORD(v6) > 491 && v20 <= 520 )
{
if ( v21 <= 761 || v21 > 790 )
{
if ( v21 > 802 && v21 <= 827 )
{
if ( (unsigned __int8)sub_6EAAF8B4(dword_6EC04178) )
(*(void (__fastcall **)(int))(*(_DWORD *)dword_6EC04178 + 16))(dword_6EC04178);
else
(*(void (__fastcall **)(int))(*(_DWORD *)dword_6EC04178 + 20))(dword_6EC04178);
}
}
else if ( (unsigned __int8)sub_6EAAF8B4(dword_6EC04170) )
{
(*(void (__fastcall **)(int))(*(_DWORD *)dword_6EC04170 + 16))(dword_6EC04170);
}
else
{
(*(void (__fastcall **)(int))(*(_DWORD *)dword_6EC04170 + 20))(dword_6EC04170);
}
}
}
if ( dword_6EC040E0 == 306 )
{
v5 = sub_6EA8177C();
v18 = HIDWORD(v5);
v19 = v5;
if ( SHIDWORD(v5) > 415 && v18 <= 431 && v19 > 883 && v19 <= 946 )
{
v17 = sub_6EA81FBD();
if ( v17 == 101 || v17 == 102 || v17 == 3 || v17 == 23 )
{
v13 = -1249005;
v12 = -16777216;
sub_6EA82D38((int)v2, (int)"[System] : You can't hide monsters on this map!");
return sub_6EA815F6((int)v2, v13, v12);
}
byte_6EC04115 ^= 1u; // here is this.
//
sub_6EA82F36(byte_6EC04115);
if ( dword_6EB8A008 )
v16 = dword_6EB8A008();
v15 = -1249005;
v14 = -16777216;
if ( byte_6EC04115 )
sub_6EA82D38((int)v2, (int)"[System] : Monsters are now hidden.");
else
sub_6EA82D38((int)v2, (int)"[System] : Monsters are now visible.");
sub_6EA815F6((int)v2, v15, v14);
}
}
v7 = sub_6EA8177C();
v11 = &dword_6EC0412C;
v4 = sub_6EB51B80(&dword_6EC0412C);
v3 = sub_6EB51B5C(v11);
while ( 1 )
{
result = sub_6EADADAC(&v4, &v3);
if ( !(_BYTE)result )
break;
v10 = *(_DWORD *)sub_6EADC6BC(&v4);
v1 = dword_6EC040E0;
sub_6EAD4380(0, v7, HIDWORD(v7));
sub_6EAAFCB8(v8, v9, HIDWORD(v9), v1);
sub_6EAD8E34(&v4);
}
}
return result;
}
in the commented line there is code that triggers this value. sub_6EA82F36 does what mixmaster.dll always does, a memory patch. it replaces monster.sct with monster_01.sct.
BOOL __cdecl sub_6EA82F36(char a1)
{
SIZE_T v1; // eax
int v2; // eax
int v3; // eax
DWORD v4; // ebx
SIZE_T v5; // eax
DWORD flOldProtect; // [esp+20h] [ebp-18h] BYREF
LPVOID lpAddress; // [esp+24h] [ebp-14h]
const char *v9; // [esp+28h] [ebp-10h]
const char *v10; // [esp+2Ch] [ebp-Ch]
v10 = ".\\Data\\script\\monster.sct";
v9 = ".\\Data\\script\\monster_01.sct";
lpAddress = (LPVOID)5423888;
v1 = j_strlen(".\\Data\\script\\monster.sct");
VirtualProtect((LPVOID)0x52C310, v1, 0x40u, &flOldProtect);
if ( a1 )
{
v2 = j_strlen(v9);
j_memcpy(lpAddress, v9, v2 + 1);
}
else
{
v3 = j_strlen(v10);
j_memcpy(lpAddress, v10, v3 + 1);
}
v4 = flOldProtect;
v5 = j_strlen(v10);
return VirtualProtect(lpAddress, v5, v4, &flOldProtect);
}
when i first started mixmaster i thought this was very important, so i hooked everything and spent days in the debugger, but it was not a path to the entity list. if you look at our .sct files you will see another monster_01.sct that sets monster.sct values to zero.

this is clearly used to hide npcs in the game. this cost me a lot of time but remember the game is very old. so how will we find the entity list?
our entity list adventure will be a bit long and a bit short.
i didnt understand how the monster hide function worked so i hooked the functions and addresses one by one and debugged them. if all monsters are hidden there should be a function that hides those npcs. there wasnt.
after leaving that approach i decided not to waste time trying to fully solve the engine. instead we should get our hands dirty and find it ourselves. time to use cheat engine. first i looked at game objects. if i could find any enemy HP value, that might lead me to functions with their info and maybe the entity list. npcs would one shot of course. i tried to lower my damage using bad items but it didnt work, so i left that approach too.
what i had to do was the method that always works. move our player and find our x,y.

first we will search unknown value. you can set shortcuts for scans if you want.

now move the character and mark changed value, then mark unchanged, and move again. spam unchanged for a while to reduce the found values in cheat engine. check the values one by one. if a value changes when you move, set a breakpoint to see access/write addresses.

here are some opcodes for values i found.

0041D421 - 8B 85 B4000000 - mov eax,[ebp+000000B4] here ebp is important for us. in the picture below you can see which address ebp is.
now inspect this ebp address in reclass. as you see in reclass when we move only 2 addresses change.

after scrolling a long time in reclass i hoped to find info for other npcs but i did not.
when i saw this offset in reclass it meant nothing to me, note it: 027EEF28. now i’m curious: if 027EEF28 is my localplayer, where are the other entity lists? i looked at references but couldn’t find them. i didn’t want to dig more because every result and every breakpoint showed me meaningless addresses. localplayer didn’t help me find the entity list, but there were other ways.
next step is to find data about enemies… we can’t find hp because i one-shot enemies. but if i attack an enemy and pause the game? the game will have my attack and the target enemy in the command, right? after repeating this 9 times, we set breakpoints to see what writes those addresses.
now let’s look at the opcodes we got from the breakpoint:
MixMaster.exe+151B3:
004151AC - 8B F0 - mov esi,eax
004151AE - B9 79050000 - mov ecx,00000579
004151B3 - BF 185C5400 - mov edi,MixMaster.exe+145C18 <<
004151B8 - F3 A5 - repe movsd
004151BA - 8D 4C 24 0C - lea ecx,[esp+0C]
EAX=0019D20C
EBX=75D42640
ECX=00000572
EDX=04AF0000
ESI=0019D228
EDI=00545C34
ESP=0019D200
EBP=60C834C0
EIP=004151B8
here my eye caught mov edi, MixMaster.exe+145C18. so what is this EDI 00545C34 address? unfortunately it’s an address that is useless.
now i tried every method i know. forget cheat engine. do we have a localplayer? let’s check it in IDA.

yes.. i did it.. i looked at all 165 functions one by one. here’s a short summary of some functions and what they do that i think may be important for you.
Player Stats
int sub_4620B0()
{
_DWORD *v0; // eax
_DWORD *v1; // eax
int v2; // esi
int v3; // edi
_DWORD *v4; // eax
_DWORD *v5; // eax
_DWORD *v6; // eax
_DWORD *v7; // eax
_DWORD *v8; // eax
_DWORD *v9; // eax
_DWORD *v10; // eax
_DWORD *v11; // eax
_DWORD *v12; // eax
_DWORD *v13; // eax
_DWORD *v14; // ecx
double Args; // [esp+0h] [ebp-10h]
char v17; // [esp+8h] [ebp-8h]
v0 = (_DWORD *)sub_4419C0(92);
sub_449180((int)&dword_A76D40, v0[64] + v0[66], v0[67] + v0[65] + 3, 0xFFFFDFBD, 0, 0, 0, 0, aNanmee5445, v17);
v1 = (_DWORD *)sub_4419C0(94);
v2 = v1[66] + v1[64] + 3;
v3 = v1[67] + v1[65] + 3;
Args = sub_41CB50(&off_27EEF28);
sub_449180((int)&dword_A76D40, v2, v3, 0xFF000000, 0, 0, 0, 0, "%.2f%%", SLOBYTE(Args));
v4 = (_DWORD *)sub_4419C0(93);
sub_449180(
(int)&dword_A76D40,
v4[64] + v4[66] + v4[68],
v4[67] + v4[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
dword_27EF1E8);
v5 = (_DWORD *)sub_4419C0(95);
sub_449180(
(int)&dword_A76D40,
v5[66] + v5[64] + 3,
v5[67] + v5[65] + 3,
0xFF000000,
0,
0,
0,
0,
"%d/%d",
word_27EF228);
v6 = (_DWORD *)sub_4419C0(96);
sub_449180(
(int)&dword_A76D40,
v6[66] + v6[64] + 2,
v6[67] + v6[65] + 3,
0xFF000000,
0,
0,
0,
0,
"%d/%d",
word_27EF22A);
v7 = (_DWORD *)sub_4419C0(97);
sub_449180(
(int)&dword_A76D40,
v7[66] + v7[68] + v7[64] - 10,
v7[67] + v7[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF216);
v8 = (_DWORD *)sub_4419C0(98);
sub_449180(
(int)&dword_A76D40,
v8[66] + v8[68] + v8[64] - 10,
v8[67] + v8[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF218);
v9 = (_DWORD *)sub_4419C0(99);
sub_449180(
(int)&dword_A76D40,
v9[66] + v9[68] + v9[64] - 10,
v9[67] + v9[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF21A);
v10 = (_DWORD *)sub_4419C0(100);
sub_449180(
(int)&dword_A76D40,
v10[66] + v10[68] + v10[64] - 10,
v10[67] + v10[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF21C);
v11 = (_DWORD *)sub_4419C0(101);
sub_449180(
(int)&dword_A76D40,
v11[66] + v11[68] + v11[64] - 10,
v11[67] + v11[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF242);
v12 = (_DWORD *)sub_4419C0(107);
sub_449180(
(int)&dword_A76D40,
v12[66] + v12[68] + v12[64] - 10,
v12[67] + v12[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF21A + word_27EF21E);
v13 = (_DWORD *)sub_4419C0(108);
sub_449180(
(int)&dword_A76D40,
v13[66] + v13[68] + v13[64] - 10,
v13[67] + v13[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d",
word_27EF218 + word_27EF220);
v14 = (_DWORD *)sub_4419C0(106);
return sub_449180(
(int)&dword_A76D40,
v14[66] + v14[68] + v14[64] - 10,
v14[67] + v14[65] + 3,
0xFF000000,
0,
2,
0,
0,
"%d~%d",
(((unsigned __int16)word_27EF21A >> 1) + 2 * (unsigned __int16)word_27EF216) / 5 + word_27EF222);
}
Sprite render entity
void sub_477C90()
{
int v0; // esi
_DWORD *v1; // eax
char v2; // bl
char v3; // cl
__int16 v4; // di
int *v5; // eax
int v6; // eax
unsigned __int16 v7; // di
int *v8; // eax
bool v9; // cc
char *v10; // [esp+10h] [ebp-30h]
int v11; // [esp+14h] [ebp-2Ch]
int v12; // [esp+18h] [ebp-28h] BYREF
int v13; // [esp+1Ch] [ebp-24h]
char v14[8]; // [esp+20h] [ebp-20h] BYREF
char v15[12]; // [esp+28h] [ebp-18h] BYREF
int v16; // [esp+3Ch] [ebp-4h]
Concurrency::details::_ReaderWriterLock::_ReaderWriterLock((Concurrency::details::_ReaderWriterLock *)&v12);
v16 = 0;
v11 = 0;
if ( dword_556A44 > 0 )
{
v10 = aBs;
do
{
v0 = *(_DWORD *)v10;
if ( *(_DWORD *)v10 )
{
v1 = *(_DWORD **)(v0 + 36);
v2 = *(_BYTE *)(v0 + 72);
if ( v1 )
{
if ( *v1 )
{
if ( v2 != 1 )
goto LABEL_11;
if ( (int (__thiscall ***)(void *, char))v0 == &off_27EEF28 || *(_BYTE *)(v0 + 22) < 2u )
{
if ( *(_BYTE *)(v0 + 22) < 2u )
{
LABEL_11:
(*(void (__thiscall **)(int, char *))(*(_DWORD *)v0 + 16))(v0, (char *)dword_564454 + 188);
(*(void (__thiscall **)(int, char *))(*(_DWORD *)v0 + 20))(v0, (char *)dword_564454 + 188);
if ( v2 == 1 )
{
v3 = byte_E73920[1336 * *(unsigned __int16 *)(v0 + 6)];
if ( v3 == 1 && dword_E73924[334 * *(unsigned __int16 *)(v0 + 6)] )
{
v4 = 90;
}
else if ( v3 == 5 && dword_E73924[334 * *(unsigned __int16 *)(v0 + 6)] )
{
v4 = 95;
}
else
{
v4 = sub_45A3B0(0, 0, 0) + 25;
}
v5 = (int *)sub_452A80(v14, dword_60E738, dword_60E73C);
v12 = *v5;
v13 = v5[1];
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v14);
v6 = sub_46C820(v0 + 344);
if ( !*(_BYTE *)(v0 + 338) || v6 )
sub_46D670(&v12, v4 + 3, v0);
if ( byte_280CF44 )
sub_46D4B0(&v12, v0);
}
else if ( v2 == 2 )
{
v7 = sub_45A3B0(0, 0, 0);
v8 = (int *)sub_452A80(v15, dword_60E738, dword_60E73C);
v12 = *v8;
v13 = v8[1];
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v15);
v13 -= v7;
sub_46D7A0(&v12, v0);
}
goto LABEL_26;
}
(*(void (__thiscall **)(int, char *))(*(_DWORD *)v0 + 16))(v0, (char *)dword_564454 + 188);
}
}
}
}
LABEL_26:
v9 = ++v11 < dword_556A44;
v10 += 16;
}
while ( v9 );
}
v16 = -1;
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(&v12);
}
this one is more important it’s the function that holds the player’s x, y and the current map.
int sub_469390()
{
_DWORD *v0; // eax
int v1; // ebp
int v2; // esi
int v3; // edi
char v5; // [esp-8h] [ebp-44h]
char v6; // [esp-8h] [ebp-44h]
int v7[2]; // [esp+10h] [ebp-2Ch] BYREF
char v8[8]; // [esp+18h] [ebp-24h] BYREF
char v9[8]; // [esp+20h] [ebp-1Ch] BYREF
char v10[8]; // [esp+28h] [ebp-14h] BYREF
int v11; // [esp+38h] [ebp-4h]
v0 = (_DWORD *)sub_4419C0(23);
v1 = v0[66] + v0[64] + 30;
v2 = v0[65] + v0[67];
v3 = v0[66] + v0[64] + 1;
sub_449180(
(int)&unk_AB0CA8,
v3,
v2,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
v7[0] = v1 - 31;
sub_449180(
(int)&unk_AB0CA8,
v1 - 31,
v2,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v1 - 29,
v2 - 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
v1 -= 30;
sub_449180(
(int)&unk_AB0CA8,
v1,
v2 - 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v7[0],
v2 - 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v3,
v2 + 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v1,
v2 + 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v7[0],
v2 + 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180(
(int)&unk_AB0CA8,
v3,
v2 + 1,
(COLORREF)&unk_FFFFFF,
0,
0,
0,
0,
"<< %s >>",
(char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_449180((int)&unk_AB0CA8, v1, v2, 0, 0, 0, 0, 0, "<< %s >>", (char)&unk_A9CEBC + 148 * dword_27EF1EC);
sub_451590(v8);
v11 = 0;
v5 = *(_DWORD *)sub_451590(v7);
LOBYTE(v11) = 1;
sub_449180((int)&unk_AB0CA8, v3, v2 + 16, 0, 0, 0, 0, 0, "X:%03d, Y: %03d", v5);
LOBYTE(v11) = 0;
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v7);
v11 = -1;
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v8);
sub_451590(v10);
v11 = 2;
v6 = *(_DWORD *)sub_451590(v9);
LOBYTE(v11) = 3;
sub_449180((int)&unk_AB0CA8, v1, v2 + 15, (COLORREF)&unk_FFFFFF, 0, 0, 0, 0, "X:%03d, Y: %03d", v6);
LOBYTE(v11) = 2;
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v9);
v11 = -1;
Concurrency::details::StructuredWorkStealingQueue<Concurrency::details::_UnrealizedChore,Concurrency::details::_CriticalNonReentrantLock>::Reinitialize(v10);
return sub_432EA0(dword_2808D9C, dword_2808DA0 - 10);
}
we found a much more critical function. it runs when we attack entities. if we look at its xrefs (i would but i don’t want to make you read 500+ pseudocode/assembly and give you the same headache), the functions before it check item times and handle movement.
char __thiscall sub_434EB0(int this)
{
int v2; // eax
int v3; // ecx
char v4; // al
const CHAR *v5; // eax
const CHAR *v6; // eax
int v7; // esi
_BYTE *v8; // ebp
const CHAR *v9; // eax
int v10; // eax
int v12; // [esp-18h] [ebp-1Ch]
int v13; // [esp-10h] [ebp-14h]
int v14; // [esp-Ch] [ebp-10h]
v2 = *(_DWORD *)(this + 48);
if ( v2 )
{
if ( *(_BYTE *)(this + 32) != 1 )
{
v2 = sub_4419C0(1131);
if ( *(_BYTE *)(v2 + 281) != 1 )
{
v2 = sub_4419C0(1135);
if ( *(_BYTE *)(v2 + 281) != 1 )
{
v3 = *(_DWORD *)(this + 48);
v4 = *(_BYTE *)(v3 + 72);
if ( v4 == 1 || v4 == 2 )
{
LOBYTE(v2) = BYTE4(dbl_55B4F8);
if ( *(_DWORD *)(v3 + 40) == WORD2(dbl_55B4F8) )
return v2;
if ( !(unsigned __int8)sub_427730(*(_DWORD *)(this + 48)) )
{
v5 = (const CHAR *)sub_430100(1, 55);
LABEL_25:
LOBYTE(v2) = sub_433850(v5, -224, -16777216);
return v2;
}
}
if ( !*(_BYTE *)(this + 52) && !*(_BYTE *)(this + 53) && !*(_BYTE *)(this + 54) )
{
if ( *(_BYTE *)(this + 55) )
{
LABEL_16:
if ( byte_27EF19A == 2 )
{
v6 = (const CHAR *)sub_430100(1, 57);
}
else
{
if ( !(unsigned __int8)sub_419690(&off_27EEF28) )
{
if ( !byte_27EF19A )
{
if ( *(_BYTE *)(*(_DWORD *)(this + 48) + 72) != 3 && !(unsigned __int8)sub_427730(&off_27EEF28) )
{
v5 = (const CHAR *)sub_430100(1, 56);
goto LABEL_25;
}
sub_41D6B0(*(_DWORD *)(this + 48));
}
goto LABEL_27;
}
v6 = (const CHAR *)sub_430100(1, 10);
}
sub_433850(v6, -224, -16777216);
LABEL_27:
v7 = 0;
v8 = &unk_27F55F8;
while ( 1 )
{
LOBYTE(v2) = *(_BYTE *)(this + v7 + 52);
if ( (_BYTE)v2 )
{
if ( *(_BYTE *)(*(_DWORD *)(this + 48) + 72) == 3 )
{
v14 = *(_DWORD *)(this + 48);
v13 = sub_41CEA0(v7);
sub_41CEA0(v7);
if ( (unsigned __int8)sub_417D20(v13, v14) )
{
v12 = sub_41CEA0(v7);
v10 = sub_41CEA0(v7);
sub_4388E0(v10, v12, 1, 1, 2);
}
v2 = *(_DWORD *)(this + 48);
LABEL_38:
LOBYTE(v2) = sub_41D7A0(v7, v2);
goto LABEL_39;
}
LOBYTE(v2) = sub_427730(v8 - 136);
if ( (_BYTE)v2 )
{
v2 = *(_DWORD *)(this + 48);
if ( *(_BYTE *)(v2 + 72) != 4 )
goto LABEL_38;
}
if ( *v8 )
{
v9 = (const CHAR *)sub_430100(1, 56);
LOBYTE(v2) = sub_433850(v9, -224, -16777216);
return v2;
}
}
LABEL_39:
v8 += 512;
++v7;
if ( (int)v8 >= (int)&unk_27F5BF8 )
return v2;
}
}
*(_BYTE *)(this + 55) = 1;
*(_BYTE *)(this + 54) = 1;
*(_BYTE *)(this + 53) = 1;
*(_BYTE *)(this + 52) = 1;
}
if ( !*(_BYTE *)(this + 55) )
goto LABEL_27;
goto LABEL_16;
}
}
}
}
return v2;
}
looking more at these functions gave me some ideas. “entity on target? wait.. entity?” so this might be a function that helps us find the damn entity list.
sub_41D6B0(*(_DWORD *)(this + 48));
after spending time in this function, another function caught my eye. this one clearly sends packets. now i’m curious: what happens if i hook these? they run with our localplayer and run when we attack. so let’s hook them and try something ingame.
thisPtr: 0xAAFCA0
Entity id: 28, Type: 3, Ptr: 0x3F7B74A0
at 0x3F7B74A0
Packet Send - thisPtr: 0x27EEF28, entity: 1065064752
result: 1057500808
yes! finally an offset for the npc we attack. it gave an offset like our localplayer (0x27EEF28) and as you can see in reclass below it gives us the npc’s x,y. next step is to find the other npcs too.

0030 and 0034 are the offsets that show an entity s x and y. for attack we only need the entity offset like we saw in the target_entity hook. so we do not need x and y. sending an attack command is enough. then we use x y and localplayer x y to check distance and attack nearby npcs.
if we put a breakpoint on the monster ptr we get the result below. (the 3F7B02B8 here belongs to another entity. don’t get confused. we didn’t put a breakpoint on a different function.)

because an entity must constantly check the monster x,y, state, hp, we should look at values that increase fast. our targets are opcodes that run about 960 times.
MixMaster.exe+77CAF - 55 - push ebp
MixMaster.exe+77CB0 - 56 - push esi
MixMaster.exe+77CB1 - 57 - push edi
MixMaster.exe+77CB2 - 8B E9 - mov ebp,ecx
MixMaster.exe+77CB4 - 8D 4C 24 18 - lea ecx,[esp+18]
MixMaster.exe+77CB8 - E8 53ADFDFF - call MixMaster.exe+52A10
MixMaster.exe+77CBD - 8B 0D 446A5500 - mov ecx,[MixMaster.exe+156A44] { (116) }
MixMaster.exe+77CC3 - 33 C0 - xor eax,eax
MixMaster.exe+77CC5 - 3B C8 - cmp ecx,eax
MixMaster.exe+77CC7 - 89 44 24 3C - mov [esp+3C],eax
MixMaster.exe+77CCB - 89 44 24 14 - mov [esp+14],eax
MixMaster.exe+77CCF - 0F8E EC010000 - jng MixMaster.exe+77EC1
MixMaster.exe+77CD5 - C7 44 24 10 40EA5400 - mov [esp+10],MixMaster.exe+14EA40 { (3E982310) }
MixMaster.exe+77CDD - 8D 49 00 - lea ecx,[ecx+00]
MixMaster.exe+77CE0 - 8B 44 24 10 - mov eax,[esp+10]
MixMaster.exe+77CE4 - 8B 30 - mov esi,[eax]
MixMaster.exe+77CE6 - 85 F6 - test esi,esi
MixMaster.exe+77CE8 - 0F84 B1010000 - je MixMaster.exe+77E9F
MixMaster.exe+77CEE - 8B 46 24 - mov eax,[esi+24]
MixMaster.exe+77CF1 - 85 C0 - test eax,eax
MixMaster.exe+77CF3 - 8A 5E 48 - mov bl,[esi+48]
MixMaster.exe+77CF6 - 0F84 A3010000 - je MixMaster.exe+77E9F
MixMaster.exe+77CFC - 83 38 00 - cmp dword ptr [eax],00 { 0 }
MixMaster.exe+77CFF - 0F84 9A010000 - je MixMaster.exe+77E9F
MixMaster.exe+77D05 - 80 FB 01 - cmp bl,01 { 1 }
MixMaster.exe+77D08 - 75 2F - jne MixMaster.exe+77D39
MixMaster.exe+77D0A - 81 FE 28EF7E02 - cmp esi,MixMaster.exe+23EEF28 { (0052BE48) }
MixMaster.exe+77D10 - 74 0A - je MixMaster.exe+77D1C
MixMaster.exe+77D12 - 80 7E 16 02 - cmp byte ptr [esi+16],02 { 2 }
MixMaster.exe+77D16 - 0F83 83010000 - jae MixMaster.exe+77E9F
MixMaster.exe+77D1C - 80 7E 16 02 - cmp byte ptr [esi+16],02 { 2 }
MixMaster.exe+77D20 - 72 17 - jb MixMaster.exe+77D39
MixMaster.exe+77D22 - A1 54445600 - mov eax,[MixMaster.exe+164454] { (047C29D0) }
MixMaster.exe+77D27 - 8B 16 - mov edx,[esi]
MixMaster.exe+77D29 - 05 BC000000 - add eax,000000BC { 188 }
MixMaster.exe+77D2E - 50 - push eax
MixMaster.exe+77D2F - 8B CE - mov ecx,esi
MixMaster.exe+77D31 - FF 52 10 - call dword ptr [edx+10]
MixMaster.exe+77D34 - E9 66010000 - jmp MixMaster.exe+77E9F
MixMaster.exe+77D39 - A1 54445600 - mov eax,[MixMaster.exe+164454] { (047C29D0) }
MixMaster.exe+77D3E - 8B 16 - mov edx,[esi]
MixMaster.exe+77D40 - 05 BC000000 - add eax,000000BC { 188 }
MixMaster.exe+77D45 - 50 - push eax
MixMaster.exe+77D46 - 8B CE - mov ecx,esi
MixMaster.exe+77D48 - FF 52 10 - call dword ptr [edx+10]
MixMaster.exe+77D4B - A1 54445600 - mov eax,[MixMaster.exe+164454] { (047C29D0) }
MixMaster.exe+77D50 - 8B 16 - mov edx,[esi]
i checked all the opcodes one by one. we mainly need to look at mov instructions.
MixMaster.exe+77CD5 - C7 44 24 10 40EA5400 - mov [esp+10],MixMaster.exe+14EA40 { (3E982310) }
after checking them i finally hit MixMaster.exe+14EA40. if we open this offset in reclass it will show the result below:
now the step is to check the entity list in IDA. maybe we find something useful. when we look at the entity list pseudocode with 26 refs, we see a similar structure and another address catches my eye: dword_556A44.

i am sure this is the entity count but i had to test. if i do not enter the game both the entity list and entity count show 0. that is expected.

when we enter the game, in places with many enemies the entity_count is around 100 to 120. it changes constantly.

if i go to a small map we see fewer entities, like below. all this is what we need to make our bot.

now we know almost everything about the game. i even understand the hench system (small pets), localplayer stats, how entities work, attack commands, mouse commands, draw functions, the network, item system, skill use functions, chat commands, glitches and many ingame functions in detail. i will not explain everything because finding just the entity list took me a month of work. yes i did not work 24/7 for a month, i checked it in my free time. i will not share some glitches or the full farmbot code. when i wandered the map not knowing anything about the game, people helped me, they offered items and gave advice to a new player. that was kind. i do not want to give anyone an advantage in their game. the info i shared is for spending time to make a bot for a very old mmorpg. i do not want to give a ready project that can be used in the game. i think the player community is very good.
in short, what we do is hook the attack function and an encrypted function i do not want to name, loop the entity list, and because we know 0030 and 0034 are entity x and y, we give the entity offset of the closest entity to our localplayer to that function and execute it.
yes it works. i forgot the entity check so it attacks other monsters. other than that no problem. project finished.
thanks for reading. see you in another blog, bye.