mirror of
https://gitea.tendokyu.moe/eamuse/docs.git
synced 2025-02-17 10:58:37 +01:00
Encryption details
This commit is contained in:
parent
281a1f5f37
commit
0daa10b01d
@ -89,8 +89,13 @@
|
||||
<h2 id="common"><code>game.sv4_common</code></h2>
|
||||
<h3>Request:</h3>
|
||||
<pre>{% highlight "cxml" %}<call ...>
|
||||
<game method="sv4_common">
|
||||
...placeholder
|
||||
<game method="sv4_common" ver="0">
|
||||
<locid __type="str" />
|
||||
<cstcode __type="str" />
|
||||
<cpycode __type="str" />
|
||||
<hadid __type="str" />
|
||||
<licid __type="str" />
|
||||
<actid __type="str" />
|
||||
</game>
|
||||
</call>{% endhighlight %}</pre>
|
||||
<h3>Response:</h3>
|
||||
@ -117,14 +122,27 @@
|
||||
<h2 id="hiscore"><code>game.sv4_hiscore</code></h2>
|
||||
<h3>Request:</h3>
|
||||
<pre>{% highlight "cxml" %}<call ...>
|
||||
<game method="sv4_hiscore">
|
||||
...placeholder
|
||||
<game method="sv4_hiscore" ver="0">
|
||||
<locid __type="str" />
|
||||
</game>
|
||||
</call>{% endhighlight %}</pre>
|
||||
<h3>Response:</h3>
|
||||
<pre>{% highlight "cxml" %}<response>
|
||||
<game status="??status">
|
||||
...placeholder
|
||||
<sc>
|
||||
<d[]>
|
||||
<id __type="s32" />
|
||||
<ty __type="u32" />
|
||||
<a_sq __type="str" />
|
||||
<a_nm __type="str" />
|
||||
<a_sc __type="u32" />
|
||||
<l_sq __type="str" />
|
||||
<l_nm __type="str" />
|
||||
<l_sc __type="u32" />
|
||||
<avg_sc __type="u32" />
|
||||
<cr __type="s32" />
|
||||
</d>
|
||||
</sc>
|
||||
</game>
|
||||
</response>{% endhighlight %}</pre>
|
||||
|
||||
|
@ -11,10 +11,44 @@
|
||||
<h3>Response:</h3>
|
||||
<pre>{% highlight "cxml" %}<response>
|
||||
<package status="??status">
|
||||
<item[] url="" />
|
||||
<item[] url="" name="" desc="" size="" pkgtype="" sumtype="" sum="" from="" till="" />
|
||||
</package>
|
||||
</response>{% endhighlight %}</pre>
|
||||
<p>A list of all packages available for download.</p>
|
||||
<table>
|
||||
<tr>
|
||||
<td><code>url</code></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>desc</code></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>size</code></td>
|
||||
<td>Size of the resource at <code>url</code> in bytes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>pkgtype</code></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sumtype</code></td>
|
||||
<td>Only allowable value is <code>md5</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>sum</code></td>
|
||||
<td>The <code>sumtype</code> digest of the file at <code>url</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>from</code></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>till</code></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2 id="intend"><code>package.intend</code></h2>
|
||||
<h3>Request:</h3>
|
||||
|
@ -178,6 +178,7 @@
|
||||
<li><code>lobby2</code></li>
|
||||
<li><code>netlog</code></li>
|
||||
<li><code>globby</code></li>
|
||||
<li><code>poseevent</code></li>
|
||||
</ul>
|
||||
<p>I'll try and figure these out in due course, promise!</p>
|
||||
{% endblock %}
|
@ -28,13 +28,83 @@
|
||||
<p>Encryption is not performed using a single static key. Instead, each request and response has its own key that is
|
||||
generated.</p>
|
||||
<p>These keys are generated baesd on the <code>X-Eamuse-Info</code> header.</p>
|
||||
<p>This header loosely follows the format <code>1-[0-9a-f]{8}-[0-9a-f]{4}</code>. This corresponds to
|
||||
<code>[version]-[serial]-[salt]</code>. <b>TODO: Confirm this</b>
|
||||
<p>Keys follow thge format <code>1-[0-9a-f]{8}-[0-9a-f]{4}</code>. This corresponds to
|
||||
<code>[version]-[seconds]-[salt]</code>. The salt is generated by a simple PRNG.
|
||||
</p>
|
||||
<p>Our per-packet key is then generated using <code>md5(serial | salt | KEY)</code>. Identifying <code>KEY</code> is
|
||||
left as an exercise for the reader, however should not be especially challenging. <span style="color: #fff">Check
|
||||
the page source if you're stuck.</span></p>
|
||||
<!-- libavs-win32-ea3.dll:0x10054160 -->
|
||||
<details>
|
||||
<summary>The PRNG</summary>
|
||||
<pre>{% highlight "c" %}
|
||||
uint32_t PRNG_STATE = 0x41c64e6d;
|
||||
|
||||
uint32_t prng() {
|
||||
int upper = (PRNG_STATE * 0x838c9cda) + 0x6072;
|
||||
PRNG_STATE = (PRNG_STATE * 0x41c64e6d + 0x3039) * 0x41c64e6d + 0x3039;
|
||||
return upper & 0x7fff0000 | PRNG_STATE >> 0xf & 0xffff;
|
||||
}
|
||||
{% endhighlight %}</pre>
|
||||
<p>This is a simple linear conguential pseudorandom number generator (what a mouthful) being stepped twice every
|
||||
call. The constants being used for the main LCPRNG are taken from glibc, along with the dropping of the "least
|
||||
random" bit. Where this implementation differs however is that the LCPRNG is stepped twice every call, and that
|
||||
a second LCPRNG is used for the upper 2 bytes.</p>
|
||||
<p>One interesting observation is that the "least random" bit, that is typically discarded by the
|
||||
<code>0x7ff...</code> mask is not actually being discarded here, as the upper two bytes of
|
||||
<code>PRNG_STATE</code>, not the lower two, are used unmasked.
|
||||
</p>
|
||||
<p>Another interseting observation is that due to the nature of LCGs, stepping it twice is no more secure than once.
|
||||
The implementation presented here is actually just a single step of
|
||||
<code>PRNG_STATE = (PRNG_STATE * 0xc2a29a69) + 0xd3dc167e</code>. Make sure to understand cryptography before
|
||||
trying to roll your own!
|
||||
</p>
|
||||
</details>
|
||||
<p>Our per-packet key is then generated using <code>md5(seconds | salt | ENC_KEY)</code>. Identifying
|
||||
<code>ENC_KEY</code> is left as an exercise for the reader, however should not be especially challenging.
|
||||
</p>
|
||||
<details>
|
||||
<summary>Source code details</summary>
|
||||
<p>The interesting stuff can be found at <code>libavs-win32-ea3.dll:0x1002a800</code>. Rather than screenshots, I've
|
||||
gone and tidied up the code somewhat to make it easier to follow. <code>eamuse_info</code> is pre-populated with
|
||||
<code>"X-Eamuse-Info: 1-"</code> by the calling function (<code>0x1000eeed</code>) after which the pointer is
|
||||
incremented to leave it right after that <code>-</code>, ready for us to <code>vsnprintf</code> into it.
|
||||
</p>
|
||||
<pre>{% highlight "c" %}
|
||||
static const char *ENC_KEY[26] = "Wait you didn't think I'd put this here, did you?";
|
||||
|
||||
int xrpc_crypt(char *packet, char *xeamuse_info) {
|
||||
char md5_key[16];
|
||||
char key[32];
|
||||
|
||||
// Copy the {8}-{4} hex char pairs into key as 6 bytes
|
||||
if (copy_from_hex(key, 4, xeamuse_info) == -1)
|
||||
return -1;
|
||||
if (xeamuse_info[8] != '-')
|
||||
return -1;
|
||||
if (copy_from_hex(key + 4, 2, xeamuse_info + 9) == -1)
|
||||
return -1;
|
||||
|
||||
// Add our constant key after the two variable parts...
|
||||
strncpy(key + 6, ENC_KEY, 26);
|
||||
// ...MD5 it all...
|
||||
mdigest_create_local(0, key, 32, md5_key, 16);
|
||||
// ...and use that digest as the key for RC4
|
||||
arc4(packet, md5_key, 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xrpc_key_and_crypt(char *packet, char *eamuse_info, size_t size) {
|
||||
uint64_t miliseconds = read_timer(0);
|
||||
uint32_t seconds = __aulldiv(miliseconds, 1000, 0);
|
||||
uint16_t salt = prng() & 0xffff;
|
||||
|
||||
int bytes_formatted = vsnprintf(eamuse_info, size, "%08x-%04x", seconds, salt);
|
||||
if (bytes_formatted < size) {
|
||||
xrpc_crypt(packet, eamuse_info);
|
||||
}
|
||||
return bytes_formatted;
|
||||
}
|
||||
{% endhighlight %}</pre>
|
||||
|
||||
<p></p>
|
||||
</details>
|
||||
|
||||
<h2 id="lz77">LZ77</h2>
|
||||
<p>Packets are compressed using lzss. The compressed data structure is a repeating cycle of an 8 bit flags byte,
|
||||
|
Loading…
x
Reference in New Issue
Block a user