O2JamO2 Launch Arguments
Overview
O2JamO2 Client (v5.89 — Client/Distribution ID: 726PNA-B1YW-28ZG9M-I5SC-Q0OPM6) is one of two O2Jam Classic clients released by NOWCOM after X2 was terminated. In addition to reworked interfaces, 3K Mode was introduced late into the update iteration, right before the major UI revamp.
It is important to note that 3K Mode introduction is considered major version update within this client sub-version. This is also affect launch arguments:
- Old: Plain text
- New: Encrypted with RSA (using slightly different keys than O2Jam Classic)
The client is unfortunately keep using the same Client/Distribution ID throughout its O2JamO2 lifetime.
This document focuses on the plain text arguments (the older client version).
Command-Line Parsing
The sub_541580 is the primary command-line parser. It is called by sub_542540, which itself is a thin wrapper function that validate against empty args before calling the actual parser logic and invoked by WinMain when the process receives a non-empty lpCmdLine.
When the official service was running, the game was launched via ActiveX from NOWCOM’s web portal, which passed all connection parameters as a command-line string.
If sub_542540 returns 0 (failure), WinMain shows a Korean error message: “홈페이지에서 로그인 후 GameStart를 실행하세요!” (“Please log in from the homepage and run GameStart!”) and exits.
Command-Line Format
OTwo.exe <mode> <unk1> <user_id> <service_name> <password> <gender> <gem> <ftp_host:ftp_port> <ftp_path> <num_servers> [<server_ip> <server_port>]...
Example
OTwo.exe INET 0 khzero76 O2Jam mypassword 1 50000 filedown2.o2jam.com:21 O2Jam/ 2 221.132.84.4 15010 218.50.4.176 15010
Parameters
Service Mode
The first token is compared against two known mode strings:
| Service Mode | Value | Description |
|---|---|---|
O2_INET | 0 | Older NOWCOM style; gender passed as "m"/"f" string |
INET | 1 | Newer NOWCOM style; gender passed as numeric 1/2 |
If the first token is neither O2_INET nor INET, the parse function implied to silently do nothing. Since those locals are uninitialized, the behaviour in this case is undefined.
Unknown Flag
It is parsed as long, stored on the stack, and never consumed. The original game launcher pass 1 as the value.
User ID
A null-terminated string username of the account. The maximum length is 64 bytes and it is to be sent in login packet (opcode 1000).
Buffer overflow happen when the maximum length is not respected. The password will be appended right after the username in the login packet.
Service Name
Retrieved but never stored or used. The original game launcher pass O2Jam as the value.
Password
A null-terminated string password of the account.
By default, the password is never included anywhere in the network payload. But when user id buffer overflow happen, it will appended right after the username.
Gender
The interpretation depends on the client mode set by <mode>
O2_INET: The value is a string;mfor male,ffor female.INET: The value is a numeric string;1for male,2for female. Internally, it is converted via atol and the corresponding letter (morf) is stored instead of the number.
Gem
This is the player’s Gem balance passed from the web portal, which converted and stored as long via atol. The value is likely to be overwritten by room or shop related packet in the game.
It is very-likely a leftover from X2 where the player Gemstar is displayed in the server selection.
FTP
FTP Host, port and path for music download. The original full address is assumed to be filedown2.o2jam.com:21/O2Jam/. Note that FTP port (e.g, :21) is optional and will assume to have value 21 if left unspecified.
Game servers
The number of server followed by pair of server ip address and port separated by space. This format is consistent with previous O2Jam clients.
Development leftover functions
A separate, unreferenced dispatch function exists at sub_542510 with no xrefs. It was likely a development/debugging launcher that was superseded by the ActiveX + cmdline path.
This dispatch checks whether an argument string is provided:
| Condition | Function Called | Behaviour |
|---|---|---|
| Empty/no argument | sub_541AE0 | Read servers from INI (up to 6 entries) |
| Non-empty argument | sub_541FA0 | Ignore argument; hardcode Korean servers |
Both functions force mode to 1 (INET) and read credentials from .\Identifaction.ini.
Note: The filename is misspelled as
Identifaction.ini(missing the secondiin “Identification”) in the binary itself. This typo appears in the string literal.
INI File Format
The file uses the standard Windows INI format, read via GetPrivateProfileStringA.
Validation
Both functions first call GetPrivateProfileStringA(NULL, NULL, NULL, buf, 256, path); passing all NULLs for section and key enumerates all section names. If the return value is 0 (no sections found / file missing), a MessageBox is shown:
- Message: “오투잼 ID를 입력” (“Enter O2Jam ID”)
- Title: “총인자” (“Total Arguments”)
And the function returns without further initialization.
Section: [IDENTIFICATION]
All fields reside under a single section called IDENTIFICATION.
Credential Fields
The credential keys vary by mode, but since both INI functions force mode = 1 (INET), only the mode-1 keys are reachable in practice. The mode-0 keys are dead code within the INI paths but documented here for completeness.
| Mode | Key | Default Value | Max Length | Stored To | Actual Meaning |
|---|---|---|---|---|---|
| 0 | USER_ID1 | khzero_o2 | 256 chars | Data (0x6B91CB) | User ID |
| 0 | PASSWORD1 | m | 256 chars | byte_6B922B | Gender ("m" or "f") |
| 1 | USER_ID | khzero76 | 256 chars | Data (0x6B91CB) | User ID |
| 1 | PASSWORD | m | 256 chars | byte_6B922B | Gender ("m" or "f") |
Despite the key names PASSWORD / PASSWORD1, the values are stored to the gender field. The default value "m". These are not actual passwords; the naming is misleading (likely a leftover from an earlier design where authentication credentials were read from the INI).
The default user IDs khzero_o2 and khzero76 are likely developer test account.
Server Fields
These fields are only read by sub_541AE0 (the “empty argument” path). sub_541FA0 hardcodes servers instead.
The function reads up to 6 server entries using generated key names IP<n> and PORT<n>:
| Key | Default Value | Description |
|---|---|---|
IP1 | 221.132.84.4 | Server 1 IP address |
PORT1 | 15010 | Server 1 port |
IP2 | 221.132.84.4 | Server 2 IP address |
PORT2 | 15010 | Server 2 port |
IP3 | 221.132.84.4 | Server 3 IP address |
PORT3 | 15010 | Server 3 port |
IP4 | 221.132.84.4 | Server 4 IP address |
PORT4 | 15010 | Server 4 port |
IP5 | 221.132.84.4 | Server 5 IP address |
PORT5 | 15010 | Server 5 port |
IP6 | 221.132.84.4 | Server 6 IP address |
PORT6 | 15010 | Server 6 port |
Each IP is read as a string (buffer size 64 chars). Each PORT is read as a string (buffer size 12 chars) and converted via atol.
Hardcoded Values
After reading the INI, both functions set the following fields to hardcoded values; these are not read from the INI:
| Field | Value in sub_541AE0 | Value in sub_541FA0 |
|---|---|---|
Host string (obj+0x114) | filedown2.o2jam.com | filedown2.o2jam.com |
FTP path (obj+0x514) | O2Jam/ | ./ |
Client mode (obj+0x30) | 1 (INET) | 1 (INET) |
Note that neither INI function sets the GEM balance (dword_6B927C), the port field (obj+0x914), or the password global (byte_6B920B). These remain at their zero-initialized defaults.
Example Identifaction.ini
[IDENTIFICATION]
USER_ID=khzero76
PASSWORD=m
IP1=221.132.84.4
PORT1=15010
IP2=218.50.4.176
PORT2=15010
IP3=218.50.4.177
PORT3=15011
IP4=218.50.4.178
PORT4=15011
IP5=221.132.84.4
PORT5=15010
IP6=218.50.4.181
PORT6=15013
Hardcoded Korean Servers
sub_541FA0 ignores both its argument and the INI server keys, instead hardcoding 7 NOWCOM production server entries:
| # | IP | Port | Object Offset |
|---|---|---|---|
| 0 | 221.132.84.4 | 15010 | +0xB0 |
| 1 | 218.50.4.176 | 15010 | +0xC0 |
| 2 | 218.50.4.177 | 15011 | +0xD0 |
| 3 | 218.50.4.178 | 15011 | +0xE0 |
| 4 | 221.132.84.4 | 15010 | +0xF0 |
| 5 | 218.50.4.181 | 15013 | +0x100 |
| 6 | 218.50.4.188 | 15014 | +0x110 |