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.

mixmasterfiles

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

mixmasterlauncher

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.

mixmasteringame mixmasteringame2

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.

mixmasterida

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.

mixmasterida2

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 ) mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug2 mixmasterdebug3

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.

mixmasterdebug4

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.

mixmasterdebug5 mixmasterdebug6 mixmasterdebug6 mixmasterdebug6

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.

mixmasterdebug

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

mixmasterdebug

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

mixmasterdebug

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.

mixmasterdebug mixmasterdebug mixmasterdebug

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.

mixmasterdebug

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

mixmasterdebug

all our network is here.

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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

mixmasterdebug

mixmasterdebug

lets search for .sct files in ida.

before looking at all .sct things, lets pick one randomly. i want to check skillinfo.

mixmasterdebug

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.

mixmasterdebug

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: mixmasterdebug

decrypted: mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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

mixmasterdebug

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.

mixmasterdebug

here are some opcodes for values i found.

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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.)

mixmasterdebug

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.

mixmasterdebug

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.

mixmasterdebug

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

mixmasterdebug

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

mixmasterdebug

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.