BIN Files
BIN is one of the most common file types in an SS3D game. As mentioned in our filetype overview post, they store the vast majority of the scripts and dialog strings that make up each game. Their format has evolved over time, from a fairly simple binary encoding, to using AES encryption on top of that encoding, but at their core they are just plain text, typically ASCII, although for some regions they may also contain UTF16 multibyte characters. The two variants of BIN files (normal and AES encrypted) both share the same headers, with the actual encoded contents themselves being the only difference. Their contents vary greatly depending on what they’re intended to do, from simple lists of dialog strings, to complex quest scripts and NPC dialog pages.
The on-disk file consists of a main header, shown below, followed by a single byte “CRC” value, the encoded (or encrypted) text contents, followed by a second “CRC” byte, which should match the first CRC byte, and is used to ensure the file is decoded properly.
struct MHFILE_HEADER
{
DWORD dwVersion;
DWORD dwType;
DWORD dwDataSize;
};
Despite being called a CRC, the two CRC bytes are not actually proper CRCs, but that is what EyaSoft refers to them as, so that is what we are going to call them here. In reality, a more accurate term for them would be a “check value” or “check byte”, but this isn’t nearly as short or reader friendly. As they do serve the purpose of detecting errors in the file, as well as ensuring proper decoding, I can see how EyaSoft came to calling them CRCs.
These CRCs, combined with the header above, give us the file layout shown below in pseudocode.
struct MHFILE
{
DWORD dwVersion;
DWORD dwType;
DWORD dwDataSize;
char CRC1;
char FileData[dwDataSize+1];
char CRC2;
};
The first header field, dwVersion, serves to indicate the version of the BIN file format, so that the client can decide how to decode the BIN file. Its value however, is not a simple unchanging number per version, but instead has to be calculated at runtime as an obfuscation measure. The value stored in the header is the actual BIN version + dwType + dwDataSize. For a normal unencrypted BIN file, the “actual” version is 20040308
, meaning that the version stored in each file’s header is (20040308 + dwType + dwDataSize). In later encrypted BIN files, this version number is different and is what determines which decryption key to use. Interestingly, although this is the first field in the header, when creating a BIN file, we can’t set the version first, although we know ahead of time the size of the data we are encoding, we don’t yet have dwType set, and it is needed to determine the version.
The next header field, dwType, isn’t particularly well named, as it is more of a seed value for the CRC’s, than a bin type like the name would imply. It sets the initial value used in calculating the BIN’s two CRC values, and serves to prevent two files with identical contents, from encoding the same. When a BIN file is saved, dwType’s value is set via rand() % m_Header.dwDataSize + 1
, which boils down to a random number, modulo the size of the data being stored inside the file, plus one. The plus 1 is to ensure the dwType value is always at least 1, regardless of the result of the randomization. In the case of an empty BIN file, dwType is set directly to 1, as seen below. This is followed by finally setting dwVersion, now that we have all the needed information to do so.
if( m_Header.dwDataSize == 0 ) m_Header.dwType = 1;
else m_Header.dwType = rand() % m_Header.dwDataSize + 1;
m_Header.dwVersion = (20040308 + m_Header.dwType + m_Header.dwDataSize);
The final header field, dwDataSize, is largely self explanatory. It stores the size of the data contained within the BIN file, and is used to allocate a correctly sized array to store the BIN contents when the file is being read. You may have noticed we didn’t set this size in the above code snippet, this is because the BIN editor keeps this size field up to date with whatever editing is being done, so the size is always correct.
This leaves us with the actual encoding of the BIN file as the last remaining step. We begin by allocating a new buffer in memory to store the BIN data while we are encoding it, and copying the unencoded text into this working buffer, so that we aren’t working on the BIN editor’s plain text copy. Then, as a safety precaution, we set the last byte of this buffer to a null terminator, just in case it isn’t one already, despite us not really needing that to be the case. The joys of C char buffers eh?
Then the actual encoding begins. We seed the initial CRC variable with dwType, and then iterate over every byte in our working buffer, applying various transforms to the data to obfuscate it. We begin by adding our loop counter to each byte, and then if the loop counter, modulo our dwType seed variable, is zero, we add dwType to that byte as well. We then add the now transformed byte we are working on, onto the CRC variable. Being a char, this is limited to a fairly small number, this relies on the value wrapping around continuously. This whole process is repeated for every byte in our working buffer, and then whatever the CRC variable ends up being once everything is done is stored for later writing out to the BIN file.
m_pBinData = new char[m_Header.dwDataSize+1];
memcpy( m_pBinData, m_pData, m_Header.dwDataSize+1 );
m_pBinData[m_Header.dwDataSize] = 0;
char crc = char(m_Header.dwType);
for( DWORD i = 0; i < m_Header.dwDataSize; ++i )
{
m_pBinData[i] = m_pBinData[i] + char(i);
if( i%m_Header.dwType == 0 ) m_pBinData[i] = m_pBinData[i] + char(m_Header.dwType);
crc = crc + m_pBinData[i];
}
m_crc1 = m_crc2 = crc;
Now that we have an encoded version of our text, and have generated all the needed header fields and the two check bytes, its time to write everything out into the BIN file itself. In the following snippet, assume that sFullFilename contains the name of the BIN file we are saving.
if( fopen_s(&m_fp, sFullFilename, "wb") != 0)
{
return FALSE;
}
if( m_fp )
{
fwrite( &m_Header, sizeof(m_Header), 1, m_fp );
fwrite( &m_crc1, sizeof( char ), 1, m_fp );
fwrite( m_pBinData, sizeof( char ), m_Header.dwDataSize, m_fp );
fwrite( &m_crc1, sizeof( char ), 1, m_fp );
fclose(m_fp);
m_fp = NULL;
}
And there you have it, a normal EyaSoft BIN file, readable by essentially every client version for every SS3D game. Now, while everything is capable of reading this unencrypted format, the later games, mainly LUNA Plus, use an AES encrypted variant. Luckily, this variant closely follows the structure of the original format. In an encrypted BIN, we read the main header, same as a normal BIN, and generate the true version number the same way (subtracting dwType + dwDataSize from dwVersion), but instead of just ensuring this is equal to 20040308
like a normal BIN, we check a list of known versions to see if we know how to decrypt the file. If the version is in fact 20040308
, we treat the file as a normal unencrypted BIN, but if it matches one of the other versions we know about, we branch into the AES specific decoding routine. Below is the list of EyaSoft’s versions, as well as their associated AES keys.
const DWORD dwVersion[] =
{
20040308,
20090506,
20101117,
};
const unsigned char aKey[][512] =
{
"",
"E76B2413958B00E193A1",
"A15H3825287T19G082K8",
};
Now that we know we are trying to read an encrypted file, and we know what key to use to decrypt it, we first have to get our plain text key, into a format that the AES system can understand. This is done by running sscanf
, with the format specifier set to extract numbers, in hexadecimal format, and store them to use as the actual AES key. This means that whatever we have defined as our AES keys in text, MUST be valid hexadecimal. This fact, although known to the EyaSoft developers who wrote this system at the time, as we will see later, wasn’t obvious to others.
int n = 0;
char p = (char*)m_aCurKey;
int keylen = 0;
unsigned char key[512];
memset( key, 0, sizeof( key ) );
while( sscanf( p, "%02X", &n ) > 0 && keylen < (int) sizeof( key ) )
{
key[keylen++] = (unsigned char) n;
p += 2;
}
We have a key, now what? We set up an AES context, a variable the underlying AES library uses to store some state information, and then we use the key we have generated to set the key for this newly created context. After that, things proceed very similarly to a normal BIN file. We read the first CRC / check byte and store it, seed our working CRC variable with dwType from the BIN header. Then we read through the encrypted BIN contents, 16 bytes at a time, and ask the AES library to use the context we set up earlier, to decrypt the 16 byte chunk we just read in. If that is successful, we copy the decrypted bytes into our output buffer, and then add each one to our CRC variable. The CRC variables final value relies on the value overflowing continuously, just like a normal BIN file. We repeat this loop until we each the end of the data, decrypting, storing and calculating our CRC check byte, 16 bytes at a time. Once we are done, we read the second CRC value from the BIN file, and ensure that both the CRCs from the file match each other (indicating successful file reading) and that the CRC from the file matches the one we calculated during our decryption loop (indicating successful decryption).
aes_context aes_ctx;
aes_setkey_dec( &aes_ctx, key, 256 );
fread( &crc1, sizeof(char), 1, fp );
crc = (char)dwType;
for( offset = 0; offset < filesize; offset += 16 )
{
if( fread( buffer, 1, 16, fp ) != 16 )
{
return FALSE;
}
aes_crypt_ecb( &aes_ctx, AES_DECRYPT, buffer, buffer );
for(int i=0; i<16; i++)
{
pData[offset+i] = buffer[i];
crc = crc + pData[offset+i];
}
}
fread( &crc2, sizeof(char), 1, fp );
if((crc1 != crc2) || (crc1 != crc))
And that’s it, we now have plain text acquired from our encrypted BIN file. Now, you may have noticed earlier, that the BIN versions seem to be dates, this holds true for all of EyaSoft’s BIN versions. Many private servers also follow this format for their versions, however it is not a requirement. In reality, the only hard limitations for the version is that they’re an appropriately sized number (32bit), and don’t match an existing version. EyaSoft’s 20090506
version was replaced by the 20101117
one due to LUNA Plus’s source code, containing that 20090506
version, leaking out. With the key public, it no longer served its purpose of protecting the BIN files from tampering, and had to be replaced. How exactly this new key came to be leaked out isn’t entirely clear, although as I later learned, retrieving these keys from any given client is not overly difficult.
Now you may be thinking, “Wait, we didn’t actually do any encryption or decryption anywhere?!” and you’re right. The actual AES functions are in a separate file, and were not written by EyaSoft. This is likely a good thing, as rolling your own encryption is rarely a good idea. Instead, EyaSoft “borrowed” the code from a library that was known at the time as PolarSSL, and is now known as MbedTLS. The latest versions of this file, extracted from MbedTLS, are usable with the BIN system, with a few minor changes to account for 15+ years of function definition changes.
LUNA Private Servers
As mentioned briefly earlier, obtaining the AES keys and versions from most clients is fairly trivial, although as time has gone on, some private servers have come up with different ways to try and prevent that, some of them quite creative. The easiest way to get them out of a normal, non obfuscated client, is to throw LUNAClient.exe (or whatever your particular server has called the client) into a hex editor, and do a search for 20090506
as a 32bit integer. You’ll find only one result, and immediately after it in the hex editor should be the next version, 20101117
, if you see them both, you know you’re on the right track. Look past 20101117
and you’ll find… Who knows? Whatever the server set as their version, most likely. Note down this number, and any additional valid looking numbers you find immediately after each other, and then scroll down a bit more. You’ll find lots of empty space, along with the first EyaSoft AES key, E76B2413958B00E193A1
. Why so much empty space around them? If you scroll back up to where I showed the definitions of the versions and keys, you’ll see they’re defined as an array of 512 byte char arrays. This means lots of wasted space, while also making the keys very easy to spot. Keep going until you find the second EyaSoft key, A15H3825287T19G082K8
, and then with any luck, you’ll find more keys after that, to correspond with those versions we dug out earlier.
A fun thing to note about AES and private servers, which I briefly mentioned earlier, is that the AES keys, in order to be handled properly by the code that turns their string version into an actual key for the AES library to use, need to be valid hexadecimal. And while EyaSoft certainly knew this limitation at the time, and stayed within it, very few others have figured it out. A very large portion of private server’s AES keys are just randomly generated strings, and don’t end up being valid hex. This results in the actual key passed to the AES library being… 0
… That’s right, the key is completely empty, just a zero. This also means that you can reconfigure your BIN editor to try an empty key upon encountering an unknown version, and it will work 50%+ of the time.
The following is a list of every private server I have come across and been able to figure out the format for. The list is roughly in chronological order by the clients last modification date, and will include the version and AES keys, along with any interesting alterations or obfuscations that particular server is using. Some clients use earlier clients versions and keys, likely indicating that they’re a continuation/rebranding of an earlier server, unless there is something new, unique, or interesting in them, these duplicate clients aren’t listed. The list should not be considered to cover EVERY server out there, its just the ones I have personally come across and archived over the years. If you have a client with unknown keys / versions that isn’t listed here, feel free to get in touch via the email in the site footer.
This list will be updated as new clients are discovered and reverse engineered, so check back occasionally if this is something you’re interested in.
Celestia LUNA - 2009
Celestia is a very special case, and has its own dedicated post. Check it out here if you’re interested.
PERFECTMOON - 2014
20140226, "A26H9825287T75G011K5"
OFFICALLUNAPLUS - 2015
Despite what the name might suggest, definitely not official.
20150204, "E76B2413958B00E192A2"
ARCH LUNA - 2016
Arch is an interesting one, both for being one of the more popular & long running private servers, as well as its interesting versions and keys. They were the first to use a non-date based version as far as I know, and the first to use non-ASCII characters in their key. As we now know, keys have to be valid hexadecimal and these are not, however I’m sure it still worked well as an obfuscation tactic.
1934861983, "w8pln4lU저장한5Z2yPYwLT저장한q1BcICOQ0zP저장한kxRP16AuZuJ53l저장한cRfr7ISec저장한ijCvirSS저장한hXPj"
2949672056, "EA59017F5D523850EFDDB4C49C7적된3FF032E82E955C41565AC84314882E1E6823"
CANDYLUNA - 2016
20130606, "E32B2413967B00E193B1"
20140305, "M32G2513856T00E193H2"
LUNAHISPANO - 2016
LUNAHISPANO is interesting in that it is the first client I came across to use a custom version number, but without using AES, although it’s technically lower security since we know the algorithm for decoding a normal BIN, it’s still a decent obfuscation measure, as everyone assumes that all servers are using AES to protect their BIN files.
20150308, "" //NO AES
20150506, "AFERTDURTY45YSD34KFT"
20151117, "ABRTELFTAKRODTER54MS"
DECADE LUNA - 2016
First server I know of to use an alteration of the actual BIN header as an obfuscation. All Decade LUNA Bin files have an extra DWORD in the header, between the version and type fields, that in all known examples has the value of 20052007
. This number doesn’t seem to be used in any actual calculations by Decade LUNA, but rather serves to significantly break any standard BIN editor trying to parse the header. They were also one of the first to use a non-date based version for their BIN files, along with Arch LUNA.
struct MHFILE_HEADER_DECADE
{
DWORD dwVersion;
DWORD dwPadding; // seems to always be 20052007
DWORD dwType;
DWORD dwDataSize;
};
42400598, "B14L2317246E56H627V3"
CLASSIC LUNA - 2017
Probably one of the most complex servers on this list to reverse engineer, this one doesn’t have a hard-coded key at all. The key is generated at runtime, via a fairly complex algorithm. Reversing this one required using IDA Pro and doing live debugging to extract the assembled key from memory once it was generated.
29840419, "D74ED98076735C67700C"
PLAYPARK - 2017
Interesting due to technically being an “Official” server, from a real publisher, developed by a company calling itself FunTime, as far as I can tell, this is just a few former EyaSoft developers who still had copies of all the LUNA assets after EyaSoft closed, it’s not clear whether they have any legal rights to them, or if they simply relied on there being no one else around to contest them on it. Also interesting, despite theoretically being actual former EyaSoft developers, the AES key is not valid hex.
20170111, "Z7KJ0149^7*T1S82@4F1"
GLORIOUS LUNA - 2019
A very interesting obfuscation, Glorious LUNA switched their BINs to use 192bit AES, rather then the default 256bit that everyone else uses. This is a bit counter intuitive, as it is technically weaker encryption, but the fact that you can extract the correct version and key, drop them into your BIN editor, and still have the BINs be unreadable, is a very effective obfuscation, and would keep the majority of people away. Reverse engineering of this one required using IDA PRO and disassembling the client.
20180721, "JLKSHDAUSKJQKLWHA231", AES192
20200322, "CHEATERCHEATERNGENTOTMMK", AES192
20200325, "GAUSAHNGERUSUHGAMEGWFUCK", AES192
CONTROLLEDCHAOS - 2020
20202020, "CCGNLUNAPLUSKEY92020"
20202021, "9OK8RHK0YL8IYCODEQNS"
INDULGE LUNA - 2020
Another interesting case, although they did have one version of their own, they also switched around EyaSoft’s versions and keys, and used them instead. To a casual observer trying to get the keys out of the client executable, you just see the known EyaSoft keys and ignore them, not realizing that they have had their keys switched around. Interestingly, this means that their client can’t read any BINs encrypted with EyaSoft’s normal keys, they had to re-encrypt every single BIN file themselves with these inverted keys.
20200507, "E76B2413958B00E193A1"
20090506, "A15H3825287T19G082K8" //Has EyaSoft's 20101117 key
20101117, "E66B2413958B00E193A2" //Has EyaSoft's 20090506 key
ECLIPSE LUNA - 2020
Eclipse is the start of an interesting trend, most private servers from here out, have similar-looking keys, of the same 64 character length. Why the sudden switch to longer keys? They still aren’t valid hexadecimal, so there is no actual increase in security from the longer string, as they still end up with an effective AES key of 0.
20181015, "GD58762BC5C60G495C869F567769F87G49B3D5G98G36FF07B844FCE372B49E49"
20192126, "HE60973CD6D71H506D970G678870G98H50C2D6H09H47GG18C955GDF483C50D58"
93842972, "FC49651AB4B50F384B958E459658E76F38A2E4F87F25EE09A733EBD261A38D38"
20192011, "MB51248DE5C85F4165E081H569961J04G3C2B3I03Y95TT26D044FES363D69C37" //conflict
UNICORN LUNA - 2022
Unicorn is the first of a long series of clients to introduce our most advanced obfuscation yet, runtime modification. The key is the same as the 20192011
version from Eclipse LUNA when observed in the client executable, however the client rewrites the first three characters to ALM at runtime, giving us the actual key used below. This makes Unicorn LUNA, and all the following clients that also have this behavior, immune to easily stealing keys from, and instead requires disassembly with a tool like IDA Pro to find out what is taking place.
20192011, "ALM1248DE5C85F4165E081H569961J04G3C2B3I03Y95TT26D044FES363D69C37" //conflict
HELIOS LUNA - 2022
Just like Unicorn LUNA, this client rewrites the first three characters to ALM at runtime. The key is otherwise quite similar to Unicorns as well.
20211117, "ALM1238DF5C55F4165E081H569966J04G3C2B3I03Y95YY26D088DES333D96E69"
RA LUNA - 2022
This one is similar to the last two, in that it rewrites the first three characters at runtime, this time to BMN. The key continues to be oddly similar to the preceding ones.
20211123, "BMN1248DE5C85F4165E081H569961J04G3C2B3I03Y95TT26D044FES363D69APR"
LEGEND LUNA - 2022
The trend continues, runtime rewrite of first three characters to ALM, but this time we have a new complication. The normal math used for figuring out the BIN version m_Header.dwVersion - (m_Header.dwType + m_Header.dwDataSize)
isn’t used, but rather that plus is changed to a minus, resulting in m_Header.dwVersion - (m_Header.dwType - m_Header.dwDataSize)
instead. This means that even with the correct key and version, a normal BIN editor won’t be able to open them, due to it computing the version the normal way, and thus it not matching the expected value.
20210110, "ALM4158TE5C85S1365E081H567751K03J1D2S3G05Y95TD26D044FES363G69H13"
20220508, "ALM8ECAADF42D30986938143A1D6CD0444764A1967BE4135B0085DA0E35859A7"
20230102, "ALMDD058C618517F30C341DF889E99E6789D95015DB1C63277BCCAFD9735DAE4"
20232801, "ALMAEC42E0DB76C46424BF89C88BA11BF6C3F175E075CC0B4BD037351B2F5E73"
LUCKY SEASON - 2023
This one uses the same exact key as RA LUNA, but with a different, slightly higher version, and it also rewrites its first three characters of its key at runtime to BMN. However unlike RA LUNA, it uses the same reversed math introduced by Legend LUNA. This means it can’t be opened by a BIN editor configured for RA LUNA, until the math is reversed, as the version will not match one generated with the normal math flow.
20211239, "BMN1248DE5C85F4165E081H569961J04G3C2B3I03Y95TT26D044FES363D69APR"
ODYSSEY LUNA - 2023
Interestingly, this one lacks the runtime rewrite behavior of the last several, and has a key that’s very similar to Eclipse LUNA’s 20192011
key, but with the last three characters modified to APR, like RA LUNA. A different fork of the same root codebase perhaps?
20211123, "MB51248DE5C85F4165E081H569961J04G3C2B3I03Y95TT26D044FES363D69APR"
IPLAY LUNA - 2023
Another oddity, this is one of the only servers to use actual words / a sentence as their AES key. Ineffectually due to it not being valid hexadecimal, but an interesting approach nonetheless. Also interesting is that this one also uses Decade LUNA’s alternate header format, suggesting it may have been based on the same codebase.
20230408, "IPLAYPROJECTWITHGIN"
ARCANE LUNA - 2023
A second server with a sentence for a key, and another, slightly different BIN header. This looks inspired by iPlay LUNA and Decade LUNA, the only other servers to use an alternate header & sentence key in iPlay’s case. This time the extra field is at the end of the header, and is always 20092007
rather than 20052007
like Decade.
struct MHFILE_HEADER_ARCANE
{
DWORD dwVersion;
DWORD dwType;
DWORD dwDataSize;
DWORD dwPadding; //seems to always be 20092007
};
20220604, "ARCANEPROJECTFTAKBAR"
LUNA SPACE - 2023
Like many before it, this key has its first three characters changed to ALM at runtime. it’s version doesn’t quite make sense as a date either.
20232033, "ALM1248DE5C85F4165E081H569961J04G3C2B3I03Y95TT16D044FES463D62H76"
GLADIUS LUNA - 2023
No interesting obfuscations here, but still a bit of an oddity, two versions using the same key.
20191130, "GH43573CD6D71H586E272Y237823V35U63S2P2T25H27RS23F37412DW246A24T23"
20221010, "GH43573CD6D71H586E272Y237823V35U63S2P2T25H27RS23F37412DW246A24T23"
CHRONICLES LUNA- 2023
One of the strangest ones yet, despite the key below being in the client executable, as far as I can tell, it’s either not used due to an error, or it exists solely as a diversion. In reality, Chronicles LUNA uses unencrypted BIN files, with the 20040308
version as expected for unencrypted BINs. However, they aren’t readable in a standard BIN editor due to having Arcane LUNA style alternate headers, with an extra DWORD after the normal header. All the effort of a different BIN header, and then not using encryption, seems like it was probably a mistake rather than the intention.
20240504, "C9F0F895FB98AB9159F5"
GALAXY LUNA - 2025
And yet again, this key has its first three characters changed to ALM at runtime. Its version doesn’t quite make sense as a date either.
20203022, "ALM1248DE5C80G495C869F56825287T1G3C2B3I03Y95TT29A733EBD261A69C37"
RIN LUNA V2 - 2025
RIN LUNA V2 is the continuation of a much earlier server, not featured here as I didn’t manage to archive it during its original run. The first key here likely originates from this earlier version of the server. That first key also conflicts with iPlay LUNA’s key. This is because these seem to have originated from the same developer, following the same AES key format of “server name + PROJECT WITH + “client”. RIN LUNA also uses Decade LUNA’s alternate header format, just like iPlay LUNA did.
In addition, this server’s patches are currently being hosted alongside the patches for a new version of iPlay LUNA, Universe LUNA, and ODIN LUNA V2 which is unreleased at the time of writing this (07/19/2025). This fact pretty conclusively proves these four servers are closely related, or at least have the involvement of some of the same people.
20230408, "MAUNGAPAINLUBANGHHA" //conflicts with iPlay LUNA
20250221, "RINPROJECTWITHME"
UNIVERSE LUNA - 2025
This one was probably the most complex I’ve come across yet, requiring real time IDA Pro debugging of the running client in order to figure out the key being used. The actual AES key is not directly present in the client but is instead contained inside an encrypted blob, that is decrypted during the very early stages of client startup by MHFile’s constructor. This blob is decrypted using the key KepoBangetLuBoyJadiOrangIdihhh
, whose meaning is completely unknown to me. The actual decrypted key in question is not ASCII, and not easily representable here, but due to the hexadecimal encoding step in AESFile, the actual key used by the AES system for encryption just ends up being a single digit, 6
, padded out to the full key length with zeroes. This is represented below as 06
because the string version of the key needs to be two characters that end up being valid hexadecimal in order to convert properly. So despite this not being the actual key used, it will successfully decrypt every single BIN file in the client.
Also of note is that this server’s patches are hosted in the same location as RIN LUNA V2 above, as well as several other servers mentioned in the RIN LUNA V2 write up, despite being very different from all the other servers related to it. The patcher itself also contains leftover strings referencing Legend LUNA, suggesting this may be based upon that code base.
19940501, "06"
IPLAY LUNA - 2025
You might be thinking, wasn’t iPlay LUNA on here already? You would be right! iPlay LUNA(2023) originally existed for a period of time back in 2023, and as far as I know, has been closed ever since, only to reopen in March of 2025, with a whole new set of AES keys! This client has the largest list of keys I’ve seen thus far, it includes all of Eclipse LUNA’s keys, Unicorn LUNA’s key, and Galaxy LUNA’s key.
Interestingly, despite including all of Eclipse LUNA’s keys, they don’t actually work, due to this client runtime rewriting all of its keys to start with ALM, and any BIN’s dating back to Eclipse LUNA weren’t generated with that particular bit of obfuscation in place. Luckily for them, there aren’t actually any original Eclipse LUNA BIN files left in the client to run into this issue with.
Also interesting, is that at the time of writing (07/19/2025), the iPlay LUNA installer (really just a RAR archive of the client) includes a copy of the BIN editor, capable of opening all the BIN files contained within, completely defeating all the security and obfuscation measures above.
24414058, "ALMU24A8GE5C80G425C869Q568253C7TVG3CRB303Y65TJ29A733EYD261H9PO28"